2 * Copyright (c) 2008 Vincent Bernat <bernat@luffy.cx>
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.
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.
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>
29 lldp_send(struct lldpd
*global
, struct lldpd_chassis
*chassis
,
30 struct lldpd_hardware
*hardware
)
32 struct ether_header eh
;
33 const u_int8_t mcastaddr
[] = LLDP_MULTICAST_ADDR
;
34 struct iovec
*iov
= NULL
;
35 struct lldp_id chid
, pid
;
38 struct lldp_string name
;
39 struct lldp_string descr
;
40 struct lldp_string str
;
42 struct lldp_mgmt mgmt
;
44 const u_int8_t dot1
[] = LLDP_TLV_ORG_DOT1
;
45 struct lldp_vlan
*ovlan
= NULL
;
47 struct lldpd_vlan
*vlan
;
50 const u_int8_t dot3
[] = LLDP_TLV_ORG_DOT3
;
51 struct lldp_aggreg aggreg
;
52 struct lldp_macphy macphy
;
57 const u_int8_t med
[] = LLDP_TLV_ORG_MED
;
58 struct lldpmed_cap medcap
;
59 struct lldp_org medhw
, medfw
, medsw
, medsn
,
60 medmodel
, medasset
, medmanuf
, medloc
[3];
62 struct lldpd_port
*port
= &hardware
->h_lport
;
63 u_int c
= -1, len
= 0;
64 struct lldpd_frame
*buffer
;
67 if ((iov = (struct iovec*)realloc(iov, (++c + 1) * \
68 sizeof(struct iovec))) == NULL) \
72 memset(&eh
, 0, sizeof(eh
));
73 memcpy(&eh
.ether_shost
, &hardware
->h_lladdr
,
74 sizeof(eh
.ether_shost
));
75 memcpy(&eh
.ether_dhost
, &mcastaddr
,
76 sizeof(eh
.ether_dhost
));
77 eh
.ether_type
= htons(ETHERTYPE_LLDP
);
79 iov
[c
].iov_base
= &eh
;
80 iov
[c
].iov_len
= sizeof(struct ether_header
);
83 memset(&chid
, 0, sizeof(chid
));
84 len
= chassis
->c_id_len
+ sizeof(chid
);
85 chid
.tlv_head
.type_len
= LLDP_TLV_HEAD(LLDP_TLV_CHASSIS_ID
,
86 len
- sizeof(struct lldp_tlv_head
));
87 chid
.tlv_id_subtype
= chassis
->c_id_subtype
;
89 iov
[c
].iov_base
= &chid
;
90 iov
[c
].iov_len
= sizeof(chid
);
92 iov
[c
].iov_base
= chassis
->c_id
;
93 iov
[c
].iov_len
= chassis
->c_id_len
;
96 memset(&pid
, 0, sizeof(pid
));
97 len
= port
->p_id_len
+ sizeof(pid
);
98 pid
.tlv_head
.type_len
= LLDP_TLV_HEAD(LLDP_TLV_PORT_ID
,
99 len
- sizeof(struct lldp_tlv_head
));
100 pid
.tlv_id_subtype
= port
->p_id_subtype
;
102 iov
[c
].iov_base
= &pid
;
103 iov
[c
].iov_len
= sizeof(pid
);
105 iov
[c
].iov_base
= port
->p_id
;
106 iov
[c
].iov_len
= port
->p_id_len
;
109 memset(&ttl
, 0, sizeof(ttl
));
111 ttl
.tlv_head
.type_len
= LLDP_TLV_HEAD(LLDP_TLV_TTL
,
112 len
- sizeof(struct lldp_tlv_head
));
113 ttl
.tlv_ttl
= htons(chassis
->c_ttl
);
115 iov
[c
].iov_base
= &ttl
;
116 iov
[c
].iov_len
= sizeof(ttl
);
119 memset(&name
, 0, sizeof(name
));
120 len
= sizeof(name
) + strlen(chassis
->c_name
);
121 name
.tlv_head
.type_len
= LLDP_TLV_HEAD(LLDP_TLV_SYSTEM_NAME
,
122 len
- sizeof(struct lldp_tlv_head
));
124 iov
[c
].iov_base
= &name
;
125 iov
[c
].iov_len
= sizeof(name
);
127 iov
[c
].iov_base
= chassis
->c_name
;
128 iov
[c
].iov_len
= strlen(chassis
->c_name
);
130 /* System description */
131 memset(&descr
, 0, sizeof(descr
));
132 len
= sizeof(descr
) + strlen(chassis
->c_descr
);
133 descr
.tlv_head
.type_len
= LLDP_TLV_HEAD(LLDP_TLV_SYSTEM_DESCR
,
134 len
- sizeof(struct lldp_tlv_head
));
136 iov
[c
].iov_base
= &descr
;
137 iov
[c
].iov_len
= sizeof(descr
);
139 iov
[c
].iov_base
= chassis
->c_descr
;
140 iov
[c
].iov_len
= strlen(chassis
->c_descr
);
142 /* System capabilities */
143 memset(&cap
, 0, sizeof(cap
));
145 cap
.tlv_head
.type_len
= LLDP_TLV_HEAD(LLDP_TLV_SYSTEM_CAP
,
146 len
- sizeof(struct lldp_tlv_head
));
147 cap
.tlv_cap_available
= htons(chassis
->c_cap_available
);
148 cap
.tlv_cap_enabled
= htons(chassis
->c_cap_enabled
);
150 iov
[c
].iov_base
= &cap
;
151 iov
[c
].iov_len
= len
;
153 if (chassis
->c_mgmt
.s_addr
!= INADDR_ANY
) {
154 /* Management address */
155 memset(&mgmt
, 0, sizeof(mgmt
));
157 mgmt
.tlv_head
.type_len
= LLDP_TLV_HEAD(LLDP_TLV_MGMT_ADDR
,
158 len
- sizeof(struct lldp_tlv_head
));
159 mgmt
.mgmt_len
= sizeof(struct in_addr
) + sizeof(u_int8_t
);
160 mgmt
.mgmt_subtype
= LLDP_MGMT_ADDR_IP4
;
161 memcpy(&mgmt
.mgmt_addr
, &chassis
->c_mgmt
,
162 sizeof(struct in_addr
));
164 /* Interface port type, OID */
165 if (chassis
->c_mgmt_if
== 0)
166 mgmt
.mgmt_iface_subtype
=
167 LLDP_MGMT_IFACE_UNKNOWN
;
169 mgmt
.mgmt_iface_subtype
=
170 LLDP_MGMT_IFACE_IFINDEX
;
172 htonl(chassis
->c_mgmt_if
);
175 iov
[c
].iov_base
= &mgmt
;
176 iov
[c
].iov_len
= len
;
179 /* Port description */
180 memset(&str
, 0, sizeof(str
));
181 len
= sizeof(str
) + strlen(port
->p_descr
);
182 str
.tlv_head
.type_len
= LLDP_TLV_HEAD(LLDP_TLV_PORT_DESCR
,
183 len
- sizeof(struct lldp_tlv_head
));
185 iov
[c
].iov_base
= &str
;
186 iov
[c
].iov_len
= sizeof(str
);
188 iov
[c
].iov_base
= port
->p_descr
;
189 iov
[c
].iov_len
= strlen(port
->p_descr
);
194 TAILQ_FOREACH(vlan
, &port
->p_vlans
, v_entries
)
197 ((ovlan
= (struct lldp_vlan
*)malloc(v
*sizeof(struct lldp_vlan
))) == NULL
))
198 LLOG_WARN("no room for vlans");
200 TAILQ_FOREACH(vlan
, &port
->p_vlans
, v_entries
) {
202 memset(&ovlan
[v
], 0, sizeof(ovlan
[v
]));
203 ovlan
[v
].tlv_head
.type_len
= LLDP_TLV_HEAD(LLDP_TLV_ORG
,
204 sizeof(ovlan
[v
].tlv_org_id
) +
205 sizeof(ovlan
[v
].tlv_org_subtype
) + sizeof(ovlan
[v
].vid
) +
206 sizeof(ovlan
[v
].len
) + strlen(vlan
->v_name
));
207 memcpy(ovlan
[v
].tlv_org_id
, dot1
, sizeof(ovlan
[v
].tlv_org_id
));
208 ovlan
[v
].tlv_org_subtype
= LLDP_TLV_DOT1_VLANNAME
;
209 ovlan
[v
].vid
= htons(vlan
->v_vid
);
210 ovlan
[v
].len
= strlen(vlan
->v_name
);
212 iov
[c
].iov_base
= &ovlan
[v
];
213 iov
[c
].iov_len
= sizeof(ovlan
[v
]);
215 iov
[c
].iov_base
= vlan
->v_name
;
216 iov
[c
].iov_len
= strlen(vlan
->v_name
);
222 /* Aggregation status */
223 memset(&aggreg
, 0, sizeof(aggreg
));
224 aggreg
.tlv_head
.type_len
= LLDP_TLV_HEAD(LLDP_TLV_ORG
,
225 sizeof(aggreg
.tlv_org_id
) +
226 sizeof(aggreg
.tlv_org_subtype
) +
227 sizeof(aggreg
.status
) + sizeof(aggreg
.id
));
228 memcpy(aggreg
.tlv_org_id
, dot3
, sizeof(aggreg
.tlv_org_id
));
229 aggreg
.tlv_org_subtype
= LLDP_TLV_DOT3_LA
;
230 aggreg
.status
= (port
->p_aggregid
) ? 3:1; /* Bit 0 = capability ; Bit 1 = status */
231 aggreg
.id
= htonl(port
->p_aggregid
);
233 iov
[c
].iov_base
= &aggreg
;
234 iov
[c
].iov_len
= sizeof(aggreg
);
237 memset(&macphy
, 0, sizeof(macphy
));
238 macphy
.tlv_head
.type_len
= LLDP_TLV_HEAD(LLDP_TLV_ORG
,
239 sizeof(macphy
.tlv_org_id
) +
240 sizeof(macphy
.tlv_org_subtype
) +
241 sizeof(macphy
.autoneg
) + sizeof(macphy
.advertised
) +
243 memcpy(macphy
.tlv_org_id
, dot3
, sizeof(macphy
.tlv_org_id
));
244 macphy
.tlv_org_subtype
= LLDP_TLV_DOT3_MAC
;
245 macphy
.autoneg
= port
->p_autoneg_support
|
246 (port
->p_autoneg_enabled
<< 1);
247 macphy
.advertised
= htons(port
->p_autoneg_advertised
);
248 macphy
.mau
= htons(port
->p_mau_type
);
250 iov
[c
].iov_base
= &macphy
;
251 iov
[c
].iov_len
= sizeof(macphy
);
254 memset(&mfs
, 0, sizeof(mfs
));
255 mfs
.tlv_head
.type_len
= LLDP_TLV_HEAD(LLDP_TLV_ORG
,
256 sizeof(mfs
.tlv_org_id
) +
257 sizeof(mfs
.tlv_org_subtype
) +
259 memcpy(mfs
.tlv_org_id
, dot3
, sizeof(mfs
.tlv_org_id
));
260 mfs
.tlv_org_subtype
= LLDP_TLV_DOT3_MFS
;
261 mfs
.mfs
= htons(port
->p_mfs
);
263 iov
[c
].iov_base
= &mfs
;
264 iov
[c
].iov_len
= sizeof(mfs
);
267 #ifdef ENABLE_LLDPMED
268 if (global
->g_lchassis
.c_med_cap_enabled
) {
270 memset(&medcap
, 0, sizeof(medcap
));
271 medcap
.tlv_head
.type_len
= LLDP_TLV_HEAD(LLDP_TLV_ORG
,
272 sizeof(medcap
.tlv_org_id
) +
273 sizeof(medcap
.tlv_org_subtype
) +
274 sizeof(medcap
.tlv_cap
) + sizeof(medcap
.tlv_type
));
275 memcpy(medcap
.tlv_org_id
, med
, sizeof(medcap
.tlv_org_id
));
276 medcap
.tlv_org_subtype
= LLDP_TLV_MED_CAP
;
277 medcap
.tlv_cap
= htons(global
->g_lchassis
.c_med_cap_available
);
278 medcap
.tlv_type
= global
->g_lchassis
.c_med_type
;
280 iov
[c
].iov_base
= &medcap
;
281 iov
[c
].iov_len
= sizeof(medcap
);
283 /* LLDP-MED inventory */
284 #define LLDP_INVENTORY(value, target, subtype) \
286 memset(&target, 0, sizeof(target)); \
287 len = (strlen(value)>32)?32:strlen(value); \
288 target.tlv_head.type_len = \
289 LLDP_TLV_HEAD(LLDP_TLV_ORG, \
290 sizeof(target.tlv_org_id) + \
291 sizeof(target.tlv_org_subtype) + \
293 memcpy(target.tlv_org_id, med, \
294 sizeof(target.tlv_org_id)); \
295 target.tlv_org_subtype = subtype; \
297 iov[c].iov_base = ⌖ \
298 iov[c].iov_len = sizeof(target); \
300 iov[c].iov_base = value; \
301 iov[c].iov_len = len; \
304 if (global
->g_lchassis
.c_med_cap_enabled
& LLDPMED_CAP_IV
) {
305 LLDP_INVENTORY(global
->g_lchassis
.c_med_hw
,
306 medhw
, LLDP_TLV_MED_IV_HW
);
307 LLDP_INVENTORY(global
->g_lchassis
.c_med_fw
,
308 medfw
, LLDP_TLV_MED_IV_FW
);
309 LLDP_INVENTORY(global
->g_lchassis
.c_med_sw
,
310 medsw
, LLDP_TLV_MED_IV_SW
);
311 LLDP_INVENTORY(global
->g_lchassis
.c_med_sn
,
312 medsn
, LLDP_TLV_MED_IV_SN
);
313 LLDP_INVENTORY(global
->g_lchassis
.c_med_manuf
,
314 medmanuf
, LLDP_TLV_MED_IV_MANUF
);
315 LLDP_INVENTORY(global
->g_lchassis
.c_med_model
,
316 medmodel
, LLDP_TLV_MED_IV_MODEL
);
317 LLDP_INVENTORY(global
->g_lchassis
.c_med_asset
,
318 medasset
, LLDP_TLV_MED_IV_ASSET
);
321 /* LLDP-MED location */
322 for (i
= 0; i
< LLDPMED_LOCFORMAT_LAST
; i
++) {
323 if (global
->g_lchassis
.c_med_location
[i
].format
== i
+ 1) {
324 memset(&medloc
[i
], 0, sizeof(struct lldp_org
));
325 medloc
[i
].tlv_head
.type_len
=
326 LLDP_TLV_HEAD(LLDP_TLV_ORG
,
327 sizeof(medloc
[i
].tlv_org_id
) +
328 sizeof(medloc
[i
].tlv_org_subtype
) + 1 +
329 global
->g_lchassis
.c_med_location
[i
].data_len
);
330 memcpy(medloc
[i
].tlv_org_id
, med
,
331 sizeof(medloc
[i
].tlv_org_id
));
332 medloc
[i
].tlv_org_subtype
= LLDP_TLV_MED_LOCATION
;
334 iov
[c
].iov_base
= &medloc
[i
];
335 iov
[c
].iov_len
= sizeof(medloc
[i
]);
338 &global
->g_lchassis
.c_med_location
[i
].format
;
342 global
->g_lchassis
.c_med_location
[i
].data
;
344 global
->g_lchassis
.c_med_location
[i
].data_len
;
351 memset(&end
, 0, sizeof(end
));
353 iov
[c
].iov_base
= &end
;
354 iov
[c
].iov_len
= sizeof(end
);
357 if (!global
->g_multi
||
358 (hardware
->h_mode
== LLDPD_MODE_ANY
) ||
359 (hardware
->h_mode
== LLDPD_MODE_LLDP
)) {
361 if (writev((hardware
->h_raw_real
> 0) ? hardware
->h_raw_real
:
362 hardware
->h_raw
, iov
, c
) == -1) {
363 LLOG_WARN("unable to send packet on real device for %s",
372 hardware
->h_tx_cnt
++;
375 iov_dump(&buffer
, iov
, c
);
380 if (buffer
!= NULL
) {
382 /* We assume that LLDP frame is the reference */
383 if ((hardware
->h_llastframe
== NULL
) ||
384 (hardware
->h_llastframe
->size
!= buffer
->size
) ||
385 (memcmp(hardware
->h_llastframe
->frame
, buffer
->frame
,
386 buffer
->size
) != 0)) {
387 free(hardware
->h_llastframe
);
388 hardware
->h_llastframe
= buffer
;
389 hardware
->h_llastchange
= time(NULL
);
398 lldp_decode(struct lldpd
*cfg
, char *frame
, int s
,
399 struct lldpd_hardware
*hardware
,
400 struct lldpd_chassis
**newchassis
, struct lldpd_port
**newport
)
402 struct lldpd_chassis
*chassis
;
403 struct lldpd_port
*port
;
404 struct ether_header
*ether
;
405 const char lldpaddr
[] = LLDP_MULTICAST_ADDR
;
406 const char dot1
[] = LLDP_TLV_ORG_DOT1
;
407 const char dot3
[] = LLDP_TLV_ORG_DOT3
;
408 const char med
[] = LLDP_TLV_ORG_MED
;
409 int f
; /* Current position in frame */
410 int size
, type
, subtype
; /* TLV header */
413 struct lldpd_vlan
*vlan
;
416 if ((chassis
= calloc(1, sizeof(struct lldpd_chassis
))) == NULL
) {
417 LLOG_WARN("failed to allocate remote chassis");
420 if ((port
= calloc(1, sizeof(struct lldpd_port
))) == NULL
) {
421 LLOG_WARN("failed to allocate remote port");
426 TAILQ_INIT(&port
->p_vlans
);
429 if (s
< sizeof(struct ether_header
)) {
430 LLOG_WARNX("too short frame received on %s", hardware
->h_ifname
);
433 ether
= (struct ether_header
*)frame
;
434 if (memcmp(ether
->ether_dhost
, lldpaddr
, sizeof(lldpaddr
)) != 0) {
435 LLOG_INFO("frame not targeted at LLDP multicast address received on %s",
439 if (ETHERTYPE_LLDP
!= ntohs(ether
->ether_type
)) {
440 LLOG_INFO("non LLDP frame received on %s",
445 f
= sizeof(struct ether_header
);
446 while ((f
< s
) && (!gotend
)) {
448 LLOG_WARNX("tlv header too short received on %s",
452 size
= ntohs(*(u_int16_t
*)(frame
+ f
)) & 0x1ff;
453 type
= ntohs(*(u_int16_t
*)(frame
+ f
)) >> 9;
456 LLOG_WARNX("tlv header too short received on %s",
463 LLOG_WARNX("lldp end received with size not null on %s",
468 LLOG_DEBUG("extra data after lldp end on %s",
472 case LLDP_TLV_CHASSIS_ID
:
473 case LLDP_TLV_PORT_ID
:
475 LLOG_WARNX("tlv id too small received on %s",
479 subtype
= *(u_int8_t
*)(frame
+ f
);
481 if ((subtype
== 0) || (subtype
> 7)) {
482 LLOG_WARNX("unknown subtype for tlv id received on %s",
486 if ((b
= (char *)calloc(1, size
- 1)) == NULL
) {
487 LLOG_WARN("unable to allocate memory for id tlv "
492 memcpy(b
, frame
+ f
, size
- 1);
493 if (type
== LLDP_TLV_PORT_ID
) {
494 port
->p_id_subtype
= subtype
;
496 port
->p_id_len
= size
- 1;
498 chassis
->c_id_subtype
= subtype
;
500 chassis
->c_id_len
= size
- 1;
506 LLOG_WARNX("too short frame for ttl tlv received on %s",
510 chassis
->c_ttl
= ntohs(*(u_int16_t
*)(frame
+ f
));
513 case LLDP_TLV_PORT_DESCR
:
514 case LLDP_TLV_SYSTEM_NAME
:
515 case LLDP_TLV_SYSTEM_DESCR
:
517 LLOG_DEBUG("empty tlv received on %s",
521 if ((b
= (char *)calloc(1, size
+ 1)) == NULL
) {
522 LLOG_WARN("unable to allocate memory for string tlv "
527 memcpy(b
, frame
+ f
, size
);
529 if (type
== LLDP_TLV_PORT_DESCR
)
531 else if (type
== LLDP_TLV_SYSTEM_NAME
)
533 else chassis
->c_descr
= b
;
535 case LLDP_TLV_SYSTEM_CAP
:
537 LLOG_WARNX("too short system cap tlv "
542 chassis
->c_cap_available
= ntohs(*(u_int16_t
*)(frame
+ f
));
544 chassis
->c_cap_enabled
= ntohs(*(u_int16_t
*)(frame
+ f
));
547 case LLDP_TLV_MGMT_ADDR
:
549 LLOG_WARNX("too short management tlv received on %s",
553 if ((chassis
->c_mgmt
.s_addr
== INADDR_ANY
) &&
554 (*(u_int8_t
*)(frame
+ f
) == 5) &&
555 (*(u_int8_t
*)(frame
+ f
+ 1) == 1)) {
556 /* We have an IPv4 address, we ignore anything else */
557 memcpy(&chassis
->c_mgmt
, frame
+ f
+ 2, sizeof(struct in_addr
));
558 chassis
->c_mgmt_if
= 0;
559 /* We only handle ifIndex subtype */
560 if (*(u_int8_t
*)(frame
+ f
+ 6) == LLDP_MGMT_IFACE_IFINDEX
)
561 chassis
->c_mgmt_if
= ntohl(*(u_int32_t
*)(frame
+ f
+ 7));
567 LLOG_WARNX("too short org tlv received on %s",
571 if (memcmp(dot1
, frame
+ f
, 3) == 0) {
574 hardware
->h_rx_unrecognized_cnt
++;
577 switch (*(u_int8_t
*)(frame
+ f
+ 3)) {
578 case LLDP_TLV_DOT1_VLANNAME
:
580 (size
< 7 + *(u_int8_t
*)(frame
+ f
+ 6))) {
581 LLOG_WARNX("too short vlan tlv "
587 if ((vlan
= (struct lldpd_vlan
*)calloc(1,
588 sizeof(struct lldpd_vlan
))) == NULL
) {
589 LLOG_WARN("unable to alloc vlan "
591 "tlv received on %s",
595 vlan
->v_vid
= ntohs(*(u_int16_t
*)(frame
+ f
));
597 vlan_len
= *(u_int8_t
*)(frame
+ f
);
600 (char *)calloc(1, vlan_len
+ 1)) == NULL
) {
601 LLOG_WARN("unable to alloc vlan name for "
602 "tlv received on %s",
606 memcpy(vlan
->v_name
, frame
+ f
,
608 TAILQ_INSERT_TAIL(&port
->p_vlans
,
612 case LLDP_TLV_DOT1_PVID
:
614 LLOG_WARNX("too short pvid tlv "
620 ntohs(*(u_int16_t
*)(frame
+ f
+ 4));
624 /* Unknown Dot1 TLV, ignore it */
626 hardware
->h_rx_unrecognized_cnt
++;
629 } else if (memcmp(dot3
, frame
+ f
, 3) == 0) {
632 hardware
->h_rx_unrecognized_cnt
++;
635 subtype
= *(u_int8_t
*)(frame
+ f
+ 3);
637 case LLDP_TLV_DOT3_MAC
:
640 LLOG_WARNX("too short mac/phy tlv "
645 port
->p_autoneg_support
=
646 *(u_int8_t
*)(frame
+ f
) && 0x1;
647 port
->p_autoneg_enabled
=
648 *(u_int8_t
*)(frame
+ f
) && 0x2;
650 port
->p_autoneg_advertised
=
651 ntohs(*(u_int16_t
*)(frame
+ f
));
654 ntohs(*(u_int16_t
*)(frame
+ f
));
657 case LLDP_TLV_DOT3_LA
:
659 LLOG_WARNX("too short aggreg tlv "
665 ntohl(*(u_int32_t
*)(frame
+ f
+ 5));
668 case LLDP_TLV_DOT3_MFS
:
670 LLOG_WARNX("too short mfs tlv "
676 ntohs(*(u_int16_t
*)(frame
+ f
+ 4));
680 /* Unknown Dot3 TLV, ignore it */
682 hardware
->h_rx_unrecognized_cnt
++;
685 } else if (memcmp(med
, frame
+ f
, 3) == 0) {
687 #ifndef ENABLE_LLDPMED
689 hardware
->h_rx_unrecognized_cnt
++;
694 subtype
= *(u_int8_t
*)(frame
+ f
+ 3);
696 case LLDP_TLV_MED_CAP
:
699 LLOG_WARNX("too short LLDP-MED cap "
700 "tlv received on %s",
704 chassis
->c_med_cap_available
=
705 ntohs(*(u_int16_t
*)(frame
+ f
));
707 chassis
->c_med_type
=
708 *(u_int8_t
*)(frame
+ f
);
710 chassis
->c_med_cap_enabled
|=
713 case LLDP_TLV_MED_POLICY
:
716 LLOG_WARNX("too short LLDP-MED policy "
717 "tlv received on %s",
721 policy
= ntohl(*((u_int32_t
*)(frame
+ f
)));
722 if (((policy
>> 24) < 1) ||
723 ((policy
>> 24) > LLDPMED_APPTYPE_LAST
)) {
724 LLOG_INFO("unknown policy field %d "
730 chassis
->c_med_policy
[(policy
>> 24) - 1].type
=
732 chassis
->c_med_policy
[(policy
>> 24) - 1].unknown
=
733 ((policy
& 0x800000) != 0);
734 chassis
->c_med_policy
[(policy
>> 24) - 1].tagged
=
735 ((policy
& 0x400000) != 0);
736 chassis
->c_med_policy
[(policy
>> 24) - 1].vid
=
737 (policy
& 0x001FFE00) >> 9;
738 chassis
->c_med_policy
[(policy
>> 24) - 1].priority
=
739 (policy
& 0x1C0) >> 6;
740 chassis
->c_med_policy
[(policy
>> 24) - 1].dscp
=
743 chassis
->c_med_cap_enabled
|=
746 case LLDP_TLV_MED_LOCATION
:
749 LLOG_WARNX("too short LLDP-MED location "
750 "tlv received on %s",
754 loctype
= *(u_int8_t
*)(frame
+ f
);
756 if ((loctype
< 1) || (loctype
> LLDPMED_LOCFORMAT_LAST
)) {
757 LLOG_INFO("unknown location type "
763 if ((chassis
->c_med_location
[loctype
- 1].data
=
764 (char*)malloc(size
- 5)) == NULL
) {
765 LLOG_WARN("unable to allocate memory "
766 "for LLDP-MED location for "
767 "frame received on %s",
771 memcpy(chassis
->c_med_location
[loctype
- 1].data
,
774 chassis
->c_med_location
[loctype
- 1].data_len
=
776 chassis
->c_med_location
[loctype
- 1].format
= loctype
;
778 chassis
->c_med_cap_enabled
|=
779 LLDPMED_CAP_LOCATION
;
781 case LLDP_TLV_MED_MDI
:
784 LLOG_WARNX("too short LLDP-MED PoE-MDI "
785 "tlv received on %s",
789 switch (*(u_int8_t
*)(frame
+ f
) & 0xC0) {
791 chassis
->c_med_pow_devicetype
= LLDPMED_POW_TYPE_PSE
;
792 chassis
->c_med_cap_enabled
|=
794 switch (*(u_int8_t
*)(frame
+ f
) & 0x30) {
796 chassis
->c_med_pow_source
=
797 LLDPMED_POW_SOURCE_UNKNOWN
;
800 chassis
->c_med_pow_source
=
801 LLDPMED_POW_SOURCE_PRIMARY
;
804 chassis
->c_med_pow_source
=
805 LLDPMED_POW_SOURCE_BACKUP
;
808 chassis
->c_med_pow_source
=
809 LLDPMED_POW_SOURCE_RESERVED
;
813 chassis
->c_med_pow_devicetype
= LLDPMED_POW_TYPE_PD
;
814 chassis
->c_med_cap_enabled
|=
816 switch (*(u_int8_t
*)(frame
+ f
) & 0x30) {
818 chassis
->c_med_pow_source
=
819 LLDPMED_POW_SOURCE_UNKNOWN
;
822 chassis
->c_med_pow_source
=
823 LLDPMED_POW_SOURCE_PSE
;
826 chassis
->c_med_pow_source
=
827 LLDPMED_POW_SOURCE_LOCAL
;
830 chassis
->c_med_pow_source
=
831 LLDPMED_POW_SOURCE_BOTH
;
835 chassis
->c_med_pow_devicetype
=
836 LLDPMED_POW_TYPE_RESERVED
;
838 switch (*(u_int8_t
*)(frame
+ f
) & 0x0F) {
840 chassis
->c_med_pow_priority
=
841 LLDPMED_POW_PRIO_UNKNOWN
;
844 chassis
->c_med_pow_priority
=
845 LLDPMED_POW_PRIO_CRITICAL
;
848 chassis
->c_med_pow_priority
=
849 LLDPMED_POW_PRIO_HIGH
;
852 chassis
->c_med_pow_priority
=
853 LLDPMED_POW_PRIO_LOW
;
856 chassis
->c_med_pow_priority
=
857 LLDPMED_POW_PRIO_UNKNOWN
;
860 chassis
->c_med_pow_val
=
861 ntohs(*(u_int16_t
*)(frame
+ f
));
864 case LLDP_TLV_MED_IV_HW
:
865 case LLDP_TLV_MED_IV_SW
:
866 case LLDP_TLV_MED_IV_FW
:
867 case LLDP_TLV_MED_IV_SN
:
868 case LLDP_TLV_MED_IV_MANUF
:
869 case LLDP_TLV_MED_IV_MODEL
:
870 case LLDP_TLV_MED_IV_ASSET
:
875 if ((b
= (char*)malloc(size
- 3)) ==
877 LLOG_WARN("unable to allocate "
878 "memory for LLDP-MED "
879 "inventory for frame "
889 case LLDP_TLV_MED_IV_HW
:
890 chassis
->c_med_hw
= b
;
892 case LLDP_TLV_MED_IV_FW
:
893 chassis
->c_med_fw
= b
;
895 case LLDP_TLV_MED_IV_SW
:
896 chassis
->c_med_sw
= b
;
898 case LLDP_TLV_MED_IV_SN
:
899 chassis
->c_med_sn
= b
;
901 case LLDP_TLV_MED_IV_MANUF
:
902 chassis
->c_med_manuf
= b
;
904 case LLDP_TLV_MED_IV_MODEL
:
905 chassis
->c_med_fw
= b
;
907 case LLDP_TLV_MED_IV_ASSET
:
908 chassis
->c_med_asset
= b
;
911 LLOG_WARNX("should not be there!");
916 chassis
->c_med_cap_enabled
|=
920 /* Unknown LLDP MED, ignore it */
922 hardware
->h_rx_unrecognized_cnt
++;
924 #endif /* ENABLE_LLDPMED */
926 LLOG_INFO("unknown org tlv received on %s",
928 hardware
->h_rx_unrecognized_cnt
++;
933 LLOG_WARNX("unknown tlv (%d) received on %s",
934 type
, hardware
->h_ifname
);
939 /* Some random check */
940 if ((chassis
->c_id
== NULL
) ||
941 (port
->p_id
== NULL
) ||
942 (chassis
->c_ttl
== 0) ||
944 LLOG_WARNX("some mandatory tlv are missing for frame received on %s",
948 #define NOTRECEIVED "Not received"
949 if (chassis
->c_name
== NULL
) {
950 if ((chassis
->c_name
= (char *)calloc(1, strlen(NOTRECEIVED
) + 1)) == NULL
) {
951 LLOG_WARNX("unable to allocate null chassis name");
954 memcpy(chassis
->c_name
, NOTRECEIVED
, strlen(NOTRECEIVED
));
956 if (chassis
->c_descr
== NULL
) {
957 if ((chassis
->c_descr
= (char *)calloc(1, strlen(NOTRECEIVED
) + 1)) == NULL
) {
958 LLOG_WARNX("unable to allocate null chassis description");
961 memcpy(chassis
->c_descr
, NOTRECEIVED
, strlen(NOTRECEIVED
));
963 if (port
->p_descr
== NULL
) {
964 if ((port
->p_descr
= (char *)calloc(1, strlen(NOTRECEIVED
) + 1)) == NULL
) {
965 LLOG_WARNX("unable to allocate null port description");
968 memcpy(port
->p_descr
, NOTRECEIVED
, strlen(NOTRECEIVED
));
970 *newchassis
= chassis
;
974 lldpd_chassis_cleanup(chassis
);
975 lldpd_port_cleanup(port
);