The Assimilation Project
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
lldp_min.c
Go to the documentation of this file.
1 
26 #include <stdio.h>
27 #include <string.h>
28 #include <lldp.h>
29 #include <tlvhelper.h>
30 #define DIMOF(a) (sizeof(a)/sizeof(a[0]))
31 
74 #define NETTLV_INITPKTOFFSET 14
75 #define NETTLV_HDRSZ 2
76 
78 
79 
82 guint8
83 get_lldptlv_type(const void* tlv_vp,
84  const void* pktend)
85 {
86  return (guint8)((tlv_get_guint8(tlv_vp, pktend)>>1) & 0x7F);
87 }
88 
92 gsize
93 get_lldptlv_len(const void* tlv_vp,
94  const void* pktend)
95 {
96  const unsigned char * tlvp = tlv_vp;
97  guint8 byte0 = tlv_get_guint8(tlvp, pktend);
98  guint8 byte1 = tlv_get_guint8(tlvp+1, pktend);
99 
100  return ((((gsize)(byte0&0x1)) << 8) & (gsize)0x1FF)
101  | ((gsize)byte1) ;
102 }
103 
105 const void *
106 get_lldptlv_body(const void * tlv_vp,
107  const void* pktend)
108 {
109  (void)pktend;
110  return ((const guint8*)tlv_vp + NETTLV_HDRSZ);
111 }
112 
115 gboolean
116 is_valid_lldp_packet(const void* tlv_vp, //<[in] pointer to beginning pf LLDP packet
117  const void* pktend) //<[in] pointer to first byte past the end of the packet
118 {
119  const unsigned reqtypes [] = {LLDP_TLV_CHID,LLDP_TLV_PID, LLDP_TLV_TTL};
120  unsigned j = 0;
121 #ifdef PEDANTIC_LLDP_NERD
122  int lasttype = -1;
123 #endif
124  if (NULL == tlv_vp || ((const guint8*)tlv_vp+NETTLV_HDRSZ) > (const guint8*)pktend) {
125  g_warning("LLDP Invalid because packet is too short\n");
126  return FALSE;
127  }
128  for (tlv_vp = get_lldptlv_first(tlv_vp, pktend)
129  ; NULL != tlv_vp
130  ; tlv_vp = get_lldptlv_next(tlv_vp, pktend)) {
131  unsigned ttype;
132  unsigned length;
133  const guint8* next;
134 
135  if (tlv_vp >= pktend) {
136  return FALSE;
137  }
138  ttype = get_lldptlv_type(tlv_vp, pktend);
139 #ifdef PEDANTIC_LLDP_NERD
140  lasttype = ttype;
141 #endif
142  length = get_lldptlv_len(tlv_vp, pktend);
143  next = (const guint8*)tlv_vp + (length+NETTLV_HDRSZ);
144  if (next > (const guint8*)pktend) {
145  g_warning("LLDP Invalid because TLV entry extends past end\n");
146  return FALSE;
147  }
148  if (ttype == LLDP_TLV_END) {
149  if (get_lldptlv_body(tlv_vp, pktend) == pktend) {
150  return length == 0;
151  }else{
152  g_warning("LLDP Invalid because END item isn't at end of packet\n");
153  return FALSE;
154  }
155  }
156  if (j < DIMOF(reqtypes) && ttype != reqtypes[j]) {
157  g_warning("LLDP Invalid because required TLV type [%d] isn't present in right position (%d)\n"
158  , reqtypes[j], j);
159  return FALSE;
160  }
161  j += 1;
162  }
163 #ifdef PEDANTIC_LLDP_NERD
164  if (lasttype != LLDP_TLV_END) {
165  g_warning("LLDP Invalid because final type wasn't LLDP_TLV_END (it was %d)\n"
166  , lasttype);
167  return FALSE;
168  }
169 #endif
170  return TRUE;
171 }
172 
173 const void *
174 get_lldptlv_first(const void* packet,
175  const void* pktend)
176 {
177  const guint8* inittlv = (const guint8*)packet + NETTLV_INITPKTOFFSET;
178  if (packet == NULL
179  || (inittlv + NETTLV_HDRSZ) > (const guint8*)pktend
180  || (inittlv + NETTLV_HDRSZ + get_lldptlv_len(inittlv, pktend)) > (const guint8*)pktend) {
181  return NULL;
182  }
183  return inittlv;
184 }
185 
187 const void *
188 get_lldptlv_next(const void* tlv_vp,
189  const void* pktend)
190 {
191  const guint8 * nexttlv;
192  const void* nextend;
193  if (tlv_vp == NULL
194  || ((const guint8*)tlv_vp+NETTLV_HDRSZ) > (const guint8*)pktend
195  || get_lldptlv_type(tlv_vp, pktend) == LLDP_TLV_END) {
196  return NULL;
197  }
198  nexttlv = (const guint8*)tlv_vp + NETTLV_HDRSZ + get_lldptlv_len(tlv_vp, pktend);
199  /* Watch out for malformed packets! (BLACKHAT, PARANOIA) */
200  nextend = nexttlv + NETTLV_HDRSZ + get_lldptlv_len(nexttlv, pktend);
201  /* fprintf(stderr, "LOOK: cur:%p, next: %p, nextend: %p, vpend: %p\n"
202  , tlv_vp, nexttlv, nextend, pktend); */
203  return nextend > pktend ? NULL : nexttlv;
204 }
205 
207 const void *
208 find_next_lldptlv_type(const void* tlv_vp,
209  unsigned tlvtype,
210  const void* pktend)
211 {
212  while (NULL != tlv_vp && ((const guint8*)tlv_vp+NETTLV_HDRSZ) <= (const guint8*)pktend) {
213  if (get_lldptlv_type(tlv_vp, pktend) == tlvtype) {
214  return tlv_vp;
215  }
216  tlv_vp = get_lldptlv_next(tlv_vp, pktend);
217  }
218  return NULL;
219 }
220 
223 const void *
224 get_lldp_chassis_id(gconstpointer tlv_vp,
225  gssize* idlength,
226  gconstpointer pktend)
227 {
228  const void * tlventry;
229  tlv_vp = get_lldptlv_first(tlv_vp, pktend);
230  tlventry = find_next_lldptlv_type(tlv_vp, LLDP_TLV_CHID, pktend);
231  if (tlventry == NULL) {
232  return NULL;
233  }
234  *idlength = get_lldptlv_len(tlv_vp, pktend);
235  return get_lldptlv_body(tlv_vp, pktend);
236 }
237 
240 const void *
241 get_lldp_port_id(gconstpointer tlv_vp,
242  gssize* idlength,
243  gconstpointer pktend)
244 {
245  const void * tlventry;
246  tlv_vp = get_lldptlv_first(tlv_vp, pktend);
247  tlventry = find_next_lldptlv_type(tlv_vp, LLDP_TLV_PID, pktend);
248  if (tlventry == NULL) {
249  return NULL;
250  }
251  *idlength = get_lldptlv_len(tlv_vp, pktend);
252  return get_lldptlv_body(tlv_vp, pktend);
253 }
const void * get_lldp_port_id(gconstpointer tlv_vp, gssize *idlength, gconstpointer pktend)
Return a pointer to the port id Value entry, and its length.
Definition: lldp_min.c:241
#define LLDP_TLV_CHID
Chassis ID.
Definition: lldp.h:43
guint8 tlv_get_guint8(const void *vitem, const void *bufend)
Retrieve an unsigned 8 bit integer from the given location with error checking.
Definition: tlvhelper.c:30
#define NETTLV_HDRSZ
Definition: lldp_min.c:75
guint8 get_lldptlv_type(const void *tlv_vp, const void *pktend)
Return the 'Type' of the given LLDP TLV entry The Type is the high order 7 bits from the zeroth byte ...
Definition: lldp_min.c:83
#define LLDP_TLV_END
end of TLV - Length must be zero
Definition: lldp.h:42
#define LLDP_TLV_PID
Port ID.
Definition: lldp.h:44
const void * find_next_lldptlv_type(const void *tlv_vp, unsigned tlvtype, const void *pktend)
Return pointer to the next LLDP entry of the given type at or after the current location.
Definition: lldp_min.c:208
Provides basic Link Layer Discovery Protocol (LLDP) definitions and accessor functions for LLPD packe...
#define DIMOF(a)
Definition: lldp_min.c:30
TLV helper interfaces definitions.
const void * get_lldp_chassis_id(gconstpointer tlv_vp, gssize *idlength, gconstpointer pktend)
Return a pointer to the chassis id Value entry, and its length.
Definition: lldp_min.c:224
const void * get_lldptlv_first(const void *packet, const void *pktend)
Definition: lldp_min.c:174
#define NETTLV_INITPKTOFFSET
Definition: lldp_min.c:74
gboolean is_valid_lldp_packet(const void *tlv_vp, const void *pktend)
Definition: lldp_min.c:116
#define LLDP_TLV_TTL
Time to Live (seconds)
Definition: lldp.h:45
const void * get_lldptlv_next(const void *tlv_vp, const void *pktend)
Return pointer to the next LLDP TLV entry after the current location.
Definition: lldp_min.c:188
gsize get_lldptlv_len(const void *tlv_vp, const void *pktend)
Return the 'Length' of the given LLDP TLV entry.
Definition: lldp_min.c:93
const void * get_lldptlv_body(const void *tlv_vp, const void *pktend)
Return the 'Value' of the given LLDP TLV entry.
Definition: lldp_min.c:106