Branch data Line data Source code
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 : 2462 : 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 : 0 : lldpd_af_to_lldp_proto(int af)
85 : : {
86 [ # # # ]: 0 : switch (af) {
87 : : case LLDPD_AF_IPV4:
88 : 0 : return LLDP_MGMT_ADDR_IP4;
89 : : case LLDPD_AF_IPV6:
90 : 0 : return LLDP_MGMT_ADDR_IP6;
91 : : default:
92 : 0 : return LLDP_MGMT_ADDR_NONE;
93 : : }
94 : : }
95 : :
96 : : static int
97 : 0 : lldpd_af_from_lldp_proto(int proto)
98 : : {
99 [ # # # ]: 0 : switch (proto) {
100 : : case LLDP_MGMT_ADDR_IP4:
101 : 0 : return LLDPD_AF_IPV4;
102 : : case LLDP_MGMT_ADDR_IP6:
103 : 0 : return LLDPD_AF_IPV6;
104 : : default:
105 : 0 : return LLDPD_AF_UNSPEC;
106 : : }
107 : : }
108 : :
109 : : static void
110 : 6 : lldp_tlv_put_u8(struct dp_packet *p, uint8_t x)
111 : : {
112 : 6 : dp_packet_put(p, &x, sizeof x);
113 : 6 : }
114 : :
115 : : static void
116 : 17 : lldp_tlv_put_u16(struct dp_packet *p, uint16_t x)
117 : : {
118 : 17 : ovs_be16 nx = htons(x);
119 : 17 : dp_packet_put(p, &nx, sizeof nx);
120 : 17 : }
121 : :
122 : : static void
123 : 0 : lldp_tlv_put_u32(struct dp_packet *p, uint32_t x)
124 : : {
125 : 0 : ovs_be32 nx = htonl(x);
126 : 0 : dp_packet_put(p, &nx, sizeof nx);
127 : 0 : }
128 : :
129 : : static void
130 : 2 : lldp_tlv_put_isid(struct dp_packet *p, uint32_t isid)
131 : : {
132 : 2 : uint8_t *data = dp_packet_put_uninit(p, 3);
133 : 2 : data[0] = isid >> 16;
134 : 2 : data[1] = isid >> 8;
135 : 2 : data[2] = isid;
136 : 2 : }
137 : :
138 : : static void
139 : 10 : lldp_tlv_start(struct dp_packet *p, uint8_t tlv, unsigned int *start)
140 : : {
141 : 10 : *start = dp_packet_size(p);
142 : 10 : lldp_tlv_put_u16(p, tlv << 9);
143 : 10 : }
144 : :
145 : : static void
146 : 10 : lldp_tlv_end(struct dp_packet *p, unsigned int start)
147 : : {
148 : 10 : ovs_be16 *tlv = dp_packet_at_assert(p, start, 2);
149 : 10 : *tlv |= htons((dp_packet_size(p) - (start + 2)) & 0x1ff);
150 : 10 : }
151 : :
152 : : int
153 : 1 : lldp_send(struct lldpd *global OVS_UNUSED,
154 : : struct lldpd_hardware *hardware,
155 : : struct dp_packet *p)
156 : : {
157 : 1 : 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 : 1 : 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 : 1 : port = &hardware->h_lport;
168 : 1 : chassis = port->p_chassis;
169 : :
170 : : /* The ethernet header is filled in elsewhere, we must save room for it. */
171 [ - + ]: 1 : VLOG_DBG("LLDP PDU send to %s mtu %d incoming",
172 : : hardware->h_ifname, hardware->h_mtu);
173 : :
174 : : /* Chassis ID */
175 : 1 : lldp_tlv_start(p, LLDP_TLV_CHASSIS_ID, &start);
176 : 1 : lldp_tlv_put_u8(p, chassis->c_id_subtype);
177 : 1 : dp_packet_put(p, chassis->c_id, chassis->c_id_len);
178 : 1 : lldp_tlv_end(p, start);
179 : :
180 : : /* Port ID */
181 : 1 : lldp_tlv_start(p, LLDP_TLV_PORT_ID, &start);
182 : 1 : lldp_tlv_put_u8(p, port->p_id_subtype);
183 : 1 : dp_packet_put(p, port->p_id, port->p_id_len);
184 : 1 : lldp_tlv_end(p, start);
185 : :
186 : : /* Time to live */
187 : 1 : lldp_tlv_start(p, LLDP_TLV_TTL, &start);
188 : 1 : lldp_tlv_put_u16(p, chassis->c_ttl);
189 : 1 : lldp_tlv_end(p, start);
190 : :
191 : : /* System name */
192 [ + - ][ + - ]: 1 : if (chassis->c_name && *chassis->c_name != '\0') {
193 : 1 : lldp_tlv_start(p, LLDP_TLV_SYSTEM_NAME, &start);
194 : 1 : dp_packet_put(p, chassis->c_name, strlen(chassis->c_name));
195 : 1 : lldp_tlv_end(p, start);
196 : : }
197 : :
198 : : /* System description (skip it if empty) */
199 [ + - ][ + - ]: 1 : if (chassis->c_descr && *chassis->c_descr != '\0') {
200 : 1 : lldp_tlv_start(p, LLDP_TLV_SYSTEM_DESCR, &start);
201 : 1 : dp_packet_put(p, chassis->c_descr, strlen(chassis->c_descr));
202 : 1 : lldp_tlv_end(p, start);
203 : : }
204 : :
205 : : /* System capabilities */
206 : 1 : lldp_tlv_start(p, LLDP_TLV_SYSTEM_CAP, &start);
207 : 1 : lldp_tlv_put_u16(p, chassis->c_cap_available);
208 : 1 : lldp_tlv_put_u16(p, chassis->c_cap_enabled);
209 : 1 : lldp_tlv_end(p, start);
210 : :
211 [ - + ]: 1 : LIST_FOR_EACH (mgmt, m_entries, &chassis->c_mgmt) {
212 : 0 : lldp_tlv_start(p, LLDP_TLV_MGMT_ADDR, &start);
213 : 0 : lldp_tlv_put_u8(p, mgmt->m_addrsize + 1);
214 : 0 : lldp_tlv_put_u8(p, lldpd_af_to_lldp_proto(mgmt->m_family));
215 : 0 : dp_packet_put(p, &mgmt->m_addr, mgmt->m_addrsize);
216 : :
217 : : /* Interface port type, OID */
218 [ # # ]: 0 : if (mgmt->m_iface == 0) {
219 : : /* We don't know the management interface */
220 : 0 : lldp_tlv_put_u8(p, LLDP_MGMT_IFACE_UNKNOWN);
221 : 0 : lldp_tlv_put_u32(p, 0);
222 : : } else {
223 : : /* We have the index of the management interface */
224 : 0 : lldp_tlv_put_u8(p, LLDP_MGMT_IFACE_IFINDEX);
225 : 0 : lldp_tlv_put_u32(p, mgmt->m_iface);
226 : : }
227 : 0 : lldp_tlv_put_u8(p, 0);
228 : 0 : lldp_tlv_end(p, start);
229 : : }
230 : :
231 : : /* Port description */
232 [ + - ][ + - ]: 1 : if (port->p_descr && *port->p_descr != '\0') {
233 : 1 : lldp_tlv_start(p, LLDP_TLV_PORT_DESCR, &start);
234 : 1 : dp_packet_put(p, port->p_descr, strlen(port->p_descr));
235 : 1 : 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 [ + - ]: 1 : if (port->p_element.type != 0) {
246 : 1 : u_int16_t aa_element_first_word = 0;
247 : 1 : u_int16_t aa_element_second_word = 0;
248 : 1 : 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 : 2 : aa_element_state = ((port->p_element.vlan_tagging & 0x1) << 5) |
255 : 1 : ((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 : 3 : aa_element_first_word = (port->p_element.type << 10) |
263 : 1 : (aa_element_state << 4) |
264 : 1 : ((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 : 1 : 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 : 2 : aa_elem_sys_id_first_byte =
274 : 1 : ((port->p_element.system_id.conn_type & 0x7) << 5) |
275 : 1 : ((port->p_element.system_id.rsvd >> 8) & 0x3);
276 : :
277 : : /* Second byte should just be the remaining 8 bits of 10 bits rsvd */
278 : 1 : aa_elem_sys_id_second_byte =
279 : 1 : (port->p_element.system_id.rsvd & 0xFF);
280 : :
281 : 1 : memset(msg_auth_digest, 0, sizeof msg_auth_digest);
282 : :
283 : 1 : lldp_tlv_start(p, LLDP_TLV_ORG, &start);
284 : 1 : dp_packet_put(p, avaya, sizeof avaya);
285 : 1 : lldp_tlv_put_u8(p, LLDP_TLV_AA_ELEMENT_SUBTYPE);
286 : 1 : dp_packet_put(p, msg_auth_digest, sizeof msg_auth_digest);
287 : 1 : lldp_tlv_put_u16(p, aa_element_first_word);
288 : 1 : lldp_tlv_put_u16(p, aa_element_second_word);
289 : 1 : dp_packet_put(p, &port->p_element.system_id.system_mac,
290 : : sizeof port->p_element.system_id.system_mac);
291 : 1 : lldp_tlv_put_u8(p, aa_elem_sys_id_first_byte);
292 : 1 : lldp_tlv_put_u8(p, aa_elem_sys_id_second_byte);
293 : 1 : dp_packet_put(p, &port->p_element.system_id.rsvd2,
294 : : sizeof port->p_element.system_id.rsvd2);
295 : 1 : lldp_tlv_end(p, start);
296 : : }
297 : :
298 [ + - ]: 1 : if (!ovs_list_is_empty(&port->p_isid_vlan_maps)) {
299 : :
300 : 1 : memset(msg_auth_digest, 0, sizeof msg_auth_digest);
301 : :
302 : 1 : lldp_tlv_start(p, LLDP_TLV_ORG, &start);
303 : 1 : dp_packet_put(p, avaya, sizeof avaya);
304 : 1 : lldp_tlv_put_u8(p, LLDP_TLV_AA_ISID_VLAN_ASGNS_SUBTYPE);
305 : 1 : dp_packet_put(p, msg_auth_digest, sizeof msg_auth_digest);
306 : :
307 [ + + ]: 3 : 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 : 4 : status_vlan_word =
312 : 2 : (vlan_isid_map->isid_vlan_data.status << 12) |
313 : 2 : vlan_isid_map->isid_vlan_data.vlan;
314 : :
315 : 2 : lldp_tlv_put_u16(p, status_vlan_word);
316 : 2 : lldp_tlv_put_isid(p, vlan_isid_map->isid_vlan_data.isid);
317 : : }
318 : :
319 : 1 : lldp_tlv_end(p, start);
320 : : }
321 : :
322 : : /* END */
323 : 1 : lldp_tlv_start(p, LLDP_TLV_END, &start);
324 : 1 : lldp_tlv_end(p, start);
325 : :
326 : 1 : hardware->h_tx_cnt++;
327 : :
328 : 1 : const char *lldp = dp_packet_at_assert(p, orig_size, 0);
329 : 1 : unsigned int lldp_len = dp_packet_size(p) - orig_size;
330 [ - + ]: 1 : if (!hardware->h_lport.p_lastframe
331 [ # # ]: 0 : || hardware->h_lport.p_lastframe->size != lldp_len
332 [ # # ]: 0 : || memcmp(hardware->h_lport.p_lastframe->frame, lldp, lldp_len)) {
333 : :
334 : 1 : struct lldpd_frame *frame = xmalloc(sizeof *frame + lldp_len);
335 : 1 : frame->size = lldp_len;
336 : 1 : memcpy(frame->frame, lldp, lldp_len);
337 : 1 : free(hardware->h_lport.p_lastframe);
338 : 1 : hardware->h_lport.p_lastframe = frame;
339 : 1 : hardware->h_lport.p_lastchange = time(NULL);
340 : : }
341 : :
342 : 1 : return dp_packet_size(p);
343 : : }
344 : :
345 : : int
346 : 1 : 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 : 1 : const struct eth_addr lldpaddr = LLDP_MULTICAST_ADDR;
353 : 1 : const char dot1[] = LLDP_TLV_ORG_DOT1;
354 : 1 : const char dot3[] = LLDP_TLV_ORG_DOT3;
355 : 1 : const char med[] = LLDP_TLV_ORG_MED;
356 : 1 : const char avaya_oid[] = LLDP_TLV_ORG_AVAYA;
357 : 1 : const char dcbx[] = LLDP_TLV_ORG_DCBX;
358 : : char orgid[3];
359 : : int length, af;
360 : 1 : bool gotend = false;
361 : 1 : bool ttl_received = false;
362 : : int tlv_size, tlv_type, tlv_subtype;
363 : : u_int8_t *pos, *tlv;
364 : : void *b;
365 : 1 : 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 [ - + ]: 1 : VLOG_DBG("receive LLDP PDU on %s", hardware->h_ifname);
373 : :
374 : 1 : chassis = xzalloc(sizeof *chassis);
375 : 1 : ovs_list_init(&chassis->c_mgmt);
376 : :
377 : 1 : port = xzalloc(sizeof *port);
378 : 1 : ovs_list_init(&port->p_isid_vlan_maps);
379 : :
380 : 1 : length = s;
381 : 1 : pos = (u_int8_t*) frame;
382 : :
383 [ - + ]: 1 : if (length < 2 * ETH_ADDR_LEN + sizeof(u_int16_t)) {
384 [ # # ]: 0 : VLOG_WARN("too short frame received on %s", hardware->h_ifname);
385 : 0 : goto malformed;
386 : : }
387 [ - + ]: 1 : if (PEEK_CMP(&lldpaddr, ETH_ADDR_LEN) != 0) {
388 [ # # ]: 0 : VLOG_INFO("frame not targeted at LLDP multicast address "
389 : : "received on %s", hardware->h_ifname);
390 : 0 : goto malformed;
391 : : }
392 : :
393 : 1 : PEEK_DISCARD(ETH_ADDR_LEN); /* Skip source address */
394 [ - + ]: 1 : if (PEEK_UINT16 != ETHERTYPE_LLDP) {
395 [ # # ]: 0 : VLOG_INFO("non LLDP frame received on %s", hardware->h_ifname);
396 : 0 : goto malformed;
397 : : }
398 : :
399 [ + + ][ + - ]: 11 : while (length && !gotend) {
400 [ - + ]: 10 : if (length < 2) {
401 [ # # ]: 0 : VLOG_WARN("tlv header too short received on %s",
402 : : hardware->h_ifname);
403 : 0 : goto malformed;
404 : : }
405 : 10 : tlv_size = PEEK_UINT16;
406 : 10 : tlv_type = tlv_size >> 9;
407 : 10 : tlv_size = tlv_size & 0x1ff;
408 : 10 : (void) PEEK_SAVE(tlv);
409 [ - + ]: 10 : if (length < tlv_size) {
410 [ # # ]: 0 : VLOG_WARN("frame too short for tlv received on %s",
411 : : hardware->h_ifname);
412 : 0 : goto malformed;
413 : : }
414 : :
415 [ + + + + : 10 : switch (tlv_type) {
+ - + - ]
416 : : case LLDP_TLV_END:
417 [ - + ]: 1 : if (tlv_size != 0) {
418 [ # # ]: 0 : VLOG_WARN("lldp end received with size not null on %s",
419 : : hardware->h_ifname);
420 : 0 : goto malformed;
421 : : }
422 [ - + ]: 1 : if (length) {
423 [ # # ]: 0 : VLOG_DBG("extra data after lldp end on %s",
424 : : hardware->h_ifname);
425 : : }
426 : 1 : gotend = true;
427 : 1 : break;
428 : :
429 : : case LLDP_TLV_CHASSIS_ID:
430 : : case LLDP_TLV_PORT_ID:
431 [ - + ][ # # ]: 2 : CHECK_TLV_SIZE(2, "Port Id");
432 : 2 : tlv_subtype = PEEK_UINT8;
433 [ + - ][ - + ]: 2 : if (tlv_subtype == 0 || tlv_subtype > 7) {
434 [ # # ]: 0 : VLOG_WARN("unknown subtype for tlv id received on %s",
435 : : hardware->h_ifname);
436 : 0 : goto malformed;
437 : : }
438 : 2 : b = xzalloc(tlv_size - 1);
439 : 2 : PEEK_BYTES(b, tlv_size - 1);
440 [ + + ]: 2 : if (tlv_type == LLDP_TLV_PORT_ID) {
441 : 1 : port->p_id_subtype = tlv_subtype;
442 : 1 : port->p_id = b;
443 : 1 : port->p_id_len = tlv_size - 1;
444 : : } else {
445 : 1 : chassis->c_id_subtype = tlv_subtype;
446 : 1 : chassis->c_id = b;
447 : 1 : chassis->c_id_len = tlv_size - 1;
448 : : }
449 : 2 : break;
450 : :
451 : : case LLDP_TLV_TTL:
452 [ - + ][ # # ]: 1 : CHECK_TLV_SIZE(2, "TTL");
453 : 1 : chassis->c_ttl = PEEK_UINT16;
454 : 1 : ttl_received = true;
455 : 1 : break;
456 : :
457 : : case LLDP_TLV_PORT_DESCR:
458 : : case LLDP_TLV_SYSTEM_NAME:
459 : : case LLDP_TLV_SYSTEM_DESCR:
460 [ - + ]: 3 : if (tlv_size < 1) {
461 [ # # ]: 0 : VLOG_DBG("empty tlv received on %s", hardware->h_ifname);
462 : 0 : break;
463 : : }
464 : 3 : b = xzalloc(tlv_size + 1);
465 : 3 : PEEK_BYTES(b, tlv_size);
466 [ + + ]: 3 : if (tlv_type == LLDP_TLV_PORT_DESCR) {
467 : 1 : port->p_descr = b;
468 [ + + ]: 2 : } else if (tlv_type == LLDP_TLV_SYSTEM_NAME) {
469 : 1 : chassis->c_name = b;
470 : : } else {
471 : 1 : chassis->c_descr = b;
472 : : }
473 : 3 : break;
474 : :
475 : : case LLDP_TLV_SYSTEM_CAP:
476 [ - + ][ # # ]: 1 : CHECK_TLV_SIZE(4, "System capabilities");
477 : 1 : chassis->c_cap_available = PEEK_UINT16;
478 : 1 : chassis->c_cap_enabled = PEEK_UINT16;
479 : 1 : break;
480 : :
481 : : case LLDP_TLV_MGMT_ADDR:
482 [ # # ][ # # ]: 0 : CHECK_TLV_SIZE(1, "Management address");
483 : 0 : addr_str_length = PEEK_UINT8;
484 [ # # ][ # # ]: 0 : CHECK_TLV_SIZE(1 + addr_str_length, "Management address");
485 : 0 : PEEK_BYTES(addr_str_buffer, addr_str_length);
486 : 0 : addr_length = addr_str_length - 1;
487 : 0 : addr_family = addr_str_buffer[0];
488 : 0 : addr_ptr = &addr_str_buffer[1];
489 [ # # ][ # # ]: 0 : CHECK_TLV_SIZE(1 + addr_str_length + 5, "Management address");
490 : 0 : iface_subtype = PEEK_UINT8;
491 : 0 : iface_number = PEEK_UINT32;
492 : :
493 : 0 : af = lldpd_af_from_lldp_proto(addr_family);
494 [ # # ]: 0 : if (af == LLDPD_AF_UNSPEC) {
495 : 0 : break;
496 : : }
497 : 0 : iface = iface_subtype == LLDP_MGMT_IFACE_IFINDEX ?
498 [ # # ]: 0 : iface_number : 0;
499 : 0 : mgmt = lldpd_alloc_mgmt(af, addr_ptr, addr_length, iface);
500 [ # # ]: 0 : if (mgmt == NULL) {
501 [ # # ]: 0 : VLOG_WARN("unable to allocate memory for management address");
502 : 0 : goto malformed;
503 : : }
504 : 0 : ovs_list_push_back(&chassis->c_mgmt, &mgmt->m_entries);
505 : 0 : break;
506 : :
507 : : case LLDP_TLV_ORG:
508 [ - + ][ # # ]: 2 : CHECK_TLV_SIZE(4, "Organisational");
509 : 2 : PEEK_BYTES(orgid, sizeof orgid);
510 : 2 : tlv_subtype = PEEK_UINT8;
511 [ - + ]: 2 : if (memcmp(dot1, orgid, sizeof orgid) == 0) {
512 : 0 : hardware->h_rx_unrecognized_cnt++;
513 [ - + ]: 2 : } else if (memcmp(dot3, orgid, sizeof orgid) == 0) {
514 : 0 : hardware->h_rx_unrecognized_cnt++;
515 [ - + ]: 2 : } else if (memcmp(med, orgid, sizeof orgid) == 0) {
516 : : /* LLDP-MED */
517 : 0 : hardware->h_rx_unrecognized_cnt++;
518 [ + - ]: 2 : } 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 [ + + - ]: 2 : switch(tlv_subtype) {
526 : : case LLDP_TLV_AA_ELEMENT_SUBTYPE:
527 : 1 : PEEK_BYTES(&msg_auth_digest, sizeof msg_auth_digest);
528 : :
529 : 1 : aa_element_dword = PEEK_UINT32;
530 : :
531 : : /* Type is first 6 most-significant bits of
532 : : * aa_element_dword */
533 : 1 : port->p_element.type = aa_element_dword >> 26;
534 : :
535 : : /* State is 6 most significant bits of aa_element_dword */
536 : 1 : 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 : 1 : 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 : 1 : 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 : 1 : port->p_element.mgmt_vlan =
551 : 1 : (aa_element_dword >> 8) & 0xFFF;
552 [ + - ]: 1 : 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 : 1 : PEEK_BYTES(&port->p_element.system_id.system_mac,
560 : : sizeof port->p_element.system_id.system_mac);
561 [ + - ]: 1 : VLOG_INFO("System mac: "ETH_ADDR_FMT,
562 : : ETH_ADDR_ARGS(port->p_element.system_id.system_mac));
563 : 1 : aa_system_id_word = PEEK_UINT16;
564 : 1 : port->p_element.system_id.conn_type =
565 : : aa_system_id_word >> 13;
566 : 1 : port->p_element.system_id.rsvd = aa_system_id_word &
567 : : 0x03FF;
568 : 1 : PEEK_BYTES(&port->p_element.system_id.rsvd2,
569 : : sizeof port->p_element.system_id.rsvd2);
570 : 1 : break;
571 : :
572 : : case LLDP_TLV_AA_ISID_VLAN_ASGNS_SUBTYPE:
573 : 1 : 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 : 1 : num_mappings = tlv_size - 4 -
579 : : LLDP_TLV_AA_ISID_VLAN_DIGEST_LENGTH;
580 [ - + ]: 1 : if (num_mappings % 5 != 0) {
581 [ # # ]: 0 : VLOG_INFO("malformed vlan-isid mappings tlv received");
582 : 0 : goto malformed;
583 : : }
584 : :
585 : 1 : num_mappings /= 5; /* Each mapping is 5 Bytes */
586 [ + + ]: 3 : for(; num_mappings > 0; num_mappings--) {
587 : : uint8_t isid[3];
588 : :
589 : 2 : isid_vlan_map = xzalloc(sizeof *isid_vlan_map);
590 : 2 : aa_status_vlan_word = PEEK_UINT16;
591 : :
592 : : /* Status is first 4 most-significant bits. */
593 : 2 : isid_vlan_map->isid_vlan_data.status =
594 : : aa_status_vlan_word >> 12;
595 : :
596 : : /* Vlan is last 12 bits */
597 : 2 : isid_vlan_map->isid_vlan_data.vlan =
598 : : aa_status_vlan_word & 0x0FFF;
599 : 2 : PEEK_BYTES(isid, 3);
600 : 2 : isid_vlan_map->isid_vlan_data.isid =
601 : 2 : (isid[0] << 16) | (isid[1] << 8) | isid[2];
602 : 2 : ovs_list_push_back(&port->p_isid_vlan_maps,
603 : : &isid_vlan_map->m_entries);
604 : 2 : isid_vlan_map = NULL;
605 : : }
606 : 1 : break;
607 : :
608 : : default:
609 : 0 : hardware->h_rx_unrecognized_cnt++;
610 [ # # ]: 0 : VLOG_INFO("Unrecogised tlv subtype received");
611 : 2 : break;
612 : : }
613 [ # # ]: 0 : } else if (memcmp(dcbx, orgid, sizeof orgid) == 0) {
614 [ # # ]: 0 : VLOG_DBG("unsupported DCBX tlv received on %s "
615 : : "- ignore", hardware->h_ifname);
616 : 0 : hardware->h_rx_unrecognized_cnt++;
617 : : } else {
618 [ # # ]: 0 : VLOG_INFO("unknown org tlv [%02x:%02x:%02x] received "
619 : : "on %s", orgid[0], orgid[1], orgid[2],
620 : : hardware->h_ifname);
621 : 0 : hardware->h_rx_unrecognized_cnt++;
622 : : }
623 : 2 : break;
624 : : default:
625 [ # # ]: 0 : VLOG_WARN("unknown tlv (%d) received on %s",
626 : : tlv_type,
627 : : hardware->h_ifname);
628 : 0 : goto malformed;
629 : : }
630 [ - + ]: 10 : if (pos > tlv + tlv_size) {
631 [ # # ]: 0 : VLOG_WARN("BUG: already past TLV!");
632 : 0 : goto malformed;
633 : : }
634 : 10 : PEEK_DISCARD(tlv + tlv_size - pos);
635 : : }
636 : :
637 : : /* Some random check */
638 [ + - ][ + - ]: 1 : if (!chassis->c_id || !port->p_id || !ttl_received || !gotend) {
[ + - ][ - + ]
639 [ # # ]: 0 : VLOG_WARN("some mandatory tlv are missing for frame received "
640 : : "on %s", hardware->h_ifname);
641 : 0 : goto malformed;
642 : : }
643 : 1 : *newchassis = chassis;
644 : 1 : *newport = port;
645 : 1 : return 1;
646 : :
647 : : malformed:
648 : 0 : lldpd_chassis_cleanup(chassis, true);
649 : 0 : lldpd_port_cleanup(port, true);
650 : 0 : free(port);
651 : 1 : return -1;
652 : : }
|