The Assimilation Project
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
cdp_min.c
Go to the documentation of this file.
1 
25 #include <stdio.h>
26 
27 #ifdef _MSC_VER
28 # include <winsock.h>
29 #else
30 # include <netinet/in.h>
31 #endif
32 
33 #include <cdp.h>
34 #include <tlvhelper.h>
59 #define CDP_OVERHEAD 22
61 #define CDP_VERSSZ 1
63 #define CDP_TTLSZ 1
65 #define CDP_CKSUMSZ 2
67 #define CDPINITHDRSZ (CDP_OVERHEAD+CDP_VERSSZ+CDP_TTLSZ+CDP_CKSUMSZ) /* 26 */
69 
77 #define CDPTLV_TYPESZ 2
79 #define CDPTLV_LENSZ 2
81 #define CDPTLV_TYPELENSZ (CDPTLV_TYPESZ+CDPTLV_LENSZ) /* 4 */
83 
85 
92 WINEXPORT gboolean
93 is_valid_cdp_packet(const void* packet,
94  const void* pktend)
95 {
96  const unsigned reqtypes [] = {1}; // The set of required initial TLV types
97  // The LLDP list is slighly more impressive ;-)
98  unsigned j = 0;
99  const void* tlv_vp; // Pointer to a TLV entry in the CDP packet.
100  const void* next = NULL;
101  unsigned vers;
102 
103 
104  fprintf(stderr, "Validating CDP packet: %p, pktend: %p\n", packet, pktend);
105  if ((const void *)((const unsigned char *)packet+CDPTLV_TYPELENSZ) > pktend || packet == NULL) {
106  fprintf(stderr, "BAD1 packet: %p, pktend: %p\n", packet, pktend);
107  return FALSE;
108  }
109  /* Heuristic - at this writing, version could be 1 or 2 - Cisco currently defaults to 2 ... */
110  if ((vers=get_cdp_vers(packet, pktend)) < 1 || vers > 4
111  || get_cdp_ttl(packet, pktend) < 3) {
112  fprintf(stderr, "BAD2 packet: %p, pktend: %p [vers=%d, ttl=%d]\n", packet, pktend
113  , get_cdp_vers(packet, pktend), get_cdp_ttl(packet, pktend));
114  return FALSE;
115  }
116 
117  for (tlv_vp = get_cdptlv_first(packet, pktend)
118  ; NULL != tlv_vp && tlv_vp < pktend
119  ; tlv_vp = next) {
120  unsigned ttype;
121  unsigned length;
122 
123  ttype = get_cdptlv_type(tlv_vp, pktend);
124  length = get_cdptlv_len (tlv_vp, pktend);
125  next = (const void *)((const unsigned char *)tlv_vp + length);
126  if ((const void *)((const unsigned char *)tlv_vp+CDPTLV_TYPELENSZ) > pktend) {
127  fprintf(stderr, "BAD3 tlv_vp: %p, pktend: %p j=%d [vers=%d, ttl=%d]\n"
128  , tlv_vp, pktend, j
129  , get_cdp_vers(packet, pktend), get_cdp_ttl(packet, pktend));
130  return FALSE;
131  }
132  if (next > pktend
133  || length < CDPTLV_TYPELENSZ
134  || (j < DIMOF(reqtypes) && ttype != reqtypes[j])) {
135  fprintf(stderr, "BAD4 packet: %p, pktend: %p, next %p, frame %d, type %d\n"
136  , packet, pktend, next, j, ttype);
137  return FALSE;
138  }
139  j += 1;
140  }
141  // The only way to exit that loop without returning FALSE is if tlp_vp == pktend
142  return TRUE;
143 }
144 
147 WINEXPORT guint8
148 get_cdp_vers(const void* pktptr,
149  const void* pktend)
150 {
151  const unsigned char * pkt_uc = pktptr;
152  return tlv_get_guint8(pkt_uc+CDP_OVERHEAD, pktend);
153 }
154 
158 WINEXPORT guint8
159 get_cdp_ttl(const void* pktptr,
160  const void* pktend)
161 {
162  const unsigned char * pkt_uc = pktptr;
163  return tlv_get_guint8(pkt_uc+CDP_OVERHEAD+1, pktend);
164 }
168 WINEXPORT guint16
169 get_cdp_cksum(const void* pktptr,
170  const void* pktend)
171 {
172  const unsigned char * pkt_uc = pktptr;
173  return tlv_get_guint16(pkt_uc+CDP_OVERHEAD+2, pktend);
174 }
175 
178 WINEXPORT guint16
179 get_cdptlv_type(const void* tlv_vp,
180  const void* pktend)
182 {
183  return tlv_get_guint16(tlv_vp, pktend);
184 }
185 
188 WINEXPORT gsize
189 get_cdptlv_len(const void* tlv_vp,
190  const void* pktend)
192 {
193  const unsigned char* tlv_uc = tlv_vp;
194  return tlv_get_guint16(tlv_uc+2, pktend);
195 }
199 WINEXPORT gsize
200 get_cdptlv_vlen(const void* tlv_vp,
201  const void* pktend)
203 {
204  return (unsigned)(get_cdptlv_len(tlv_vp, pktend) - CDPTLV_TYPELENSZ);
205 }
206 
211 WINEXPORT const void *
212 get_cdptlv_body(const void* tlv_vp,
213  const void* pktend)
215 {
216  g_return_val_if_fail(tlv_vp < pktend, NULL);
217  return (const void*)((const unsigned char *)tlv_vp + CDPTLV_TYPELENSZ);
218 }
222 WINEXPORT const void *
223 get_cdptlv_first(const void* pkt,
224  const void* pktend)
225 {
226  gsize len = (const char *)pktend - (const char *)pkt;
227  const unsigned char* ret = (const unsigned char*)pkt;
228  unsigned vers;
229  /*fprintf(stderr, "%s.%d: pkt %p, pktend %p, len %d\n", __FUNCTION__, __LINE__
230  , pkt, pktend, (int)len);*/
231  if (ret == NULL || len < (CDPINITHDRSZ + CDPTLV_TYPELENSZ)
232  /* Note that these version and ttl constraints are heuristics, not absolutes */
233  || (vers=get_cdp_vers(ret, pktend)) < 1 || vers > 5
234  || get_cdp_ttl(ret, pktend) < 2) {
235  /*fprintf(stderr, "%s.%d: pkt %p, pktend %p, len %d vers %d ttl %d\n"
236  , __FUNCTION__, __LINE__
237  , pkt, pktend, (int)len, vers, get_cdp_ttl(ret, pktend));*/
238  return NULL;
239  }
240  ret += CDPINITHDRSZ;
241  if ((ret + get_cdptlv_len(ret, pktend)) > (const unsigned char *)pktend) {
242  /*fprintf(stderr, "%s.%d: pkt %p, pktend %p, tlvlen %d\n"
243  , __FUNCTION__, __LINE__, pkt, pktend, (int)get_cdptlv_len(ret, pktend));*/
244  return NULL;
245  }
246  /*fprintf(stderr, "%s.%d: pkt %p, pktend %p, returning %p\n"
247  , __FUNCTION__, __LINE__, pkt, pktend, ret);*/
248  return (const void *)ret;
249 }
253 WINEXPORT const void *
254 get_cdptlv_next(const void* tlv_vp,
255  const void* tlv_vpend)
256 {
257  const unsigned char* nexttlv;
258  const unsigned char* nextend;
259  if (tlv_vp == NULL) {
260  return NULL;
261  }
262  nexttlv = (const unsigned char*)tlv_vp + get_cdptlv_len(tlv_vp, tlv_vpend);
263  if ((const void *)(nexttlv + CDPTLV_TYPELENSZ) > tlv_vpend) {
264  // In an ideal world nexttlv would exactly equal tlv_vpend...
265  return NULL;
266  }
267  /* Watch out for malformed packets! (BLACKHAT, PARANOIA) */
268  nextend = nexttlv + get_cdptlv_len(nexttlv, tlv_vpend);
269  return ((const void *)nextend > tlv_vpend) ? NULL : nexttlv;
270 }
271 
272 
275 WINEXPORT const void*
276 get_cdp_chassis_id(gconstpointer packet,
277  gssize* idlength,
278  gconstpointer pktend)
279 {
280  const void * tlv_vp;
281  for (tlv_vp=get_cdptlv_first(packet, pktend);
282  tlv_vp != NULL;
283  tlv_vp = get_cdptlv_next(tlv_vp, pktend)) {
284  if (get_cdptlv_type(tlv_vp, pktend) == CDP_TLV_DEVID) {
285  *idlength = get_cdptlv_vlen(tlv_vp, pktend);
286  return get_cdptlv_body(tlv_vp, pktend);
287  }
288  tlv_vp = get_cdptlv_next(tlv_vp, pktend);
289  }
290  return NULL;
291 }
292 
293 
296 WINEXPORT const void*
297 get_cdp_port_id(gconstpointer packet,
298  gssize* idlength,
299  gconstpointer pktend)
300 {
301  const void * tlv_vp;
302  for (tlv_vp=get_cdptlv_first(packet, pktend);
303  tlv_vp != NULL;
304  tlv_vp = get_cdptlv_next(tlv_vp, pktend)) {
305  if (get_cdptlv_type(tlv_vp, pktend) == CDP_TLV_PORTID) {
306  *idlength = get_cdptlv_vlen(tlv_vp, pktend);
307  return get_cdptlv_body(tlv_vp, pktend);
308  }
309  tlv_vp = get_cdptlv_next(tlv_vp, pktend);
310  }
311  return NULL;
312 }
WINEXPORT const void * get_cdptlv_next(const void *tlv_vp, const void *tlv_vpend)
Locate the next CDP TLV triple (iterator).
Definition: cdp_min.c:254
#define CDPTLV_TYPELENSZ
Overhead - offset to the beginning of the CDP TLV Value.
Definition: cdp_min.c:82
WINEXPORT guint16 get_cdptlv_type(const void *tlv_vp, const void *pktend)
Return type from the given TLV triplet in a CDP packet.
Definition: cdp_min.c:179
WINEXPORT guint8 get_cdp_ttl(const void *pktptr, const void *pktend)
Return the time to live for this CDP packet.
Definition: cdp_min.c:159
WINEXPORT guint16 get_cdp_cksum(const void *pktptr, const void *pktend)
Return the 16-bit checksum for this CDP packet.
Definition: cdp_min.c:169
WINEXPORT gsize get_cdptlv_vlen(const void *tlv_vp, const void *pktend)
Return length of the value blob int a given TLV triplet in a CDP packet - value size only...
Definition: cdp_min.c:200
#define CDP_TLV_PORTID
The port from which the CDP update has been sent (ASCII)
Definition: cdp.h:46
WINEXPORT gboolean is_valid_cdp_packet(const void *packet, const void *pktend)
Check to see if this is a valid CDP packet.
Definition: cdp_min.c:93
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
WINEXPORT const void * get_cdp_port_id(gconstpointer packet, gssize *idlength, gconstpointer pktend)
get the port ID associated with this CDP packet
Definition: cdp_min.c:297
WINEXPORT const void * get_cdptlv_first(const void *pkt, const void *pktend)
Return the first CDP TLV triple in a CDP packet.
Definition: cdp_min.c:223
#define WINEXPORT
Definition: projectcommon.h:45
WINEXPORT gsize get_cdptlv_len(const void *tlv_vp, const void *pktend)
Return size of the given TLV triplet.
Definition: cdp_min.c:189
WINEXPORT const void * get_cdp_chassis_id(gconstpointer packet, gssize *idlength, gconstpointer pktend)
Get the chassis ID associated with this CDP packet.
Definition: cdp_min.c:276
#define CDP_TLV_DEVID
Hostname of the device or hardware serial number in ASCII.
Definition: cdp.h:33
#define DIMOF(a)
Definition: lldp_min.c:30
TLV helper interfaces definitions.
WINEXPORT guint8 get_cdp_vers(const void *pktptr, const void *pktend)
Return the CDP protocol version for this packet.
Definition: cdp_min.c:148
Header file for various basic CDP (Cisco Discovery Protocol definitions and accessor functions...
WINEXPORT const void * get_cdptlv_body(const void *tlv_vp, const void *pktend)
Return the body (value) blob of a CDP TLV triplet.
Definition: cdp_min.c:212
#define CDP_OVERHEAD
Number of bytes before the CDP packet itself starts.
Definition: cdp_min.c:60
guint16 tlv_get_guint16(const void *vitem, const void *bufend)
Retrieve an unsigned 16 bit integer from the given location with error checking and without caring ab...
Definition: tlvhelper.c:53
#define CDPINITHDRSZ
Start of the TLV (type, length, value) portion of a CDP packet.
Definition: cdp_min.c:68