]> git.ipfire.org Git - thirdparty/lldpd.git/blame - src/lldp.c
Fix manual page (missing .El)
[thirdparty/lldpd.git] / src / lldp.c
CommitLineData
43c02e7b
VB
1/*
2 * Copyright (c) 2008 Vincent Bernat <bernat@luffy.cx>
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17#include "lldpd.h"
18
19#include <unistd.h>
20#include <errno.h>
21#include <time.h>
22#include <sys/types.h>
23#include <sys/socket.h>
24#include <sys/ioctl.h>
25#include <netpacket/packet.h>
26#include <linux/sockios.h>
27
28int
29lldp_send(struct lldpd *global, struct lldpd_chassis *chassis,
30 struct lldpd_hardware *hardware)
31{
32 struct ether_header eh;
33 const u_int8_t mcastaddr[] = LLDP_MULTICAST_ADDR;
43c02e7b 34 struct iovec *iov = NULL;
43c02e7b
VB
35 struct lldp_id chid, pid;
36 struct lldp_ttl ttl;
37 struct lldp_end end;
38 struct lldp_string name;
39 struct lldp_string descr;
40 struct lldp_string str;
41 struct lldp_cap cap;
42 struct lldp_mgmt mgmt;
a1347cd8
VB
43#ifdef ENABLE_DOT1
44 const u_int8_t dot1[] = LLDP_TLV_ORG_DOT1;
45 struct lldp_vlan *ovlan = NULL;
46 int v;
47 struct lldpd_vlan *vlan;
48#endif
49#ifdef ENABLE_DOT3
50 const u_int8_t dot3[] = LLDP_TLV_ORG_DOT3;
43c02e7b
VB
51 struct lldp_aggreg aggreg;
52 struct lldp_macphy macphy;
a1347cd8 53#endif
89840df0 54#ifdef ENABLE_LLDPMED
115ff55c 55 int i;
89840df0
VB
56 const u_int8_t med[] = LLDP_TLV_ORG_MED;
57 struct lldpmed_cap medcap;
58 struct lldp_org medhw, medfw, medsw, medsn,
115ff55c 59 medmodel, medasset, medmanuf, medloc[3];
89840df0 60#endif
43c02e7b 61 struct lldpd_port *port = &hardware->h_lport;
a1347cd8 62 u_int c = -1, len = 0;
43c02e7b
VB
63 struct lldpd_frame *buffer;
64
65#define IOV_NEW \
66 if ((iov = (struct iovec*)realloc(iov, (++c + 1) * \
67 sizeof(struct iovec))) == NULL) \
68 fatal(NULL);
69
70 /* Ethernet header */
71 memset(&eh, 0, sizeof(eh));
72 memcpy(&eh.ether_shost, &hardware->h_lladdr,
73 sizeof(eh.ether_shost));
74 memcpy(&eh.ether_dhost, &mcastaddr,
75 sizeof(eh.ether_dhost));
76 eh.ether_type = htons(ETHERTYPE_LLDP);
77 IOV_NEW;
78 iov[c].iov_base = &eh;
79 iov[c].iov_len = sizeof(struct ether_header);
80
81 /* Chassis ID */
82 memset(&chid, 0, sizeof(chid));
83 len = chassis->c_id_len + sizeof(chid);
84 chid.tlv_head.type_len = LLDP_TLV_HEAD(LLDP_TLV_CHASSIS_ID,
85 len - sizeof(struct lldp_tlv_head));
86 chid.tlv_id_subtype = chassis->c_id_subtype;
87 IOV_NEW;
88 iov[c].iov_base = &chid;
89 iov[c].iov_len = sizeof(chid);
90 IOV_NEW;
91 iov[c].iov_base = chassis->c_id;
92 iov[c].iov_len = chassis->c_id_len;
93
94 /* Port ID */
95 memset(&pid, 0, sizeof(pid));
96 len = port->p_id_len + sizeof(pid);
97 pid.tlv_head.type_len = LLDP_TLV_HEAD(LLDP_TLV_PORT_ID,
98 len - sizeof(struct lldp_tlv_head));
99 pid.tlv_id_subtype = port->p_id_subtype;
100 IOV_NEW;
101 iov[c].iov_base = &pid;
102 iov[c].iov_len = sizeof(pid);
103 IOV_NEW;
104 iov[c].iov_base = port->p_id;
105 iov[c].iov_len = port->p_id_len;
106
107 /* Time to live */
108 memset(&ttl, 0, sizeof(ttl));
109 len = sizeof(ttl);
110 ttl.tlv_head.type_len = LLDP_TLV_HEAD(LLDP_TLV_TTL,
111 len - sizeof(struct lldp_tlv_head));
112 ttl.tlv_ttl = htons(chassis->c_ttl);
113 IOV_NEW;
114 iov[c].iov_base = &ttl;
115 iov[c].iov_len = sizeof(ttl);
116
117 /* System name */
118 memset(&name, 0, sizeof(name));
119 len = sizeof(name) + strlen(chassis->c_name);
120 name.tlv_head.type_len = LLDP_TLV_HEAD(LLDP_TLV_SYSTEM_NAME,
121 len - sizeof(struct lldp_tlv_head));
122 IOV_NEW;
123 iov[c].iov_base = &name;
124 iov[c].iov_len = sizeof(name);
125 IOV_NEW;
126 iov[c].iov_base = chassis->c_name;
127 iov[c].iov_len = strlen(chassis->c_name);
128
129 /* System description */
130 memset(&descr, 0, sizeof(descr));
131 len = sizeof(descr) + strlen(chassis->c_descr);
132 descr.tlv_head.type_len = LLDP_TLV_HEAD(LLDP_TLV_SYSTEM_DESCR,
133 len - sizeof(struct lldp_tlv_head));
134 IOV_NEW;
135 iov[c].iov_base = &descr;
136 iov[c].iov_len = sizeof(descr);
137 IOV_NEW;
138 iov[c].iov_base = chassis->c_descr;
139 iov[c].iov_len = strlen(chassis->c_descr);
140
141 /* System capabilities */
142 memset(&cap, 0, sizeof(cap));
143 len = sizeof(cap);
144 cap.tlv_head.type_len = LLDP_TLV_HEAD(LLDP_TLV_SYSTEM_CAP,
145 len - sizeof(struct lldp_tlv_head));
146 cap.tlv_cap_available = htons(chassis->c_cap_available);
147 cap.tlv_cap_enabled = htons(chassis->c_cap_enabled);
148 IOV_NEW;
149 iov[c].iov_base = &cap;
150 iov[c].iov_len = len;
151
152 if (chassis->c_mgmt.s_addr != INADDR_ANY) {
153 /* Management address */
154 memset(&mgmt, 0, sizeof(mgmt));
155 len = sizeof(mgmt);
156 mgmt.tlv_head.type_len = LLDP_TLV_HEAD(LLDP_TLV_MGMT_ADDR,
157 len - sizeof(struct lldp_tlv_head));
158 mgmt.mgmt_len = sizeof(struct in_addr) + sizeof(u_int8_t);
159 mgmt.mgmt_subtype = LLDP_MGMT_ADDR_IP4;
160 memcpy(&mgmt.mgmt_addr, &chassis->c_mgmt,
161 sizeof(struct in_addr));
162
163 /* Interface port type, OID */
164 if (chassis->c_mgmt_if == 0)
165 mgmt.mgmt_iface_subtype =
166 LLDP_MGMT_IFACE_UNKNOWN;
167 else {
168 mgmt.mgmt_iface_subtype =
169 LLDP_MGMT_IFACE_IFINDEX;
170 mgmt.mgmt_iface_id =
171 htonl(chassis->c_mgmt_if);
172 }
173 IOV_NEW;
174 iov[c].iov_base = &mgmt;
175 iov[c].iov_len = len;
176 }
177
178 /* Port description */
179 memset(&str, 0, sizeof(str));
180 len = sizeof(str) + strlen(port->p_descr);
181 str.tlv_head.type_len = LLDP_TLV_HEAD(LLDP_TLV_PORT_DESCR,
182 len - sizeof(struct lldp_tlv_head));
183 IOV_NEW;
184 iov[c].iov_base = &str;
185 iov[c].iov_len = sizeof(str);
186 IOV_NEW;
187 iov[c].iov_base = port->p_descr;
188 iov[c].iov_len = strlen(port->p_descr);
189
a1347cd8 190#ifdef ENABLE_DOT1
43c02e7b
VB
191 /* VLANs */
192 v = 0;
193 TAILQ_FOREACH(vlan, &port->p_vlans, v_entries)
194 v++;
195 if ((v > 0) &&
196 ((ovlan = (struct lldp_vlan*)malloc(v*sizeof(struct lldp_vlan))) == NULL))
197 LLOG_WARN("no room for vlans");
198 else {
199 TAILQ_FOREACH(vlan, &port->p_vlans, v_entries) {
200 v--;
201 memset(&ovlan[v], 0, sizeof(ovlan[v]));
202 ovlan[v].tlv_head.type_len = LLDP_TLV_HEAD(LLDP_TLV_ORG,
203 sizeof(ovlan[v].tlv_org_id) +
204 sizeof(ovlan[v].tlv_org_subtype) + sizeof(ovlan[v].vid) +
205 sizeof(ovlan[v].len) + strlen(vlan->v_name));
206 memcpy(ovlan[v].tlv_org_id, dot1, sizeof(ovlan[v].tlv_org_id));
207 ovlan[v].tlv_org_subtype = LLDP_TLV_DOT1_VLANNAME;
208 ovlan[v].vid = htons(vlan->v_vid);
209 ovlan[v].len = strlen(vlan->v_name);
210 IOV_NEW;
211 iov[c].iov_base = &ovlan[v];
212 iov[c].iov_len = sizeof(ovlan[v]);
213 IOV_NEW;
214 iov[c].iov_base = vlan->v_name;
215 iov[c].iov_len = strlen(vlan->v_name);
216 }
217 }
a1347cd8 218#endif
43c02e7b 219
a1347cd8 220#ifdef ENABLE_DOT3
43c02e7b
VB
221 /* Aggregation status */
222 memset(&aggreg, 0, sizeof(aggreg));
223 aggreg.tlv_head.type_len = LLDP_TLV_HEAD(LLDP_TLV_ORG,
224 sizeof(aggreg.tlv_org_id) +
225 sizeof(aggreg.tlv_org_subtype) +
226 sizeof(aggreg.status) + sizeof(aggreg.id));
227 memcpy(aggreg.tlv_org_id, dot3, sizeof(aggreg.tlv_org_id));
228 aggreg.tlv_org_subtype = LLDP_TLV_DOT3_LA;
229 aggreg.status = (port->p_aggregid) ? 3:1; /* Bit 0 = capability ; Bit 1 = status */
230 aggreg.id = htonl(port->p_aggregid);
231 IOV_NEW;
232 iov[c].iov_base = &aggreg;
233 iov[c].iov_len = sizeof(aggreg);
234
235 /* MAC/PHY */
236 memset(&macphy, 0, sizeof(macphy));
237 macphy.tlv_head.type_len = LLDP_TLV_HEAD(LLDP_TLV_ORG,
238 sizeof(macphy.tlv_org_id) +
239 sizeof(macphy.tlv_org_subtype) +
240 sizeof(macphy.autoneg) + sizeof(macphy.advertised) +
241 sizeof(macphy.mau));
242 memcpy(macphy.tlv_org_id, dot3, sizeof(macphy.tlv_org_id));
243 macphy.tlv_org_subtype = LLDP_TLV_DOT3_MAC;
244 macphy.autoneg = port->p_autoneg_support |
245 (port->p_autoneg_enabled << 1);
246 macphy.advertised = htons(port->p_autoneg_advertised);
247 macphy.mau = htons(port->p_mau_type);
248 IOV_NEW;
249 iov[c].iov_base = &macphy;
250 iov[c].iov_len = sizeof(macphy);
a1347cd8 251#endif
43c02e7b 252
89840df0 253#ifdef ENABLE_LLDPMED
40ecae87 254 if (global->g_lchassis.c_med_cap_enabled) {
89840df0
VB
255 /* LLDP-MED cap */
256 memset(&medcap, 0, sizeof(medcap));
257 medcap.tlv_head.type_len = LLDP_TLV_HEAD(LLDP_TLV_ORG,
258 sizeof(medcap.tlv_org_id) +
259 sizeof(medcap.tlv_org_subtype) +
260 sizeof(medcap.tlv_cap) + sizeof(medcap.tlv_type));
261 memcpy(medcap.tlv_org_id, med, sizeof(medcap.tlv_org_id));
262 medcap.tlv_org_subtype = LLDP_TLV_MED_CAP;
40ecae87 263 medcap.tlv_cap = htons(global->g_lchassis.c_med_cap_available);
89840df0
VB
264 medcap.tlv_type = global->g_lchassis.c_med_type;
265 IOV_NEW;
266 iov[c].iov_base = &medcap;
267 iov[c].iov_len = sizeof(medcap);
268
269 /* LLDP-MED inventory */
270#define LLDP_INVENTORY(value, target, subtype) \
271 if (value) { \
272 memset(&target, 0, sizeof(target)); \
273 len = (strlen(value)>32)?32:strlen(value); \
274 target.tlv_head.type_len = \
275 LLDP_TLV_HEAD(LLDP_TLV_ORG, \
276 sizeof(target.tlv_org_id) + \
277 sizeof(target.tlv_org_subtype) + \
278 len); \
279 memcpy(target.tlv_org_id, med, \
280 sizeof(target.tlv_org_id)); \
281 target.tlv_org_subtype = subtype; \
282 IOV_NEW; \
283 iov[c].iov_base = &target; \
284 iov[c].iov_len = sizeof(target); \
285 IOV_NEW; \
286 iov[c].iov_base = value; \
287 iov[c].iov_len = len; \
288 }
e809a587 289
40ecae87 290 if (global->g_lchassis.c_med_cap_enabled & LLDPMED_CAP_IV) {
e809a587
VB
291 LLDP_INVENTORY(global->g_lchassis.c_med_hw,
292 medhw, LLDP_TLV_MED_IV_HW);
293 LLDP_INVENTORY(global->g_lchassis.c_med_fw,
294 medfw, LLDP_TLV_MED_IV_FW);
295 LLDP_INVENTORY(global->g_lchassis.c_med_sw,
296 medsw, LLDP_TLV_MED_IV_SW);
297 LLDP_INVENTORY(global->g_lchassis.c_med_sn,
298 medsn, LLDP_TLV_MED_IV_SN);
299 LLDP_INVENTORY(global->g_lchassis.c_med_manuf,
300 medmanuf, LLDP_TLV_MED_IV_MANUF);
301 LLDP_INVENTORY(global->g_lchassis.c_med_model,
302 medmodel, LLDP_TLV_MED_IV_MODEL);
303 LLDP_INVENTORY(global->g_lchassis.c_med_asset,
304 medasset, LLDP_TLV_MED_IV_ASSET);
305 }
115ff55c
VB
306
307 /* LLDP-MED location */
308 for (i = 0; i < LLDPMED_LOCFORMAT_LAST; i++) {
309 if (global->g_lchassis.c_med_location[i].format == i + 1) {
310 memset(&medloc[i], 0, sizeof(struct lldp_org));
311 medloc[i].tlv_head.type_len =
312 LLDP_TLV_HEAD(LLDP_TLV_ORG,
313 sizeof(medloc[i].tlv_org_id) +
314 sizeof(medloc[i].tlv_org_subtype) + 1 +
315 global->g_lchassis.c_med_location[i].data_len);
316 memcpy(medloc[i].tlv_org_id, med,
317 sizeof(medloc[i].tlv_org_id));
318 medloc[i].tlv_org_subtype = LLDP_TLV_MED_LOCATION;
319 IOV_NEW;
320 iov[c].iov_base = &medloc[i];
321 iov[c].iov_len = sizeof(medloc[i]);
322 IOV_NEW;
323 iov[c].iov_base =
324 &global->g_lchassis.c_med_location[i].format;
325 iov[c].iov_len = 1;
326 IOV_NEW;
327 iov[c].iov_base =
328 global->g_lchassis.c_med_location[i].data;
329 iov[c].iov_len =
330 global->g_lchassis.c_med_location[i].data_len;
331 }
332 }
89840df0
VB
333 }
334#endif
335
43c02e7b
VB
336 /* END */
337 memset(&end, 0, sizeof(end));
338 IOV_NEW;
339 iov[c].iov_base = &end;
340 iov[c].iov_len = sizeof(end);
341
342 c++;
343 if (!global->g_multi ||
344 (hardware->h_mode == LLDPD_MODE_ANY) ||
345 (hardware->h_mode == LLDPD_MODE_LLDP)) {
346
347 if (writev((hardware->h_raw_real > 0) ? hardware->h_raw_real :
348 hardware->h_raw, iov, c) == -1) {
349 LLOG_WARN("unable to send packet on real device for %s",
350 hardware->h_ifname);
351 free(iov);
a1347cd8 352#ifdef ENABLE_DOT1
43c02e7b 353 free(ovlan);
a1347cd8 354#endif
43c02e7b
VB
355 return ENETDOWN;
356 }
357
358 hardware->h_tx_cnt++;
359 }
360
361 iov_dump(&buffer, iov, c);
362 free(iov);
a1347cd8 363#ifdef ENABLE_DOT1
43c02e7b 364 free(ovlan);
a1347cd8 365#endif
43c02e7b
VB
366 if (buffer != NULL) {
367
368 /* We assume that LLDP frame is the reference */
369 if ((hardware->h_llastframe == NULL) ||
370 (hardware->h_llastframe->size != buffer->size) ||
371 (memcmp(hardware->h_llastframe->frame, buffer->frame,
372 buffer->size) != 0)) {
373 free(hardware->h_llastframe);
374 hardware->h_llastframe = buffer;
375 hardware->h_llastchange = time(NULL);
376 } else
377 free(buffer);
378 }
379
380 return 0;
381}
382
383int
384lldp_decode(struct lldpd *cfg, char *frame, int s,
385 struct lldpd_hardware *hardware,
386 struct lldpd_chassis **newchassis, struct lldpd_port **newport)
387{
388 struct lldpd_chassis *chassis;
389 struct lldpd_port *port;
390 struct ether_header *ether;
391 const char lldpaddr[] = LLDP_MULTICAST_ADDR;
392 const char dot1[] = LLDP_TLV_ORG_DOT1;
393 const char dot3[] = LLDP_TLV_ORG_DOT3;
6772b237 394 const char med[] = LLDP_TLV_ORG_MED;
43c02e7b
VB
395 int f; /* Current position in frame */
396 int size, type, subtype; /* TLV header */
397 char *b;
398 int gotend = 0;
399
400 if ((chassis = calloc(1, sizeof(struct lldpd_chassis))) == NULL) {
401 LLOG_WARN("failed to allocate remote chassis");
402 return -1;
403 }
404 if ((port = calloc(1, sizeof(struct lldpd_port))) == NULL) {
405 LLOG_WARN("failed to allocate remote port");
406 free(chassis);
407 return -1;
408 }
a1347cd8 409#ifdef ENABLE_DOT1
43c02e7b 410 TAILQ_INIT(&port->p_vlans);
a1347cd8 411#endif
43c02e7b
VB
412
413 if (s < sizeof(struct ether_header)) {
414 LLOG_WARNX("too short frame received on %s", hardware->h_ifname);
415 goto malformed;
416 }
417 ether = (struct ether_header *)frame;
418 if (memcmp(ether->ether_dhost, lldpaddr, sizeof(lldpaddr)) != 0) {
419 LLOG_INFO("frame not targeted at LLDP multicast address received on %s",
420 hardware->h_ifname);
421 goto malformed;
422 }
423 if (ETHERTYPE_LLDP != ntohs(ether->ether_type)) {
424 LLOG_INFO("non LLDP frame received on %s",
425 hardware->h_ifname);
426 goto malformed;
427 }
428
429 f = sizeof(struct ether_header);
430 while ((f < s) && (!gotend)) {
431 if (f + 2 > s) {
432 LLOG_WARNX("tlv header too short received on %s",
433 hardware->h_ifname);
434 goto malformed;
435 }
436 size = ntohs(*(u_int16_t*)(frame + f)) & 0x1ff;
437 type = ntohs(*(u_int16_t*)(frame + f)) >> 9;
438 f += 2;
439 if (f + size > s) {
440 LLOG_WARNX("tlv header too short received on %s",
441 hardware->h_ifname);
442 goto malformed;
443 }
444 switch (type) {
445 case LLDP_TLV_END:
446 if (size != 0) {
447 LLOG_WARNX("lldp end received with size not null on %s",
448 hardware->h_ifname);
449 goto malformed;
450 }
451 if (f != s)
452 LLOG_DEBUG("extra data after lldp end on %s",
453 hardware->h_ifname);
454 gotend = 1;
455 break;
456 case LLDP_TLV_CHASSIS_ID:
457 case LLDP_TLV_PORT_ID:
458 if (size < 2) {
459 LLOG_WARNX("tlv id too small received on %s",
460 hardware->h_ifname);
461 goto malformed;
462 }
463 subtype = *(u_int8_t*)(frame + f);
464 f++;
465 if ((subtype == 0) || (subtype > 7)) {
466 LLOG_WARNX("unknown subtype for tlv id received on %s",
467 hardware->h_ifname);
468 goto malformed;
469 }
470 if ((b = (char *)calloc(1, size - 1)) == NULL) {
471 LLOG_WARN("unable to allocate memory for id tlv "
472 "received on %s",
473 hardware->h_ifname);
474 goto malformed;
475 }
476 memcpy(b, frame + f, size - 1);
477 if (type == LLDP_TLV_PORT_ID) {
478 port->p_id_subtype = subtype;
479 port->p_id = b;
480 port->p_id_len = size - 1;
481 } else {
482 chassis->c_id_subtype = subtype;
483 chassis->c_id = b;
484 chassis->c_id_len = size - 1;
485 }
486 f += size - 1;
487 break;
488 case LLDP_TLV_TTL:
c790233e
VB
489 if (size < 2) {
490 LLOG_WARNX("too short frame for ttl tlv received on %s",
43c02e7b
VB
491 hardware->h_ifname);
492 goto malformed;
493 }
494 chassis->c_ttl = ntohs(*(u_int16_t*)(frame + f));
c790233e 495 f += size;
43c02e7b
VB
496 break;
497 case LLDP_TLV_PORT_DESCR:
498 case LLDP_TLV_SYSTEM_NAME:
499 case LLDP_TLV_SYSTEM_DESCR:
500 if (size < 1) {
a700e935 501 LLOG_DEBUG("empty tlv received on %s",
43c02e7b 502 hardware->h_ifname);
a700e935 503 break;
43c02e7b
VB
504 }
505 if ((b = (char *)calloc(1, size + 1)) == NULL) {
506 LLOG_WARN("unable to allocate memory for string tlv "
507 "received on %s",
508 hardware->h_ifname);
509 goto malformed;
510 }
511 memcpy(b, frame + f, size);
512 f += size;
513 if (type == LLDP_TLV_PORT_DESCR)
514 port->p_descr = b;
515 else if (type == LLDP_TLV_SYSTEM_NAME)
516 chassis->c_name = b;
517 else chassis->c_descr = b;
518 break;
519 case LLDP_TLV_SYSTEM_CAP:
c790233e
VB
520 if (size < 4) {
521 LLOG_WARNX("too short system cap tlv "
efe3f9b0 522 "received on %s",
43c02e7b
VB
523 hardware->h_ifname);
524 goto malformed;
525 }
526 chassis->c_cap_available = ntohs(*(u_int16_t*)(frame + f));
527 f += 2;
528 chassis->c_cap_enabled = ntohs(*(u_int16_t*)(frame + f));
c790233e 529 f += size - 2;
43c02e7b
VB
530 break;
531 case LLDP_TLV_MGMT_ADDR:
532 if (size < 11) {
533 LLOG_WARNX("too short management tlv received on %s",
534 hardware->h_ifname);
535 goto malformed;
536 }
537 if ((chassis->c_mgmt.s_addr == INADDR_ANY) &&
538 (*(u_int8_t*)(frame + f) == 5) &&
539 (*(u_int8_t*)(frame + f + 1) == 1)) {
540 /* We have an IPv4 address, we ignore anything else */
541 memcpy(&chassis->c_mgmt, frame + f + 2, sizeof(struct in_addr));
542 chassis->c_mgmt_if = 0;
543 /* We only handle ifIndex subtype */
544 if (*(u_int8_t*)(frame + f + 6) == LLDP_MGMT_IFACE_IFINDEX)
545 chassis->c_mgmt_if = ntohl(*(u_int32_t*)(frame + f + 7));
546 }
547 f += size;
548 break;
549 case LLDP_TLV_ORG:
550 if (size < 4) {
551 LLOG_WARNX("too short org tlv received on %s",
552 hardware->h_ifname);
553 goto malformed;
554 }
555 if (memcmp(dot1, frame + f, 3) == 0) {
a1347cd8
VB
556#ifndef ENABLE_DOT1
557 f += size;
558 hardware->h_rx_unrecognized_cnt++;
559#else
43c02e7b
VB
560 /* Dot1 */
561 if ((*(u_int8_t*)(frame + f + 3)) ==
562 LLDP_TLV_DOT1_VLANNAME) {
563 struct lldpd_vlan *vlan;
564 int vlan_len;
565
566 if ((size < 7) ||
c790233e 567 (size < 7 + *(u_int8_t*)(frame + f + 6))) {
efe3f9b0
VB
568 LLOG_WARNX("too short vlan tlv "
569 "received on %s",
43c02e7b
VB
570 hardware->h_ifname);
571 goto malformed;
572 }
573 f += 4;
574 if ((vlan = (struct lldpd_vlan *)calloc(1,
575 sizeof(struct lldpd_vlan))) == NULL) {
efe3f9b0
VB
576 LLOG_WARN("unable to alloc vlan "
577 "structure for "
43c02e7b
VB
578 "tlv received on %s",
579 hardware->h_ifname);
580 goto malformed;
581 }
582 vlan->v_vid = ntohs(*(u_int16_t*)(frame + f));
583 f += 2;
584 vlan_len = *(u_int8_t*)(frame + f);
585 f += 1;
586 if ((vlan->v_name =
587 (char *)calloc(1, vlan_len + 1)) == NULL) {
588 LLOG_WARN("unable to alloc vlan name for "
589 "tlv received on %s",
590 hardware->h_ifname);
591 goto malformed;
592 }
593 memcpy(vlan->v_name, frame + f,
594 vlan_len);
595 TAILQ_INSERT_TAIL(&port->p_vlans,
596 vlan, v_entries);
c790233e 597 f += size - 7;
a1347cd8 598 } else {
43c02e7b
VB
599 /* Unknown Dot1 TLV, ignore it */
600 f += size;
a1347cd8
VB
601 hardware->h_rx_unrecognized_cnt++;
602 }
603#endif
43c02e7b 604 } else if (memcmp(dot3, frame + f, 3) == 0) {
a1347cd8
VB
605#ifndef ENABLE_DOT3
606 f += size;
607 hardware->h_rx_unrecognized_cnt++;
608#else
43c02e7b
VB
609 /* Dot3 */
610 subtype = *(u_int8_t*)(frame + f + 3);
611 switch (subtype) {
612 case LLDP_TLV_DOT3_MAC:
613 f += 4;
c790233e 614 if (size < 9) {
43c02e7b
VB
615 LLOG_WARNX("too short mac/phy tlv "
616 "received on %s",
617 hardware->h_ifname);
618 goto malformed;
619 }
620 port->p_autoneg_support =
621 *(u_int8_t*)(frame + f) && 0x1;
622 port->p_autoneg_enabled =
623 *(u_int8_t*)(frame + f) && 0x2;
624 f += 1;
625 port->p_autoneg_advertised =
626 ntohs(*(u_int16_t*)(frame + f));
627 f += 2;
628 port->p_mau_type =
629 ntohs(*(u_int16_t*)(frame + f));
c790233e 630 f += size - 7;
43c02e7b
VB
631 break;
632 case LLDP_TLV_DOT3_LA:
c790233e 633 if (size < 9) {
43c02e7b
VB
634 LLOG_WARNX("too short aggreg tlv "
635 "received on %s",
636 hardware->h_ifname);
637 goto malformed;
638 }
639 port->p_aggregid =
640 ntohl(*(u_int32_t*)(frame + f + 5));
c790233e 641 f += size;
43c02e7b
VB
642 break;
643 default:
644 /* Unknown Dot3 TLV, ignore it */
645 f += size;
37387046 646 hardware->h_rx_unrecognized_cnt++;
43c02e7b 647 }
a1347cd8 648#endif
6772b237
VB
649 } else if (memcmp(med, frame + f, 3) == 0) {
650 /* LLDP-MED */
651#ifndef ENABLE_LLDPMED
652 f += size;
653 hardware->h_rx_unrecognized_cnt++;
654#else
e3a44efb
VB
655 u_int32_t policy;
656 int loctype;
657
6772b237
VB
658 subtype = *(u_int8_t*)(frame + f + 3);
659 switch (subtype) {
660 case LLDP_TLV_MED_CAP:
661 f += 4;
c790233e 662 if (size < 7) {
efe3f9b0 663 LLOG_WARNX("too short LLDP-MED cap "
6772b237
VB
664 "tlv received on %s",
665 hardware->h_ifname);
666 goto malformed;
667 }
40ecae87 668 chassis->c_med_cap_available =
6772b237
VB
669 ntohs(*(u_int16_t*)(frame + f));
670 f += 2;
671 chassis->c_med_type =
672 *(u_int8_t*)(frame + f);
c790233e 673 f += size - 6;
40ecae87
VB
674 chassis->c_med_cap_enabled |=
675 LLDPMED_CAP_CAP;
6772b237 676 break;
efe3f9b0
VB
677 case LLDP_TLV_MED_POLICY:
678 f += 4;
c790233e 679 if (size < 8) {
efe3f9b0
VB
680 LLOG_WARNX("too short LLDP-MED policy "
681 "tlv received on %s",
682 hardware->h_ifname);
683 goto malformed;
684 }
e3a44efb
VB
685 policy = ntohl(*((u_int32_t *)(frame + f)));
686 if (((policy >> 24) < 1) ||
687 ((policy >> 24) > LLDPMED_APPTYPE_LAST)) {
688 LLOG_INFO("unknown policy field %d "
689 "received on %s",
690 hardware->h_ifname);
691 f += 4;
692 break;
693 }
694 chassis->c_med_policy[(policy >> 24) - 1].type =
695 (policy >> 24);
696 chassis->c_med_policy[(policy >> 24) - 1].unknown =
697 ((policy & 0x800000) != 0);
698 chassis->c_med_policy[(policy >> 24) - 1].tagged =
699 ((policy & 0x400000) != 0);
700 chassis->c_med_policy[(policy >> 24) - 1].vid =
701 (policy & 0x001FFE00) >> 9;
702 chassis->c_med_policy[(policy >> 24) - 1].priority =
703 (policy & 0x1C0) >> 6;
704 chassis->c_med_policy[(policy >> 24) - 1].dscp =
705 policy & 0x3F;
c790233e 706 f += size - 4;
40ecae87
VB
707 chassis->c_med_cap_enabled |=
708 LLDPMED_CAP_POLICY;
efe3f9b0
VB
709 break;
710 case LLDP_TLV_MED_LOCATION:
711 f += 4;
712 if (size <= 5) {
713 LLOG_WARNX("too short LLDP-MED location "
714 "tlv received on %s",
715 hardware->h_ifname);
716 goto malformed;
717 }
e3a44efb 718 loctype = *(u_int8_t*)(frame + f);
efe3f9b0 719 f += 1;
e3a44efb
VB
720 if ((loctype < 1) || (loctype > LLDPMED_LOCFORMAT_LAST)) {
721 LLOG_INFO("unknown location type "
722 "received on %s",
723 hardware->h_ifname);
724 f += size - 5;
725 break;
726 }
727 if ((chassis->c_med_location[loctype - 1].data =
b530152e 728 (char*)malloc(size - 5)) == NULL) {
efe3f9b0
VB
729 LLOG_WARN("unable to allocate memory "
730 "for LLDP-MED location for "
731 "frame received on %s",
732 hardware->h_ifname);
733 goto malformed;
734 }
e3a44efb 735 memcpy(chassis->c_med_location[loctype - 1].data,
efe3f9b0
VB
736 (char*)(frame + f),
737 size - 5);
e3a44efb
VB
738 chassis->c_med_location[loctype - 1].data_len =
739 size - 5;
740 chassis->c_med_location[loctype - 1].format = loctype;
efe3f9b0 741 f += size - 5;
40ecae87
VB
742 chassis->c_med_cap_enabled |=
743 LLDPMED_CAP_LOCATION;
efe3f9b0
VB
744 break;
745 case LLDP_TLV_MED_MDI:
746 f += 4;
c790233e 747 if (size < 7) {
efe3f9b0
VB
748 LLOG_WARNX("too short LLDP-MED PoE-MDI "
749 "tlv received on %s",
750 hardware->h_ifname);
751 goto malformed;
752 }
994812b9
VB
753 switch (*(u_int8_t*)(frame + f) & 0xC0) {
754 case 0x0:
755 chassis->c_med_pow_devicetype = LLDPMED_POW_TYPE_PSE;
a49b3a79
VB
756 chassis->c_med_cap_enabled |=
757 LLDPMED_CAP_MDI_PSE;
994812b9
VB
758 switch (*(u_int8_t*)(frame + f) & 0x30) {
759 case 0x0:
760 chassis->c_med_pow_source =
761 LLDPMED_POW_SOURCE_UNKNOWN;
762 break;
763 case 0x10:
764 chassis->c_med_pow_source =
765 LLDPMED_POW_SOURCE_PRIMARY;
766 break;
767 case 0x20:
768 chassis->c_med_pow_source =
769 LLDPMED_POW_SOURCE_BACKUP;
770 break;
771 default:
772 chassis->c_med_pow_source =
773 LLDPMED_POW_SOURCE_RESERVED;
774 }
775 break;
776 case 0x40:
777 chassis->c_med_pow_devicetype = LLDPMED_POW_TYPE_PD;
a49b3a79
VB
778 chassis->c_med_cap_enabled |=
779 LLDPMED_CAP_MDI_PD;
994812b9
VB
780 switch (*(u_int8_t*)(frame + f) & 0x30) {
781 case 0x0:
782 chassis->c_med_pow_source =
783 LLDPMED_POW_SOURCE_UNKNOWN;
784 break;
785 case 0x10:
786 chassis->c_med_pow_source =
787 LLDPMED_POW_SOURCE_PSE;
788 break;
789 case 0x20:
790 chassis->c_med_pow_source =
791 LLDPMED_POW_SOURCE_LOCAL;
792 break;
793 default:
794 chassis->c_med_pow_source =
795 LLDPMED_POW_SOURCE_BOTH;
796 }
797 break;
798 default:
799 chassis->c_med_pow_devicetype =
800 LLDPMED_POW_TYPE_RESERVED;
801 }
802 switch (*(u_int8_t*)(frame + f) & 0x0F) {
803 case 0x0:
804 chassis->c_med_pow_priority =
805 LLDPMED_POW_PRIO_UNKNOWN;
806 break;
807 case 0x1:
808 chassis->c_med_pow_priority =
809 LLDPMED_POW_PRIO_CRITICAL;
810 break;
811 case 0x2:
812 chassis->c_med_pow_priority =
813 LLDPMED_POW_PRIO_HIGH;
814 break;
815 case 0x3:
816 chassis->c_med_pow_priority =
817 LLDPMED_POW_PRIO_LOW;
818 break;
819 default:
820 chassis->c_med_pow_priority =
821 LLDPMED_POW_PRIO_UNKNOWN;
822 }
efe3f9b0 823 f += 1;
994812b9 824 chassis->c_med_pow_val =
efe3f9b0 825 ntohs(*(u_int16_t*)(frame + f));
c790233e 826 f += size - 5;
efe3f9b0 827 break;
6772b237
VB
828 case LLDP_TLV_MED_IV_HW:
829 case LLDP_TLV_MED_IV_SW:
830 case LLDP_TLV_MED_IV_FW:
831 case LLDP_TLV_MED_IV_SN:
832 case LLDP_TLV_MED_IV_MANUF:
833 case LLDP_TLV_MED_IV_MODEL:
834 case LLDP_TLV_MED_IV_ASSET:
835 f += 4;
836 if (size <= 4)
837 b = NULL;
838 else {
efe3f9b0
VB
839 if ((b = (char*)malloc(size - 3)) ==
840 NULL) {
841 LLOG_WARN("unable to allocate "
842 "memory for LLDP-MED "
843 "inventory for frame "
844 "received on %s",
845 hardware->h_ifname);
846 goto malformed;
847 }
6772b237
VB
848 strlcpy(b,
849 (char*)(frame + f),
44cbe568 850 size - 3);
6772b237
VB
851 }
852 switch (subtype) {
853 case LLDP_TLV_MED_IV_HW:
854 chassis->c_med_hw = b;
855 break;
856 case LLDP_TLV_MED_IV_FW:
857 chassis->c_med_fw = b;
858 break;
859 case LLDP_TLV_MED_IV_SW:
860 chassis->c_med_sw = b;
861 break;
862 case LLDP_TLV_MED_IV_SN:
863 chassis->c_med_sn = b;
864 break;
865 case LLDP_TLV_MED_IV_MANUF:
866 chassis->c_med_manuf = b;
867 break;
868 case LLDP_TLV_MED_IV_MODEL:
869 chassis->c_med_fw = b;
870 break;
871 case LLDP_TLV_MED_IV_ASSET:
72c4c96f 872 chassis->c_med_asset = b;
6772b237
VB
873 break;
874 default:
875 LLOG_WARNX("should not be there!");
876 free(b);
877 break;
878 }
879 f += size - 4;
40ecae87
VB
880 chassis->c_med_cap_enabled |=
881 LLDPMED_CAP_IV;
6772b237
VB
882 break;
883 default:
884 /* Unknown LLDP MED, ignore it */
885 f += size;
886 hardware->h_rx_unrecognized_cnt++;
887 }
888#endif /* ENABLE_LLDPMED */
43c02e7b 889 } else {
9ca19b69 890 LLOG_INFO("unknown org tlv received on %s",
43c02e7b 891 hardware->h_ifname);
37387046 892 hardware->h_rx_unrecognized_cnt++;
9ca19b69 893 f += size;
43c02e7b
VB
894 }
895 break;
896 default:
897 LLOG_WARNX("unknown tlv (%d) received on %s",
898 type, hardware->h_ifname);
899 goto malformed;
900 }
901 }
902
903 /* Some random check */
904 if ((chassis->c_id == NULL) ||
905 (port->p_id == NULL) ||
906 (chassis->c_ttl == 0) ||
907 (gotend == 0)) {
908 LLOG_WARNX("some mandatory tlv are missing for frame received on %s",
909 hardware->h_ifname);
910 goto malformed;
911 }
912#define NOTRECEIVED "Not received"
913 if (chassis->c_name == NULL) {
914 if ((chassis->c_name = (char *)calloc(1, strlen(NOTRECEIVED) + 1)) == NULL) {
915 LLOG_WARNX("unable to allocate null chassis name");
916 goto malformed;
917 }
918 memcpy(chassis->c_name, NOTRECEIVED, strlen(NOTRECEIVED));
919 }
920 if (chassis->c_descr == NULL) {
921 if ((chassis->c_descr = (char *)calloc(1, strlen(NOTRECEIVED) + 1)) == NULL) {
922 LLOG_WARNX("unable to allocate null chassis description");
923 goto malformed;
924 }
925 memcpy(chassis->c_descr, NOTRECEIVED, strlen(NOTRECEIVED));
926 }
927 if (port->p_descr == NULL) {
928 if ((port->p_descr = (char *)calloc(1, strlen(NOTRECEIVED) + 1)) == NULL) {
929 LLOG_WARNX("unable to allocate null port description");
930 goto malformed;
931 }
932 memcpy(port->p_descr, NOTRECEIVED, strlen(NOTRECEIVED));
933 }
934 *newchassis = chassis;
935 *newport = port;
936 return 1;
937malformed:
d3322e23
VB
938 lldpd_chassis_cleanup(chassis);
939 lldpd_port_cleanup(port);
43c02e7b
VB
940 return -1;
941}