The Assimilation Project  based on Assimilation version 1.1.7.1474836767
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  if (ttype != 127 && ttype > 16) { // As of this writing, current limit is actually 8...
140  //g_warning("%s.%d: LLDP Invalid because TLV type %d is invalid \n"
141  //, __FUNCTION__, __LINE__, ttype);
142  return FALSE;
143  }
144 #ifdef PEDANTIC_LLDP_NERD
145  lasttype = ttype;
146 #endif
147  length = get_lldptlv_len(tlv_vp, pktend);
148  next = (const guint8*)tlv_vp + (length+NETTLV_HDRSZ);
149  if (next > (const guint8*)pktend) {
150  g_warning("%s.%d: LLDP Invalid because TLV entry extends past end\n"
151  , __FUNCTION__, __LINE__);
152  return FALSE;
153  }
154  if (ttype == LLDP_TLV_END) {
155  if (get_lldptlv_body(tlv_vp, pktend) == pktend) {
156  return length == 0;
157  }else{
158  g_warning("%s.%d: LLDP Invalid because END item isn't at end of packet\n"
159  , __FUNCTION__, __LINE__);
160  return FALSE;
161  }
162  }
163  if (j < DIMOF(reqtypes) && ttype != reqtypes[j]) {
164  g_warning("%s.%d: LLDP Invalid because required TLV type [%d] isn't present in right position (%d)\n"
165  , __FUNCTION__, __LINE__, reqtypes[j], j);
166  return FALSE;
167  }
168  j += 1;
169  }
170 
171  if (j < DIMOF(reqtypes)) {
172  // If it's wildly invalid - it's probably a CDP packet...
173  if (j > 0) {
174  g_warning("%s.%d: LLDP Invalid because required TLV types are missing (%d)\n"
175  , __FUNCTION__, __LINE__, j);
176  }
177  return FALSE;
178  }
179 #ifdef PEDANTIC_LLDP_NERD
180  if (tlv_vp != NULL || tlv_vp < pktend) {
181  g_warning("%s.%d: LLDP Invalid because packet longer than TLVs account for (%d)\n"
182  , __FUNCTION__, __LINE__, j);
183  return FALSE;
184  }
185  if (lasttype != LLDP_TLV_END) {
186  g_warning("LLDP Invalid because final type wasn't LLDP_TLV_END (it was %d)\n"
187  , lasttype);
188  return FALSE;
189  }
190 #endif
191  return TRUE;
192 }
193 
194 const void *
195 get_lldptlv_first(const void* packet,
196  const void* pktend)
197 {
198  const guint8* inittlv = (const guint8*)packet + NETTLV_INITPKTOFFSET;
199  if (packet == NULL
200  || (inittlv + NETTLV_HDRSZ) > (const guint8*)pktend
201  || (inittlv + NETTLV_HDRSZ + get_lldptlv_len(inittlv, pktend)) > (const guint8*)pktend) {
202  return NULL;
203  }
204  return inittlv;
205 }
206 
208 const void *
209 get_lldptlv_next(const void* tlv_vp,
210  const void* pktend)
211 {
212  const guint8 * nexttlv;
213  const void* nextend;
214  if (tlv_vp == NULL
215  || ((const guint8*)tlv_vp+NETTLV_HDRSZ) > (const guint8*)pktend
216  || get_lldptlv_type(tlv_vp, pktend) == LLDP_TLV_END) {
217  return NULL;
218  }
219  nexttlv = (const guint8*)tlv_vp + NETTLV_HDRSZ + get_lldptlv_len(tlv_vp, pktend);
220  /* Watch out for malformed packets! (BLACKHAT, PARANOIA) */
221  nextend = nexttlv + NETTLV_HDRSZ + get_lldptlv_len(nexttlv, pktend);
222  /* fprintf(stderr, "LOOK: cur:%p, next: %p, nextend: %p, vpend: %p\n"
223  , tlv_vp, nexttlv, nextend, pktend); */
224  return nextend > pktend ? NULL : nexttlv;
225 }
226 
228 const void *
229 find_next_lldptlv_type(const void* tlv_vp,
230  unsigned tlvtype,
231  const void* pktend)
232 {
233  while (NULL != tlv_vp && ((const guint8*)tlv_vp+NETTLV_HDRSZ) <= (const guint8*)pktend) {
234  if (get_lldptlv_type(tlv_vp, pktend) == tlvtype) {
235  return tlv_vp;
236  }
237  tlv_vp = get_lldptlv_next(tlv_vp, pktend);
238  }
239  return NULL;
240 }
241 
244 const void *
245 get_lldp_chassis_id(gconstpointer tlv_vp,
246  gssize* idlength,
247  gconstpointer pktend)
248 {
249  const void * tlventry;
250  tlv_vp = get_lldptlv_first(tlv_vp, pktend);
251  tlventry = find_next_lldptlv_type(tlv_vp, LLDP_TLV_CHID, pktend);
252  if (tlventry == NULL) {
253  return NULL;
254  }
255  *idlength = get_lldptlv_len(tlventry, pktend);
256  return get_lldptlv_body(tlventry, pktend);
257 }
258 
261 const void *
262 get_lldp_port_id(gconstpointer tlv_vp,
263  gssize* idlength,
264  gconstpointer pktend)
265 {
266  const void * tlventry;
267  tlv_vp = get_lldptlv_first(tlv_vp, pktend);
268  tlventry = find_next_lldptlv_type(tlv_vp, LLDP_TLV_PID, pktend);
269  if (tlventry == NULL) {
270  return NULL;
271  }
272  *idlength = get_lldptlv_len(tlventry, pktend);
273  return get_lldptlv_body(tlventry, pktend);
274 }
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:262
#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:31
#define NETTLV_HDRSZ
Definition: lldp_min.c:75
#define __FUNCTION__
guint8 get_lldptlv_type(const void *tlv_vp, const void *pktend)
Return the &#39;Type&#39; 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:229
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:245
const void * get_lldptlv_first(const void *packet, const void *pktend)
Definition: lldp_min.c:195
#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:209
gsize get_lldptlv_len(const void *tlv_vp, const void *pktend)
Return the &#39;Length&#39; 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 &#39;Value&#39; of the given LLDP TLV entry.
Definition: lldp_min.c:106