1 /* -*- mode: c; c-file-style: "openbsd" -*- */
3 * Copyright (c) 2008 Vincent Bernat <bernat@luffy.cx>
4 * Copyright (c) 2014 Michael Chapman
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
24 #include <sys/ioctl.h>
25 #include <sys/socket.h>
26 #include <sys/types.h>
28 #include "dp-packet.h"
31 VLOG_DEFINE_THIS_MODULE(lldp);
33 /* This set of macro are used to build packets. The current position in buffer
34 * is `pos'. The length of the remaining space in buffer is `length'. `type'
35 * should be a member of `types'.
37 * This was stolen from ladvd which was adapted from Net::CDP. The original
38 * author of those macros, Michael Chapman, has relicensed those macros under
42 #define POKE(value, type, func) \
43 ((length >= sizeof type) && \
46 memcpy(pos, &type, sizeof type), \
47 length -= sizeof type, \
52 #define POKE_UINT8(value) POKE(value, types.f_uint8, )
53 #define POKE_UINT16(value) POKE(value, types.f_uint16, htons)
54 #define POKE_UINT32(value) POKE(value, types.f_uint32, htonl)
55 #define POKE_BYTES(value, bytes) \
56 ((length >= (bytes)) && \
58 memcpy(pos, value, bytes), \
64 #define POKE_SAVE(where) (where = pos, 1)
65 #define POKE_RESTORE(where) \
68 length -= ((where) - pos); \
70 length += (pos - (where)); \
74 /* This set of macro are used to parse packets. The same variable as for POKE_
75 * are used. There is no check on boundaries.
78 #define PEEK(type, func) \
80 memcpy(&type, pos, sizeof type), \
81 length -= sizeof type, \
85 #define PEEK_UINT8 PEEK(types.f_uint8, )
86 #define PEEK_UINT16 PEEK(types.f_uint16, ntohs)
87 #define PEEK_UINT32 PEEK(types.f_uint32, ntohl)
88 #define PEEK_BYTES(value, bytes) \
90 memcpy(value, pos, bytes); \
94 #define PEEK_DISCARD(bytes) \
99 #define PEEK_DISCARD_UINT8 PEEK_DISCARD(1)
100 #define PEEK_DISCARD_UINT16 PEEK_DISCARD(2)
101 #define PEEK_DISCARD_UINT32 PEEK_DISCARD(3)
102 #define PEEK_CMP(value, bytes) \
103 (length -= (bytes), \
105 memcmp(pos-bytes, value, bytes))
106 #define PEEK_SAVE POKE_SAVE
107 #define PEEK_RESTORE POKE_RESTORE
109 /* LLDP specific. We need a `tlv' pointer. */
110 #define POKE_START_LLDP_TLV(type) \
113 POKE_UINT16(type << 9) \
115 #define POKE_END_LLDP_TLV \
117 memcpy(&types.f_uint16, tlv, sizeof(uint16_t)), \
118 types.f_uint16 |= htons((pos - (tlv + 2)) & 0x01ff), \
119 memcpy(tlv, &types.f_uint16, sizeof(uint16_t)), \
123 #define CHECK_TLV_SIZE(x, name) \
125 if (tlv_size < (x)) { \
126 VLOG_WARN(name " TLV too short received on %s", \
127 hardware->h_ifname); \
139 lldpd_af_to_lldp_proto(int af)
143 return LLDP_MGMT_ADDR_IP4;
145 return LLDP_MGMT_ADDR_IP6;
147 return LLDP_MGMT_ADDR_NONE;
152 lldpd_af_from_lldp_proto(int proto)
155 case LLDP_MGMT_ADDR_IP4:
156 return LLDPD_AF_IPV4;
157 case LLDP_MGMT_ADDR_IP6:
158 return LLDPD_AF_IPV6;
160 return LLDPD_AF_UNSPEC;
165 lldp_send(struct lldpd *global OVS_UNUSED,
166 struct lldpd_hardware *hardware,
169 struct lldpd_port *port;
170 struct lldpd_chassis *chassis;
171 struct lldpd_frame *frame;
172 uint8_t *packet, *pos, *tlv;
173 struct lldpd_mgmt *mgmt;
175 const uint8_t avaya[] = LLDP_TLV_ORG_AVAYA;
176 struct lldpd_aa_isid_vlan_maps_tlv *vlan_isid_map;
177 uint8_t msg_auth_digest[LLDP_TLV_AA_ISID_VLAN_DIGEST_LENGTH];
179 port = &hardware->h_lport;
180 chassis = port->p_chassis;
182 /* The ethernet header is filled in elsewhere, we must save room for it. */
183 length = hardware->h_mtu - sizeof(struct eth_header);
184 packet = dp_packet_l3(p);
185 VLOG_DBG("LLDP PDU send to %s mtu %d incoming with ptr=%p",
186 hardware->h_ifname, hardware->h_mtu, packet);
190 * Make room in dp_packet for chassis ID, Port ID, System Name, System
193 pos = dp_packet_put_uninit(p, sizeof chassis->c_id_subtype +
195 sizeof port->p_id_subtype +
197 sizeof chassis->c_ttl +
198 strlen(chassis->c_name) +
199 strlen(chassis->c_descr) +
200 sizeof chassis->c_cap_available +
201 sizeof chassis->c_cap_enabled + 12);
204 if (!(POKE_START_LLDP_TLV(LLDP_TLV_CHASSIS_ID) &&
205 POKE_UINT8(chassis->c_id_subtype) &&
206 POKE_BYTES(chassis->c_id, chassis->c_id_len) &&
207 POKE_END_LLDP_TLV)) {
212 if (!(POKE_START_LLDP_TLV(LLDP_TLV_PORT_ID) &&
213 POKE_UINT8(port->p_id_subtype) &&
214 POKE_BYTES(port->p_id, port->p_id_len) &&
215 POKE_END_LLDP_TLV)) {
220 if (!(POKE_START_LLDP_TLV(LLDP_TLV_TTL) &&
221 POKE_UINT16(chassis->c_ttl) &&
222 POKE_END_LLDP_TLV)) {
227 if (chassis->c_name && *chassis->c_name != '\0') {
228 if (!(POKE_START_LLDP_TLV(LLDP_TLV_SYSTEM_NAME) &&
229 POKE_BYTES(chassis->c_name, strlen(chassis->c_name)) &&
230 POKE_END_LLDP_TLV)) {
235 /* System description (skip it if empty) */
236 if (chassis->c_descr && *chassis->c_descr != '\0') {
237 if (!(POKE_START_LLDP_TLV(LLDP_TLV_SYSTEM_DESCR) &&
238 POKE_BYTES(chassis->c_descr, strlen(chassis->c_descr)) &&
239 POKE_END_LLDP_TLV)) {
244 /* System capabilities */
245 if (!(POKE_START_LLDP_TLV(LLDP_TLV_SYSTEM_CAP) &&
246 POKE_UINT16(chassis->c_cap_available) &&
247 POKE_UINT16(chassis->c_cap_enabled) &&
248 POKE_END_LLDP_TLV)) {
252 LIST_FOR_EACH (mgmt, m_entries, &chassis->c_mgmt.m_entries) {
254 * Make room for 1 mgmt interface
256 dp_packet_put_uninit(p, 2 + sizeof(uint8_t) +
263 proto = lldpd_af_to_lldp_proto(mgmt->m_family);
264 if (!(POKE_START_LLDP_TLV(LLDP_TLV_MGMT_ADDR) &&
265 /* Size of the address, including its type */
266 POKE_UINT8(mgmt->m_addrsize + 1) &&
268 POKE_BYTES(&mgmt->m_addr, mgmt->m_addrsize))) {
272 /* Interface port type, OID */
273 if (mgmt->m_iface == 0) {
274 if (!(/* We don't know the management interface */
275 POKE_UINT8(LLDP_MGMT_IFACE_UNKNOWN) &&
280 if (!(/* We have the index of the management interface */
281 POKE_UINT8(LLDP_MGMT_IFACE_IFINDEX) &&
282 POKE_UINT32(mgmt->m_iface))) {
286 if (!(/* We don't provide an OID for management */
288 POKE_END_LLDP_TLV)) {
293 /* Port description */
294 if (port->p_descr && *port->p_descr != '\0') {
295 /* make room for port descr */
296 dp_packet_put_uninit(p, 2 + strlen(port->p_descr));
298 if (!(POKE_START_LLDP_TLV(LLDP_TLV_PORT_DESCR) &&
299 POKE_BYTES(port->p_descr, strlen(port->p_descr)) &&
300 POKE_END_LLDP_TLV)) {
305 /* Add Auto Attach tlvs to packet */
307 if (port->p_element.type != 0) {
308 u_int8_t aa_element_first_byte;
309 u_int8_t aa_element_second_byte = 0;
310 u_int8_t aa_elem_sys_id_first_byte;
311 u_int8_t aa_elem_sys_id_second_byte;
313 /* Element type should be first 4 most significant bits, so bitwise OR
314 * that with the first 4 bits of the 12-bit-wide mgmt_vlan
316 aa_element_first_byte = ((port->p_element.type & 0xF) << 4) |
317 ((port->p_element.mgmt_vlan >> 8) & 0xF);
319 /* Second byte should just be the remaining 8 bits of .mgmt_vlan */
320 aa_element_second_byte = port->p_element.mgmt_vlan & 0x0FF;
322 /* .conn_type should be 4 most sig. bits, so bitwise OR that
323 * with the first 4 bits of the 12-bit-wide .smlt_id
325 aa_elem_sys_id_first_byte =
326 ((port->p_element.system_id.conn_type & 0xF) << 4) |
327 ((port->p_element.system_id.smlt_id >> 8) & 0xF);
329 /* Second byte should just be the remaining 8 bits of .smlt_id */
330 aa_elem_sys_id_second_byte = port->p_element.system_id.smlt_id & 0x0FF;
332 /* make room for element type tlv */
333 dp_packet_put_uninit(p, 2 + sizeof avaya +
335 sizeof aa_element_first_byte +
336 sizeof aa_element_second_byte +
337 sizeof port->p_element.system_id.system_mac +
338 sizeof aa_elem_sys_id_first_byte +
339 sizeof aa_elem_sys_id_second_byte +
340 sizeof port->p_element.system_id.mlt_id);
342 if (!(POKE_START_LLDP_TLV(LLDP_TLV_ORG) &&
343 POKE_BYTES(avaya, sizeof avaya) &&
344 POKE_UINT8(LLDP_TLV_AA_ELEMENT_SUBTYPE) &&
345 POKE_UINT8(aa_element_first_byte) &&
346 POKE_UINT8(aa_element_second_byte) &&
347 POKE_BYTES(&port->p_element.system_id.system_mac,
348 sizeof port->p_element.system_id.system_mac) &&
349 POKE_UINT8(aa_elem_sys_id_first_byte) &&
350 POKE_UINT8(aa_elem_sys_id_second_byte) &&
351 POKE_BYTES(&port->p_element.system_id.mlt_id,
352 sizeof port->p_element.system_id.mlt_id) &&
353 POKE_END_LLDP_TLV)) {
358 if (!list_is_empty(&port->p_isid_vlan_maps.m_entries)) {
362 * make room for aa_isid_digest
364 dp_packet_put_uninit(p, 2 + sizeof avaya +
366 sizeof msg_auth_digest);
368 for (j = 0; j < LLDP_TLV_AA_ISID_VLAN_DIGEST_LENGTH; j++) {
369 msg_auth_digest[j] = 0;
372 if (!(POKE_START_LLDP_TLV(LLDP_TLV_ORG) &&
373 POKE_BYTES(avaya, sizeof avaya) &&
374 POKE_UINT8(LLDP_TLV_AA_ISID_VLAN_ASGNS_SUBTYPE) &&
375 POKE_BYTES(msg_auth_digest, sizeof msg_auth_digest))) {
379 LIST_FOR_EACH (vlan_isid_map,
381 &hardware->h_lport.p_isid_vlan_maps.m_entries) {
382 u_int16_t status_vlan_word;
384 (vlan_isid_map->isid_vlan_data.status << 12) |
385 vlan_isid_map->isid_vlan_data.vlan;
388 * Make room for one isid-vlan mapping
390 dp_packet_put_uninit(p, sizeof status_vlan_word +
391 sizeof vlan_isid_map->isid_vlan_data.isid);
393 if (!(POKE_UINT16(status_vlan_word) &&
394 POKE_BYTES(&vlan_isid_map->isid_vlan_data.isid,
395 sizeof vlan_isid_map->isid_vlan_data.isid))) {
400 if (!(POKE_END_LLDP_TLV)) {
405 /* Make room for the End TLV 0x0000 */
406 dp_packet_put_uninit(p, sizeof(uint16_t));
409 if (!(POKE_START_LLDP_TLV(LLDP_TLV_END) &&
410 POKE_END_LLDP_TLV)) {
414 hardware->h_tx_cnt++;
416 /* We assume that LLDP frame is the reference */
417 if ((frame = malloc(sizeof(int) + pos - packet)) != NULL) {
418 frame->size = pos - packet;
419 length = frame->size;
420 memcpy(&frame->frame, packet, frame->size);
422 if ((hardware->h_lport.p_lastframe == NULL) ||
423 (hardware->h_lport.p_lastframe->size != frame->size) ||
424 (memcmp(hardware->h_lport.p_lastframe->frame, frame->frame,
425 frame->size) != 0)) {
426 free(hardware->h_lport.p_lastframe);
427 hardware->h_lport.p_lastframe = frame;
428 hardware->h_lport.p_lastchange = time(NULL);
443 lldp_decode(struct lldpd *cfg OVS_UNUSED, char *frame, int s,
444 struct lldpd_hardware *hardware, struct lldpd_chassis **newchassis,
445 struct lldpd_port **newport)
447 struct lldpd_chassis *chassis;
448 struct lldpd_port *port;
449 const char lldpaddr[] = LLDP_MULTICAST_ADDR;
450 const char dot1[] = LLDP_TLV_ORG_DOT1;
451 const char dot3[] = LLDP_TLV_ORG_DOT3;
452 const char med[] = LLDP_TLV_ORG_MED;
453 const char avaya_oid[] = LLDP_TLV_ORG_AVAYA;
454 const char dcbx[] = LLDP_TLV_ORG_DCBX;
456 int length, gotend = 0, ttl_received = 0, af;
457 int tlv_size, tlv_type, tlv_subtype;
460 struct lldpd_aa_isid_vlan_maps_tlv *isid_vlan_map = NULL;
461 u_int8_t msg_auth_digest[LLDP_TLV_AA_ISID_VLAN_DIGEST_LENGTH];
462 struct lldpd_mgmt *mgmt;
463 u_int8_t addr_str_length, addr_str_buffer[32];
464 u_int8_t addr_family, addr_length, *addr_ptr, iface_subtype;
465 u_int32_t iface_number, iface;
467 VLOG_DBG("receive LLDP PDU on %s", hardware->h_ifname);
469 if ((chassis = calloc(1, sizeof *chassis)) == NULL) {
470 VLOG_WARN("failed to allocate remote chassis");
473 list_init(&chassis->c_mgmt.m_entries);
475 if ((port = calloc(1, sizeof *port)) == NULL) {
476 VLOG_WARN("failed to allocate remote port");
480 list_init(&port->p_isid_vlan_maps.m_entries);
483 pos = (u_int8_t*) frame;
485 if (length < 2 * ETH_ADDR_LEN + sizeof(u_int16_t)) {
486 VLOG_WARN("too short frame received on %s", hardware->h_ifname);
489 if (PEEK_CMP(lldpaddr, ETH_ADDR_LEN) != 0) {
490 VLOG_INFO("frame not targeted at LLDP multicast address "
491 "received on %s", hardware->h_ifname);
494 PEEK_DISCARD(ETH_ADDR_LEN); /* Skip source address */
495 if (PEEK_UINT16 != ETHERTYPE_LLDP) {
496 VLOG_INFO("non LLDP frame received on %s", hardware->h_ifname);
500 while (length && (!gotend)) {
502 VLOG_WARN("tlv header too short received on %s",
506 tlv_size = PEEK_UINT16;
507 tlv_type = tlv_size >> 9;
508 tlv_size = tlv_size & 0x1ff;
509 (void) PEEK_SAVE(tlv);
510 if (length < tlv_size) {
511 VLOG_WARN("frame too short for tlv received on %s",
519 VLOG_WARN("lldp end received with size not null on %s",
524 VLOG_DBG("extra data after lldp end on %s",
530 case LLDP_TLV_CHASSIS_ID:
531 case LLDP_TLV_PORT_ID:
532 CHECK_TLV_SIZE(2, "Port Id");
533 tlv_subtype = PEEK_UINT8;
534 if ((tlv_subtype == 0) || (tlv_subtype > 7)) {
535 VLOG_WARN("unknown subtype for tlv id received on %s",
539 if ((b = (char *) calloc(1, tlv_size - 1)) == NULL) {
540 VLOG_WARN("unable to allocate memory for id tlv received "
545 PEEK_BYTES(b, tlv_size - 1);
546 if (tlv_type == LLDP_TLV_PORT_ID) {
547 port->p_id_subtype = tlv_subtype;
549 port->p_id_len = tlv_size - 1;
551 chassis->c_id_subtype = tlv_subtype;
553 chassis->c_id_len = tlv_size - 1;
558 CHECK_TLV_SIZE(2, "TTL");
559 chassis->c_ttl = PEEK_UINT16;
563 case LLDP_TLV_PORT_DESCR:
564 case LLDP_TLV_SYSTEM_NAME:
565 case LLDP_TLV_SYSTEM_DESCR:
567 VLOG_DBG("empty tlv received on %s", hardware->h_ifname);
570 if ((b = (char *) calloc(1, tlv_size + 1)) == NULL) {
571 VLOG_WARN("unable to allocate memory for string tlv "
576 PEEK_BYTES(b, tlv_size);
577 if (tlv_type == LLDP_TLV_PORT_DESCR) {
579 } else if (tlv_type == LLDP_TLV_SYSTEM_NAME) {
582 chassis->c_descr = b;
586 case LLDP_TLV_SYSTEM_CAP:
587 CHECK_TLV_SIZE(4, "System capabilities");
588 chassis->c_cap_available = PEEK_UINT16;
589 chassis->c_cap_enabled = PEEK_UINT16;
592 case LLDP_TLV_MGMT_ADDR:
593 CHECK_TLV_SIZE(1, "Management address");
594 addr_str_length = PEEK_UINT8;
595 CHECK_TLV_SIZE(1 + addr_str_length, "Management address");
596 PEEK_BYTES(addr_str_buffer, addr_str_length);
597 addr_length = addr_str_length - 1;
598 addr_family = addr_str_buffer[0];
599 addr_ptr = &addr_str_buffer[1];
600 CHECK_TLV_SIZE(1 + addr_str_length + 5, "Management address");
601 iface_subtype = PEEK_UINT8;
602 iface_number = PEEK_UINT32;
604 af = lldpd_af_from_lldp_proto(addr_family);
605 if (af == LLDPD_AF_UNSPEC) {
608 iface = iface_subtype == LLDP_MGMT_IFACE_IFINDEX ?
610 mgmt = lldpd_alloc_mgmt(af, addr_ptr, addr_length, iface);
612 VLOG_WARN("unable to allocate memory for management address");
615 list_push_back(&chassis->c_mgmt.m_entries, &mgmt->m_entries);
619 CHECK_TLV_SIZE(4, "Organisational");
620 PEEK_BYTES(orgid, sizeof orgid);
621 tlv_subtype = PEEK_UINT8;
622 if (memcmp(dot1, orgid, sizeof orgid) == 0) {
623 hardware->h_rx_unrecognized_cnt++;
624 } else if (memcmp(dot3, orgid, sizeof orgid) == 0) {
625 hardware->h_rx_unrecognized_cnt++;
626 } else if (memcmp(med, orgid, sizeof orgid) == 0) {
628 hardware->h_rx_unrecognized_cnt++;
629 } else if (memcmp(avaya_oid, orgid, sizeof orgid) == 0) {
630 u_int16_t aa_element_word;
631 u_int16_t aa_status_vlan_word;
632 u_int16_t aa_system_id_word;
633 unsigned short num_mappings;
635 switch(tlv_subtype) {
636 case LLDP_TLV_AA_ELEMENT_SUBTYPE:
637 aa_element_word = PEEK_UINT16;
639 /* Type is first 4 most-significant bits */
640 port->p_element.type = aa_element_word >> 12;
642 /* mgmt_vlan is last 12 bits */
643 port->p_element.mgmt_vlan = aa_element_word & 0x0FFF;
644 VLOG_INFO("Element type: %X, Mgmt vlan: %X",
645 port->p_element.type,
646 port->p_element.mgmt_vlan);
647 PEEK_BYTES(&port->p_element.system_id.system_mac,
648 sizeof port->p_element.system_id.system_mac);
649 VLOG_INFO("System mac: 0x%.2X%.2X%.2X%.2X%.2X%.2X",
650 port->p_element.system_id.system_mac[0],
651 port->p_element.system_id.system_mac[1],
652 port->p_element.system_id.system_mac[2],
653 port->p_element.system_id.system_mac[3],
654 port->p_element.system_id.system_mac[4],
655 port->p_element.system_id.system_mac[5]);
656 aa_system_id_word = PEEK_UINT16;
657 port->p_element.system_id.conn_type =
658 aa_system_id_word >> 12;
659 port->p_element.system_id.smlt_id =
660 aa_system_id_word & 0x0FFF;
661 PEEK_BYTES(&port->p_element.system_id.mlt_id,
662 sizeof port->p_element.system_id.mlt_id);
665 case LLDP_TLV_AA_ISID_VLAN_ASGNS_SUBTYPE:
666 PEEK_BYTES(&msg_auth_digest, sizeof msg_auth_digest);
668 /* Subtract off tlv type and length (2Bytes) + OUI (3B) +
669 * Subtype (1B) + MSG DIGEST (32B).
671 num_mappings = tlv_size - 4 -
672 LLDP_TLV_AA_ISID_VLAN_DIGEST_LENGTH;
673 if ((num_mappings % 5) != 0) {
674 VLOG_INFO("malformed vlan-isid mappings tlv received");
678 num_mappings /= 5; /* Each mapping is 5 Bytes */
679 for(; num_mappings > 0; num_mappings--) {
680 isid_vlan_map = (struct lldpd_aa_isid_vlan_maps_tlv *)
681 calloc(1, sizeof *isid_vlan_map);
682 if (!isid_vlan_map) {
683 VLOG_WARN("unable to allocate memory "
684 "for aa_isid_vlan_maps_tlv struct");
687 aa_status_vlan_word = PEEK_UINT16;
689 /* Status is first 4 most-significant bits. */
690 isid_vlan_map->isid_vlan_data.status =
691 aa_status_vlan_word >> 12;
693 /* Vlan is last 12 bits */
694 isid_vlan_map->isid_vlan_data.vlan =
695 aa_status_vlan_word & 0x0FFF;
696 PEEK_BYTES(&isid_vlan_map->isid_vlan_data.isid,
697 sizeof isid_vlan_map->isid_vlan_data.isid);
699 (struct ovs_list *) &port->p_isid_vlan_maps,
700 (struct ovs_list *) isid_vlan_map);
701 isid_vlan_map = NULL;
706 hardware->h_rx_unrecognized_cnt++;
707 VLOG_INFO("Unrecogised tlv subtype received");
710 } else if (memcmp(dcbx, orgid, sizeof orgid) == 0) {
711 VLOG_DBG("unsupported DCBX tlv received on %s "
712 "- ignore", hardware->h_ifname);
713 hardware->h_rx_unrecognized_cnt++;
715 VLOG_INFO("unknown org tlv [%02x:%02x:%02x] received "
716 "on %s", orgid[0], orgid[1], orgid[2],
718 hardware->h_rx_unrecognized_cnt++;
722 VLOG_WARN("unknown tlv (%d) received on %s",
727 if (pos > tlv + tlv_size) {
728 VLOG_WARN("BUG: already past TLV!");
731 PEEK_DISCARD(tlv + tlv_size - pos);
734 /* Some random check */
735 if ((chassis->c_id == NULL) ||
736 (port->p_id == NULL) ||
739 VLOG_WARN("some mandatory tlv are missing for frame received "
740 "on %s", hardware->h_ifname);
743 *newchassis = chassis;
748 lldpd_chassis_cleanup(chassis, 1);
749 lldpd_port_cleanup(port, 1);