The Assimilation Project  based on Assimilation version 1.1.6.1462071269
cdp_min.c
Go to the documentation of this file.
1 
25 #include <stdio.h>
26 #include <memory.h>
27 
28 #ifdef _MSC_VER
29 # include <winsock.h>
30 #else
31 # include <netinet/in.h>
32 #endif
33 
34 #include <cdp.h>
35 #include <tlvhelper.h>
60 #define CDP_OVERHEAD 22
62 #define CDP_VERSSZ 1
64 #define CDP_TTLSZ 1
66 #define CDP_CKSUMSZ 2
68 #define CDPINITHDRSZ (CDP_OVERHEAD+CDP_VERSSZ+CDP_TTLSZ+CDP_CKSUMSZ) /* 26 */
70 
78 #define CDPTLV_TYPESZ 2
80 #define CDPTLV_LENSZ 2
82 #define CDPTLV_TYPELENSZ (CDPTLV_TYPESZ+CDPTLV_LENSZ) /* 4 */
84 
86 
93 WINEXPORT gboolean
94 is_valid_cdp_packet(const void* packet,
95  const void* pktend)
96 {
97 
98  const unsigned reqtypes [] = {CDP_TLV_DEVID, CDP_TLV_PLATFORM, CDP_TLV_VERS, CDP_TLV_CAPS};
99  unsigned foundtypes[32]; // TLV types in this packet
100  unsigned j = 0;
101  const void* tlv_vp; // Pointer to a TLV entry in the CDP packet.
102  const void* next = NULL;
103  unsigned vers;
104 
105 
106  memset(foundtypes, 0, sizeof(foundtypes));
107  //fprintf(stderr, "Validating CDP packet: %p, pktend: %p\n", packet, pktend);
108  if ((const void *)((const unsigned char *)packet+CDPTLV_TYPELENSZ) > pktend || packet == NULL) {
109  fprintf(stderr, "BAD1 packet: %p, pktend: %p\n", packet, pktend);
110  return FALSE;
111  }
112  /* Heuristic - at this writing, version could be 1 or 2 - Cisco currently defaults to 2 ... */
113  vers=get_cdp_vers(packet, pktend);
114  if (vers < 1 || vers > 4) {
115  // Clearly not a CDP packet.
116  return FALSE;
117  }
118  if (get_cdp_ttl(packet, pktend) < 3) {
119  fprintf(stderr, "BAD2 packet: %p, pktend: %p [ttl=%d]\n", packet, pktend
120  , get_cdp_ttl(packet, pktend));
121  return FALSE;
122  }
123 
124  for (tlv_vp = get_cdptlv_first(packet, pktend)
125  ; NULL != tlv_vp && tlv_vp < pktend
126  ; tlv_vp = next) {
127  unsigned ttype;
128  unsigned length;
129 
130  ttype = get_cdptlv_type(tlv_vp, pktend);
131  length = get_cdptlv_len (tlv_vp, pktend);
132  next = (const void *)((const unsigned char *)tlv_vp + length);
133  //fprintf(stderr, "ttype=0x%x, length = %d, here=%p, next=%p end=%p\n"
134  //, ttype, length, tlv_vp, next, pktend);
135  if ((const void *)((const unsigned char *)tlv_vp+CDPTLV_TYPELENSZ) > pktend) {
136  fprintf(stderr, "BAD3 tlv_vp: %p, pktend: %p j=%d [vers=%d, ttl=%d]\n"
137  , tlv_vp, pktend, j
138  , get_cdp_vers(packet, pktend), get_cdp_ttl(packet, pktend));
139  return FALSE;
140  }
141  if (next > pktend || length < CDPTLV_TYPELENSZ) {
142  fprintf(stderr, "BAD4 packet: %p, pktend: %p, next %p, frame %d, type %d\n"
143  , packet, pktend, next, j, ttype);
144  return FALSE;
145  }
146  if (ttype < DIMOF(foundtypes)) {
147  foundtypes[ttype] = TRUE;
148  }
149  j += 1;
150  }
151  // The only way to exit that loop without returning FALSE is if tlp_vp == pktend
152  for (j=0; j < DIMOF(reqtypes); ++j) {
153  if (!foundtypes[reqtypes[j]]) {
154  fprintf(stderr, "%s.%d: invalid CDP packet missing TLV %d"
155  , __FUNCTION__, __LINE__, reqtypes[j]);
156  return FALSE;
157  }
158  }
159  return TRUE;
160 }
161 
164 WINEXPORT guint8
165 get_cdp_vers(const void* pktptr,
166  const void* pktend)
167 {
168  const unsigned char * pkt_uc = pktptr;
169  return tlv_get_guint8(pkt_uc+CDP_OVERHEAD, pktend);
170 }
171 
175 WINEXPORT guint8
176 get_cdp_ttl(const void* pktptr,
177  const void* pktend)
178 {
179  const unsigned char * pkt_uc = pktptr;
180  return tlv_get_guint8(pkt_uc+CDP_OVERHEAD+1, pktend);
181 }
185 WINEXPORT guint16
186 get_cdp_cksum(const void* pktptr,
187  const void* pktend)
188 {
189  const unsigned char * pkt_uc = pktptr;
190  return tlv_get_guint16(pkt_uc+CDP_OVERHEAD+2, pktend);
191 }
192 
195 WINEXPORT guint16
196 get_cdptlv_type(const void* tlv_vp,
197  const void* pktend)
199 {
200  return tlv_get_guint16(tlv_vp, pktend);
201 }
202 
205 WINEXPORT gsize
206 get_cdptlv_len(const void* tlv_vp,
207  const void* pktend)
209 {
210  const unsigned char* tlv_uc = tlv_vp;
211  return tlv_get_guint16(tlv_uc+2, pktend);
212 }
216 WINEXPORT gsize
217 get_cdptlv_vlen(const void* tlv_vp,
218  const void* pktend)
220 {
221  return (unsigned)(get_cdptlv_len(tlv_vp, pktend) - CDPTLV_TYPELENSZ);
222 }
223 
228 WINEXPORT const void *
229 get_cdptlv_body(const void* tlv_vp,
230  const void* pktend)
232 {
233  g_return_val_if_fail(tlv_vp < pktend, NULL);
234  return (const void*)((const unsigned char *)tlv_vp + CDPTLV_TYPELENSZ);
235 }
239 WINEXPORT const void *
240 get_cdptlv_first(const void* pkt,
241  const void* pktend)
242 {
243  gsize len = (const char *)pktend - (const char *)pkt;
244  const unsigned char* ret = (const unsigned char*)pkt;
245  unsigned vers;
246  /*fprintf(stderr, "%s.%d: pkt %p, pktend %p, len %d\n", __FUNCTION__, __LINE__
247  , pkt, pktend, (int)len);*/
248  if (ret == NULL || len < (CDPINITHDRSZ + CDPTLV_TYPELENSZ)
249  /* Note that these version and ttl constraints are heuristics, not absolutes */
250  || (vers=get_cdp_vers(ret, pktend)) < 1 || vers > 5
251  || get_cdp_ttl(ret, pktend) < 2) {
252  /*fprintf(stderr, "%s.%d: pkt %p, pktend %p, len %d vers %d ttl %d\n"
253  , __FUNCTION__, __LINE__
254  , pkt, pktend, (int)len, vers, get_cdp_ttl(ret, pktend));*/
255  return NULL;
256  }
257  ret += CDPINITHDRSZ;
258  if ((ret + get_cdptlv_len(ret, pktend)) > (const unsigned char *)pktend) {
259  /*fprintf(stderr, "%s.%d: pkt %p, pktend %p, tlvlen %d\n"
260  , __FUNCTION__, __LINE__, pkt, pktend, (int)get_cdptlv_len(ret, pktend));*/
261  return NULL;
262  }
263  /*fprintf(stderr, "%s.%d: pkt %p, pktend %p, returning %p\n"
264  , __FUNCTION__, __LINE__, pkt, pktend, ret);*/
265  return (const void *)ret;
266 }
270 WINEXPORT const void *
271 get_cdptlv_next(const void* tlv_vp,
272  const void* tlv_vpend)
273 {
274  const unsigned char* nexttlv;
275  const unsigned char* nextend;
276  if (tlv_vp == NULL) {
277  return NULL;
278  }
279  nexttlv = (const unsigned char*)tlv_vp + get_cdptlv_len(tlv_vp, tlv_vpend);
280  if ((const void *)(nexttlv + CDPTLV_TYPELENSZ) > tlv_vpend) {
281  // In an ideal world nexttlv would exactly equal tlv_vpend...
282  return NULL;
283  }
284  /* Watch out for malformed packets! (BLACKHAT, PARANOIA) */
285  nextend = nexttlv + get_cdptlv_len(nexttlv, tlv_vpend);
286  return ((const void *)nextend > tlv_vpend) ? NULL : nexttlv;
287 }
288 
289 
292 WINEXPORT const void*
293 get_cdp_chassis_id(gconstpointer packet,
294  gssize* idlength,
295  gconstpointer pktend)
296 {
297  const void * tlv_vp;
298  for (tlv_vp=get_cdptlv_first(packet, pktend);
299  tlv_vp != NULL;
300  tlv_vp = get_cdptlv_next(tlv_vp, pktend)) {
301  if (get_cdptlv_type(tlv_vp, pktend) == CDP_TLV_DEVID) {
302  *idlength = get_cdptlv_vlen(tlv_vp, pktend);
303  return get_cdptlv_body(tlv_vp, pktend);
304  }
305  tlv_vp = get_cdptlv_next(tlv_vp, pktend);
306  }
307  return NULL;
308 }
309 
310 
313 WINEXPORT const void*
314 get_cdp_port_id(gconstpointer packet,
315  gssize* idlength,
316  gconstpointer pktend)
317 {
318  const void * tlv_vp;
319  for (tlv_vp=get_cdptlv_first(packet, pktend);
320  tlv_vp != NULL;
321  tlv_vp = get_cdptlv_next(tlv_vp, pktend)) {
322  if (get_cdptlv_type(tlv_vp, pktend) == CDP_TLV_PORTID) {
323  *idlength = get_cdptlv_vlen(tlv_vp, pktend);
324  return get_cdptlv_body(tlv_vp, pktend);
325  }
326  tlv_vp = get_cdptlv_next(tlv_vp, pktend);
327  }
328  return NULL;
329 }
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:271
#define CDPTLV_TYPELENSZ
Overhead - offset to the beginning of the CDP TLV Value.
Definition: cdp_min.c:83
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:196
WINEXPORT guint8 get_cdp_ttl(const void *pktptr, const void *pktend)
Return the time to live for this CDP packet.
Definition: cdp_min.c:176
WINEXPORT guint16 get_cdp_cksum(const void *pktptr, const void *pktend)
Return the 16-bit checksum for this CDP packet.
Definition: cdp_min.c:186
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:217
#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:94
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
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:314
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:240
#define WINEXPORT
Definition: projectcommon.h:45
#define __FUNCTION__
WINEXPORT gsize get_cdptlv_len(const void *tlv_vp, const void *pktend)
Return size of the given TLV triplet.
Definition: cdp_min.c:206
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:293
#define CDP_TLV_VERS
A character string containing the (IOS) software version (same as in show version).
Definition: cdp.h:49
#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.
#define CDP_TLV_PLATFORM
Hardware platform, such as WS-C5000, WS-C6009, or Cisco RSP.
Definition: cdp.h:50
WINEXPORT guint8 get_cdp_vers(const void *pktptr, const void *pktend)
Return the CDP protocol version for this packet.
Definition: cdp_min.c:165
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:229
#define CDP_TLV_CAPS
Bit mask describing the functional capabilities of the device.
Definition: cdp.h:48
#define CDP_OVERHEAD
Number of bytes before the CDP packet itself starts.
Definition: cdp_min.c:61
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:55
#define CDPINITHDRSZ
Start of the TLV (type, length, value) portion of a CDP packet.
Definition: cdp_min.c:69