]> git.ipfire.org Git - thirdparty/lldpd.git/blame - src/daemon/protocols/cdp.c
cdp: don't use comma expression and ternary operator
[thirdparty/lldpd.git] / src / daemon / protocols / cdp.c
CommitLineData
4b292b55 1/* -*- mode: c; c-file-style: "openbsd" -*- */
43c02e7b
VB
2/*
3 * Copyright (c) 2008 Vincent Bernat <bernat@luffy.cx>
4 *
51434125 5 * Permission to use, copy, modify, and/or distribute this software for any
43c02e7b
VB
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
031118c4 18/* We also supports FDP which is very similar to CDPv1 */
43c02e7b 19#include "lldpd.h"
a8105c1b 20#include "frame.h"
43c02e7b 21
4bad1937
VB
22#if defined (ENABLE_CDP) || defined (ENABLE_FDP)
23
aff85bf3 24#include <stdio.h>
a8105c1b 25#include <unistd.h>
43c02e7b
VB
26#include <errno.h>
27#include <arpa/inet.h>
28
8888d191 29static int
77507b69 30cdp_send(struct lldpd *global,
43c02e7b
VB
31 struct lldpd_hardware *hardware, int version)
32{
96beef68 33 const char *platform = "Unknown";
77507b69 34 struct lldpd_chassis *chassis;
e6b36c87 35 struct lldpd_mgmt *mgmt;
619c3799 36 struct lldpd_port *port;
031118c4
VB
37 u_int8_t mcastaddr[] = CDP_MULTICAST_ADDR;
38 u_int8_t llcorg[] = LLC_ORG_CISCO;
6d07eaee 39#ifdef ENABLE_FDP
bf517088 40 char *capstr;
6d07eaee 41#endif
a8105c1b 42 u_int16_t checksum;
f1e5d0cd 43 int length, i;
a8105c1b
VB
44 u_int32_t cap;
45 u_int8_t *packet;
46 u_int8_t *pos, *pos_len_eh, *pos_llc, *pos_cdp, *pos_checksum, *tlv, *end;
43c02e7b 47
6f8925be
VB
48 log_debug("cdp", "send CDP frame on %s", hardware->h_ifname);
49
619c3799
MS
50 port = &(hardware->h_lport);
51 chassis = port->p_chassis;
77507b69 52
6d07eaee 53#ifdef ENABLE_FDP
031118c4 54 if (version == 0) {
a8105c1b 55 /* With FDP, change multicast address and LLC PID */
031118c4
VB
56 const u_int8_t fdpmcastaddr[] = FDP_MULTICAST_ADDR;
57 const u_int8_t fdpllcorg[] = LLC_ORG_FOUNDRY;
58 memcpy(mcastaddr, fdpmcastaddr, sizeof(mcastaddr));
59 memcpy(llcorg, fdpllcorg, sizeof(llcorg));
60 }
6d07eaee 61#endif
031118c4 62
a8105c1b 63 length = hardware->h_mtu;
b0cb07f7 64 if ((packet = (u_int8_t*)calloc(1, length)) == NULL)
a8105c1b 65 return ENOMEM;
a8105c1b
VB
66 pos = packet;
67
68 /* Ethernet header */
69 if (!(
70 POKE_BYTES(mcastaddr, sizeof(mcastaddr)) &&
ed409ccd 71 POKE_BYTES(&hardware->h_lladdr, ETHER_ADDR_LEN) &&
a8105c1b
VB
72 POKE_SAVE(pos_len_eh) && /* We compute the len later */
73 POKE_UINT16(0)))
74 goto toobig;
75
76 /* LLC */
77 if (!(
78 POKE_SAVE(pos_llc) &&
79 POKE_UINT8(0xaa) && /* SSAP */
80 POKE_UINT8(0xaa) && /* DSAP */
81 POKE_UINT8(0x03) && /* Control field */
82 POKE_BYTES(llcorg, sizeof(llcorg)) &&
83 POKE_UINT16(LLC_PID_CDP)))
84 goto toobig;
43c02e7b
VB
85
86 /* CDP header */
a8105c1b
VB
87 if (!(
88 POKE_SAVE(pos_cdp) &&
a8db6007 89 POKE_UINT8((version == 0)?1:version) &&
a8105c1b
VB
90 POKE_UINT8(chassis->c_ttl) &&
91 POKE_SAVE(pos_checksum) && /* Save checksum position */
92 POKE_UINT16(0)))
93 goto toobig;
43c02e7b
VB
94
95 /* Chassis ID */
cdc32f2c 96 const char *chassis_name = chassis->c_name?chassis->c_name:"";
a8105c1b
VB
97 if (!(
98 POKE_START_CDP_TLV(CDP_TLV_CHASSIS) &&
cdc32f2c 99 POKE_BYTES(chassis_name, strlen(chassis_name)) &&
a8105c1b
VB
100 POKE_END_CDP_TLV))
101 goto toobig;
43c02e7b
VB
102
103 /* Adresses */
f1e5d0cd
VB
104 /* See:
105 * http://www.cisco.com/univercd/cc/td/doc/product/lan/trsrb/frames.htm#xtocid12
106 *
107 * It seems that Cisco implies that CDP supports IPv6 using
108 * 802.2 address format with 0xAAAA03 0x000000 0x0800, but
109 * 0x0800 is the Ethernet protocol type for IPv4. Therefore,
110 * we support only IPv4. */
111 i = 0;
112 TAILQ_FOREACH(mgmt, &chassis->c_mgmt, m_entries)
113 if (mgmt->m_family == LLDPD_AF_IPV4) i++;
114 if (i > 0) {
115 if (!(
116 POKE_START_CDP_TLV(CDP_TLV_ADDRESSES) &&
117 POKE_UINT32(i)))
118 goto toobig;
119 TAILQ_FOREACH(mgmt, &chassis->c_mgmt, m_entries) {
120 switch (mgmt->m_family) {
121 case LLDPD_AF_IPV4:
122 if (!(
123 POKE_UINT8(1) && /* Type: NLPID */
124 POKE_UINT8(1) && /* Length: 1 */
125 POKE_UINT8(CDP_ADDRESS_PROTO_IP) && /* IP */
126 POKE_UINT16(sizeof(struct in_addr)) && /* Address length */
127 POKE_BYTES(&mgmt->m_addr, sizeof(struct in_addr))))
128 goto toobig;
129 break;
e6b36c87 130 }
e6b36c87 131 }
f1e5d0cd
VB
132 if (!(POKE_END_CDP_TLV))
133 goto toobig;
e6b36c87 134 }
43c02e7b
VB
135
136 /* Port ID */
cdc32f2c 137 const char *port_descr = hardware->h_lport.p_descr?hardware->h_lport.p_descr:"";
a8105c1b
VB
138 if (!(
139 POKE_START_CDP_TLV(CDP_TLV_PORT) &&
cdc32f2c 140 POKE_BYTES(port_descr, strlen(port_descr)) &&
a8105c1b
VB
141 POKE_END_CDP_TLV))
142 goto toobig;
43c02e7b 143
031118c4
VB
144 /* Capabilities */
145 if (version != 0) {
a8105c1b 146 cap = 0;
031118c4 147 if (chassis->c_cap_enabled & LLDP_CAP_ROUTER)
a8105c1b 148 cap |= CDP_CAP_ROUTER;
031118c4 149 if (chassis->c_cap_enabled & LLDP_CAP_BRIDGE)
e1933880
VB
150 cap |= CDP_CAP_SWITCH;
151 cap |= CDP_CAP_HOST;
a8105c1b
VB
152 if (!(
153 POKE_START_CDP_TLV(CDP_TLV_CAPABILITIES) &&
154 POKE_UINT32(cap) &&
155 POKE_END_CDP_TLV))
156 goto toobig;
6d07eaee 157#ifdef ENABLE_FDP
bf517088
VB
158 } else {
159 /* With FDP, it seems that a string is used in place of an int */
bf517088
VB
160 if (chassis->c_cap_enabled & LLDP_CAP_ROUTER)
161 capstr = "Router";
162 else if (chassis->c_cap_enabled & LLDP_CAP_BRIDGE)
163 capstr = "Switch";
164 else if (chassis->c_cap_enabled & LLDP_CAP_REPEATER)
165 capstr = "Bridge";
166 else
167 capstr = "Host";
a8105c1b
VB
168 if (!(
169 POKE_START_CDP_TLV(CDP_TLV_CAPABILITIES) &&
170 POKE_BYTES(capstr, strlen(capstr)) &&
171 POKE_END_CDP_TLV))
172 goto toobig;
6d07eaee 173#endif
031118c4 174 }
2a19e9ea
VB
175
176 /* Native VLAN */
177#ifdef ENABLE_DOT1
edcce8ce 178 if (version >=2 && hardware->h_lport.p_pvid != 0) {
2a19e9ea
VB
179 if (!(
180 POKE_START_CDP_TLV(CDP_TLV_NATIVEVLAN) &&
181 POKE_UINT16(hardware->h_lport.p_pvid) &&
182 POKE_END_CDP_TLV))
183 goto toobig;
184 }
185#endif
806eaef4 186
43c02e7b 187 /* Software version */
cdc32f2c 188 const char * chassis_descr = chassis->c_descr?chassis->c_descr:"";
a8105c1b
VB
189 if (!(
190 POKE_START_CDP_TLV(CDP_TLV_SOFTWARE) &&
cdc32f2c 191 POKE_BYTES(chassis_descr, strlen(chassis_descr)) &&
a8105c1b
VB
192 POKE_END_CDP_TLV))
193 goto toobig;
43c02e7b
VB
194
195 /* Platform */
96beef68 196 if (global && global->g_config.c_platform) platform = global->g_config.c_platform;
fc37317f 197
a8105c1b
VB
198 if (!(
199 POKE_START_CDP_TLV(CDP_TLV_PLATFORM) &&
d4afb919 200 POKE_BYTES(platform, strlen(platform)) &&
a8105c1b
VB
201 POKE_END_CDP_TLV))
202 goto toobig;
619c3799
MS
203
204#ifdef ENABLE_LLDPMED
205 /* Power use */
206 if ((version >= 2) &&
207 port->p_med_cap_enabled &&
208 (port->p_med_power.source != LLDP_MED_POW_SOURCE_LOCAL) &&
209 (port->p_med_power.val > 0) &&
210 (port->p_med_power.val <= 655)) {
211 if (!(
212 POKE_START_CDP_TLV(CDP_TLV_POWER_CONSUMPTION) &&
213 POKE_UINT16(port->p_med_power.val * 100) &&
214 POKE_END_CDP_TLV))
215 goto toobig;
216 }
217#endif
2d1fe392 218 (void)POKE_SAVE(end);
43c02e7b
VB
219
220 /* Compute len and checksum */
a8105c1b
VB
221 POKE_RESTORE(pos_len_eh);
222 if (!(POKE_UINT16(end - pos_llc))) goto toobig;
223 checksum = frame_checksum(pos_cdp, end - pos_cdp, (version != 0) ? 1 : 0);
224 POKE_RESTORE(pos_checksum);
63e52965 225 if (!(POKE_UINT16(checksum))) goto toobig;
43c02e7b 226
5347914e 227 if (interfaces_send_helper(global, hardware,
6e75df87 228 (char *)packet, end - packet) == -1) {
6f8925be 229 log_warn("cdp", "unable to send packet on real device for %s",
43c02e7b 230 hardware->h_ifname);
a8105c1b 231 free(packet);
43c02e7b
VB
232 return ENETDOWN;
233 }
234
235 hardware->h_tx_cnt++;
236
a8105c1b 237 free(packet);
43c02e7b 238 return 0;
a8105c1b
VB
239 toobig:
240 free(packet);
241 return -1;
43c02e7b
VB
242}
243
a8105c1b
VB
244#define CHECK_TLV_SIZE(x, name) \
245 do { if (tlv_len < (x)) { \
6f8925be 246 log_warnx("cdp", name " CDP/FDP TLV too short received on %s", \
a8105c1b
VB
247 hardware->h_ifname); \
248 goto malformed; \
249 } } while (0)
031118c4 250/* cdp_decode also decodes FDP */
43c02e7b
VB
251int
252cdp_decode(struct lldpd *cfg, char *frame, int s,
253 struct lldpd_hardware *hardware,
254 struct lldpd_chassis **newchassis, struct lldpd_port **newport)
255{
256 struct lldpd_chassis *chassis;
257 struct lldpd_port *port;
e6b36c87
JV
258 struct lldpd_mgmt *mgmt;
259 struct in_addr addr;
4ea50809 260#if 0
43c02e7b 261 u_int16_t cksum;
4ea50809 262#endif
a8105c1b
VB
263 u_int8_t *software = NULL, *platform = NULL;
264 int software_len = 0, platform_len = 0, proto, version, nb, caps;
43c02e7b 265 const unsigned char cdpaddr[] = CDP_MULTICAST_ADDR;
6d07eaee 266#ifdef ENABLE_FDP
031118c4 267 const unsigned char fdpaddr[] = CDP_MULTICAST_ADDR;
6d07eaee
VB
268 int fdp = 0;
269#endif
a8105c1b
VB
270 u_int8_t *pos, *tlv, *pos_address, *pos_next_address;
271 int length, len_eth, tlv_type, tlv_len, addresses_len, address_len;
aff85bf3
VB
272#ifdef ENABLE_DOT1
273 struct lldpd_vlan *vlan;
274#endif
43c02e7b 275
6f8925be
VB
276 log_debug("cdp", "decode CDP frame received on %s",
277 hardware->h_ifname);
278
43c02e7b 279 if ((chassis = calloc(1, sizeof(struct lldpd_chassis))) == NULL) {
6f8925be 280 log_warn("cdp", "failed to allocate remote chassis");
43c02e7b
VB
281 return -1;
282 }
e6b36c87 283 TAILQ_INIT(&chassis->c_mgmt);
43c02e7b 284 if ((port = calloc(1, sizeof(struct lldpd_port))) == NULL) {
6f8925be 285 log_warn("cdp", "failed to allocate remote port");
43c02e7b
VB
286 free(chassis);
287 return -1;
288 }
a1347cd8 289#ifdef ENABLE_DOT1
43c02e7b 290 TAILQ_INIT(&port->p_vlans);
a1347cd8 291#endif
43c02e7b 292
a8105c1b
VB
293 length = s;
294 pos = (u_int8_t*)frame;
295
4e5f34c5 296 if (length < 2*ETHER_ADDR_LEN + sizeof(u_int16_t) /* Ethernet */ +
a8105c1b 297 8 /* LLC */ + 4 /* CDP header */) {
6f8925be 298 log_warn("cdp", "too short CDP/FDP frame received on %s", hardware->h_ifname);
43c02e7b
VB
299 goto malformed;
300 }
301
a8105c1b 302 if (PEEK_CMP(cdpaddr, sizeof(cdpaddr)) != 0) {
6d07eaee 303#ifdef ENABLE_FDP
a8105c1b
VB
304 PEEK_RESTORE((u_int8_t*)frame);
305 if (PEEK_CMP(fdpaddr, sizeof(fdpaddr)) != 0)
031118c4
VB
306 fdp = 1;
307 else {
6d07eaee 308#endif
6f8925be 309 log_info("cdp", "frame not targeted at CDP/FDP multicast address received on %s",
031118c4
VB
310 hardware->h_ifname);
311 goto malformed;
6d07eaee 312#ifdef ENABLE_FDP
031118c4 313 }
6d07eaee 314#endif
43c02e7b 315 }
4e5f34c5 316 PEEK_DISCARD(ETHER_ADDR_LEN); /* Don't care of source address */
a8105c1b
VB
317 len_eth = PEEK_UINT16;
318 if (len_eth > length) {
6f8925be 319 log_warnx("cdp", "incorrect 802.3 frame size reported on %s",
348f6df6
VB
320 hardware->h_ifname);
321 goto malformed;
43c02e7b 322 }
a8105c1b
VB
323 PEEK_DISCARD(6); /* Skip beginning of LLC */
324 proto = PEEK_UINT16;
325 if (proto != LLC_PID_CDP) {
326 if ((proto != LLC_PID_DRIP) &&
327 (proto != LLC_PID_PAGP) &&
328 (proto != LLC_PID_PVSTP) &&
329 (proto != LLC_PID_UDLD) &&
330 (proto != LLC_PID_VTP) &&
331 (proto != LLC_PID_DTP) &&
332 (proto != LLC_PID_STP))
6f8925be 333 log_debug("cdp", "incorrect LLC protocol ID received on %s",
0d2c6d16 334 hardware->h_ifname);
43c02e7b
VB
335 goto malformed;
336 }
a8105c1b 337
4ea50809 338#if 0
a8105c1b
VB
339 /* Check checksum */
340 cksum = frame_checksum(pos, len_eth - 8,
9ec6b111
VB
341#ifdef ENABLE_FDP
342 !fdp /* fdp = 0 -> cisco checksum */
343#else
344 1 /* cisco checksum */
345#endif
346 );
806eaef4 347 if (cksum != 0) {
6f8925be 348 log_info("cdp", "incorrect CDP/FDP checksum for frame received on %s (%d)",
43c02e7b
VB
349 hardware->h_ifname, cksum);
350 goto malformed;
351 }
4ea50809 352#endif
43c02e7b 353
a8105c1b
VB
354 /* Check version */
355 version = PEEK_UINT8;
356 if ((version != 1) && (version != 2)) {
6f8925be 357 log_warnx("cdp", "incorrect CDP/FDP version (%d) for frame received on %s",
a8105c1b
VB
358 version, hardware->h_ifname);
359 goto malformed;
360 }
361 chassis->c_ttl = PEEK_UINT8; /* TTL */
362 PEEK_DISCARD_UINT16; /* Checksum, already checked */
363
364 while (length) {
365 if (length < 4) {
6f8925be 366 log_warnx("cdp", "CDP/FDP TLV header is too large for "
43c02e7b
VB
367 "frame received on %s",
368 hardware->h_ifname);
369 goto malformed;
370 }
a8105c1b
VB
371 tlv_type = PEEK_UINT16;
372 tlv_len = PEEK_UINT16 - 4;
2d1fe392 373 (void)PEEK_SAVE(tlv);
a8105c1b 374 if ((tlv_len < 0) || (length < tlv_len)) {
6f8925be 375 log_warnx("cdp", "incorrect size in CDP/FDP TLV header for frame "
43c02e7b
VB
376 "received on %s",
377 hardware->h_ifname);
378 goto malformed;
379 }
a8105c1b 380 switch (tlv_type) {
43c02e7b 381 case CDP_TLV_CHASSIS:
a8105c1b 382 if ((chassis->c_name = (char *)calloc(1, tlv_len + 1)) == NULL) {
6f8925be 383 log_warn("cdp", "unable to allocate memory for chassis name");
43c02e7b
VB
384 goto malformed;
385 }
a8105c1b 386 PEEK_BYTES(chassis->c_name, tlv_len);
43c02e7b 387 chassis->c_id_subtype = LLDP_CHASSISID_SUBTYPE_LOCAL;
a8105c1b 388 if ((chassis->c_id = (char *)malloc(tlv_len)) == NULL) {
6f8925be 389 log_warn("cdp", "unable to allocate memory for chassis ID");
43c02e7b
VB
390 goto malformed;
391 }
a8105c1b
VB
392 memcpy(chassis->c_id, chassis->c_name, tlv_len);
393 chassis->c_id_len = tlv_len;
43c02e7b
VB
394 break;
395 case CDP_TLV_ADDRESSES:
a8105c1b
VB
396 CHECK_TLV_SIZE(4, "Address");
397 addresses_len = tlv_len - 4;
398 for (nb = PEEK_UINT32; nb > 0; nb--) {
2d1fe392 399 (void)PEEK_SAVE(pos_address);
a8105c1b
VB
400 /* We first try to get the real length of the packet */
401 if (addresses_len < 2) {
6f8925be 402 log_warn("cdp", "too short address subframe "
a8105c1b
VB
403 "received on %s",
404 hardware->h_ifname);
43c02e7b
VB
405 goto malformed;
406 }
a8105c1b
VB
407 PEEK_DISCARD_UINT8; addresses_len--;
408 address_len = PEEK_UINT8; addresses_len--;
409 if (addresses_len < address_len + 2) {
6f8925be 410 log_warn("cdp", "too short address subframe "
a8105c1b
VB
411 "received on %s",
412 hardware->h_ifname);
43c02e7b
VB
413 goto malformed;
414 }
a8105c1b
VB
415 PEEK_DISCARD(address_len);
416 addresses_len -= address_len;
417 address_len = PEEK_UINT16; addresses_len -= 2;
418 if (addresses_len < address_len) {
6f8925be 419 log_warn("cdp", "too short address subframe "
a8105c1b
VB
420 "received on %s",
421 hardware->h_ifname);
422 goto malformed;
423 }
424 PEEK_DISCARD(address_len);
2d1fe392 425 (void)PEEK_SAVE(pos_next_address);
a8105c1b
VB
426 /* Next, we go back and try to extract
427 IPv4 address */
428 PEEK_RESTORE(pos_address);
429 if ((PEEK_UINT8 == 1) && (PEEK_UINT8 == 1) &&
430 (PEEK_UINT8 == CDP_ADDRESS_PROTO_IP) &&
e6b36c87
JV
431 (PEEK_UINT16 == sizeof(struct in_addr))) {
432 PEEK_BYTES(&addr, sizeof(struct in_addr));
433 mgmt = lldpd_alloc_mgmt(LLDPD_AF_IPV4, &addr,
434 sizeof(struct in_addr), 0);
435 if (mgmt == NULL) {
9221b5c2
VB
436 if (errno == ENOMEM)
437 log_warn("cdp",
438 "unable to allocate memory for management address");
439 else
440 log_warn("cdp",
441 "too large management address received on %s",
442 hardware->h_ifname);
e6b36c87
JV
443 goto malformed;
444 }
445 TAILQ_INSERT_TAIL(&chassis->c_mgmt, mgmt, m_entries);
446 }
a8105c1b
VB
447 /* Go to the end of the address */
448 PEEK_RESTORE(pos_next_address);
43c02e7b
VB
449 }
450 break;
451 case CDP_TLV_PORT:
506273e9 452 if (tlv_len == 0) {
0d19619a 453 log_warn("cdp", "too short port description received");
506273e9
VB
454 goto malformed;
455 }
a8105c1b 456 if ((port->p_descr = (char *)calloc(1, tlv_len + 1)) == NULL) {
6f8925be 457 log_warn("cdp", "unable to allocate memory for port description");
43c02e7b
VB
458 goto malformed;
459 }
a8105c1b
VB
460 PEEK_BYTES(port->p_descr, tlv_len);
461 port->p_id_subtype = LLDP_PORTID_SUBTYPE_IFNAME;
462 if ((port->p_id = (char *)calloc(1, tlv_len)) == NULL) {
6f8925be 463 log_warn("cdp", "unable to allocate memory for port ID");
43c02e7b
VB
464 goto malformed;
465 }
a8105c1b
VB
466 memcpy(port->p_id, port->p_descr, tlv_len);
467 port->p_id_len = tlv_len;
43c02e7b
VB
468 break;
469 case CDP_TLV_CAPABILITIES:
6d07eaee 470#ifdef ENABLE_FDP
031118c4 471 if (fdp) {
bf517088 472 /* Capabilities are string with FDP */
a8105c1b 473 if (!strncmp("Router", (char*)pos, tlv_len))
bf517088 474 chassis->c_cap_enabled = LLDP_CAP_ROUTER;
a8105c1b 475 else if (!strncmp("Switch", (char*)pos, tlv_len))
bf517088 476 chassis->c_cap_enabled = LLDP_CAP_BRIDGE;
a8105c1b 477 else if (!strncmp("Bridge", (char*)pos, tlv_len))
bf517088
VB
478 chassis->c_cap_enabled = LLDP_CAP_REPEATER;
479 else
480 chassis->c_cap_enabled = LLDP_CAP_STATION;
481 chassis->c_cap_available = chassis->c_cap_enabled;
031118c4
VB
482 break;
483 }
6d07eaee 484#endif
a8105c1b
VB
485 CHECK_TLV_SIZE(4, "Capabilities");
486 caps = PEEK_UINT32;
487 if (caps & CDP_CAP_ROUTER)
43c02e7b 488 chassis->c_cap_enabled |= LLDP_CAP_ROUTER;
a8105c1b 489 if (caps & 0x0e)
43c02e7b
VB
490 chassis->c_cap_enabled |= LLDP_CAP_BRIDGE;
491 if (chassis->c_cap_enabled == 0)
492 chassis->c_cap_enabled = LLDP_CAP_STATION;
493 chassis->c_cap_available = chassis->c_cap_enabled;
43c02e7b
VB
494 break;
495 case CDP_TLV_SOFTWARE:
a8105c1b 496 software_len = tlv_len;
2d1fe392 497 (void)PEEK_SAVE(software);
43c02e7b
VB
498 break;
499 case CDP_TLV_PLATFORM:
a8105c1b 500 platform_len = tlv_len;
2d1fe392 501 (void)PEEK_SAVE(platform);
43c02e7b 502 break;
aff85bf3
VB
503#ifdef ENABLE_DOT1
504 case CDP_TLV_NATIVEVLAN:
505 CHECK_TLV_SIZE(2, "Native VLAN");
506 if ((vlan = (struct lldpd_vlan *)calloc(1,
507 sizeof(struct lldpd_vlan))) == NULL) {
6f8925be 508 log_warn("cdp", "unable to alloc vlan "
aff85bf3
VB
509 "structure for "
510 "tlv received on %s",
511 hardware->h_ifname);
512 goto malformed;
513 }
514 vlan->v_vid = port->p_pvid = PEEK_UINT16;
515 if (asprintf(&vlan->v_name, "VLAN #%d", vlan->v_vid) == -1) {
6f8925be 516 log_warn("cdp", "unable to alloc VLAN name for "
aff85bf3
VB
517 "TLV received on %s",
518 hardware->h_ifname);
519 free(vlan);
520 goto malformed;
521 }
522 TAILQ_INSERT_TAIL(&port->p_vlans,
523 vlan, v_entries);
524 break;
525#endif
43c02e7b 526 default:
6f8925be 527 log_debug("cdp", "unknown CDP/FDP TLV type (%d) received on %s",
a8105c1b 528 ntohs(tlv_type), hardware->h_ifname);
37387046 529 hardware->h_rx_unrecognized_cnt++;
43c02e7b 530 }
a8105c1b 531 PEEK_DISCARD(tlv + tlv_len - pos);
43c02e7b
VB
532 }
533 if (!software && platform) {
534 if ((chassis->c_descr = (char *)calloc(1,
535 platform_len + 1)) == NULL) {
6f8925be 536 log_warn("cdp", "unable to allocate memory for chassis description");
43c02e7b
VB
537 goto malformed;
538 }
539 memcpy(chassis->c_descr, platform, platform_len);
540 } else if (software && !platform) {
541 if ((chassis->c_descr = (char *)calloc(1,
542 software_len + 1)) == NULL) {
6f8925be 543 log_warn("cdp", "unable to allocate memory for chassis description");
43c02e7b
VB
544 goto malformed;
545 }
546 memcpy(chassis->c_descr, software, software_len);
547 } else if (software && platform) {
548#define CONCAT_PLATFORM " running on\n"
549 if ((chassis->c_descr = (char *)calloc(1,
550 software_len + platform_len +
551 strlen(CONCAT_PLATFORM) + 1)) == NULL) {
6f8925be 552 log_warn("cdp", "unable to allocate memory for chassis description");
43c02e7b
VB
553 goto malformed;
554 }
555 memcpy(chassis->c_descr, platform, platform_len);
556 memcpy(chassis->c_descr + platform_len,
557 CONCAT_PLATFORM, strlen(CONCAT_PLATFORM));
558 memcpy(chassis->c_descr + platform_len + strlen(CONCAT_PLATFORM),
559 software, software_len);
560 }
561 if ((chassis->c_id == NULL) ||
562 (port->p_id == NULL) ||
563 (chassis->c_name == NULL) ||
564 (chassis->c_descr == NULL) ||
565 (port->p_descr == NULL) ||
566 (chassis->c_ttl == 0) ||
567 (chassis->c_cap_enabled == 0)) {
6f8925be 568 log_warnx("cdp", "some mandatory CDP/FDP tlv are missing for frame received on %s",
43c02e7b
VB
569 hardware->h_ifname);
570 goto malformed;
571 }
572 *newchassis = chassis;
573 *newport = port;
574 return 1;
575
576malformed:
77507b69 577 lldpd_chassis_cleanup(chassis, 1);
4b292b55 578 lldpd_port_cleanup(port, 1);
4e624dc2 579 free(port);
43c02e7b
VB
580 return -1;
581}
582
6d07eaee 583#ifdef ENABLE_CDP
43c02e7b 584int
77507b69 585cdpv1_send(struct lldpd *global,
43c02e7b
VB
586 struct lldpd_hardware *hardware)
587{
77507b69 588 return cdp_send(global, hardware, 1);
43c02e7b
VB
589}
590
591int
77507b69 592cdpv2_send(struct lldpd *global,
43c02e7b
VB
593 struct lldpd_hardware *hardware)
594{
77507b69 595 return cdp_send(global, hardware, 2);
43c02e7b 596}
6d07eaee 597#endif
43c02e7b 598
6d07eaee 599#ifdef ENABLE_FDP
031118c4 600int
77507b69 601fdp_send(struct lldpd *global,
031118c4
VB
602 struct lldpd_hardware *hardware)
603{
77507b69 604 return cdp_send(global, hardware, 0);
031118c4 605}
6d07eaee 606#endif
031118c4 607
6d07eaee 608#ifdef ENABLE_CDP
8888d191 609static int
a8105c1b 610cdp_guess(char *pos, int length, int version)
43c02e7b
VB
611{
612 const u_int8_t mcastaddr[] = CDP_MULTICAST_ADDR;
4e5f34c5 613 if (length < 2*ETHER_ADDR_LEN + sizeof(u_int16_t) /* Ethernet */ +
a8105c1b 614 8 /* LLC */ + 4 /* CDP header */)
43c02e7b 615 return 0;
4e5f34c5 616 if (PEEK_CMP(mcastaddr, ETHER_ADDR_LEN) != 0)
43c02e7b 617 return 0;
4e5f34c5 618 PEEK_DISCARD(ETHER_ADDR_LEN); PEEK_DISCARD_UINT16; /* Ethernet */
a8105c1b
VB
619 PEEK_DISCARD(8); /* LLC */
620 return (PEEK_UINT8 == version);
43c02e7b
VB
621}
622
623int
624cdpv1_guess(char *frame, int len)
625{
626 return cdp_guess(frame, len, 1);
627}
628
629int
630cdpv2_guess(char *frame, int len)
631{
632 return cdp_guess(frame, len, 2);
633}
6d07eaee 634#endif
4bad1937
VB
635
636#endif /* defined (ENABLE_CDP) || defined (ENABLE_FDP) */