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.
25 #include <sys/types.h>
26 #include <sys/socket.h>
27 #include <sys/ioctl.h>
28 #include <netpacket/packet.h>
29 #include <linux/sockios.h>
32 lldpd_af_to_lldp_proto(int af
)
36 return LLDP_MGMT_ADDR_IP4
;
38 return LLDP_MGMT_ADDR_IP6
;
40 return LLDP_MGMT_ADDR_NONE
;
45 lldpd_af_from_lldp_proto(int proto
)
48 case LLDP_MGMT_ADDR_IP4
:
50 case LLDP_MGMT_ADDR_IP6
:
53 return LLDPD_AF_UNSPEC
;
58 lldp_send(struct lldpd
*global
,
59 struct lldpd_hardware
*hardware
)
61 struct lldpd_port
*port
;
62 struct lldpd_chassis
*chassis
;
63 struct lldpd_frame
*frame
;
65 u_int8_t
*packet
, *pos
, *tlv
;
66 struct lldpd_mgmt
*mgmt
;
69 u_int8_t mcastaddr
[] = LLDP_MULTICAST_ADDR
;
71 const u_int8_t dot1
[] = LLDP_TLV_ORG_DOT1
;
72 struct lldpd_vlan
*vlan
;
73 struct lldpd_ppvid
*ppvid
;
77 const u_int8_t dot3
[] = LLDP_TLV_ORG_DOT3
;
81 const u_int8_t med
[] = LLDP_TLV_ORG_MED
;
84 port
= &hardware
->h_lport
;
85 chassis
= port
->p_chassis
;
86 length
= hardware
->h_mtu
;
87 if ((packet
= (u_int8_t
*)malloc(length
)) == NULL
)
89 memset(packet
, 0, length
);
94 /* LLDP multicast address */
95 POKE_BYTES(mcastaddr
, sizeof(mcastaddr
)) &&
96 /* Source MAC address */
97 POKE_BYTES(&hardware
->h_lladdr
, sizeof(hardware
->h_lladdr
)) &&
99 POKE_UINT16(ETHERTYPE_LLDP
)))
104 POKE_START_LLDP_TLV(LLDP_TLV_CHASSIS_ID
) &&
105 POKE_UINT8(chassis
->c_id_subtype
) &&
106 POKE_BYTES(chassis
->c_id
, chassis
->c_id_len
) &&
112 POKE_START_LLDP_TLV(LLDP_TLV_PORT_ID
) &&
113 POKE_UINT8(port
->p_id_subtype
) &&
114 POKE_BYTES(port
->p_id
, port
->p_id_len
) &&
120 POKE_START_LLDP_TLV(LLDP_TLV_TTL
) &&
121 POKE_UINT16(chassis
->c_ttl
) &&
127 POKE_START_LLDP_TLV(LLDP_TLV_SYSTEM_NAME
) &&
128 POKE_BYTES(chassis
->c_name
, strlen(chassis
->c_name
)) &&
132 /* System description */
134 POKE_START_LLDP_TLV(LLDP_TLV_SYSTEM_DESCR
) &&
135 POKE_BYTES(chassis
->c_descr
, strlen(chassis
->c_descr
)) &&
139 /* System capabilities */
141 POKE_START_LLDP_TLV(LLDP_TLV_SYSTEM_CAP
) &&
142 POKE_UINT16(chassis
->c_cap_available
) &&
143 POKE_UINT16(chassis
->c_cap_enabled
) &&
147 /* Management addresses */
148 TAILQ_FOREACH(mgmt
, &chassis
->c_mgmt
, m_entries
) {
149 proto
= lldpd_af_to_lldp_proto(mgmt
->m_family
);
150 assert(proto
!= LLDP_MGMT_ADDR_NONE
);
152 POKE_START_LLDP_TLV(LLDP_TLV_MGMT_ADDR
) &&
153 /* Size of the address, including its type */
154 POKE_UINT8(mgmt
->m_addrsize
+ 1) &&
156 POKE_BYTES(&mgmt
->m_addr
, mgmt
->m_addrsize
)))
159 /* Interface port type, OID */
160 if (mgmt
->m_iface
== 0) {
162 /* We don't know the management interface */
163 POKE_UINT8(LLDP_MGMT_IFACE_UNKNOWN
) &&
168 /* We have the index of the management interface */
169 POKE_UINT8(LLDP_MGMT_IFACE_IFINDEX
) &&
170 POKE_UINT32(mgmt
->m_iface
)))
174 /* We don't provide an OID for management */
180 /* Port description */
182 POKE_START_LLDP_TLV(LLDP_TLV_PORT_DESCR
) &&
183 POKE_BYTES(port
->p_descr
, strlen(port
->p_descr
)) &&
189 if(port
->p_pvid
!= 0) {
191 POKE_START_LLDP_TLV(LLDP_TLV_ORG
) &&
192 POKE_BYTES(dot1
, sizeof(dot1
)) &&
193 POKE_UINT8(LLDP_TLV_DOT1_PVID
) &&
194 POKE_UINT16(port
->p_pvid
) &&
195 POKE_END_LLDP_TLV
)) {
199 /* Port and Protocol VLAN IDs */
200 TAILQ_FOREACH(ppvid
, &port
->p_ppvids
, p_entries
) {
202 POKE_START_LLDP_TLV(LLDP_TLV_ORG
) &&
203 POKE_BYTES(dot1
, sizeof(dot1
)) &&
204 POKE_UINT8(LLDP_TLV_DOT1_PPVID
) &&
205 POKE_UINT8(ppvid
->p_cap_status
) &&
206 POKE_UINT16(ppvid
->p_ppvid
) &&
207 POKE_END_LLDP_TLV
)) {
212 TAILQ_FOREACH(vlan
, &port
->p_vlans
, v_entries
) {
214 POKE_START_LLDP_TLV(LLDP_TLV_ORG
) &&
215 POKE_BYTES(dot1
, sizeof(dot1
)) &&
216 POKE_UINT8(LLDP_TLV_DOT1_VLANNAME
) &&
217 POKE_UINT16(vlan
->v_vid
) &&
218 POKE_UINT8(strlen(vlan
->v_name
)) &&
219 POKE_BYTES(vlan
->v_name
, strlen(vlan
->v_name
)) &&
223 /* Protocol Identities */
224 TAILQ_FOREACH(pi
, &port
->p_pids
, p_entries
) {
226 POKE_START_LLDP_TLV(LLDP_TLV_ORG
) &&
227 POKE_BYTES(dot1
, sizeof(dot1
)) &&
228 POKE_UINT8(LLDP_TLV_DOT1_PI
) &&
229 POKE_UINT8(pi
->p_pi_len
) &&
230 POKE_BYTES(pi
->p_pi
, pi
->p_pi_len
) &&
237 /* Aggregation status */
239 POKE_START_LLDP_TLV(LLDP_TLV_ORG
) &&
240 POKE_BYTES(dot3
, sizeof(dot3
)) &&
241 POKE_UINT8(LLDP_TLV_DOT3_LA
) &&
242 /* Bit 0 = capability ; Bit 1 = status */
243 POKE_UINT8((port
->p_aggregid
) ? 3:1) &&
244 POKE_UINT32(port
->p_aggregid
) &&
250 POKE_START_LLDP_TLV(LLDP_TLV_ORG
) &&
251 POKE_BYTES(dot3
, sizeof(dot3
)) &&
252 POKE_UINT8(LLDP_TLV_DOT3_MAC
) &&
253 POKE_UINT8(port
->p_macphy
.autoneg_support
|
254 (port
->p_macphy
.autoneg_enabled
<< 1)) &&
255 POKE_UINT16(port
->p_macphy
.autoneg_advertised
) &&
256 POKE_UINT16(port
->p_macphy
.mau_type
) &&
263 POKE_START_LLDP_TLV(LLDP_TLV_ORG
) &&
264 POKE_BYTES(dot3
, sizeof(dot3
)) &&
265 POKE_UINT8(LLDP_TLV_DOT3_MFS
) &&
266 POKE_UINT16(port
->p_mfs
) &&
271 if (port
->p_power
.devicetype
) {
273 POKE_START_LLDP_TLV(LLDP_TLV_ORG
) &&
274 POKE_BYTES(dot3
, sizeof(dot3
)) &&
275 POKE_UINT8(LLDP_TLV_DOT3_POWER
) &&
277 (((2 - port
->p_power
.devicetype
) %(1<< 1))<<0) |
278 (( port
->p_power
.supported
%(1<< 1))<<1) |
279 (( port
->p_power
.enabled
%(1<< 1))<<2) |
280 (( port
->p_power
.paircontrol
%(1<< 1))<<3))) &&
281 POKE_UINT8(port
->p_power
.pairs
) &&
282 POKE_UINT8(port
->p_power
.class)))
285 if (port
->p_power
.powertype
!= LLDP_DOT3_POWER_8023AT_OFF
) {
288 (((port
->p_power
.powertype
==
289 LLDP_DOT3_POWER_8023AT_TYPE1
)?1:0) << 7) |
290 (((port
->p_power
.devicetype
==
291 LLDP_DOT3_POWER_PSE
)?0:1) << 6) |
292 ((port
->p_power
.source
%(1<< 2))<<4) |
293 ((port
->p_power
.priority
%(1<< 2))<<0))) &&
294 POKE_UINT16(port
->p_power
.requested
) &&
295 POKE_UINT16(port
->p_power
.allocated
)))
298 if (!(POKE_END_LLDP_TLV
))
303 #ifdef ENABLE_LLDPMED
304 if (port
->p_med_cap_enabled
) {
307 POKE_START_LLDP_TLV(LLDP_TLV_ORG
) &&
308 POKE_BYTES(med
, sizeof(med
)) &&
309 POKE_UINT8(LLDP_TLV_MED_CAP
) &&
310 POKE_UINT16(chassis
->c_med_cap_available
) &&
311 POKE_UINT8(chassis
->c_med_type
) &&
315 /* LLDP-MED inventory */
316 #define LLDP_INVENTORY(value, subtype) \
319 POKE_START_LLDP_TLV(LLDP_TLV_ORG) && \
320 POKE_BYTES(med, sizeof(med)) && \
321 POKE_UINT8(subtype) && \
323 (strlen(value)>32)?32:strlen(value)) && \
324 POKE_END_LLDP_TLV)) \
328 if (port
->p_med_cap_enabled
& LLDP_MED_CAP_IV
) {
329 LLDP_INVENTORY(chassis
->c_med_hw
,
331 LLDP_INVENTORY(chassis
->c_med_fw
,
333 LLDP_INVENTORY(chassis
->c_med_sw
,
335 LLDP_INVENTORY(chassis
->c_med_sn
,
337 LLDP_INVENTORY(chassis
->c_med_manuf
,
338 LLDP_TLV_MED_IV_MANUF
);
339 LLDP_INVENTORY(chassis
->c_med_model
,
340 LLDP_TLV_MED_IV_MODEL
);
341 LLDP_INVENTORY(chassis
->c_med_asset
,
342 LLDP_TLV_MED_IV_ASSET
);
345 /* LLDP-MED location */
346 for (i
= 0; i
< LLDP_MED_LOCFORMAT_LAST
; i
++) {
347 if (port
->p_med_location
[i
].format
== i
+ 1) {
349 POKE_START_LLDP_TLV(LLDP_TLV_ORG
) &&
350 POKE_BYTES(med
, sizeof(med
)) &&
351 POKE_UINT8(LLDP_TLV_MED_LOCATION
) &&
352 POKE_UINT8(port
->p_med_location
[i
].format
) &&
353 POKE_BYTES(port
->p_med_location
[i
].data
,
354 port
->p_med_location
[i
].data_len
) &&
360 /* LLDP-MED network policy */
361 for (i
= 0; i
< LLDP_MED_APPTYPE_LAST
; i
++) {
362 if (port
->p_med_policy
[i
].type
== i
+ 1) {
364 POKE_START_LLDP_TLV(LLDP_TLV_ORG
) &&
365 POKE_BYTES(med
, sizeof(med
)) &&
366 POKE_UINT8(LLDP_TLV_MED_POLICY
) &&
368 ((port
->p_med_policy
[i
].type
%(1<< 8))<<24) |
369 ((port
->p_med_policy
[i
].unknown
%(1<< 1))<<23) |
370 ((port
->p_med_policy
[i
].tagged
%(1<< 1))<<22) |
371 /*((0 %(1<< 1))<<21) |*/
372 ((port
->p_med_policy
[i
].vid
%(1<<12))<< 9) |
373 ((port
->p_med_policy
[i
].priority
%(1<< 3))<< 6) |
374 ((port
->p_med_policy
[i
].dscp
%(1<< 6))<< 0) )) &&
380 /* LLDP-MED POE-MDI */
381 if ((port
->p_med_power
.devicetype
== LLDP_MED_POW_TYPE_PSE
) ||
382 (port
->p_med_power
.devicetype
== LLDP_MED_POW_TYPE_PD
)) {
383 int devicetype
= 0, source
= 0;
385 POKE_START_LLDP_TLV(LLDP_TLV_ORG
) &&
386 POKE_BYTES(med
, sizeof(med
)) &&
387 POKE_UINT8(LLDP_TLV_MED_MDI
)))
389 switch (port
->p_med_power
.devicetype
) {
390 case LLDP_MED_POW_TYPE_PSE
:
392 switch (port
->p_med_power
.source
) {
393 case LLDP_MED_POW_SOURCE_PRIMARY
: source
= 1; break;
394 case LLDP_MED_POW_SOURCE_BACKUP
: source
= 2; break;
395 case LLDP_MED_POW_SOURCE_RESERVED
: source
= 3; break;
396 default: source
= 0; break;
399 case LLDP_MED_POW_TYPE_PD
:
401 switch (port
->p_med_power
.source
) {
402 case LLDP_MED_POW_SOURCE_PSE
: source
= 1; break;
403 case LLDP_MED_POW_SOURCE_LOCAL
: source
= 2; break;
404 case LLDP_MED_POW_SOURCE_BOTH
: source
= 3; break;
405 default: source
= 0; break;
411 ((devicetype
%(1<< 2))<<6) |
412 ((source
%(1<< 2))<<4) |
413 ((port
->p_med_power
.priority
%(1<< 4))<<0) )) &&
414 POKE_UINT16(port
->p_med_power
.val
) &&
423 POKE_START_LLDP_TLV(LLDP_TLV_END
) &&
427 if (hardware
->h_ops
->send(global
, hardware
,
428 (char *)packet
, pos
- packet
) == -1) {
429 LLOG_WARN("unable to send packet on real device for %s",
435 hardware
->h_tx_cnt
++;
437 /* We assume that LLDP frame is the reference */
438 if ((frame
= (struct lldpd_frame
*)malloc(
439 sizeof(int) + pos
- packet
)) != NULL
) {
440 frame
->size
= pos
- packet
;
441 memcpy(&frame
->frame
, packet
, frame
->size
);
442 if ((hardware
->h_lport
.p_lastframe
== NULL
) ||
443 (hardware
->h_lport
.p_lastframe
->size
!= frame
->size
) ||
444 (memcmp(hardware
->h_lport
.p_lastframe
->frame
, frame
->frame
,
445 frame
->size
) != 0)) {
446 free(hardware
->h_lport
.p_lastframe
);
447 hardware
->h_lport
.p_lastframe
= frame
;
448 hardware
->h_lport
.p_lastchange
= time(NULL
);
461 #define CHECK_TLV_SIZE(x, name) \
462 do { if (tlv_size < (x)) { \
463 LLOG_WARNX(name " TLV too short received on %s",\
464 hardware->h_ifname); \
469 lldp_decode(struct lldpd
*cfg
, char *frame
, int s
,
470 struct lldpd_hardware
*hardware
,
471 struct lldpd_chassis
**newchassis
, struct lldpd_port
**newport
)
473 struct lldpd_chassis
*chassis
;
474 struct lldpd_port
*port
;
475 const char lldpaddr
[] = LLDP_MULTICAST_ADDR
;
476 const char dot1
[] = LLDP_TLV_ORG_DOT1
;
477 const char dot3
[] = LLDP_TLV_ORG_DOT3
;
478 const char med
[] = LLDP_TLV_ORG_MED
;
480 int length
, gotend
= 0;
481 int tlv_size
, tlv_type
, tlv_subtype
;
485 struct lldpd_vlan
*vlan
;
487 struct lldpd_ppvid
*ppvid
;
490 struct lldpd_mgmt
*mgmt
;
492 u_int8_t addr_str_length
, addr_str_buffer
[32];
493 u_int8_t addr_family
, addr_length
, *addr_ptr
, iface_subtype
;
494 u_int32_t iface_number
, iface
;
496 if ((chassis
= calloc(1, sizeof(struct lldpd_chassis
))) == NULL
) {
497 LLOG_WARN("failed to allocate remote chassis");
500 TAILQ_INIT(&chassis
->c_mgmt
);
501 if ((port
= calloc(1, sizeof(struct lldpd_port
))) == NULL
) {
502 LLOG_WARN("failed to allocate remote port");
507 TAILQ_INIT(&port
->p_vlans
);
508 TAILQ_INIT(&port
->p_ppvids
);
509 TAILQ_INIT(&port
->p_pids
);
513 pos
= (u_int8_t
*)frame
;
515 if (length
< 2*ETH_ALEN
+ sizeof(u_int16_t
)) {
516 LLOG_WARNX("too short frame received on %s", hardware
->h_ifname
);
519 if (PEEK_CMP(lldpaddr
, ETH_ALEN
) != 0) {
520 LLOG_INFO("frame not targeted at LLDP multicast address received on %s",
524 PEEK_DISCARD(ETH_ALEN
); /* Skip source address */
525 if (PEEK_UINT16
!= ETHERTYPE_LLDP
) {
526 LLOG_INFO("non LLDP frame received on %s",
531 while (length
&& (!gotend
)) {
533 LLOG_WARNX("tlv header too short received on %s",
537 tlv_size
= PEEK_UINT16
;
538 tlv_type
= tlv_size
>> 9;
539 tlv_size
= tlv_size
& 0x1ff;
541 if (length
< tlv_size
) {
542 LLOG_WARNX("frame too short for tlv received on %s",
549 LLOG_WARNX("lldp end received with size not null on %s",
554 LLOG_DEBUG("extra data after lldp end on %s",
558 case LLDP_TLV_CHASSIS_ID
:
559 case LLDP_TLV_PORT_ID
:
560 CHECK_TLV_SIZE(2, "Port Id");
561 tlv_subtype
= PEEK_UINT8
;
562 if ((tlv_subtype
== 0) || (tlv_subtype
> 7)) {
563 LLOG_WARNX("unknown subtype for tlv id received on %s",
567 if ((b
= (char *)calloc(1, tlv_size
- 1)) == NULL
) {
568 LLOG_WARN("unable to allocate memory for id tlv "
573 PEEK_BYTES(b
, tlv_size
- 1);
574 if (tlv_type
== LLDP_TLV_PORT_ID
) {
575 port
->p_id_subtype
= tlv_subtype
;
577 port
->p_id_len
= tlv_size
- 1;
579 chassis
->c_id_subtype
= tlv_subtype
;
581 chassis
->c_id_len
= tlv_size
- 1;
585 CHECK_TLV_SIZE(2, "TTL");
586 chassis
->c_ttl
= PEEK_UINT16
;
588 case LLDP_TLV_PORT_DESCR
:
589 case LLDP_TLV_SYSTEM_NAME
:
590 case LLDP_TLV_SYSTEM_DESCR
:
592 LLOG_DEBUG("empty tlv received on %s",
596 if ((b
= (char *)calloc(1, tlv_size
+ 1)) == NULL
) {
597 LLOG_WARN("unable to allocate memory for string tlv "
602 PEEK_BYTES(b
, tlv_size
);
603 if (tlv_type
== LLDP_TLV_PORT_DESCR
)
605 else if (tlv_type
== LLDP_TLV_SYSTEM_NAME
)
607 else chassis
->c_descr
= b
;
609 case LLDP_TLV_SYSTEM_CAP
:
610 CHECK_TLV_SIZE(4, "System capabilities");
611 chassis
->c_cap_available
= PEEK_UINT16
;
612 chassis
->c_cap_enabled
= PEEK_UINT16
;
614 case LLDP_TLV_MGMT_ADDR
:
615 CHECK_TLV_SIZE(1, "Management address");
616 addr_str_length
= PEEK_UINT8
;
617 CHECK_TLV_SIZE(addr_str_length
, "Management address");
618 PEEK_BYTES(addr_str_buffer
, addr_str_length
);
619 addr_length
= addr_str_length
- 1;
620 addr_family
= addr_str_buffer
[0];
621 addr_ptr
= &addr_str_buffer
[1];
622 CHECK_TLV_SIZE(5, "Management address");
623 iface_subtype
= PEEK_UINT8
;
624 iface_number
= PEEK_UINT32
;
626 af
= lldpd_af_from_lldp_proto(addr_family
);
627 if (af
== LLDPD_AF_UNSPEC
)
629 if (iface_subtype
== LLDP_MGMT_IFACE_IFINDEX
)
630 iface
= iface_number
;
633 mgmt
= lldpd_alloc_mgmt(af
, addr_ptr
, addr_length
, iface
);
635 assert(errno
== ENOMEM
);
636 LLOG_WARN("unable to allocate memory "
637 "for management address");
640 TAILQ_INSERT_TAIL(&chassis
->c_mgmt
, mgmt
, m_entries
);
643 CHECK_TLV_SIZE(4, "Organisational");
644 PEEK_BYTES(orgid
, sizeof(orgid
));
645 tlv_subtype
= PEEK_UINT8
;
646 if (memcmp(dot1
, orgid
, sizeof(orgid
)) == 0) {
648 hardware
->h_rx_unrecognized_cnt
++;
651 switch (tlv_subtype
) {
652 case LLDP_TLV_DOT1_VLANNAME
:
653 CHECK_TLV_SIZE(7, "VLAN");
654 if ((vlan
= (struct lldpd_vlan
*)calloc(1,
655 sizeof(struct lldpd_vlan
))) == NULL
) {
656 LLOG_WARN("unable to alloc vlan "
658 "tlv received on %s",
662 vlan
->v_vid
= PEEK_UINT16
;
663 vlan_len
= PEEK_UINT8
;
664 CHECK_TLV_SIZE(7 + vlan_len
, "VLAN");
666 (char *)calloc(1, vlan_len
+ 1)) == NULL
) {
667 LLOG_WARN("unable to alloc vlan name for "
668 "tlv received on %s",
672 PEEK_BYTES(vlan
->v_name
, vlan_len
);
673 TAILQ_INSERT_TAIL(&port
->p_vlans
,
676 case LLDP_TLV_DOT1_PVID
:
677 CHECK_TLV_SIZE(6, "PVID");
678 port
->p_pvid
= PEEK_UINT16
;
680 case LLDP_TLV_DOT1_PPVID
:
681 CHECK_TLV_SIZE(7, "PPVID");
682 /* validation needed */
683 /* PPVID has to be unique if more than
684 one PPVID TLVs are received -
685 discard if duplicate */
686 /* if support bit is not set and
687 enabled bit is set - PPVID TLV is
688 considered error and discarded */
689 /* if PPVID > 4096 - bad and discard */
690 if ((ppvid
= (struct lldpd_ppvid
*)calloc(1,
691 sizeof(struct lldpd_ppvid
))) == NULL
) {
692 LLOG_WARN("unable to alloc ppvid "
694 "tlv received on %s",
698 ppvid
->p_cap_status
= PEEK_UINT8
;
699 ppvid
->p_ppvid
= PEEK_UINT16
;
700 TAILQ_INSERT_TAIL(&port
->p_ppvids
,
703 case LLDP_TLV_DOT1_PI
:
704 /* validation needed */
705 /* PI has to be unique if more than
706 one PI TLVs are received - discard
708 CHECK_TLV_SIZE(5, "PI");
709 if ((pi
= (struct lldpd_pi
*)calloc(1,
710 sizeof(struct lldpd_pi
))) == NULL
) {
711 LLOG_WARN("unable to alloc PI "
713 "tlv received on %s",
717 pi
->p_pi_len
= PEEK_UINT8
;
718 CHECK_TLV_SIZE(1 + pi
->p_pi_len
, "PI");
720 (char *)calloc(1, pi
->p_pi_len
)) == NULL
) {
721 LLOG_WARN("unable to alloc pid name for "
722 "tlv received on %s",
726 PEEK_BYTES(pi
->p_pi
, pi
->p_pi_len
);
727 TAILQ_INSERT_TAIL(&port
->p_pids
,
731 /* Unknown Dot1 TLV, ignore it */
732 hardware
->h_rx_unrecognized_cnt
++;
735 } else if (memcmp(dot3
, orgid
, sizeof(orgid
)) == 0) {
737 hardware
->h_rx_unrecognized_cnt
++;
740 switch (tlv_subtype
) {
741 case LLDP_TLV_DOT3_MAC
:
742 CHECK_TLV_SIZE(9, "MAC/PHY");
743 port
->p_macphy
.autoneg_support
= PEEK_UINT8
;
744 port
->p_macphy
.autoneg_enabled
=
745 (port
->p_macphy
.autoneg_support
& 0x2) >> 1;
746 port
->p_macphy
.autoneg_support
=
747 port
->p_macphy
.autoneg_support
& 0x1;
748 port
->p_macphy
.autoneg_advertised
=
750 port
->p_macphy
.mau_type
= PEEK_UINT16
;
752 case LLDP_TLV_DOT3_LA
:
753 CHECK_TLV_SIZE(9, "Link aggregation");
755 port
->p_aggregid
= PEEK_UINT32
;
757 case LLDP_TLV_DOT3_MFS
:
758 CHECK_TLV_SIZE(6, "MFS");
759 port
->p_mfs
= PEEK_UINT16
;
761 case LLDP_TLV_DOT3_POWER
:
762 CHECK_TLV_SIZE(7, "Power");
763 port
->p_power
.devicetype
= PEEK_UINT8
;
764 port
->p_power
.supported
=
765 (port
->p_power
.devicetype
& 0x2) >> 1;
766 port
->p_power
.enabled
=
767 (port
->p_power
.devicetype
& 0x4) >> 2;
768 port
->p_power
.paircontrol
=
769 (port
->p_power
.devicetype
& 0x8) >> 3;
770 port
->p_power
.devicetype
=
771 (port
->p_power
.devicetype
& 0x1)?
772 LLDP_DOT3_POWER_PSE
:LLDP_DOT3_POWER_PD
;
773 port
->p_power
.pairs
= PEEK_UINT8
;
774 port
->p_power
.class = PEEK_UINT8
;
776 if (tlv_size
>= 12) {
777 port
->p_power
.powertype
= PEEK_UINT8
;
778 port
->p_power
.source
=
779 (port
->p_power
.powertype
& (1<<5 | 1<<4)) >> 4;
780 port
->p_power
.priority
=
781 (port
->p_power
.powertype
& (1<<1 | 1<<0));
782 port
->p_power
.powertype
=
783 (port
->p_power
.powertype
& (1<<7))?
784 LLDP_DOT3_POWER_8023AT_TYPE1
:
785 LLDP_DOT3_POWER_8023AT_TYPE2
;
786 port
->p_power
.requested
= PEEK_UINT16
;
787 port
->p_power
.allocated
= PEEK_UINT16
;
789 port
->p_power
.powertype
=
790 LLDP_DOT3_POWER_8023AT_OFF
;
793 /* Unknown Dot3 TLV, ignore it */
794 hardware
->h_rx_unrecognized_cnt
++;
797 } else if (memcmp(med
, orgid
, sizeof(orgid
)) == 0) {
799 #ifndef ENABLE_LLDPMED
800 hardware
->h_rx_unrecognized_cnt
++;
806 switch (tlv_subtype
) {
807 case LLDP_TLV_MED_CAP
:
808 CHECK_TLV_SIZE(7, "LLDP-MED capabilities");
809 chassis
->c_med_cap_available
= PEEK_UINT16
;
810 chassis
->c_med_type
= PEEK_UINT8
;
811 port
->p_med_cap_enabled
|=
814 case LLDP_TLV_MED_POLICY
:
815 CHECK_TLV_SIZE(8, "LLDP-MED policy");
816 policy
= PEEK_UINT32
;
817 if (((policy
>> 24) < 1) ||
818 ((policy
>> 24) > LLDP_MED_APPTYPE_LAST
)) {
819 LLOG_INFO("unknown policy field %d "
825 port
->p_med_policy
[(policy
>> 24) - 1].type
=
827 port
->p_med_policy
[(policy
>> 24) - 1].unknown
=
828 ((policy
& 0x800000) != 0);
829 port
->p_med_policy
[(policy
>> 24) - 1].tagged
=
830 ((policy
& 0x400000) != 0);
831 port
->p_med_policy
[(policy
>> 24) - 1].vid
=
832 (policy
& 0x001FFE00) >> 9;
833 port
->p_med_policy
[(policy
>> 24) - 1].priority
=
834 (policy
& 0x1C0) >> 6;
835 port
->p_med_policy
[(policy
>> 24) - 1].dscp
=
837 port
->p_med_cap_enabled
|=
840 case LLDP_TLV_MED_LOCATION
:
841 CHECK_TLV_SIZE(5, "LLDP-MED Location");
842 loctype
= PEEK_UINT8
;
844 (loctype
> LLDP_MED_LOCFORMAT_LAST
)) {
845 LLOG_INFO("unknown location type "
850 if ((port
->p_med_location
[loctype
- 1].data
=
851 (char*)malloc(tlv_size
- 5)) == NULL
) {
852 LLOG_WARN("unable to allocate memory "
853 "for LLDP-MED location for "
854 "frame received on %s",
858 PEEK_BYTES(port
->p_med_location
[loctype
- 1].data
,
860 port
->p_med_location
[loctype
- 1].data_len
=
862 port
->p_med_location
[loctype
- 1].format
= loctype
;
863 port
->p_med_cap_enabled
|=
864 LLDP_MED_CAP_LOCATION
;
866 case LLDP_TLV_MED_MDI
:
867 CHECK_TLV_SIZE(7, "LLDP-MED PoE-MDI");
869 switch (power
& 0xC0) {
871 port
->p_med_power
.devicetype
= LLDP_MED_POW_TYPE_PSE
;
872 port
->p_med_cap_enabled
|=
873 LLDP_MED_CAP_MDI_PSE
;
874 switch (power
& 0x30) {
876 port
->p_med_power
.source
=
877 LLDP_MED_POW_SOURCE_UNKNOWN
;
880 port
->p_med_power
.source
=
881 LLDP_MED_POW_SOURCE_PRIMARY
;
884 port
->p_med_power
.source
=
885 LLDP_MED_POW_SOURCE_BACKUP
;
888 port
->p_med_power
.source
=
889 LLDP_MED_POW_SOURCE_RESERVED
;
893 port
->p_med_power
.devicetype
= LLDP_MED_POW_TYPE_PD
;
894 port
->p_med_cap_enabled
|=
896 switch (power
& 0x30) {
898 port
->p_med_power
.source
=
899 LLDP_MED_POW_SOURCE_UNKNOWN
;
902 port
->p_med_power
.source
=
903 LLDP_MED_POW_SOURCE_PSE
;
906 port
->p_med_power
.source
=
907 LLDP_MED_POW_SOURCE_LOCAL
;
910 port
->p_med_power
.source
=
911 LLDP_MED_POW_SOURCE_BOTH
;
915 port
->p_med_power
.devicetype
=
916 LLDP_MED_POW_TYPE_RESERVED
;
918 if (((power
& 0x0F) < 0) ||
919 ((power
& 0x0F) > LLDP_MED_POW_PRIO_LOW
))
920 port
->p_med_power
.priority
=
921 LLDP_MED_POW_PRIO_UNKNOWN
;
923 port
->p_med_power
.priority
=
925 port
->p_med_power
.val
= PEEK_UINT16
;
927 case LLDP_TLV_MED_IV_HW
:
928 case LLDP_TLV_MED_IV_SW
:
929 case LLDP_TLV_MED_IV_FW
:
930 case LLDP_TLV_MED_IV_SN
:
931 case LLDP_TLV_MED_IV_MANUF
:
932 case LLDP_TLV_MED_IV_MODEL
:
933 case LLDP_TLV_MED_IV_ASSET
:
937 if ((b
= (char*)malloc(tlv_size
- 3)) ==
939 LLOG_WARN("unable to allocate "
940 "memory for LLDP-MED "
941 "inventory for frame "
946 PEEK_BYTES(b
, tlv_size
- 4);
947 b
[tlv_size
- 4] = '\0';
949 switch (tlv_subtype
) {
950 case LLDP_TLV_MED_IV_HW
:
951 chassis
->c_med_hw
= b
;
953 case LLDP_TLV_MED_IV_FW
:
954 chassis
->c_med_fw
= b
;
956 case LLDP_TLV_MED_IV_SW
:
957 chassis
->c_med_sw
= b
;
959 case LLDP_TLV_MED_IV_SN
:
960 chassis
->c_med_sn
= b
;
962 case LLDP_TLV_MED_IV_MANUF
:
963 chassis
->c_med_manuf
= b
;
965 case LLDP_TLV_MED_IV_MODEL
:
966 chassis
->c_med_model
= b
;
968 case LLDP_TLV_MED_IV_ASSET
:
969 chassis
->c_med_asset
= b
;
972 LLOG_WARNX("should not be there!");
976 port
->p_med_cap_enabled
|=
980 /* Unknown LLDP MED, ignore it */
981 hardware
->h_rx_unrecognized_cnt
++;
983 #endif /* ENABLE_LLDPMED */
985 LLOG_INFO("unknown org tlv received on %s",
987 hardware
->h_rx_unrecognized_cnt
++;
991 LLOG_WARNX("unknown tlv (%d) received on %s",
992 tlv_type
, hardware
->h_ifname
);
995 if (pos
> tlv
+ tlv_size
) {
996 LLOG_WARNX("BUG: already past TLV!");
999 PEEK_DISCARD(tlv
+ tlv_size
- pos
);
1002 /* Some random check */
1003 if ((chassis
->c_id
== NULL
) ||
1004 (port
->p_id
== NULL
) ||
1005 (chassis
->c_ttl
== 0) ||
1007 LLOG_WARNX("some mandatory tlv are missing for frame received on %s",
1008 hardware
->h_ifname
);
1011 #define NOTRECEIVED "Not received"
1012 if (chassis
->c_name
== NULL
) {
1013 if ((chassis
->c_name
= (char *)calloc(1, strlen(NOTRECEIVED
) + 1)) == NULL
) {
1014 LLOG_WARNX("unable to allocate null chassis name");
1017 memcpy(chassis
->c_name
, NOTRECEIVED
, strlen(NOTRECEIVED
));
1019 if (chassis
->c_descr
== NULL
) {
1020 if ((chassis
->c_descr
= (char *)calloc(1, strlen(NOTRECEIVED
) + 1)) == NULL
) {
1021 LLOG_WARNX("unable to allocate null chassis description");
1024 memcpy(chassis
->c_descr
, NOTRECEIVED
, strlen(NOTRECEIVED
));
1026 if (port
->p_descr
== NULL
) {
1027 if ((port
->p_descr
= (char *)calloc(1, strlen(NOTRECEIVED
) + 1)) == NULL
) {
1028 LLOG_WARNX("unable to allocate null port description");
1031 memcpy(port
->p_descr
, NOTRECEIVED
, strlen(NOTRECEIVED
));
1033 *newchassis
= chassis
;
1037 lldpd_chassis_cleanup(chassis
, 1);
1038 lldpd_port_cleanup(port
, 1);