lldp: Remove excessive parentheses.
[cascardo/ovs.git] / lib / lldp / lldp.c
1 /* -*- mode: c; c-file-style: "openbsd" -*- */
2 /*
3  * Copyright (c) 2015 Nicira, Inc.
4  * Copyright (c) 2008 Vincent Bernat <bernat@luffy.cx>
5  * Copyright (c) 2014 Michael Chapman
6  *
7  * Permission to use, copy, modify, and/or distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19
20 #include <config.h>
21 #include "lldpd.h"
22 #include <errno.h>
23 #include <time.h>
24 #include <unistd.h>
25 #include <sys/ioctl.h>
26 #include <sys/socket.h>
27 #include <sys/types.h>
28 #include "compiler.h"
29 #include "dp-packet.h"
30 #include "packets.h"
31
32 VLOG_DEFINE_THIS_MODULE(lldp);
33
34 /* This set of macro are used to parse packets. The current position in buffer
35  * is `pos'. The length of the remaining space in buffer is `length'.  There is
36  * no check on boundaries.
37  */
38
39 #define PEEK(type, func)                  \
40     (                                     \
41         memcpy(&type, pos, sizeof type), \
42         length -= sizeof type,           \
43         pos += sizeof type,              \
44         func(type)                        \
45     )
46 #define PEEK_UINT8 PEEK(types.f_uint8, )
47 #define PEEK_UINT16 PEEK(types.f_uint16, ntohs)
48 #define PEEK_UINT32 PEEK(types.f_uint32, ntohl)
49 #define PEEK_BYTES(value, bytes)   \
50     do {                           \
51         memcpy(value, pos, bytes); \
52         length -= (bytes);         \
53         pos += (bytes);            \
54     } while (0)
55 #define PEEK_DISCARD(bytes) \
56     do {                    \
57         length -= (bytes);  \
58         pos += (bytes);     \
59     } while (0)
60 #define PEEK_DISCARD_UINT8 PEEK_DISCARD(1)
61 #define PEEK_DISCARD_UINT16 PEEK_DISCARD(2)
62 #define PEEK_DISCARD_UINT32 PEEK_DISCARD(3)
63 #define PEEK_CMP(value, bytes) \
64      (length -= (bytes),       \
65      pos += (bytes),           \
66      memcmp(pos-bytes, value, bytes))
67 #define CHECK_TLV_SIZE(x, name)                             \
68     do {                                                    \
69         if (tlv_size < (x)) {                               \
70             VLOG_WARN(name " TLV too short received on %s", \
71                       hardware->h_ifname);                  \
72             goto malformed;                                 \
73         }                                                   \
74     } while (0)
75 #define PEEK_SAVE(where) (where = pos, 1)
76
77 static union {
78     uint8_t  f_uint8;
79     ovs_be16 f_uint16;
80     ovs_be32 f_uint32;
81 } types;
82
83 static int
84 lldpd_af_to_lldp_proto(int af)
85 {
86     switch (af) {
87     case LLDPD_AF_IPV4:
88         return LLDP_MGMT_ADDR_IP4;
89     case LLDPD_AF_IPV6:
90         return LLDP_MGMT_ADDR_IP6;
91     default:
92         return LLDP_MGMT_ADDR_NONE;
93     }
94 }
95
96 static int
97 lldpd_af_from_lldp_proto(int proto)
98 {
99     switch (proto) {
100     case LLDP_MGMT_ADDR_IP4:
101         return LLDPD_AF_IPV4;
102     case LLDP_MGMT_ADDR_IP6:
103         return LLDPD_AF_IPV6;
104     default:
105         return LLDPD_AF_UNSPEC;
106     }
107 }
108
109 static void
110 lldp_tlv_put_u8(struct dp_packet *p, uint8_t x)
111 {
112     dp_packet_put(p, &x, sizeof x);
113 }
114
115 static void
116 lldp_tlv_put_u16(struct dp_packet *p, uint16_t x)
117 {
118     ovs_be16 nx = htons(x);
119     dp_packet_put(p, &nx, sizeof nx);
120 }
121
122 static void
123 lldp_tlv_put_u32(struct dp_packet *p, uint32_t x)
124 {
125     ovs_be32 nx = htonl(x);
126     dp_packet_put(p, &nx, sizeof nx);
127 }
128
129 static void
130 lldp_tlv_put_isid(struct dp_packet *p, uint32_t isid)
131 {
132     uint8_t *data = dp_packet_put_uninit(p, 3);
133     data[0] = isid >> 16;
134     data[1] = isid >> 8;
135     data[2] = isid;
136 }
137
138 static void
139 lldp_tlv_start(struct dp_packet *p, uint8_t tlv, unsigned int *start)
140 {
141     *start = dp_packet_size(p);
142     lldp_tlv_put_u16(p, tlv << 9);
143 }
144
145 static void
146 lldp_tlv_end(struct dp_packet *p, unsigned int start)
147 {
148     ovs_be16 *tlv = dp_packet_at_assert(p, start, 2);
149     *tlv |= htons((dp_packet_size(p) - (start + 2)) & 0x1ff);
150 }
151
152 int
153 lldp_send(struct lldpd *global OVS_UNUSED,
154           struct lldpd_hardware *hardware,
155           struct dp_packet *p)
156 {
157     unsigned int orig_size = dp_packet_size(p);
158     unsigned int start;
159
160     struct lldpd_port *port;
161     struct lldpd_chassis *chassis;
162     struct lldpd_mgmt *mgmt;
163     const uint8_t avaya[] = LLDP_TLV_ORG_AVAYA;
164     struct lldpd_aa_isid_vlan_maps_tlv *vlan_isid_map;
165     uint8_t msg_auth_digest[LLDP_TLV_AA_ISID_VLAN_DIGEST_LENGTH];
166
167     port = &hardware->h_lport;
168     chassis = port->p_chassis;
169
170     /* The ethernet header is filled in elsewhere, we must save room for it. */
171     VLOG_DBG("LLDP PDU send to %s mtu %d incoming",
172               hardware->h_ifname, hardware->h_mtu);
173
174     /* Chassis ID */
175     lldp_tlv_start(p, LLDP_TLV_CHASSIS_ID, &start);
176     lldp_tlv_put_u8(p, chassis->c_id_subtype);
177     dp_packet_put(p, chassis->c_id, chassis->c_id_len);
178     lldp_tlv_end(p, start);
179
180     /* Port ID */
181     lldp_tlv_start(p, LLDP_TLV_PORT_ID, &start);
182     lldp_tlv_put_u8(p, port->p_id_subtype);
183     dp_packet_put(p, port->p_id, port->p_id_len);
184     lldp_tlv_end(p, start);
185
186     /* Time to live */
187     lldp_tlv_start(p, LLDP_TLV_TTL, &start);
188     lldp_tlv_put_u16(p, chassis->c_ttl);
189     lldp_tlv_end(p, start);
190
191     /* System name */
192     if (chassis->c_name && *chassis->c_name != '\0') {
193         lldp_tlv_start(p, LLDP_TLV_SYSTEM_NAME, &start);
194         dp_packet_put(p, chassis->c_name, strlen(chassis->c_name));
195         lldp_tlv_end(p, start);
196     }
197
198     /* System description (skip it if empty) */
199     if (chassis->c_descr && *chassis->c_descr != '\0') {
200         lldp_tlv_start(p, LLDP_TLV_SYSTEM_DESCR, &start);
201         dp_packet_put(p, chassis->c_descr, strlen(chassis->c_descr));
202         lldp_tlv_end(p, start);
203     }
204
205     /* System capabilities */
206     lldp_tlv_start(p, LLDP_TLV_SYSTEM_CAP, &start);
207     lldp_tlv_put_u16(p, chassis->c_cap_available);
208     lldp_tlv_put_u16(p, chassis->c_cap_enabled);
209     lldp_tlv_end(p, start);
210
211     LIST_FOR_EACH (mgmt, m_entries, &chassis->c_mgmt) {
212         lldp_tlv_start(p, LLDP_TLV_MGMT_ADDR, &start);
213         lldp_tlv_put_u8(p, mgmt->m_addrsize + 1);
214         lldp_tlv_put_u8(p, lldpd_af_to_lldp_proto(mgmt->m_family));
215         dp_packet_put(p, &mgmt->m_addr, mgmt->m_addrsize);
216
217         /* Interface port type, OID */
218         if (mgmt->m_iface == 0) {
219             /* We don't know the management interface */
220             lldp_tlv_put_u8(p, LLDP_MGMT_IFACE_UNKNOWN);
221             lldp_tlv_put_u32(p, 0);
222         } else {
223             /* We have the index of the management interface */
224             lldp_tlv_put_u8(p, LLDP_MGMT_IFACE_IFINDEX);
225             lldp_tlv_put_u32(p, mgmt->m_iface);
226         }
227         lldp_tlv_put_u8(p, 0);
228         lldp_tlv_end(p, start);
229     }
230
231     /* Port description */
232     if (port->p_descr && *port->p_descr != '\0') {
233         lldp_tlv_start(p, LLDP_TLV_PORT_DESCR, &start);
234         dp_packet_put(p, port->p_descr, strlen(port->p_descr));
235         lldp_tlv_end(p, start);
236     }
237
238     /* Add Auto Attach tlvs to packet */
239     /* AA-ELEMENT */
240     if (port->p_element.type != 0) {
241         u_int8_t aa_element_first_byte;
242         u_int8_t aa_element_second_byte = 0;
243         u_int8_t aa_elem_sys_id_first_byte;
244         u_int8_t aa_elem_sys_id_second_byte;
245
246         /* Element type should be first 4 most significant bits, so bitwise OR
247          * that with the first 4 bits of the 12-bit-wide mgmt_vlan
248          */
249         aa_element_first_byte = (((port->p_element.type & 0xF) << 4) |
250                                  ((port->p_element.mgmt_vlan >> 8) & 0xF));
251
252         /* Second byte should just be the remaining 8 bits of .mgmt_vlan */
253         aa_element_second_byte = port->p_element.mgmt_vlan & 0x0FF;
254
255         /* .conn_type should be 4 most sig. bits, so bitwise OR that
256          * with the first 4 bits of the 12-bit-wide .smlt_id
257          */
258         aa_elem_sys_id_first_byte =
259             ((port->p_element.system_id.conn_type & 0xF) << 4) |
260             ((port->p_element.system_id.smlt_id >> 8) & 0xF);
261
262         /* Second byte should just be the remaining 8 bits of .smlt_id */
263         aa_elem_sys_id_second_byte = port->p_element.system_id.smlt_id & 0x0FF;
264
265         lldp_tlv_start(p, LLDP_TLV_ORG, &start);
266         dp_packet_put(p, avaya, sizeof avaya);
267         lldp_tlv_put_u8(p, LLDP_TLV_AA_ELEMENT_SUBTYPE);
268         lldp_tlv_put_u8(p, aa_element_first_byte);
269         lldp_tlv_put_u8(p, aa_element_second_byte);
270         dp_packet_put(p, &port->p_element.system_id.system_mac,
271                       sizeof port->p_element.system_id.system_mac);
272         lldp_tlv_put_u8(p, aa_elem_sys_id_first_byte);
273         lldp_tlv_put_u8(p, aa_elem_sys_id_second_byte);
274         dp_packet_put(p, &port->p_element.system_id.mlt_id,
275                       sizeof port->p_element.system_id.mlt_id);
276         lldp_tlv_end(p, start);
277     }
278
279     if (!list_is_empty(&port->p_isid_vlan_maps)) {
280         int j;
281
282         for (j = 0; j < LLDP_TLV_AA_ISID_VLAN_DIGEST_LENGTH; j++) {
283             msg_auth_digest[j] = 0;
284         }
285
286         lldp_tlv_start(p, LLDP_TLV_ORG, &start);
287         dp_packet_put(p, avaya, sizeof avaya);
288         lldp_tlv_put_u8(p, LLDP_TLV_AA_ISID_VLAN_ASGNS_SUBTYPE);
289         dp_packet_put(p, msg_auth_digest, sizeof msg_auth_digest);
290
291         LIST_FOR_EACH (vlan_isid_map,
292                        m_entries,
293                        &hardware->h_lport.p_isid_vlan_maps) {
294             u_int16_t status_vlan_word;
295             status_vlan_word =
296                 (vlan_isid_map->isid_vlan_data.status << 12) |
297                 vlan_isid_map->isid_vlan_data.vlan;
298
299             lldp_tlv_put_u16(p, status_vlan_word);
300             lldp_tlv_put_isid(p, vlan_isid_map->isid_vlan_data.isid);
301         }
302
303         lldp_tlv_end(p, start);
304     }
305
306     /* END */
307     lldp_tlv_start(p, LLDP_TLV_END, &start);
308     lldp_tlv_end(p, start);
309
310     hardware->h_tx_cnt++;
311
312     const char *lldp = dp_packet_at_assert(p, orig_size, 0);
313     unsigned int lldp_len = dp_packet_size(p) - orig_size;
314     if (!hardware->h_lport.p_lastframe
315         || hardware->h_lport.p_lastframe->size != lldp_len
316         || memcmp(hardware->h_lport.p_lastframe->frame, lldp, lldp_len)) {
317         struct lldpd_frame *frame = xmalloc(sizeof *frame + lldp_len);
318         frame->size = lldp_len;
319         memcpy(frame->frame, lldp, lldp_len);
320         free(hardware->h_lport.p_lastframe);
321         hardware->h_lport.p_lastframe = frame;
322         hardware->h_lport.p_lastchange = time(NULL);
323     }
324
325     return dp_packet_size(p);
326 }
327
328 int
329 lldp_decode(struct lldpd *cfg OVS_UNUSED, char *frame, int s,
330     struct lldpd_hardware *hardware, struct lldpd_chassis **newchassis,
331     struct lldpd_port **newport)
332 {
333     struct lldpd_chassis *chassis;
334     struct lldpd_port *port;
335     const char lldpaddr[] = LLDP_MULTICAST_ADDR;
336     const char dot1[] = LLDP_TLV_ORG_DOT1;
337     const char dot3[] = LLDP_TLV_ORG_DOT3;
338     const char med[] = LLDP_TLV_ORG_MED;
339     const char avaya_oid[] = LLDP_TLV_ORG_AVAYA;
340     const char dcbx[] = LLDP_TLV_ORG_DCBX;
341     char orgid[3];
342     int length, af;
343     bool gotend = false;
344     bool ttl_received = false;
345     int tlv_size, tlv_type, tlv_subtype;
346     u_int8_t *pos, *tlv;
347     void *b;
348     struct lldpd_aa_isid_vlan_maps_tlv *isid_vlan_map = NULL;
349     u_int8_t msg_auth_digest[LLDP_TLV_AA_ISID_VLAN_DIGEST_LENGTH];
350     struct lldpd_mgmt *mgmt;
351     u_int8_t addr_str_length, addr_str_buffer[32];
352     u_int8_t addr_family, addr_length, *addr_ptr, iface_subtype;
353     u_int32_t iface_number, iface;
354
355     VLOG_DBG("receive LLDP PDU on %s", hardware->h_ifname);
356
357     chassis = xzalloc(sizeof *chassis);
358     list_init(&chassis->c_mgmt);
359
360     port = xzalloc(sizeof *port);
361     list_init(&port->p_isid_vlan_maps);
362
363     length = s;
364     pos = (u_int8_t*) frame;
365
366     if (length < 2 * ETH_ADDR_LEN + sizeof(u_int16_t)) {
367         VLOG_WARN("too short frame received on %s", hardware->h_ifname);
368         goto malformed;
369     }
370     if (PEEK_CMP(lldpaddr, ETH_ADDR_LEN) != 0) {
371         VLOG_INFO("frame not targeted at LLDP multicast address "
372                   "received on %s", hardware->h_ifname);
373         goto malformed;
374     }
375     PEEK_DISCARD(ETH_ADDR_LEN); /* Skip source address */
376     if (PEEK_UINT16 != ETHERTYPE_LLDP) {
377         VLOG_INFO("non LLDP frame received on %s", hardware->h_ifname);
378         goto malformed;
379     }
380
381     while (length && !gotend) {
382         if (length < 2) {
383             VLOG_WARN("tlv header too short received on %s",
384                       hardware->h_ifname);
385             goto malformed;
386         }
387         tlv_size = PEEK_UINT16;
388         tlv_type = tlv_size >> 9;
389         tlv_size = tlv_size & 0x1ff;
390         (void) PEEK_SAVE(tlv);
391         if (length < tlv_size) {
392             VLOG_WARN("frame too short for tlv received on %s",
393                       hardware->h_ifname);
394             goto malformed;
395         }
396
397         switch (tlv_type) {
398         case LLDP_TLV_END:
399             if (tlv_size != 0) {
400                 VLOG_WARN("lldp end received with size not null on %s",
401                           hardware->h_ifname);
402                 goto malformed;
403             }
404             if (length) {
405                 VLOG_DBG("extra data after lldp end on %s",
406                          hardware->h_ifname);
407             }
408             gotend = true;
409             break;
410
411         case LLDP_TLV_CHASSIS_ID:
412         case LLDP_TLV_PORT_ID:
413             CHECK_TLV_SIZE(2, "Port Id");
414             tlv_subtype = PEEK_UINT8;
415             if (tlv_subtype == 0 || tlv_subtype > 7) {
416                 VLOG_WARN("unknown subtype for tlv id received on %s",
417                           hardware->h_ifname);
418                 goto malformed;
419             }
420             b = xzalloc(tlv_size - 1);
421             PEEK_BYTES(b, tlv_size - 1);
422             if (tlv_type == LLDP_TLV_PORT_ID) {
423                 port->p_id_subtype = tlv_subtype;
424                 port->p_id = b;
425                 port->p_id_len = tlv_size - 1;
426             } else {
427                 chassis->c_id_subtype = tlv_subtype;
428                 chassis->c_id = b;
429                 chassis->c_id_len = tlv_size - 1;
430             }
431             break;
432
433         case LLDP_TLV_TTL:
434             CHECK_TLV_SIZE(2, "TTL");
435             chassis->c_ttl = PEEK_UINT16;
436             ttl_received = true;
437             break;
438
439         case LLDP_TLV_PORT_DESCR:
440         case LLDP_TLV_SYSTEM_NAME:
441         case LLDP_TLV_SYSTEM_DESCR:
442             if (tlv_size < 1) {
443                 VLOG_DBG("empty tlv received on %s", hardware->h_ifname);
444                 break;
445             }
446             b = xzalloc(tlv_size + 1);
447             PEEK_BYTES(b, tlv_size);
448             if (tlv_type == LLDP_TLV_PORT_DESCR) {
449                 port->p_descr = b;
450             } else if (tlv_type == LLDP_TLV_SYSTEM_NAME) {
451                 chassis->c_name = b;
452             } else {
453                 chassis->c_descr = b;
454             }
455             break;
456
457         case LLDP_TLV_SYSTEM_CAP:
458             CHECK_TLV_SIZE(4, "System capabilities");
459             chassis->c_cap_available = PEEK_UINT16;
460             chassis->c_cap_enabled = PEEK_UINT16;
461             break;
462
463         case LLDP_TLV_MGMT_ADDR:
464             CHECK_TLV_SIZE(1, "Management address");
465             addr_str_length = PEEK_UINT8;
466             CHECK_TLV_SIZE(1 + addr_str_length, "Management address");
467             PEEK_BYTES(addr_str_buffer, addr_str_length);
468             addr_length = addr_str_length - 1;
469             addr_family = addr_str_buffer[0];
470             addr_ptr = &addr_str_buffer[1];
471             CHECK_TLV_SIZE(1 + addr_str_length + 5, "Management address");
472             iface_subtype = PEEK_UINT8;
473             iface_number = PEEK_UINT32;
474
475             af = lldpd_af_from_lldp_proto(addr_family);
476             if (af == LLDPD_AF_UNSPEC) {
477                 break;
478             }
479             iface = iface_subtype == LLDP_MGMT_IFACE_IFINDEX ?
480                 iface_number : 0;
481             mgmt = lldpd_alloc_mgmt(af, addr_ptr, addr_length, iface);
482             if (mgmt == NULL) {
483                 VLOG_WARN("unable to allocate memory for management address");
484                 goto malformed;
485             }
486             list_push_back(&chassis->c_mgmt, &mgmt->m_entries);
487             break;
488
489         case LLDP_TLV_ORG:
490             CHECK_TLV_SIZE(4, "Organisational");
491             PEEK_BYTES(orgid, sizeof orgid);
492             tlv_subtype = PEEK_UINT8;
493             if (memcmp(dot1, orgid, sizeof orgid) == 0) {
494                 hardware->h_rx_unrecognized_cnt++;
495             } else if (memcmp(dot3, orgid, sizeof orgid) == 0) {
496                 hardware->h_rx_unrecognized_cnt++;
497             } else if (memcmp(med, orgid, sizeof orgid) == 0) {
498                 /* LLDP-MED */
499                 hardware->h_rx_unrecognized_cnt++;
500             } else if (memcmp(avaya_oid, orgid, sizeof orgid) == 0) {
501                 u_int16_t aa_element_word;
502                 u_int16_t aa_status_vlan_word;
503                 u_int16_t aa_system_id_word;
504                 unsigned short num_mappings;
505
506                 switch(tlv_subtype) {
507                 case LLDP_TLV_AA_ELEMENT_SUBTYPE:
508                     aa_element_word = PEEK_UINT16;
509
510                     /* Type is first 4 most-significant bits */
511                     port->p_element.type = aa_element_word >> 12;
512
513                     /* mgmt_vlan is last 12 bits */
514                     port->p_element.mgmt_vlan = aa_element_word & 0x0FFF;
515                     VLOG_INFO("Element type: %X, Mgmt vlan: %X",
516                               port->p_element.type,
517                               port->p_element.mgmt_vlan);
518                     PEEK_BYTES(&port->p_element.system_id.system_mac,
519                                sizeof port->p_element.system_id.system_mac);
520                     VLOG_INFO("System mac: 0x%.2X%.2X%.2X%.2X%.2X%.2X",
521                               port->p_element.system_id.system_mac[0],
522                               port->p_element.system_id.system_mac[1],
523                               port->p_element.system_id.system_mac[2],
524                               port->p_element.system_id.system_mac[3],
525                               port->p_element.system_id.system_mac[4],
526                               port->p_element.system_id.system_mac[5]);
527                     aa_system_id_word = PEEK_UINT16;
528                     port->p_element.system_id.conn_type =
529                         aa_system_id_word >> 12;
530                     port->p_element.system_id.smlt_id =
531                         aa_system_id_word & 0x0FFF;
532                     PEEK_BYTES(&port->p_element.system_id.mlt_id,
533                                sizeof port->p_element.system_id.mlt_id);
534                     break;
535
536                 case LLDP_TLV_AA_ISID_VLAN_ASGNS_SUBTYPE:
537                     PEEK_BYTES(&msg_auth_digest, sizeof msg_auth_digest);
538
539                     /* Subtract off tlv type and length (2Bytes) + OUI (3B) +
540                      * Subtype (1B) + MSG DIGEST (32B).
541                      */
542                     num_mappings = tlv_size - 4 -
543                         LLDP_TLV_AA_ISID_VLAN_DIGEST_LENGTH;
544                     if (num_mappings % 5 != 0) {
545                         VLOG_INFO("malformed vlan-isid mappings tlv received");
546                         goto malformed;
547                     }
548
549                     num_mappings /= 5; /* Each mapping is 5 Bytes */
550                     for(; num_mappings > 0; num_mappings--) {
551                         uint8_t isid[3];
552
553                         isid_vlan_map = xzalloc(sizeof *isid_vlan_map);
554                         aa_status_vlan_word = PEEK_UINT16;
555
556                         /* Status is first 4 most-significant bits. */
557                         isid_vlan_map->isid_vlan_data.status =
558                             aa_status_vlan_word >> 12;
559
560                         /* Vlan is last 12 bits */
561                         isid_vlan_map->isid_vlan_data.vlan =
562                             aa_status_vlan_word & 0x0FFF;
563                         PEEK_BYTES(isid, 3);
564                         isid_vlan_map->isid_vlan_data.isid =
565                             (isid[0] << 16) | (isid[1] << 8) | isid[2];
566                         list_push_back(&port->p_isid_vlan_maps,
567                                        &isid_vlan_map->m_entries);
568                         isid_vlan_map = NULL;
569                     }
570                     break;
571
572                 default:
573                     hardware->h_rx_unrecognized_cnt++;
574                     VLOG_INFO("Unrecogised tlv subtype received");
575                     break;
576                 }
577             } else if (memcmp(dcbx, orgid, sizeof orgid) == 0) {
578                 VLOG_DBG("unsupported DCBX tlv received on %s "
579                          "- ignore", hardware->h_ifname);
580                 hardware->h_rx_unrecognized_cnt++;
581             } else {
582                 VLOG_INFO("unknown org tlv [%02x:%02x:%02x] received "
583                           "on %s", orgid[0], orgid[1], orgid[2],
584                           hardware->h_ifname);
585                 hardware->h_rx_unrecognized_cnt++;
586             }
587             break;
588         default:
589             VLOG_WARN("unknown tlv (%d) received on %s",
590                       tlv_type,
591                       hardware->h_ifname);
592             goto malformed;
593         }
594         if (pos > tlv + tlv_size) {
595             VLOG_WARN("BUG: already past TLV!");
596             goto malformed;
597         }
598         PEEK_DISCARD(tlv + tlv_size - pos);
599     }
600
601     /* Some random check */
602     if (!chassis->c_id || !port->p_id || !ttl_received || !gotend) {
603         VLOG_WARN("some mandatory tlv are missing for frame received "
604                   "on %s", hardware->h_ifname);
605         goto malformed;
606     }
607     *newchassis = chassis;
608     *newport = port;
609     return 1;
610
611 malformed:
612     lldpd_chassis_cleanup(chassis, true);
613     lldpd_port_cleanup(port, true);
614     free(port);
615     return -1;
616 }