auto-attach: Add auto-attach support to ofproto layer
[cascardo/ovs.git] / lib / lldp / lldp.c
1 /* -*- mode: c; c-file-style: "openbsd" -*- */
2 /*
3  * Copyright (c) 2008 Vincent Bernat <bernat@luffy.cx>
4  * Copyright (c) 2014 Michael Chapman
5  *
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.
9  *
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.
17  */
18
19 #include <config.h>
20 #include "lldpd.h"
21 #include <errno.h>
22 #include <time.h>
23 #include <unistd.h>
24 #include <sys/ioctl.h>
25 #include <sys/socket.h>
26 #include <sys/types.h>
27 #include "compiler.h"
28 #include "dp-packet.h"
29 #include "packets.h"
30
31 VLOG_DEFINE_THIS_MODULE(lldp);
32
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'.
36  *
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
39  * the ISC license.
40  */
41
42 #define POKE(value, type, func)               \
43     ((length >= sizeof type) &&              \
44         (                                     \
45             type = func(value),               \
46             memcpy(pos, &type, sizeof type), \
47             length -= sizeof type,           \
48             pos += sizeof type,              \
49             1                                 \
50         )                                     \
51     )
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)) &&            \
57         (                              \
58             memcpy(pos, value, bytes), \
59             length -= (bytes),         \
60             pos += (bytes),            \
61             1                          \
62         )                              \
63     )
64 #define POKE_SAVE(where) (where = pos, 1)
65 #define POKE_RESTORE(where)            \
66     do {                               \
67         if ((where) > pos)             \
68             length -= ((where) - pos); \
69         else                           \
70             length += (pos - (where)); \
71         pos = (where);                 \
72     } while(0)
73
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.
76  */
77
78 #define PEEK(type, func)                  \
79     (                                     \
80         memcpy(&type, pos, sizeof type), \
81         length -= sizeof type,           \
82         pos += sizeof type,              \
83         func(type)                        \
84     )
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)   \
89     do {                           \
90         memcpy(value, pos, bytes); \
91         length -= (bytes);         \
92         pos += (bytes);            \
93     } while (0)
94 #define PEEK_DISCARD(bytes) \
95     do {                    \
96         length -= (bytes);  \
97         pos += (bytes);     \
98     } while (0)
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),       \
104      pos += (bytes),           \
105      memcmp(pos-bytes, value, bytes))
106 #define PEEK_SAVE POKE_SAVE
107 #define PEEK_RESTORE POKE_RESTORE
108
109 /* LLDP specific. We need a `tlv' pointer. */
110 #define POKE_START_LLDP_TLV(type) \
111     (                             \
112         tlv = pos,                \
113         POKE_UINT16(type << 9)    \
114     )
115 #define POKE_END_LLDP_TLV                                    \
116     (                                                        \
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)),      \
120         1                                                    \
121     )
122
123 #define CHECK_TLV_SIZE(x, name)                             \
124     do {                                                    \
125         if (tlv_size < (x)) {                               \
126             VLOG_WARN(name " TLV too short received on %s", \
127                       hardware->h_ifname);                  \
128             goto malformed;                                 \
129         }                                                   \
130     } while (0)
131
132 static union {
133     uint8_t  f_uint8;
134     ovs_be16 f_uint16;
135     ovs_be32 f_uint32;
136 } types;
137
138 static int
139 lldpd_af_to_lldp_proto(int af)
140 {
141     switch (af) {
142     case LLDPD_AF_IPV4:
143         return LLDP_MGMT_ADDR_IP4;
144     case LLDPD_AF_IPV6:
145         return LLDP_MGMT_ADDR_IP6;
146     default:
147         return LLDP_MGMT_ADDR_NONE;
148     }
149 }
150
151 static int
152 lldpd_af_from_lldp_proto(int proto)
153 {
154     switch (proto) {
155     case LLDP_MGMT_ADDR_IP4:
156         return LLDPD_AF_IPV4;
157     case LLDP_MGMT_ADDR_IP6:
158         return LLDPD_AF_IPV6;
159     default:
160         return LLDPD_AF_UNSPEC;
161     }
162 }
163
164 int
165 lldp_send(struct lldpd *global OVS_UNUSED,
166           struct lldpd_hardware *hardware,
167           struct dp_packet *p)
168 {
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;
174     int length, proto;
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];
178
179     port = &hardware->h_lport;
180     chassis = port->p_chassis;
181
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);
187     pos = packet;
188
189     /*
190      * Make room in dp_packet for chassis ID, Port ID, System Name, System
191      * Descr, System Cap
192      */
193     pos = dp_packet_put_uninit(p, sizeof chassis->c_id_subtype +
194                                chassis->c_id_len +
195                                sizeof port->p_id_subtype +
196                                port->p_id_len +
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);
202
203     /* Chassis ID */
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)) {
208         goto toobig;
209     }
210
211     /* Port ID */
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)) {
216         goto toobig;
217     }
218
219     /* Time to live */
220     if (!(POKE_START_LLDP_TLV(LLDP_TLV_TTL) &&
221           POKE_UINT16(chassis->c_ttl) &&
222           POKE_END_LLDP_TLV)) {
223         goto toobig;
224     }
225
226     /* System name */
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)) {
231             goto toobig;
232         }
233     }
234
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)) {
240             goto toobig;
241         }
242     }
243
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)) {
249         goto toobig;
250     }
251
252     LIST_FOR_EACH (mgmt, m_entries, &chassis->c_mgmt.m_entries) {
253        /*
254         * Make room for 1 mgmt interface
255         */
256         dp_packet_put_uninit(p, 2 + sizeof(uint8_t) +
257                              sizeof(uint8_t) +
258                              mgmt->m_addrsize +
259                              sizeof(uint8_t) +
260                              sizeof(uint32_t) +
261                              sizeof(uint8_t));
262
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) &&
267               POKE_UINT8(proto) &&
268               POKE_BYTES(&mgmt->m_addr, mgmt->m_addrsize))) {
269             goto toobig;
270         }
271
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) &&
276                   POKE_UINT32(0))) {
277                 goto toobig;
278             }
279         } else {
280             if (!(/* We have the index of the management interface */
281                   POKE_UINT8(LLDP_MGMT_IFACE_IFINDEX) &&
282                   POKE_UINT32(mgmt->m_iface))) {
283                 goto toobig;
284             }
285         }
286         if (!(/* We don't provide an OID for management */
287               POKE_UINT8(0) &&
288               POKE_END_LLDP_TLV)) {
289             goto toobig;
290         }
291     }
292
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));
297
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)) {
301             goto toobig;
302         }
303     }
304
305     /* Add Auto Attach tlvs to packet */
306     /* AA-ELEMENT */
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;
312
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
315          */
316         aa_element_first_byte = ((port->p_element.type & 0xF) << 4) |
317             ((port->p_element.mgmt_vlan >> 8) & 0xF);
318
319         /* Second byte should just be the remaining 8 bits of .mgmt_vlan */
320         aa_element_second_byte = port->p_element.mgmt_vlan & 0x0FF;
321
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
324          */
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);
328
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;
331
332         /* make room for element type tlv */
333         dp_packet_put_uninit(p, 2 + sizeof avaya +
334                              sizeof(uint8_t) +
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);
341
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)) {
354             goto toobig;
355         }
356     }
357
358     if (!list_is_empty(&port->p_isid_vlan_maps.m_entries)) {
359         int j;
360
361        /*
362         * make room for aa_isid_digest
363         */
364         dp_packet_put_uninit(p, 2 + sizeof avaya +
365                              sizeof(uint8_t) +
366                              sizeof msg_auth_digest);
367
368         for (j = 0; j < LLDP_TLV_AA_ISID_VLAN_DIGEST_LENGTH; j++) {
369             msg_auth_digest[j] = 0;
370         }
371
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))) {
376             goto toobig;
377         }
378
379         LIST_FOR_EACH (vlan_isid_map,
380                        m_entries,
381                        &hardware->h_lport.p_isid_vlan_maps.m_entries) {
382             u_int16_t status_vlan_word;
383             status_vlan_word =
384                 (vlan_isid_map->isid_vlan_data.status << 12) |
385                 vlan_isid_map->isid_vlan_data.vlan;
386
387             /*
388              * Make room for one isid-vlan mapping
389              */
390             dp_packet_put_uninit(p, sizeof status_vlan_word +
391                                  sizeof vlan_isid_map->isid_vlan_data.isid);
392
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))) {
396                 goto toobig;
397             }
398         }
399
400         if (!(POKE_END_LLDP_TLV)) {
401            goto toobig;
402         }
403     }
404
405     /* Make room for the End TLV 0x0000 */
406     dp_packet_put_uninit(p, sizeof(uint16_t));
407
408     /* END */
409     if (!(POKE_START_LLDP_TLV(LLDP_TLV_END) &&
410           POKE_END_LLDP_TLV)) {
411         goto toobig;
412     }
413
414     hardware->h_tx_cnt++;
415
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);
421
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);
429         } else {
430             free(frame);
431         }
432     }
433
434     return length;
435
436 toobig:
437     free(packet);
438
439     return E2BIG;
440 }
441
442 int
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)
446 {
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;
455     char orgid[3];
456     int length, gotend = 0, ttl_received = 0, af;
457     int tlv_size, tlv_type, tlv_subtype;
458     u_int8_t *pos, *tlv;
459     char *b;
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;
466
467     VLOG_DBG("receive LLDP PDU on %s", hardware->h_ifname);
468
469     if ((chassis = calloc(1, sizeof *chassis)) == NULL) {
470         VLOG_WARN("failed to allocate remote chassis");
471         return -1;
472     }
473     list_init(&chassis->c_mgmt.m_entries);
474
475     if ((port = calloc(1, sizeof *port)) == NULL) {
476         VLOG_WARN("failed to allocate remote port");
477         free(chassis);
478         return -1;
479     }
480     list_init(&port->p_isid_vlan_maps.m_entries);
481
482     length = s;
483     pos = (u_int8_t*) frame;
484
485     if (length < 2 * ETH_ADDR_LEN + sizeof(u_int16_t)) {
486         VLOG_WARN("too short frame received on %s", hardware->h_ifname);
487         goto malformed;
488     }
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);
492         goto malformed;
493     }
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);
497         goto malformed;
498     }
499
500     while (length && (!gotend)) {
501         if (length < 2) {
502             VLOG_WARN("tlv header too short received on %s",
503                       hardware->h_ifname);
504             goto malformed;
505         }
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",
512                       hardware->h_ifname);
513             goto malformed;
514         }
515
516         switch (tlv_type) {
517         case LLDP_TLV_END:
518             if (tlv_size != 0) {
519                 VLOG_WARN("lldp end received with size not null on %s",
520                           hardware->h_ifname);
521                 goto malformed;
522             }
523             if (length) {
524                 VLOG_DBG("extra data after lldp end on %s",
525                          hardware->h_ifname);
526             }
527             gotend = 1;
528             break;
529
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",
536                           hardware->h_ifname);
537                 goto malformed;
538             }
539             if ((b = (char *) calloc(1, tlv_size - 1)) == NULL) {
540                 VLOG_WARN("unable to allocate memory for id tlv received "
541                           "on %s",
542                           hardware->h_ifname);
543                 goto malformed;
544             }
545             PEEK_BYTES(b, tlv_size - 1);
546             if (tlv_type == LLDP_TLV_PORT_ID) {
547                 port->p_id_subtype = tlv_subtype;
548                 port->p_id = b;
549                 port->p_id_len = tlv_size - 1;
550             } else {
551                 chassis->c_id_subtype = tlv_subtype;
552                 chassis->c_id = b;
553                 chassis->c_id_len = tlv_size - 1;
554             }
555             break;
556
557         case LLDP_TLV_TTL:
558             CHECK_TLV_SIZE(2, "TTL");
559             chassis->c_ttl = PEEK_UINT16;
560             ttl_received = 1;
561             break;
562
563         case LLDP_TLV_PORT_DESCR:
564         case LLDP_TLV_SYSTEM_NAME:
565         case LLDP_TLV_SYSTEM_DESCR:
566             if (tlv_size < 1) {
567                 VLOG_DBG("empty tlv received on %s", hardware->h_ifname);
568                 break;
569             }
570             if ((b = (char *) calloc(1, tlv_size + 1)) == NULL) {
571                 VLOG_WARN("unable to allocate memory for string tlv "
572                           "received on %s",
573                           hardware->h_ifname);
574                 goto malformed;
575             }
576             PEEK_BYTES(b, tlv_size);
577             if (tlv_type == LLDP_TLV_PORT_DESCR) {
578                 port->p_descr = b;
579             } else if (tlv_type == LLDP_TLV_SYSTEM_NAME) {
580                 chassis->c_name = b;
581             } else {
582                 chassis->c_descr = b;
583             }
584             break;
585
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;
590             break;
591
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;
603
604             af = lldpd_af_from_lldp_proto(addr_family);
605             if (af == LLDPD_AF_UNSPEC) {
606                 break;
607             }
608             iface = iface_subtype == LLDP_MGMT_IFACE_IFINDEX ?
609                 iface_number : 0;
610             mgmt = lldpd_alloc_mgmt(af, addr_ptr, addr_length, iface);
611             if (mgmt == NULL) {
612                 VLOG_WARN("unable to allocate memory for management address");
613                 goto malformed;
614             }
615             list_push_back(&chassis->c_mgmt.m_entries, &mgmt->m_entries);
616             break;
617
618         case LLDP_TLV_ORG:
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) {
627                 /* LLDP-MED */
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;
634
635                 switch(tlv_subtype) {
636                 case LLDP_TLV_AA_ELEMENT_SUBTYPE:
637                     aa_element_word = PEEK_UINT16;
638
639                     /* Type is first 4 most-significant bits */
640                     port->p_element.type = aa_element_word >> 12;
641
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);
663                     break;
664
665                 case LLDP_TLV_AA_ISID_VLAN_ASGNS_SUBTYPE:
666                     PEEK_BYTES(&msg_auth_digest, sizeof msg_auth_digest);
667
668                     /* Subtract off tlv type and length (2Bytes) + OUI (3B) +
669                      * Subtype (1B) + MSG DIGEST (32B).
670                      */
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");
675                         goto malformed;
676                     }
677
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");
685                             goto malformed;
686                         }
687                         aa_status_vlan_word = PEEK_UINT16;
688
689                         /* Status is first 4 most-significant bits. */
690                         isid_vlan_map->isid_vlan_data.status =
691                             aa_status_vlan_word >> 12;
692
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);
698                         list_push_back(
699                             (struct ovs_list *) &port->p_isid_vlan_maps,
700                             (struct ovs_list *) isid_vlan_map);
701                         isid_vlan_map = NULL;
702                     }
703                     break;
704
705                 default:
706                     hardware->h_rx_unrecognized_cnt++;
707                     VLOG_INFO("Unrecogised tlv subtype received");
708                     break;
709                 }
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++;
714             } else {
715                 VLOG_INFO("unknown org tlv [%02x:%02x:%02x] received "
716                           "on %s", orgid[0], orgid[1], orgid[2],
717                           hardware->h_ifname);
718                 hardware->h_rx_unrecognized_cnt++;
719             }
720             break;
721         default:
722             VLOG_WARN("unknown tlv (%d) received on %s",
723                       tlv_type,
724                       hardware->h_ifname);
725             goto malformed;
726         }
727         if (pos > tlv + tlv_size) {
728             VLOG_WARN("BUG: already past TLV!");
729             goto malformed;
730         }
731         PEEK_DISCARD(tlv + tlv_size - pos);
732     }
733
734     /* Some random check */
735     if ((chassis->c_id == NULL) ||
736         (port->p_id == NULL) ||
737         (!ttl_received) ||
738         (gotend == 0)) {
739         VLOG_WARN("some mandatory tlv are missing for frame received "
740                   "on %s", hardware->h_ifname);
741         goto malformed;
742     }
743     *newchassis = chassis;
744     *newport = port;
745     return 1;
746
747 malformed:
748     lldpd_chassis_cleanup(chassis, 1);
749     lldpd_port_cleanup(port, 1);
750     free(port);
751     return -1;
752 }