493c2ffa936770a3c09f57ae39787aa9ddf87d25
[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 V3.1 to packet. LLDP FA element v3.1 format:
239     TLV Type[127]   TLV Length[50 octets] Avaya OUI[00-04-0D] Subtype[11]
240     7 bits                9 bits                3 octets      1 octet
241     HMAC-SHA Digest  Element Type   State   Mgmt VLAN   Rsvd    System ID
242       32 octets       6 bits        6 bits   12 bits    1 octet 10 octets
243     */
244     /* AA-ELEMENT */
245     if (port->p_element.type != 0) {
246         u_int16_t aa_element_first_word = 0;
247         u_int16_t aa_element_second_word = 0;
248         u_int16_t aa_element_state = 0;
249         u_int8_t aa_elem_sys_id_first_byte;
250         u_int8_t aa_elem_sys_id_second_byte;
251
252         /* Link VLAN Tagging Requirements (bit 1),
253          * Automatic Provisioning Mode (bit 2/3) (left to right, 1 based) */
254         aa_element_state = ((port->p_element.vlan_tagging & 0x1) << 5) |
255             ((port->p_element.auto_prov_mode & 0x3) << 3);
256
257         /* Element first word should be first 6 most significant bits of
258          * element type, bitwise OR that with the next 6 bits of the state,
259          * bitwise OR with the first 4 bits of mgmt vlan id.
260          * Element type should be LLDP_TLV_AA_ELEM_TYPE_VIRTUAL_SWITCH for
261          * AA client */
262         aa_element_first_word = (port->p_element.type << 10) |
263             (aa_element_state << 4) |
264             ((port->p_element.mgmt_vlan & 0x0F00)>> 8);
265
266         /* Element second type should be the first 8 most significant bits
267          * of the remaining 8 bits of mgmt vlan id. */
268         aa_element_second_word = (port->p_element.mgmt_vlan & 0xFF) << 8;
269
270         /* System id first byte should be first 3 most significant bits of
271          * connecion type, bitwise OR that with the device state and bitwise
272          * OR that with the first 2 most significant bitsof rsvd (10 bits). */
273         aa_elem_sys_id_first_byte =
274             ((port->p_element.system_id.conn_type & 0x7) << 5) |
275             ((port->p_element.system_id.rsvd >> 8) & 0x3);
276
277         /* Second byte should just be the remaining 8 bits of 10 bits rsvd */
278         aa_elem_sys_id_second_byte =
279             (port->p_element.system_id.rsvd & 0xFF);
280
281         memset(msg_auth_digest, 0, sizeof msg_auth_digest);
282
283         lldp_tlv_start(p, LLDP_TLV_ORG, &start);
284         dp_packet_put(p, avaya, sizeof avaya);
285         lldp_tlv_put_u8(p, LLDP_TLV_AA_ELEMENT_SUBTYPE);
286         dp_packet_put(p, msg_auth_digest, sizeof msg_auth_digest);
287         lldp_tlv_put_u16(p, aa_element_first_word);
288         lldp_tlv_put_u16(p, aa_element_second_word);
289         dp_packet_put(p, &port->p_element.system_id.system_mac,
290                       sizeof port->p_element.system_id.system_mac);
291         lldp_tlv_put_u8(p, aa_elem_sys_id_first_byte);
292         lldp_tlv_put_u8(p, aa_elem_sys_id_second_byte);
293         dp_packet_put(p, &port->p_element.system_id.rsvd2,
294                       sizeof port->p_element.system_id.rsvd2);
295         lldp_tlv_end(p, start);
296     }
297
298     if (!list_is_empty(&port->p_isid_vlan_maps)) {
299
300         memset(msg_auth_digest, 0, sizeof msg_auth_digest);
301
302         lldp_tlv_start(p, LLDP_TLV_ORG, &start);
303         dp_packet_put(p, avaya, sizeof avaya);
304         lldp_tlv_put_u8(p, LLDP_TLV_AA_ISID_VLAN_ASGNS_SUBTYPE);
305         dp_packet_put(p, msg_auth_digest, sizeof msg_auth_digest);
306
307         LIST_FOR_EACH (vlan_isid_map,
308                        m_entries,
309                        &hardware->h_lport.p_isid_vlan_maps) {
310             u_int16_t status_vlan_word;
311             status_vlan_word =
312                 (vlan_isid_map->isid_vlan_data.status << 12) |
313                 vlan_isid_map->isid_vlan_data.vlan;
314
315             lldp_tlv_put_u16(p, status_vlan_word);
316             lldp_tlv_put_isid(p, vlan_isid_map->isid_vlan_data.isid);
317         }
318
319         lldp_tlv_end(p, start);
320     }
321
322     /* END */
323     lldp_tlv_start(p, LLDP_TLV_END, &start);
324     lldp_tlv_end(p, start);
325
326     hardware->h_tx_cnt++;
327
328     const char *lldp = dp_packet_at_assert(p, orig_size, 0);
329     unsigned int lldp_len = dp_packet_size(p) - orig_size;
330     if (!hardware->h_lport.p_lastframe
331         || hardware->h_lport.p_lastframe->size != lldp_len
332         || memcmp(hardware->h_lport.p_lastframe->frame, lldp, lldp_len)) {
333
334         struct lldpd_frame *frame = xmalloc(sizeof *frame + lldp_len);
335         frame->size = lldp_len;
336         memcpy(frame->frame, lldp, lldp_len);
337         free(hardware->h_lport.p_lastframe);
338         hardware->h_lport.p_lastframe = frame;
339         hardware->h_lport.p_lastchange = time(NULL);
340     }
341
342     return dp_packet_size(p);
343 }
344
345 int
346 lldp_decode(struct lldpd *cfg OVS_UNUSED, char *frame, int s,
347             struct lldpd_hardware *hardware, struct lldpd_chassis **newchassis,
348             struct lldpd_port **newport)
349 {
350     struct lldpd_chassis *chassis;
351     struct lldpd_port *port;
352     const char lldpaddr[] = LLDP_MULTICAST_ADDR;
353     const char dot1[] = LLDP_TLV_ORG_DOT1;
354     const char dot3[] = LLDP_TLV_ORG_DOT3;
355     const char med[] = LLDP_TLV_ORG_MED;
356     const char avaya_oid[] = LLDP_TLV_ORG_AVAYA;
357     const char dcbx[] = LLDP_TLV_ORG_DCBX;
358     char orgid[3];
359     int length, af;
360     bool gotend = false;
361     bool ttl_received = false;
362     int tlv_size, tlv_type, tlv_subtype;
363     u_int8_t *pos, *tlv;
364     void *b;
365     struct lldpd_aa_isid_vlan_maps_tlv *isid_vlan_map = NULL;
366     u_int8_t msg_auth_digest[LLDP_TLV_AA_ISID_VLAN_DIGEST_LENGTH];
367     struct lldpd_mgmt *mgmt;
368     u_int8_t addr_str_length, addr_str_buffer[32];
369     u_int8_t addr_family, addr_length, *addr_ptr, iface_subtype;
370     u_int32_t iface_number, iface;
371
372     VLOG_DBG("receive LLDP PDU on %s", hardware->h_ifname);
373
374     chassis = xzalloc(sizeof *chassis);
375     list_init(&chassis->c_mgmt);
376
377     port = xzalloc(sizeof *port);
378     list_init(&port->p_isid_vlan_maps);
379
380     length = s;
381     pos = (u_int8_t*) frame;
382
383     if (length < 2 * ETH_ADDR_LEN + sizeof(u_int16_t)) {
384         VLOG_WARN("too short frame received on %s", hardware->h_ifname);
385         goto malformed;
386     }
387     if (PEEK_CMP(lldpaddr, ETH_ADDR_LEN) != 0) {
388         VLOG_INFO("frame not targeted at LLDP multicast address "
389                   "received on %s", hardware->h_ifname);
390         goto malformed;
391     }
392
393     PEEK_DISCARD(ETH_ADDR_LEN); /* Skip source address */
394     if (PEEK_UINT16 != ETHERTYPE_LLDP) {
395         VLOG_INFO("non LLDP frame received on %s", hardware->h_ifname);
396         goto malformed;
397     }
398
399     while (length && !gotend) {
400         if (length < 2) {
401             VLOG_WARN("tlv header too short received on %s",
402                       hardware->h_ifname);
403             goto malformed;
404         }
405         tlv_size = PEEK_UINT16;
406         tlv_type = tlv_size >> 9;
407         tlv_size = tlv_size & 0x1ff;
408         (void) PEEK_SAVE(tlv);
409         if (length < tlv_size) {
410             VLOG_WARN("frame too short for tlv received on %s",
411                       hardware->h_ifname);
412             goto malformed;
413         }
414
415         switch (tlv_type) {
416         case LLDP_TLV_END:
417             if (tlv_size != 0) {
418                 VLOG_WARN("lldp end received with size not null on %s",
419                           hardware->h_ifname);
420                 goto malformed;
421             }
422             if (length) {
423                 VLOG_DBG("extra data after lldp end on %s",
424                          hardware->h_ifname);
425             }
426             gotend = true;
427             break;
428
429         case LLDP_TLV_CHASSIS_ID:
430         case LLDP_TLV_PORT_ID:
431             CHECK_TLV_SIZE(2, "Port Id");
432             tlv_subtype = PEEK_UINT8;
433             if (tlv_subtype == 0 || tlv_subtype > 7) {
434                 VLOG_WARN("unknown subtype for tlv id received on %s",
435                           hardware->h_ifname);
436                 goto malformed;
437             }
438             b = xzalloc(tlv_size - 1);
439             PEEK_BYTES(b, tlv_size - 1);
440             if (tlv_type == LLDP_TLV_PORT_ID) {
441                 port->p_id_subtype = tlv_subtype;
442                 port->p_id = b;
443                 port->p_id_len = tlv_size - 1;
444             } else {
445                 chassis->c_id_subtype = tlv_subtype;
446                 chassis->c_id = b;
447                 chassis->c_id_len = tlv_size - 1;
448             }
449             break;
450
451         case LLDP_TLV_TTL:
452             CHECK_TLV_SIZE(2, "TTL");
453             chassis->c_ttl = PEEK_UINT16;
454             ttl_received = true;
455             break;
456
457         case LLDP_TLV_PORT_DESCR:
458         case LLDP_TLV_SYSTEM_NAME:
459         case LLDP_TLV_SYSTEM_DESCR:
460             if (tlv_size < 1) {
461                 VLOG_DBG("empty tlv received on %s", hardware->h_ifname);
462                 break;
463             }
464             b = xzalloc(tlv_size + 1);
465             PEEK_BYTES(b, tlv_size);
466             if (tlv_type == LLDP_TLV_PORT_DESCR) {
467                 port->p_descr = b;
468             } else if (tlv_type == LLDP_TLV_SYSTEM_NAME) {
469                 chassis->c_name = b;
470             } else {
471                 chassis->c_descr = b;
472             }
473             break;
474
475         case LLDP_TLV_SYSTEM_CAP:
476             CHECK_TLV_SIZE(4, "System capabilities");
477             chassis->c_cap_available = PEEK_UINT16;
478             chassis->c_cap_enabled = PEEK_UINT16;
479             break;
480
481         case LLDP_TLV_MGMT_ADDR:
482             CHECK_TLV_SIZE(1, "Management address");
483             addr_str_length = PEEK_UINT8;
484             CHECK_TLV_SIZE(1 + addr_str_length, "Management address");
485             PEEK_BYTES(addr_str_buffer, addr_str_length);
486             addr_length = addr_str_length - 1;
487             addr_family = addr_str_buffer[0];
488             addr_ptr = &addr_str_buffer[1];
489             CHECK_TLV_SIZE(1 + addr_str_length + 5, "Management address");
490             iface_subtype = PEEK_UINT8;
491             iface_number = PEEK_UINT32;
492
493             af = lldpd_af_from_lldp_proto(addr_family);
494             if (af == LLDPD_AF_UNSPEC) {
495                 break;
496             }
497             iface = iface_subtype == LLDP_MGMT_IFACE_IFINDEX ?
498                 iface_number : 0;
499             mgmt = lldpd_alloc_mgmt(af, addr_ptr, addr_length, iface);
500             if (mgmt == NULL) {
501                 VLOG_WARN("unable to allocate memory for management address");
502                 goto malformed;
503             }
504             list_push_back(&chassis->c_mgmt, &mgmt->m_entries);
505             break;
506
507         case LLDP_TLV_ORG:
508             CHECK_TLV_SIZE(4, "Organisational");
509             PEEK_BYTES(orgid, sizeof orgid);
510             tlv_subtype = PEEK_UINT8;
511             if (memcmp(dot1, orgid, sizeof orgid) == 0) {
512                 hardware->h_rx_unrecognized_cnt++;
513             } else if (memcmp(dot3, orgid, sizeof orgid) == 0) {
514                 hardware->h_rx_unrecognized_cnt++;
515             } else if (memcmp(med, orgid, sizeof orgid) == 0) {
516                 /* LLDP-MED */
517                 hardware->h_rx_unrecognized_cnt++;
518             } else if (memcmp(avaya_oid, orgid, sizeof orgid) == 0) {
519                 u_int32_t aa_element_dword;
520                 u_int16_t aa_system_id_word;
521                 u_int16_t aa_status_vlan_word;
522                 u_int8_t aa_element_state;
523                 unsigned short num_mappings;
524
525                 switch(tlv_subtype) {
526                 case LLDP_TLV_AA_ELEMENT_SUBTYPE:
527                     PEEK_BYTES(&msg_auth_digest, sizeof msg_auth_digest);
528
529                     aa_element_dword = PEEK_UINT32;
530
531                     /* Type is first 6 most-significant bits of
532                      * aa_element_dword */
533                     port->p_element.type = aa_element_dword >> 26;
534
535                     /* State is 6 most significant bits of aa_element_dword */
536                     aa_element_state = (aa_element_dword >> 20) & 0x3F;
537
538                     /* vlan tagging requirement is the bit 1(left to right)
539                      * of the 6 bits state (1 based) */
540                     port->p_element.vlan_tagging =
541                         (aa_element_state >> 5) & 0x1;
542
543                     /* Automatic provision mode is the bit 2/3(left to right)
544                      * of the 6 bits state (1 based) */
545                     port->p_element.auto_prov_mode =
546                         (aa_element_state >> 3) & 0x3;
547
548                     /* mgmt_vlan is the 12 bits of aa_element_dword from
549                      * bit 12 */
550                     port->p_element.mgmt_vlan =
551                         (aa_element_dword >> 8) & 0xFFF;
552                     VLOG_INFO("Element type: %X, vlan tagging %X, "
553                               "auto prov mode %x, Mgmt vlan: %X",
554                               port->p_element.type,
555                               port->p_element.vlan_tagging,
556                               port->p_element.auto_prov_mode,
557                               port->p_element.mgmt_vlan);
558
559                     PEEK_BYTES(&port->p_element.system_id.system_mac,
560                                sizeof port->p_element.system_id.system_mac);
561                     VLOG_INFO("System mac: "ETH_ADDR_FMT,
562                         ETH_ADDR_ARGS(port->p_element.system_id.system_mac));
563                     aa_system_id_word = PEEK_UINT16;
564                     port->p_element.system_id.conn_type =
565                         aa_system_id_word >> 13;
566                     port->p_element.system_id.rsvd = aa_system_id_word &
567                         0x03FF;
568                     PEEK_BYTES(&port->p_element.system_id.rsvd2,
569                                sizeof port->p_element.system_id.rsvd2);
570                     break;
571
572                 case LLDP_TLV_AA_ISID_VLAN_ASGNS_SUBTYPE:
573                     PEEK_BYTES(&msg_auth_digest, sizeof msg_auth_digest);
574
575                     /* Subtract off tlv type and length (2Bytes) + OUI (3B) +
576                      * Subtype (1B) + MSG DIGEST (32B).
577                      */
578                     num_mappings = tlv_size - 4 -
579                         LLDP_TLV_AA_ISID_VLAN_DIGEST_LENGTH;
580                     if (num_mappings % 5 != 0) {
581                         VLOG_INFO("malformed vlan-isid mappings tlv received");
582                         goto malformed;
583                     }
584
585                     num_mappings /= 5; /* Each mapping is 5 Bytes */
586                     for(; num_mappings > 0; num_mappings--) {
587                         uint8_t isid[3];
588
589                         isid_vlan_map = xzalloc(sizeof *isid_vlan_map);
590                         aa_status_vlan_word = PEEK_UINT16;
591
592                         /* Status is first 4 most-significant bits. */
593                         isid_vlan_map->isid_vlan_data.status =
594                             aa_status_vlan_word >> 12;
595
596                         /* Vlan is last 12 bits */
597                         isid_vlan_map->isid_vlan_data.vlan =
598                             aa_status_vlan_word & 0x0FFF;
599                         PEEK_BYTES(isid, 3);
600                         isid_vlan_map->isid_vlan_data.isid =
601                             (isid[0] << 16) | (isid[1] << 8) | isid[2];
602                         list_push_back(&port->p_isid_vlan_maps,
603                                        &isid_vlan_map->m_entries);
604                         isid_vlan_map = NULL;
605                     }
606                     break;
607
608                 default:
609                     hardware->h_rx_unrecognized_cnt++;
610                     VLOG_INFO("Unrecogised tlv subtype received");
611                     break;
612                 }
613             } else if (memcmp(dcbx, orgid, sizeof orgid) == 0) {
614                 VLOG_DBG("unsupported DCBX tlv received on %s "
615                          "- ignore", hardware->h_ifname);
616                 hardware->h_rx_unrecognized_cnt++;
617             } else {
618                 VLOG_INFO("unknown org tlv [%02x:%02x:%02x] received "
619                           "on %s", orgid[0], orgid[1], orgid[2],
620                           hardware->h_ifname);
621                 hardware->h_rx_unrecognized_cnt++;
622             }
623             break;
624         default:
625             VLOG_WARN("unknown tlv (%d) received on %s",
626                       tlv_type,
627                       hardware->h_ifname);
628             goto malformed;
629         }
630         if (pos > tlv + tlv_size) {
631             VLOG_WARN("BUG: already past TLV!");
632             goto malformed;
633         }
634         PEEK_DISCARD(tlv + tlv_size - pos);
635     }
636
637     /* Some random check */
638     if (!chassis->c_id || !port->p_id || !ttl_received || !gotend) {
639         VLOG_WARN("some mandatory tlv are missing for frame received "
640                   "on %s", hardware->h_ifname);
641         goto malformed;
642     }
643     *newchassis = chassis;
644     *newport = port;
645     return 1;
646
647 malformed:
648     lldpd_chassis_cleanup(chassis, true);
649     lldpd_port_cleanup(port, true);
650     free(port);
651     return -1;
652 }