1 /* -*- mode: c; c-file-style: "openbsd" -*- */
3 * Copyright (c) 2008 Vincent Bernat <bernat@luffy.cx>
5 * Permission to use, copy, modify, and/or distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
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.
24 #include <sys/types.h>
25 #include <sys/socket.h>
26 #include <sys/ioctl.h>
29 lldpd_af_to_lldp_proto(int af
)
33 return LLDP_MGMT_ADDR_IP4
;
35 return LLDP_MGMT_ADDR_IP6
;
37 return LLDP_MGMT_ADDR_NONE
;
42 lldpd_af_from_lldp_proto(int proto
)
45 case LLDP_MGMT_ADDR_IP4
:
47 case LLDP_MGMT_ADDR_IP6
:
50 return LLDPD_AF_UNSPEC
;
54 static int _lldp_send(struct lldpd
*global
,
55 struct lldpd_hardware
*hardware
,
56 u_int8_t c_id_subtype
,
59 u_int8_t p_id_subtype
,
64 struct lldpd_port
*port
;
65 struct lldpd_chassis
*chassis
;
66 struct lldpd_frame
*frame
;
68 u_int8_t
*packet
, *pos
, *tlv
;
69 struct lldpd_mgmt
*mgmt
;
72 u_int8_t mcastaddr_regular
[] = LLDP_ADDR_NEAREST_BRIDGE
;
73 u_int8_t mcastaddr_nontpmr
[] = LLDP_ADDR_NEAREST_NONTPMR_BRIDGE
;
74 u_int8_t mcastaddr_customer
[] = LLDP_ADDR_NEAREST_CUSTOMER_BRIDGE
;
77 const u_int8_t dot1
[] = LLDP_TLV_ORG_DOT1
;
78 struct lldpd_vlan
*vlan
;
79 struct lldpd_ppvid
*ppvid
;
83 const u_int8_t dot3
[] = LLDP_TLV_ORG_DOT3
;
87 const u_int8_t med
[] = LLDP_TLV_ORG_MED
;
90 struct lldpd_custom
*custom
;
92 port
= &hardware
->h_lport
;
93 chassis
= port
->p_chassis
;
94 length
= hardware
->h_mtu
;
95 if ((packet
= (u_int8_t
*)calloc(1, length
)) == NULL
)
100 switch (global
->g_config
.c_lldp_agent_type
) {
101 case LLDP_AGENT_TYPE_NEAREST_NONTPMR_BRIDGE
: mcastaddr
= mcastaddr_nontpmr
; break;
102 case LLDP_AGENT_TYPE_NEAREST_CUSTOMER_BRIDGE
: mcastaddr
= mcastaddr_customer
; break;
103 case LLDP_AGENT_TYPE_NEAREST_BRIDGE
:
104 default: mcastaddr
= mcastaddr_regular
; break;
107 /* LLDP multicast address */
108 POKE_BYTES(mcastaddr
, ETHER_ADDR_LEN
) &&
109 /* Source MAC address */
110 POKE_BYTES(&hardware
->h_lladdr
, ETHER_ADDR_LEN
) &&
112 POKE_UINT16(ETHERTYPE_LLDP
)))
117 POKE_START_LLDP_TLV(LLDP_TLV_CHASSIS_ID
) &&
118 POKE_UINT8(c_id_subtype
) &&
119 POKE_BYTES(c_id
, c_id_len
) &&
125 POKE_START_LLDP_TLV(LLDP_TLV_PORT_ID
) &&
126 POKE_UINT8(p_id_subtype
) &&
127 POKE_BYTES(p_id
, p_id_len
) &&
133 POKE_START_LLDP_TLV(LLDP_TLV_TTL
) &&
134 POKE_UINT16(shutdown
?0:(global
?global
->g_config
.c_ttl
:180)) &&
142 if (chassis
->c_name
&& *chassis
->c_name
!= '\0') {
144 POKE_START_LLDP_TLV(LLDP_TLV_SYSTEM_NAME
) &&
145 POKE_BYTES(chassis
->c_name
, strlen(chassis
->c_name
)) &&
150 /* System description (skip it if empty) */
151 if (chassis
->c_descr
&& *chassis
->c_descr
!= '\0') {
153 POKE_START_LLDP_TLV(LLDP_TLV_SYSTEM_DESCR
) &&
154 POKE_BYTES(chassis
->c_descr
, strlen(chassis
->c_descr
)) &&
159 /* System capabilities */
160 if (global
->g_config
.c_cap_advertise
&& chassis
->c_cap_available
) {
162 POKE_START_LLDP_TLV(LLDP_TLV_SYSTEM_CAP
) &&
163 POKE_UINT16(chassis
->c_cap_available
) &&
164 POKE_UINT16(chassis
->c_cap_enabled
) &&
169 /* Management addresses */
170 TAILQ_FOREACH(mgmt
, &chassis
->c_mgmt
, m_entries
) {
171 proto
= lldpd_af_to_lldp_proto(mgmt
->m_family
);
172 if (proto
== LLDP_MGMT_ADDR_NONE
) continue;
174 POKE_START_LLDP_TLV(LLDP_TLV_MGMT_ADDR
) &&
175 /* Size of the address, including its type */
176 POKE_UINT8(mgmt
->m_addrsize
+ 1) &&
178 POKE_BYTES(&mgmt
->m_addr
, mgmt
->m_addrsize
)))
181 /* Interface port type, OID */
182 if (mgmt
->m_iface
== 0) {
184 /* We don't know the management interface */
185 POKE_UINT8(LLDP_MGMT_IFACE_UNKNOWN
) &&
190 /* We have the index of the management interface */
191 POKE_UINT8(LLDP_MGMT_IFACE_IFINDEX
) &&
192 POKE_UINT32(mgmt
->m_iface
)))
196 /* We don't provide an OID for management */
202 /* Port description */
203 if (port
->p_descr
&& *port
->p_descr
!= '\0') {
205 POKE_START_LLDP_TLV(LLDP_TLV_PORT_DESCR
) &&
206 POKE_BYTES(port
->p_descr
, strlen(port
->p_descr
)) &&
213 if(port
->p_pvid
!= 0) {
215 POKE_START_LLDP_TLV(LLDP_TLV_ORG
) &&
216 POKE_BYTES(dot1
, sizeof(dot1
)) &&
217 POKE_UINT8(LLDP_TLV_DOT1_PVID
) &&
218 POKE_UINT16(port
->p_pvid
) &&
219 POKE_END_LLDP_TLV
)) {
223 /* Port and Protocol VLAN IDs */
224 TAILQ_FOREACH(ppvid
, &port
->p_ppvids
, p_entries
) {
226 POKE_START_LLDP_TLV(LLDP_TLV_ORG
) &&
227 POKE_BYTES(dot1
, sizeof(dot1
)) &&
228 POKE_UINT8(LLDP_TLV_DOT1_PPVID
) &&
229 POKE_UINT8(ppvid
->p_cap_status
) &&
230 POKE_UINT16(ppvid
->p_ppvid
) &&
231 POKE_END_LLDP_TLV
)) {
236 TAILQ_FOREACH(vlan
, &port
->p_vlans
, v_entries
) {
238 POKE_START_LLDP_TLV(LLDP_TLV_ORG
) &&
239 POKE_BYTES(dot1
, sizeof(dot1
)) &&
240 POKE_UINT8(LLDP_TLV_DOT1_VLANNAME
) &&
241 POKE_UINT16(vlan
->v_vid
) &&
242 POKE_UINT8(strlen(vlan
->v_name
)) &&
243 POKE_BYTES(vlan
->v_name
, strlen(vlan
->v_name
)) &&
247 /* Protocol Identities */
248 TAILQ_FOREACH(pi
, &port
->p_pids
, p_entries
) {
250 POKE_START_LLDP_TLV(LLDP_TLV_ORG
) &&
251 POKE_BYTES(dot1
, sizeof(dot1
)) &&
252 POKE_UINT8(LLDP_TLV_DOT1_PI
) &&
253 POKE_UINT8(pi
->p_pi_len
) &&
254 POKE_BYTES(pi
->p_pi
, pi
->p_pi_len
) &&
261 /* Aggregation status */
263 POKE_START_LLDP_TLV(LLDP_TLV_ORG
) &&
264 POKE_BYTES(dot3
, sizeof(dot3
)) &&
265 POKE_UINT8(LLDP_TLV_DOT3_LA
) &&
266 /* Bit 0 = capability ; Bit 1 = status */
267 POKE_UINT8((port
->p_aggregid
) ? 3:1) &&
268 POKE_UINT32(port
->p_aggregid
) &&
274 POKE_START_LLDP_TLV(LLDP_TLV_ORG
) &&
275 POKE_BYTES(dot3
, sizeof(dot3
)) &&
276 POKE_UINT8(LLDP_TLV_DOT3_MAC
) &&
277 POKE_UINT8(port
->p_macphy
.autoneg_support
|
278 (port
->p_macphy
.autoneg_enabled
<< 1)) &&
279 POKE_UINT16(port
->p_macphy
.autoneg_advertised
) &&
280 POKE_UINT16(port
->p_macphy
.mau_type
) &&
287 POKE_START_LLDP_TLV(LLDP_TLV_ORG
) &&
288 POKE_BYTES(dot3
, sizeof(dot3
)) &&
289 POKE_UINT8(LLDP_TLV_DOT3_MFS
) &&
290 POKE_UINT16(port
->p_mfs
) &&
295 if (port
->p_power
.devicetype
) {
297 POKE_START_LLDP_TLV(LLDP_TLV_ORG
) &&
298 POKE_BYTES(dot3
, sizeof(dot3
)) &&
299 POKE_UINT8(LLDP_TLV_DOT3_POWER
) &&
301 (((2 - port
->p_power
.devicetype
) %(1<< 1))<<0) |
302 (( port
->p_power
.supported
%(1<< 1))<<1) |
303 (( port
->p_power
.enabled
%(1<< 1))<<2) |
304 (( port
->p_power
.paircontrol
%(1<< 1))<<3))) &&
305 POKE_UINT8(port
->p_power
.pairs
) &&
306 POKE_UINT8(port
->p_power
.class)))
309 if (port
->p_power
.powertype
!= LLDP_DOT3_POWER_8023AT_OFF
) {
312 (((port
->p_power
.powertype
==
313 LLDP_DOT3_POWER_8023AT_TYPE1
)?1:0) << 7) |
314 (((port
->p_power
.devicetype
==
315 LLDP_DOT3_POWER_PSE
)?0:1) << 6) |
316 ((port
->p_power
.source
%(1<< 2))<<4) |
317 ((port
->p_power
.priority
%(1<< 2))<<0))) &&
318 POKE_UINT16(port
->p_power
.requested
) &&
319 POKE_UINT16(port
->p_power
.allocated
)))
322 if (!(POKE_END_LLDP_TLV
))
327 #ifdef ENABLE_LLDPMED
328 if (port
->p_med_cap_enabled
) {
330 if (port
->p_med_cap_enabled
& LLDP_MED_CAP_CAP
) {
332 POKE_START_LLDP_TLV(LLDP_TLV_ORG
) &&
333 POKE_BYTES(med
, sizeof(med
)) &&
334 POKE_UINT8(LLDP_TLV_MED_CAP
) &&
335 POKE_UINT16(chassis
->c_med_cap_available
) &&
336 POKE_UINT8(chassis
->c_med_type
) &&
341 /* LLDP-MED inventory */
342 #define LLDP_INVENTORY(value, subtype) \
345 POKE_START_LLDP_TLV(LLDP_TLV_ORG) && \
346 POKE_BYTES(med, sizeof(med)) && \
347 POKE_UINT8(subtype) && \
349 (strlen(value)>32)?32:strlen(value)) && \
350 POKE_END_LLDP_TLV)) \
354 if (port
->p_med_cap_enabled
& LLDP_MED_CAP_IV
) {
355 LLDP_INVENTORY(chassis
->c_med_hw
,
357 LLDP_INVENTORY(chassis
->c_med_fw
,
359 LLDP_INVENTORY(chassis
->c_med_sw
,
361 LLDP_INVENTORY(chassis
->c_med_sn
,
363 LLDP_INVENTORY(chassis
->c_med_manuf
,
364 LLDP_TLV_MED_IV_MANUF
);
365 LLDP_INVENTORY(chassis
->c_med_model
,
366 LLDP_TLV_MED_IV_MODEL
);
367 LLDP_INVENTORY(chassis
->c_med_asset
,
368 LLDP_TLV_MED_IV_ASSET
);
371 /* LLDP-MED location */
372 for (i
= 0; i
< LLDP_MED_LOCFORMAT_LAST
; i
++) {
373 if (port
->p_med_location
[i
].format
== i
+ 1) {
375 POKE_START_LLDP_TLV(LLDP_TLV_ORG
) &&
376 POKE_BYTES(med
, sizeof(med
)) &&
377 POKE_UINT8(LLDP_TLV_MED_LOCATION
) &&
378 POKE_UINT8(port
->p_med_location
[i
].format
) &&
379 POKE_BYTES(port
->p_med_location
[i
].data
,
380 port
->p_med_location
[i
].data_len
) &&
386 /* LLDP-MED network policy */
387 for (i
= 0; i
< LLDP_MED_APPTYPE_LAST
; i
++) {
388 if (port
->p_med_policy
[i
].type
== i
+ 1) {
390 POKE_START_LLDP_TLV(LLDP_TLV_ORG
) &&
391 POKE_BYTES(med
, sizeof(med
)) &&
392 POKE_UINT8(LLDP_TLV_MED_POLICY
) &&
394 ((port
->p_med_policy
[i
].type
%(1<< 8))<<24) |
395 ((port
->p_med_policy
[i
].unknown
%(1<< 1))<<23) |
396 ((port
->p_med_policy
[i
].tagged
%(1<< 1))<<22) |
397 /*((0 %(1<< 1))<<21) |*/
398 ((port
->p_med_policy
[i
].vid
%(1<<12))<< 9) |
399 ((port
->p_med_policy
[i
].priority
%(1<< 3))<< 6) |
400 ((port
->p_med_policy
[i
].dscp
%(1<< 6))<< 0) )) &&
406 /* LLDP-MED POE-MDI */
407 if ((port
->p_med_power
.devicetype
== LLDP_MED_POW_TYPE_PSE
) ||
408 (port
->p_med_power
.devicetype
== LLDP_MED_POW_TYPE_PD
)) {
409 int devicetype
= 0, source
= 0;
411 POKE_START_LLDP_TLV(LLDP_TLV_ORG
) &&
412 POKE_BYTES(med
, sizeof(med
)) &&
413 POKE_UINT8(LLDP_TLV_MED_MDI
)))
415 switch (port
->p_med_power
.devicetype
) {
416 case LLDP_MED_POW_TYPE_PSE
:
418 switch (port
->p_med_power
.source
) {
419 case LLDP_MED_POW_SOURCE_PRIMARY
: source
= 1; break;
420 case LLDP_MED_POW_SOURCE_BACKUP
: source
= 2; break;
421 case LLDP_MED_POW_SOURCE_RESERVED
: source
= 3; break;
422 default: source
= 0; break;
425 case LLDP_MED_POW_TYPE_PD
:
427 switch (port
->p_med_power
.source
) {
428 case LLDP_MED_POW_SOURCE_PSE
: source
= 1; break;
429 case LLDP_MED_POW_SOURCE_LOCAL
: source
= 2; break;
430 case LLDP_MED_POW_SOURCE_BOTH
: source
= 3; break;
431 default: source
= 0; break;
437 ((devicetype
%(1<< 2))<<6) |
438 ((source
%(1<< 2))<<4) |
439 ((port
->p_med_power
.priority
%(1<< 4))<<0) )) &&
440 POKE_UINT16(port
->p_med_power
.val
) &&
448 TAILQ_FOREACH(custom
, &port
->p_custom_list
, next
) {
450 POKE_START_LLDP_TLV(LLDP_TLV_ORG
) &&
451 POKE_BYTES(custom
->oui
, sizeof(custom
->oui
)) &&
452 POKE_UINT8(custom
->subtype
) &&
453 POKE_BYTES(custom
->oui_info
, custom
->oui_info_len
) &&
462 POKE_START_LLDP_TLV(LLDP_TLV_END
) &&
466 if (interfaces_send_helper(global
, hardware
,
467 (char *)packet
, pos
- packet
) == -1) {
468 log_warn("lldp", "unable to send packet on real device for %s",
474 hardware
->h_tx_cnt
++;
476 /* We assume that LLDP frame is the reference */
477 if (!shutdown
&& (frame
= (struct lldpd_frame
*)malloc(
478 sizeof(int) + pos
- packet
)) != NULL
) {
479 frame
->size
= pos
- packet
;
480 memcpy(&frame
->frame
, packet
, frame
->size
);
481 if ((hardware
->h_lport
.p_lastframe
== NULL
) ||
482 (hardware
->h_lport
.p_lastframe
->size
!= frame
->size
) ||
483 (memcmp(hardware
->h_lport
.p_lastframe
->frame
, frame
->frame
,
484 frame
->size
) != 0)) {
485 free(hardware
->h_lport
.p_lastframe
);
486 hardware
->h_lport
.p_lastframe
= frame
;
487 hardware
->h_lport
.p_lastchange
= time(NULL
);
499 /* Send a shutdown LLDPDU. */
501 lldp_send_shutdown(struct lldpd
*global
,
502 struct lldpd_hardware
*hardware
)
504 if (hardware
->h_lchassis_previous_id
== NULL
||
505 hardware
->h_lport_previous_id
== NULL
)
507 return _lldp_send(global
, hardware
,
508 hardware
->h_lchassis_previous_id_subtype
,
509 hardware
->h_lchassis_previous_id
,
510 hardware
->h_lchassis_previous_id_len
,
511 hardware
->h_lport_previous_id_subtype
,
512 hardware
->h_lport_previous_id
,
513 hardware
->h_lport_previous_id_len
,
518 lldp_send(struct lldpd
*global
,
519 struct lldpd_hardware
*hardware
)
521 struct lldpd_port
*port
= &hardware
->h_lport
;
522 struct lldpd_chassis
*chassis
= port
->p_chassis
;
525 /* Check if we have a change. */
526 if (hardware
->h_lchassis_previous_id
!= NULL
&&
527 hardware
->h_lport_previous_id
!= NULL
&&
528 (hardware
->h_lchassis_previous_id_subtype
!= chassis
->c_id_subtype
||
529 hardware
->h_lchassis_previous_id_len
!= chassis
->c_id_len
||
530 hardware
->h_lport_previous_id_subtype
!= port
->p_id_subtype
||
531 hardware
->h_lport_previous_id_len
!= port
->p_id_len
||
532 memcmp(hardware
->h_lchassis_previous_id
,
533 chassis
->c_id
, chassis
->c_id_len
) ||
534 memcmp(hardware
->h_lport_previous_id
,
535 port
->p_id
, port
->p_id_len
))) {
536 log_info("lldp", "MSAP has changed for port %s, sending a shutdown LLDPDU",
538 if ((ret
= lldp_send_shutdown(global
, hardware
)) != 0)
542 log_debug("lldp", "send LLDP PDU to %s",
545 if ((ret
= _lldp_send(global
, hardware
,
546 chassis
->c_id_subtype
,
555 /* Record current chassis and port ID */
556 free(hardware
->h_lchassis_previous_id
);
557 hardware
->h_lchassis_previous_id_subtype
= chassis
->c_id_subtype
;
558 hardware
->h_lchassis_previous_id_len
= chassis
->c_id_len
;
559 if ((hardware
->h_lchassis_previous_id
= malloc(chassis
->c_id_len
)) != NULL
)
560 memcpy(hardware
->h_lchassis_previous_id
, chassis
->c_id
,
562 free(hardware
->h_lport_previous_id
);
563 hardware
->h_lport_previous_id_subtype
= port
->p_id_subtype
;
564 hardware
->h_lport_previous_id_len
= port
->p_id_len
;
565 if ((hardware
->h_lport_previous_id
= malloc(port
->p_id_len
)) != NULL
)
566 memcpy(hardware
->h_lport_previous_id
, port
->p_id
,
572 #define CHECK_TLV_SIZE(x, name) \
573 do { if (tlv_size < (x)) { \
574 log_warnx("lldp", name " TLV too short received on %s", \
575 hardware->h_ifname); \
580 lldp_decode(struct lldpd
*cfg
, char *frame
, int s
,
581 struct lldpd_hardware
*hardware
,
582 struct lldpd_chassis
**newchassis
, struct lldpd_port
**newport
)
584 struct lldpd_chassis
*chassis
;
585 struct lldpd_port
*port
;
586 char lldpaddr
[ETHER_ADDR_LEN
];
587 const char dot1
[] = LLDP_TLV_ORG_DOT1
;
588 const char dot3
[] = LLDP_TLV_ORG_DOT3
;
589 const char med
[] = LLDP_TLV_ORG_MED
;
590 const char dcbx
[] = LLDP_TLV_ORG_DCBX
;
591 unsigned char orgid
[3];
592 int length
, gotend
= 0, ttl_received
= 0;
593 int tlv_size
, tlv_type
, tlv_subtype
;
597 struct lldpd_vlan
*vlan
= NULL
;
599 struct lldpd_ppvid
*ppvid
;
600 struct lldpd_pi
*pi
= NULL
;
602 struct lldpd_mgmt
*mgmt
;
604 u_int8_t addr_str_length
, addr_str_buffer
[32];
605 u_int8_t addr_family
, addr_length
, *addr_ptr
, iface_subtype
;
606 u_int32_t iface_number
, iface
;
608 struct lldpd_custom
*custom
= NULL
;
611 log_debug("lldp", "receive LLDP PDU on %s",
614 if ((chassis
= calloc(1, sizeof(struct lldpd_chassis
))) == NULL
) {
615 log_warn("lldp", "failed to allocate remote chassis");
618 TAILQ_INIT(&chassis
->c_mgmt
);
619 if ((port
= calloc(1, sizeof(struct lldpd_port
))) == NULL
) {
620 log_warn("lldp", "failed to allocate remote port");
625 TAILQ_INIT(&port
->p_vlans
);
626 TAILQ_INIT(&port
->p_ppvids
);
627 TAILQ_INIT(&port
->p_pids
);
630 TAILQ_INIT(&port
->p_custom_list
);
634 pos
= (u_int8_t
*)frame
;
636 if (length
< 2*ETHER_ADDR_LEN
+ sizeof(u_int16_t
)) {
637 log_warnx("lldp", "too short frame received on %s", hardware
->h_ifname
);
640 PEEK_BYTES(lldpaddr
, ETHER_ADDR_LEN
);
641 if (memcmp(lldpaddr
, (const char [])LLDP_ADDR_NEAREST_BRIDGE
, ETHER_ADDR_LEN
) &&
642 memcmp(lldpaddr
, (const char [])LLDP_ADDR_NEAREST_NONTPMR_BRIDGE
, ETHER_ADDR_LEN
) &&
643 memcmp(lldpaddr
, (const char [])LLDP_ADDR_NEAREST_CUSTOMER_BRIDGE
, ETHER_ADDR_LEN
)) {
644 log_info("lldp", "frame not targeted at LLDP multicast address received on %s",
648 PEEK_DISCARD(ETHER_ADDR_LEN
); /* Skip source address */
649 if (PEEK_UINT16
!= ETHERTYPE_LLDP
) {
650 log_info("lldp", "non LLDP frame received on %s",
655 while (length
&& (!gotend
)) {
657 log_warnx("lldp", "tlv header too short received on %s",
661 tlv_size
= PEEK_UINT16
;
662 tlv_type
= tlv_size
>> 9;
663 tlv_size
= tlv_size
& 0x1ff;
664 (void)PEEK_SAVE(tlv
);
665 if (length
< tlv_size
) {
666 log_warnx("lldp", "frame too short for tlv received on %s",
673 log_warnx("lldp", "lldp end received with size not null on %s",
678 log_debug("lldp", "extra data after lldp end on %s",
682 case LLDP_TLV_CHASSIS_ID
:
683 case LLDP_TLV_PORT_ID
:
684 CHECK_TLV_SIZE(2, "Port Id");
685 tlv_subtype
= PEEK_UINT8
;
686 if ((tlv_subtype
== 0) || (tlv_subtype
> 7)) {
687 log_warnx("lldp", "unknown subtype for tlv id received on %s",
691 if ((b
= (char *)calloc(1, tlv_size
- 1)) == NULL
) {
692 log_warn("lldp", "unable to allocate memory for id tlv "
697 PEEK_BYTES(b
, tlv_size
- 1);
698 if (tlv_type
== LLDP_TLV_PORT_ID
) {
699 port
->p_id_subtype
= tlv_subtype
;
701 port
->p_id_len
= tlv_size
- 1;
703 chassis
->c_id_subtype
= tlv_subtype
;
705 chassis
->c_id_len
= tlv_size
- 1;
709 CHECK_TLV_SIZE(2, "TTL");
710 port
->p_ttl
= PEEK_UINT16
;
713 case LLDP_TLV_PORT_DESCR
:
714 case LLDP_TLV_SYSTEM_NAME
:
715 case LLDP_TLV_SYSTEM_DESCR
:
717 log_debug("lldp", "empty tlv received on %s",
721 if ((b
= (char *)calloc(1, tlv_size
+ 1)) == NULL
) {
722 log_warn("lldp", "unable to allocate memory for string tlv "
727 PEEK_BYTES(b
, tlv_size
);
728 if (tlv_type
== LLDP_TLV_PORT_DESCR
)
730 else if (tlv_type
== LLDP_TLV_SYSTEM_NAME
)
732 else chassis
->c_descr
= b
;
734 case LLDP_TLV_SYSTEM_CAP
:
735 CHECK_TLV_SIZE(4, "System capabilities");
736 chassis
->c_cap_available
= PEEK_UINT16
;
737 chassis
->c_cap_enabled
= PEEK_UINT16
;
739 case LLDP_TLV_MGMT_ADDR
:
740 CHECK_TLV_SIZE(1, "Management address");
741 addr_str_length
= PEEK_UINT8
;
742 if (addr_str_length
> sizeof(addr_str_buffer
)) {
743 log_warnx("lldp", "too large management address on %s",
747 CHECK_TLV_SIZE(1 + addr_str_length
, "Management address");
748 PEEK_BYTES(addr_str_buffer
, addr_str_length
);
749 addr_length
= addr_str_length
- 1;
750 addr_family
= addr_str_buffer
[0];
751 addr_ptr
= &addr_str_buffer
[1];
752 CHECK_TLV_SIZE(1 + addr_str_length
+ 5, "Management address");
753 iface_subtype
= PEEK_UINT8
;
754 iface_number
= PEEK_UINT32
;
756 af
= lldpd_af_from_lldp_proto(addr_family
);
757 if (af
== LLDPD_AF_UNSPEC
)
759 if (iface_subtype
== LLDP_MGMT_IFACE_IFINDEX
)
760 iface
= iface_number
;
763 mgmt
= lldpd_alloc_mgmt(af
, addr_ptr
, addr_length
, iface
);
766 log_warn("lldp", "unable to allocate memory "
767 "for management address");
769 log_warn("lldp", "too large management address "
770 "received on %s", hardware
->h_ifname
);
773 TAILQ_INSERT_TAIL(&chassis
->c_mgmt
, mgmt
, m_entries
);
776 CHECK_TLV_SIZE(1 + (int)sizeof(orgid
), "Organisational");
777 PEEK_BYTES(orgid
, sizeof(orgid
));
778 tlv_subtype
= PEEK_UINT8
;
779 if (memcmp(dot1
, orgid
, sizeof(orgid
)) == 0) {
781 hardware
->h_rx_unrecognized_cnt
++;
784 switch (tlv_subtype
) {
785 case LLDP_TLV_DOT1_VLANNAME
:
786 CHECK_TLV_SIZE(7, "VLAN");
787 if ((vlan
= (struct lldpd_vlan
*)calloc(1,
788 sizeof(struct lldpd_vlan
))) == NULL
) {
789 log_warn("lldp", "unable to alloc vlan "
791 "tlv received on %s",
795 vlan
->v_vid
= PEEK_UINT16
;
796 vlan_len
= PEEK_UINT8
;
797 CHECK_TLV_SIZE(7 + vlan_len
, "VLAN");
799 (char *)calloc(1, vlan_len
+ 1)) == NULL
) {
800 log_warn("lldp", "unable to alloc vlan name for "
801 "tlv received on %s",
805 PEEK_BYTES(vlan
->v_name
, vlan_len
);
806 TAILQ_INSERT_TAIL(&port
->p_vlans
,
810 case LLDP_TLV_DOT1_PVID
:
811 CHECK_TLV_SIZE(6, "PVID");
812 port
->p_pvid
= PEEK_UINT16
;
814 case LLDP_TLV_DOT1_PPVID
:
815 CHECK_TLV_SIZE(7, "PPVID");
816 /* validation needed */
817 /* PPVID has to be unique if more than
818 one PPVID TLVs are received -
819 discard if duplicate */
820 /* if support bit is not set and
821 enabled bit is set - PPVID TLV is
822 considered error and discarded */
823 /* if PPVID > 4096 - bad and discard */
824 if ((ppvid
= (struct lldpd_ppvid
*)calloc(1,
825 sizeof(struct lldpd_ppvid
))) == NULL
) {
826 log_warn("lldp", "unable to alloc ppvid "
828 "tlv received on %s",
832 ppvid
->p_cap_status
= PEEK_UINT8
;
833 ppvid
->p_ppvid
= PEEK_UINT16
;
834 TAILQ_INSERT_TAIL(&port
->p_ppvids
,
837 case LLDP_TLV_DOT1_PI
:
838 /* validation needed */
839 /* PI has to be unique if more than
840 one PI TLVs are received - discard
842 CHECK_TLV_SIZE(5, "PI");
843 if ((pi
= (struct lldpd_pi
*)calloc(1,
844 sizeof(struct lldpd_pi
))) == NULL
) {
845 log_warn("lldp", "unable to alloc PI "
847 "tlv received on %s",
851 pi
->p_pi_len
= PEEK_UINT8
;
852 CHECK_TLV_SIZE(5 + pi
->p_pi_len
, "PI");
854 (char *)calloc(1, pi
->p_pi_len
)) == NULL
) {
855 log_warn("lldp", "unable to alloc pid name for "
856 "tlv received on %s",
860 PEEK_BYTES(pi
->p_pi
, pi
->p_pi_len
);
861 TAILQ_INSERT_TAIL(&port
->p_pids
,
866 /* Unknown Dot1 TLV, ignore it */
867 hardware
->h_rx_unrecognized_cnt
++;
870 } else if (memcmp(dot3
, orgid
, sizeof(orgid
)) == 0) {
872 hardware
->h_rx_unrecognized_cnt
++;
875 switch (tlv_subtype
) {
876 case LLDP_TLV_DOT3_MAC
:
877 CHECK_TLV_SIZE(9, "MAC/PHY");
878 port
->p_macphy
.autoneg_support
= PEEK_UINT8
;
879 port
->p_macphy
.autoneg_enabled
=
880 (port
->p_macphy
.autoneg_support
& 0x2) >> 1;
881 port
->p_macphy
.autoneg_support
=
882 port
->p_macphy
.autoneg_support
& 0x1;
883 port
->p_macphy
.autoneg_advertised
=
885 port
->p_macphy
.mau_type
= PEEK_UINT16
;
887 case LLDP_TLV_DOT3_LA
:
888 CHECK_TLV_SIZE(9, "Link aggregation");
890 port
->p_aggregid
= PEEK_UINT32
;
892 case LLDP_TLV_DOT3_MFS
:
893 CHECK_TLV_SIZE(6, "MFS");
894 port
->p_mfs
= PEEK_UINT16
;
896 case LLDP_TLV_DOT3_POWER
:
897 CHECK_TLV_SIZE(7, "Power");
898 port
->p_power
.devicetype
= PEEK_UINT8
;
899 port
->p_power
.supported
=
900 (port
->p_power
.devicetype
& 0x2) >> 1;
901 port
->p_power
.enabled
=
902 (port
->p_power
.devicetype
& 0x4) >> 2;
903 port
->p_power
.paircontrol
=
904 (port
->p_power
.devicetype
& 0x8) >> 3;
905 port
->p_power
.devicetype
=
906 (port
->p_power
.devicetype
& 0x1)?
907 LLDP_DOT3_POWER_PSE
:LLDP_DOT3_POWER_PD
;
908 port
->p_power
.pairs
= PEEK_UINT8
;
909 port
->p_power
.class = PEEK_UINT8
;
911 if (tlv_size
>= 12) {
912 port
->p_power
.powertype
= PEEK_UINT8
;
913 port
->p_power
.source
=
914 (port
->p_power
.powertype
& (1<<5 | 1<<4)) >> 4;
915 port
->p_power
.priority
=
916 (port
->p_power
.powertype
& (1<<1 | 1<<0));
917 port
->p_power
.powertype
=
918 (port
->p_power
.powertype
& (1<<7))?
919 LLDP_DOT3_POWER_8023AT_TYPE1
:
920 LLDP_DOT3_POWER_8023AT_TYPE2
;
921 port
->p_power
.requested
= PEEK_UINT16
;
922 port
->p_power
.allocated
= PEEK_UINT16
;
924 port
->p_power
.powertype
=
925 LLDP_DOT3_POWER_8023AT_OFF
;
928 /* Unknown Dot3 TLV, ignore it */
929 hardware
->h_rx_unrecognized_cnt
++;
932 } else if (memcmp(med
, orgid
, sizeof(orgid
)) == 0) {
934 #ifndef ENABLE_LLDPMED
935 hardware
->h_rx_unrecognized_cnt
++;
941 switch (tlv_subtype
) {
942 case LLDP_TLV_MED_CAP
:
943 CHECK_TLV_SIZE(7, "LLDP-MED capabilities");
944 chassis
->c_med_cap_available
= PEEK_UINT16
;
945 chassis
->c_med_type
= PEEK_UINT8
;
946 port
->p_med_cap_enabled
|=
949 case LLDP_TLV_MED_POLICY
:
950 CHECK_TLV_SIZE(8, "LLDP-MED policy");
951 policy
= PEEK_UINT32
;
952 if (((policy
>> 24) < 1) ||
953 ((policy
>> 24) > LLDP_MED_APPTYPE_LAST
)) {
954 log_info("lldp", "unknown policy field %d "
960 port
->p_med_policy
[(policy
>> 24) - 1].type
=
962 port
->p_med_policy
[(policy
>> 24) - 1].unknown
=
963 ((policy
& 0x800000) != 0);
964 port
->p_med_policy
[(policy
>> 24) - 1].tagged
=
965 ((policy
& 0x400000) != 0);
966 port
->p_med_policy
[(policy
>> 24) - 1].vid
=
967 (policy
& 0x001FFE00) >> 9;
968 port
->p_med_policy
[(policy
>> 24) - 1].priority
=
969 (policy
& 0x1C0) >> 6;
970 port
->p_med_policy
[(policy
>> 24) - 1].dscp
=
972 port
->p_med_cap_enabled
|=
975 case LLDP_TLV_MED_LOCATION
:
976 CHECK_TLV_SIZE(5, "LLDP-MED Location");
977 loctype
= PEEK_UINT8
;
979 (loctype
> LLDP_MED_LOCFORMAT_LAST
)) {
980 log_info("lldp", "unknown location type "
985 if ((port
->p_med_location
[loctype
- 1].data
=
986 (char*)malloc(tlv_size
- 5)) == NULL
) {
987 log_warn("lldp", "unable to allocate memory "
988 "for LLDP-MED location for "
989 "frame received on %s",
993 PEEK_BYTES(port
->p_med_location
[loctype
- 1].data
,
995 port
->p_med_location
[loctype
- 1].data_len
=
997 port
->p_med_location
[loctype
- 1].format
= loctype
;
998 port
->p_med_cap_enabled
|=
999 LLDP_MED_CAP_LOCATION
;
1001 case LLDP_TLV_MED_MDI
:
1002 CHECK_TLV_SIZE(7, "LLDP-MED PoE-MDI");
1004 switch (power
& 0xC0) {
1006 port
->p_med_power
.devicetype
= LLDP_MED_POW_TYPE_PSE
;
1007 port
->p_med_cap_enabled
|=
1008 LLDP_MED_CAP_MDI_PSE
;
1009 switch (power
& 0x30) {
1011 port
->p_med_power
.source
=
1012 LLDP_MED_POW_SOURCE_UNKNOWN
;
1015 port
->p_med_power
.source
=
1016 LLDP_MED_POW_SOURCE_PRIMARY
;
1019 port
->p_med_power
.source
=
1020 LLDP_MED_POW_SOURCE_BACKUP
;
1023 port
->p_med_power
.source
=
1024 LLDP_MED_POW_SOURCE_RESERVED
;
1028 port
->p_med_power
.devicetype
= LLDP_MED_POW_TYPE_PD
;
1029 port
->p_med_cap_enabled
|=
1030 LLDP_MED_CAP_MDI_PD
;
1031 switch (power
& 0x30) {
1033 port
->p_med_power
.source
=
1034 LLDP_MED_POW_SOURCE_UNKNOWN
;
1037 port
->p_med_power
.source
=
1038 LLDP_MED_POW_SOURCE_PSE
;
1041 port
->p_med_power
.source
=
1042 LLDP_MED_POW_SOURCE_LOCAL
;
1045 port
->p_med_power
.source
=
1046 LLDP_MED_POW_SOURCE_BOTH
;
1050 port
->p_med_power
.devicetype
=
1051 LLDP_MED_POW_TYPE_RESERVED
;
1053 if ((power
& 0x0F) > LLDP_MED_POW_PRIO_LOW
)
1054 port
->p_med_power
.priority
=
1055 LLDP_MED_POW_PRIO_UNKNOWN
;
1057 port
->p_med_power
.priority
=
1059 port
->p_med_power
.val
= PEEK_UINT16
;
1061 case LLDP_TLV_MED_IV_HW
:
1062 case LLDP_TLV_MED_IV_SW
:
1063 case LLDP_TLV_MED_IV_FW
:
1064 case LLDP_TLV_MED_IV_SN
:
1065 case LLDP_TLV_MED_IV_MANUF
:
1066 case LLDP_TLV_MED_IV_MODEL
:
1067 case LLDP_TLV_MED_IV_ASSET
:
1071 if ((b
= (char*)malloc(tlv_size
- 3)) ==
1073 log_warn("lldp", "unable to allocate "
1074 "memory for LLDP-MED "
1075 "inventory for frame "
1077 hardware
->h_ifname
);
1080 PEEK_BYTES(b
, tlv_size
- 4);
1081 b
[tlv_size
- 4] = '\0';
1083 switch (tlv_subtype
) {
1084 case LLDP_TLV_MED_IV_HW
:
1085 chassis
->c_med_hw
= b
;
1087 case LLDP_TLV_MED_IV_FW
:
1088 chassis
->c_med_fw
= b
;
1090 case LLDP_TLV_MED_IV_SW
:
1091 chassis
->c_med_sw
= b
;
1093 case LLDP_TLV_MED_IV_SN
:
1094 chassis
->c_med_sn
= b
;
1096 case LLDP_TLV_MED_IV_MANUF
:
1097 chassis
->c_med_manuf
= b
;
1099 case LLDP_TLV_MED_IV_MODEL
:
1100 chassis
->c_med_model
= b
;
1102 case LLDP_TLV_MED_IV_ASSET
:
1103 chassis
->c_med_asset
= b
;
1106 port
->p_med_cap_enabled
|=
1110 /* Unknown LLDP MED, ignore it */
1111 hardware
->h_rx_unrecognized_cnt
++;
1113 #endif /* ENABLE_LLDPMED */
1114 } else if (memcmp(dcbx
, orgid
, sizeof(orgid
)) == 0) {
1115 log_debug("lldp", "unsupported DCBX tlv received on %s - ignore",
1116 hardware
->h_ifname
);
1117 hardware
->h_rx_unrecognized_cnt
++;
1119 log_debug("lldp", "unknown org tlv [%02x:%02x:%02x] received on %s",
1120 orgid
[0], orgid
[1], orgid
[2],
1121 hardware
->h_ifname
);
1122 hardware
->h_rx_unrecognized_cnt
++;
1123 #ifdef ENABLE_CUSTOM
1124 custom
= (struct lldpd_custom
*)calloc(1, sizeof(struct lldpd_custom
));
1127 "unable to allocate memory for custom TLV");
1130 custom
->oui_info_len
= tlv_size
> 4 ? tlv_size
- 4 : 0;
1131 memcpy(custom
->oui
, orgid
, sizeof(custom
->oui
));
1132 custom
->subtype
= tlv_subtype
;
1133 if (custom
->oui_info_len
> 0) {
1134 custom
->oui_info
= malloc(custom
->oui_info_len
);
1135 if (!custom
->oui_info
) {
1137 "unable to allocate memory for custom TLV data");
1140 PEEK_BYTES(custom
->oui_info
, custom
->oui_info_len
);
1142 TAILQ_INSERT_TAIL(&port
->p_custom_list
, custom
, next
);
1148 log_warnx("lldp", "unknown tlv (%d) received on %s",
1149 tlv_type
, hardware
->h_ifname
);
1152 if (pos
> tlv
+ tlv_size
) {
1153 log_warnx("lldp", "BUG: already past TLV!");
1156 PEEK_DISCARD(tlv
+ tlv_size
- pos
);
1159 /* Some random check */
1160 if ((chassis
->c_id
== NULL
) ||
1161 (port
->p_id
== NULL
) ||
1164 log_warnx("lldp", "some mandatory tlv are missing for frame received on %s",
1165 hardware
->h_ifname
);
1168 *newchassis
= chassis
;
1172 #ifdef ENABLE_CUSTOM
1179 lldpd_chassis_cleanup(chassis
, 1);
1180 lldpd_port_cleanup(port
, 1);