]> git.ipfire.org Git - thirdparty/lldpd.git/blame - src/lldp.c
Update lldpd.h to support a list of remote systems.
[thirdparty/lldpd.git] / src / lldp.c
CommitLineData
43c02e7b
VB
1/*
2 * Copyright (c) 2008 Vincent Bernat <bernat@luffy.cx>
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17#include "lldpd.h"
a8105c1b 18#include "frame.h"
43c02e7b
VB
19
20#include <unistd.h>
21#include <errno.h>
22#include <time.h>
23#include <sys/types.h>
24#include <sys/socket.h>
25#include <sys/ioctl.h>
26#include <netpacket/packet.h>
27#include <linux/sockios.h>
28
29int
30lldp_send(struct lldpd *global, struct lldpd_chassis *chassis,
a8105c1b 31 struct lldpd_hardware *hardware)
43c02e7b 32{
a8105c1b
VB
33 struct lldpd_port *port;
34 struct lldpd_frame *frame;
35 int length;
36 u_int8_t *packet, *pos, *tlv;
37
38 u_int8_t mcastaddr[] = LLDP_MULTICAST_ADDR;
a1347cd8
VB
39#ifdef ENABLE_DOT1
40 const u_int8_t dot1[] = LLDP_TLV_ORG_DOT1;
a1347cd8
VB
41 struct lldpd_vlan *vlan;
42#endif
43#ifdef ENABLE_DOT3
44 const u_int8_t dot3[] = LLDP_TLV_ORG_DOT3;
a1347cd8 45#endif
89840df0 46#ifdef ENABLE_LLDPMED
115ff55c 47 int i;
89840df0 48 const u_int8_t med[] = LLDP_TLV_ORG_MED;
89840df0 49#endif
43c02e7b 50
a8105c1b
VB
51 port = &hardware->h_lport;
52 length = hardware->h_mtu;
53 if ((packet = (u_int8_t*)malloc(length)) == NULL)
54 return ENOMEM;
55 memset(packet, 0, length);
56 pos = packet;
43c02e7b
VB
57
58 /* Ethernet header */
a8105c1b
VB
59 if (!(
60 /* LLDP multicast address */
61 POKE_BYTES(mcastaddr, sizeof(mcastaddr)) &&
62 /* Source MAC address */
63 POKE_BYTES(&hardware->h_lladdr, sizeof(hardware->h_lladdr)) &&
64 /* LLDP frame */
65 POKE_UINT16(ETHERTYPE_LLDP)))
66 goto toobig;
43c02e7b
VB
67
68 /* Chassis ID */
a8105c1b
VB
69 if (!(
70 POKE_START_LLDP_TLV(LLDP_TLV_CHASSIS_ID) &&
71 POKE_UINT8(chassis->c_id_subtype) &&
72 POKE_BYTES(chassis->c_id, chassis->c_id_len) &&
73 POKE_END_LLDP_TLV))
74 goto toobig;
43c02e7b
VB
75
76 /* Port ID */
a8105c1b
VB
77 if (!(
78 POKE_START_LLDP_TLV(LLDP_TLV_PORT_ID) &&
79 POKE_UINT8(port->p_id_subtype) &&
80 POKE_BYTES(port->p_id, port->p_id_len) &&
81 POKE_END_LLDP_TLV))
82 goto toobig;
43c02e7b
VB
83
84 /* Time to live */
a8105c1b
VB
85 if (!(
86 POKE_START_LLDP_TLV(LLDP_TLV_TTL) &&
87 POKE_UINT16(chassis->c_ttl) &&
88 POKE_END_LLDP_TLV))
89 goto toobig;
43c02e7b
VB
90
91 /* System name */
a8105c1b
VB
92 if (!(
93 POKE_START_LLDP_TLV(LLDP_TLV_SYSTEM_NAME) &&
94 POKE_BYTES(chassis->c_name, strlen(chassis->c_name)) &&
95 POKE_END_LLDP_TLV))
96 goto toobig;
43c02e7b
VB
97
98 /* System description */
a8105c1b
VB
99 if (!(
100 POKE_START_LLDP_TLV(LLDP_TLV_SYSTEM_DESCR) &&
101 POKE_BYTES(chassis->c_descr, strlen(chassis->c_descr)) &&
102 POKE_END_LLDP_TLV))
103 goto toobig;
43c02e7b
VB
104
105 /* System capabilities */
a8105c1b
VB
106 if (!(
107 POKE_START_LLDP_TLV(LLDP_TLV_SYSTEM_CAP) &&
108 POKE_UINT16(chassis->c_cap_available) &&
109 POKE_UINT16(chassis->c_cap_enabled) &&
110 POKE_END_LLDP_TLV))
111 goto toobig;
43c02e7b
VB
112
113 if (chassis->c_mgmt.s_addr != INADDR_ANY) {
114 /* Management address */
a8105c1b
VB
115 if (!(
116 POKE_START_LLDP_TLV(LLDP_TLV_MGMT_ADDR) &&
117 /* Size of the address, including its type */
118 POKE_UINT8(sizeof(struct in_addr) + 1) &&
119 /* Address is IPv4 */
120 POKE_UINT8(LLDP_MGMT_ADDR_IP4) &&
121 POKE_BYTES(&chassis->c_mgmt, sizeof(struct in_addr))))
122 goto toobig;
43c02e7b
VB
123
124 /* Interface port type, OID */
a8105c1b
VB
125 if (chassis->c_mgmt_if == 0) {
126 if (!(
127 /* We don't know the management interface */
128 POKE_UINT8(LLDP_MGMT_IFACE_UNKNOWN) &&
129 POKE_UINT32(0)))
130 goto toobig;
131 } else {
132 if (!(
133 /* We have the index of the management interface */
134 POKE_UINT8(LLDP_MGMT_IFACE_IFINDEX) &&
135 POKE_UINT32(chassis->c_mgmt_if)))
136 goto toobig;
43c02e7b 137 }
a8105c1b
VB
138 if (!(
139 /* We don't provide an OID for management */
140 POKE_UINT8(0) &&
141 POKE_END_LLDP_TLV))
142 goto toobig;
43c02e7b
VB
143 }
144
145 /* Port description */
a8105c1b
VB
146 if (!(
147 POKE_START_LLDP_TLV(LLDP_TLV_PORT_DESCR) &&
148 POKE_BYTES(port->p_descr, strlen(port->p_descr)) &&
149 POKE_END_LLDP_TLV))
150 goto toobig;
43c02e7b 151
a1347cd8 152#ifdef ENABLE_DOT1
43c02e7b 153 /* VLANs */
a8105c1b
VB
154 TAILQ_FOREACH(vlan, &port->p_vlans, v_entries) {
155 if (!(
156 POKE_START_LLDP_TLV(LLDP_TLV_ORG) &&
157 POKE_BYTES(dot1, sizeof(dot1)) &&
158 POKE_UINT8(LLDP_TLV_DOT1_VLANNAME) &&
159 POKE_UINT16(vlan->v_vid) &&
160 POKE_UINT8(strlen(vlan->v_name)) &&
161 POKE_BYTES(vlan->v_name, strlen(vlan->v_name)) &&
162 POKE_END_LLDP_TLV))
163 goto toobig;
43c02e7b 164 }
a1347cd8 165#endif
43c02e7b 166
a1347cd8 167#ifdef ENABLE_DOT3
43c02e7b 168 /* Aggregation status */
a8105c1b
VB
169 if (!(
170 POKE_START_LLDP_TLV(LLDP_TLV_ORG) &&
171 POKE_BYTES(dot3, sizeof(dot3)) &&
172 POKE_UINT8(LLDP_TLV_DOT3_LA) &&
173 /* Bit 0 = capability ; Bit 1 = status */
174 POKE_UINT8((port->p_aggregid) ? 3:1) &&
175 POKE_UINT32(port->p_aggregid) &&
176 POKE_END_LLDP_TLV))
177 goto toobig;
43c02e7b
VB
178
179 /* MAC/PHY */
a8105c1b
VB
180 if (!(
181 POKE_START_LLDP_TLV(LLDP_TLV_ORG) &&
182 POKE_BYTES(dot3, sizeof(dot3)) &&
183 POKE_UINT8(LLDP_TLV_DOT3_MAC) &&
184 POKE_UINT8(port->p_autoneg_support |
185 (port->p_autoneg_enabled << 1)) &&
186 POKE_UINT16(port->p_autoneg_advertised) &&
187 POKE_UINT16(port->p_mau_type) &&
188 POKE_END_LLDP_TLV))
189 goto toobig;
548109b2
VB
190
191 /* MFS */
a8105c1b
VB
192 if (!(
193 POKE_START_LLDP_TLV(LLDP_TLV_ORG) &&
194 POKE_BYTES(dot3, sizeof(dot3)) &&
195 POKE_UINT8(LLDP_TLV_DOT3_MFS) &&
196 POKE_UINT16(port->p_mfs) &&
197 POKE_END_LLDP_TLV))
198 goto toobig;
a1347cd8 199#endif
43c02e7b 200
89840df0 201#ifdef ENABLE_LLDPMED
740593ff 202 if (port->p_med_cap_enabled) {
89840df0 203 /* LLDP-MED cap */
a8105c1b
VB
204 if (!(
205 POKE_START_LLDP_TLV(LLDP_TLV_ORG) &&
206 POKE_BYTES(med, sizeof(med)) &&
207 POKE_UINT8(LLDP_TLV_MED_CAP) &&
208 POKE_UINT16(chassis->c_med_cap_available) &&
bc08499a 209 POKE_UINT8(chassis->c_med_type) &&
a8105c1b
VB
210 POKE_END_LLDP_TLV))
211 goto toobig;
89840df0
VB
212
213 /* LLDP-MED inventory */
a8105c1b 214#define LLDP_INVENTORY(value, subtype) \
89840df0 215 if (value) { \
a8105c1b
VB
216 if (!( \
217 POKE_START_LLDP_TLV(LLDP_TLV_ORG) && \
218 POKE_BYTES(med, sizeof(med)) && \
219 POKE_UINT8(subtype) && \
220 POKE_BYTES(value, \
221 (strlen(value)>32)?32:strlen(value)) && \
222 POKE_END_LLDP_TLV)) \
223 goto toobig; \
89840df0 224 }
e809a587 225
740593ff 226 if (port->p_med_cap_enabled & LLDPMED_CAP_IV) {
a8105c1b
VB
227 LLDP_INVENTORY(chassis->c_med_hw,
228 LLDP_TLV_MED_IV_HW);
229 LLDP_INVENTORY(chassis->c_med_fw,
230 LLDP_TLV_MED_IV_FW);
231 LLDP_INVENTORY(chassis->c_med_sw,
232 LLDP_TLV_MED_IV_SW);
233 LLDP_INVENTORY(chassis->c_med_sn,
234 LLDP_TLV_MED_IV_SN);
235 LLDP_INVENTORY(chassis->c_med_manuf,
236 LLDP_TLV_MED_IV_MANUF);
237 LLDP_INVENTORY(chassis->c_med_model,
238 LLDP_TLV_MED_IV_MODEL);
239 LLDP_INVENTORY(chassis->c_med_asset,
240 LLDP_TLV_MED_IV_ASSET);
e809a587 241 }
115ff55c
VB
242
243 /* LLDP-MED location */
244 for (i = 0; i < LLDPMED_LOCFORMAT_LAST; i++) {
740593ff 245 if (port->p_med_location[i].format == i + 1) {
a8105c1b
VB
246 if (!(
247 POKE_START_LLDP_TLV(LLDP_TLV_ORG) &&
248 POKE_BYTES(med, sizeof(med)) &&
249 POKE_UINT8(LLDP_TLV_MED_LOCATION) &&
250 POKE_UINT8(port->p_med_location[i].format) &&
251 POKE_BYTES(port->p_med_location[i].data,
252 port->p_med_location[i].data_len) &&
253 POKE_END_LLDP_TLV))
254 goto toobig;
115ff55c
VB
255 }
256 }
89840df0
VB
257 }
258#endif
259
43c02e7b 260 /* END */
a8105c1b
VB
261 if (!(
262 POKE_START_LLDP_TLV(LLDP_TLV_END) &&
263 POKE_END_LLDP_TLV))
264 goto toobig;
43c02e7b 265
f2dcb180
VB
266 if (write(hardware->h_raw, packet,
267 pos - packet) == -1) {
268 LLOG_WARN("unable to send packet on real device for %s",
269 hardware->h_ifname);
270 free(packet);
271 return ENETDOWN;
43c02e7b
VB
272 }
273
f2dcb180
VB
274 hardware->h_tx_cnt++;
275
a8105c1b
VB
276 /* We assume that LLDP frame is the reference */
277 if ((frame = (struct lldpd_frame*)malloc(
278 sizeof(int) + pos - packet)) != NULL) {
279 frame->size = pos - packet;
280 memcpy(&frame->frame, packet, frame->size);
43c02e7b 281 if ((hardware->h_llastframe == NULL) ||
a8105c1b
VB
282 (hardware->h_llastframe->size != frame->size) ||
283 (memcmp(hardware->h_llastframe->frame, frame->frame,
284 frame->size) != 0)) {
43c02e7b 285 free(hardware->h_llastframe);
a8105c1b
VB
286 hardware->h_llastframe = frame;
287 hardware->h_llastchange = time(NULL);
43c02e7b 288 } else
a8105c1b 289 free(frame);
43c02e7b
VB
290 }
291
a8105c1b 292 free(packet);
43c02e7b 293 return 0;
a8105c1b
VB
294
295toobig:
296 free(packet);
297 return E2BIG;
43c02e7b
VB
298}
299
a8105c1b
VB
300#define CHECK_TLV_SIZE(x, name) \
301 do { if (tlv_size < (x)) { \
302 LLOG_WARNX(name " TLV too short received on %s",\
303 hardware->h_ifname); \
304 goto malformed; \
305 } } while (0)
306
43c02e7b
VB
307int
308lldp_decode(struct lldpd *cfg, char *frame, int s,
309 struct lldpd_hardware *hardware,
310 struct lldpd_chassis **newchassis, struct lldpd_port **newport)
311{
312 struct lldpd_chassis *chassis;
313 struct lldpd_port *port;
43c02e7b
VB
314 const char lldpaddr[] = LLDP_MULTICAST_ADDR;
315 const char dot1[] = LLDP_TLV_ORG_DOT1;
316 const char dot3[] = LLDP_TLV_ORG_DOT3;
6772b237 317 const char med[] = LLDP_TLV_ORG_MED;
a8105c1b
VB
318 char orgid[3];
319 int length, gotend = 0;
320 int tlv_size, tlv_type, tlv_subtype;
321 u_int8_t *pos, *tlv;
43c02e7b 322 char *b;
a8105c1b 323#ifdef ENABLE_DOT1
75b3469d
VB
324 struct lldpd_vlan *vlan;
325 int vlan_len;
a8105c1b 326#endif
43c02e7b
VB
327
328 if ((chassis = calloc(1, sizeof(struct lldpd_chassis))) == NULL) {
329 LLOG_WARN("failed to allocate remote chassis");
330 return -1;
331 }
332 if ((port = calloc(1, sizeof(struct lldpd_port))) == NULL) {
333 LLOG_WARN("failed to allocate remote port");
334 free(chassis);
335 return -1;
336 }
a1347cd8 337#ifdef ENABLE_DOT1
43c02e7b 338 TAILQ_INIT(&port->p_vlans);
a1347cd8 339#endif
43c02e7b 340
a8105c1b
VB
341 length = s;
342 pos = (u_int8_t*)frame;
343
344 if (length < 2*ETH_ALEN + sizeof(u_int16_t)) {
43c02e7b
VB
345 LLOG_WARNX("too short frame received on %s", hardware->h_ifname);
346 goto malformed;
347 }
a8105c1b 348 if (PEEK_CMP(lldpaddr, ETH_ALEN) != 0) {
43c02e7b
VB
349 LLOG_INFO("frame not targeted at LLDP multicast address received on %s",
350 hardware->h_ifname);
351 goto malformed;
352 }
a8105c1b
VB
353 PEEK_DISCARD(ETH_ALEN); /* Skip source address */
354 if (PEEK_UINT16 != ETHERTYPE_LLDP) {
43c02e7b
VB
355 LLOG_INFO("non LLDP frame received on %s",
356 hardware->h_ifname);
357 goto malformed;
358 }
359
a8105c1b
VB
360 while (length && (!gotend)) {
361 if (length < 2) {
43c02e7b
VB
362 LLOG_WARNX("tlv header too short received on %s",
363 hardware->h_ifname);
364 goto malformed;
365 }
a8105c1b
VB
366 tlv_size = PEEK_UINT16;
367 tlv_type = tlv_size >> 9;
368 tlv_size = tlv_size & 0x1ff;
369 PEEK_SAVE(tlv);
370 if (length < tlv_size) {
371 LLOG_WARNX("frame too short for tlv received on %s",
43c02e7b
VB
372 hardware->h_ifname);
373 goto malformed;
374 }
a8105c1b 375 switch (tlv_type) {
43c02e7b 376 case LLDP_TLV_END:
a8105c1b 377 if (tlv_size != 0) {
43c02e7b
VB
378 LLOG_WARNX("lldp end received with size not null on %s",
379 hardware->h_ifname);
380 goto malformed;
381 }
a8105c1b 382 if (length)
43c02e7b
VB
383 LLOG_DEBUG("extra data after lldp end on %s",
384 hardware->h_ifname);
385 gotend = 1;
386 break;
387 case LLDP_TLV_CHASSIS_ID:
388 case LLDP_TLV_PORT_ID:
a8105c1b
VB
389 CHECK_TLV_SIZE(2, "Port Id");
390 tlv_subtype = PEEK_UINT8;
391 if ((tlv_subtype == 0) || (tlv_subtype > 7)) {
43c02e7b
VB
392 LLOG_WARNX("unknown subtype for tlv id received on %s",
393 hardware->h_ifname);
394 goto malformed;
395 }
a8105c1b 396 if ((b = (char *)calloc(1, tlv_size - 1)) == NULL) {
43c02e7b
VB
397 LLOG_WARN("unable to allocate memory for id tlv "
398 "received on %s",
399 hardware->h_ifname);
400 goto malformed;
401 }
a8105c1b
VB
402 PEEK_BYTES(b, tlv_size - 1);
403 if (tlv_type == LLDP_TLV_PORT_ID) {
404 port->p_id_subtype = tlv_subtype;
43c02e7b 405 port->p_id = b;
a8105c1b 406 port->p_id_len = tlv_size - 1;
43c02e7b 407 } else {
a8105c1b 408 chassis->c_id_subtype = tlv_subtype;
43c02e7b 409 chassis->c_id = b;
a8105c1b 410 chassis->c_id_len = tlv_size - 1;
43c02e7b 411 }
43c02e7b
VB
412 break;
413 case LLDP_TLV_TTL:
a8105c1b
VB
414 CHECK_TLV_SIZE(2, "TTL");
415 chassis->c_ttl = PEEK_UINT16;
43c02e7b
VB
416 break;
417 case LLDP_TLV_PORT_DESCR:
418 case LLDP_TLV_SYSTEM_NAME:
419 case LLDP_TLV_SYSTEM_DESCR:
a8105c1b 420 if (tlv_size < 1) {
a700e935 421 LLOG_DEBUG("empty tlv received on %s",
43c02e7b 422 hardware->h_ifname);
a700e935 423 break;
43c02e7b 424 }
a8105c1b 425 if ((b = (char *)calloc(1, tlv_size + 1)) == NULL) {
43c02e7b
VB
426 LLOG_WARN("unable to allocate memory for string tlv "
427 "received on %s",
428 hardware->h_ifname);
429 goto malformed;
430 }
a8105c1b
VB
431 PEEK_BYTES(b, tlv_size);
432 if (tlv_type == LLDP_TLV_PORT_DESCR)
43c02e7b 433 port->p_descr = b;
a8105c1b 434 else if (tlv_type == LLDP_TLV_SYSTEM_NAME)
43c02e7b
VB
435 chassis->c_name = b;
436 else chassis->c_descr = b;
437 break;
438 case LLDP_TLV_SYSTEM_CAP:
a8105c1b
VB
439 CHECK_TLV_SIZE(4, "System capabilities");
440 chassis->c_cap_available = PEEK_UINT16;
441 chassis->c_cap_enabled = PEEK_UINT16;
43c02e7b
VB
442 break;
443 case LLDP_TLV_MGMT_ADDR:
a8105c1b 444 CHECK_TLV_SIZE(11, "Management address");
43c02e7b 445 if ((chassis->c_mgmt.s_addr == INADDR_ANY) &&
a8105c1b
VB
446 (PEEK_UINT8 == 1+sizeof(struct in_addr)) &&
447 (PEEK_UINT8 == LLDP_MGMT_ADDR_IP4)) {
43c02e7b 448 /* We have an IPv4 address, we ignore anything else */
a8105c1b 449 PEEK_BYTES(&chassis->c_mgmt, sizeof(struct in_addr));
43c02e7b
VB
450 chassis->c_mgmt_if = 0;
451 /* We only handle ifIndex subtype */
a8105c1b
VB
452 if (PEEK_UINT8 == LLDP_MGMT_IFACE_IFINDEX)
453 chassis->c_mgmt_if = PEEK_UINT32;
43c02e7b 454 }
43c02e7b
VB
455 break;
456 case LLDP_TLV_ORG:
a8105c1b
VB
457 CHECK_TLV_SIZE(4, "Organisational");
458 PEEK_BYTES(orgid, sizeof(orgid));
459 tlv_subtype = PEEK_UINT8;
460 if (memcmp(dot1, orgid, sizeof(orgid)) == 0) {
a1347cd8 461#ifndef ENABLE_DOT1
a1347cd8
VB
462 hardware->h_rx_unrecognized_cnt++;
463#else
43c02e7b 464 /* Dot1 */
a8105c1b 465 switch (tlv_subtype) {
75b3469d 466 case LLDP_TLV_DOT1_VLANNAME:
a8105c1b 467 CHECK_TLV_SIZE(7, "VLAN");
43c02e7b
VB
468 if ((vlan = (struct lldpd_vlan *)calloc(1,
469 sizeof(struct lldpd_vlan))) == NULL) {
efe3f9b0
VB
470 LLOG_WARN("unable to alloc vlan "
471 "structure for "
43c02e7b
VB
472 "tlv received on %s",
473 hardware->h_ifname);
474 goto malformed;
475 }
a8105c1b
VB
476 vlan->v_vid = PEEK_UINT16;
477 vlan_len = PEEK_UINT8;
478 CHECK_TLV_SIZE(7 + vlan_len, "VLAN");
43c02e7b
VB
479 if ((vlan->v_name =
480 (char *)calloc(1, vlan_len + 1)) == NULL) {
481 LLOG_WARN("unable to alloc vlan name for "
482 "tlv received on %s",
483 hardware->h_ifname);
484 goto malformed;
485 }
a8105c1b 486 PEEK_BYTES(vlan->v_name, vlan_len);
43c02e7b
VB
487 TAILQ_INSERT_TAIL(&port->p_vlans,
488 vlan, v_entries);
75b3469d
VB
489 break;
490 case LLDP_TLV_DOT1_PVID:
a8105c1b
VB
491 CHECK_TLV_SIZE(6, "PVID");
492 port->p_pvid = PEEK_UINT16;
75b3469d
VB
493 break;
494 default:
43c02e7b 495 /* Unknown Dot1 TLV, ignore it */
a1347cd8
VB
496 hardware->h_rx_unrecognized_cnt++;
497 }
498#endif
a8105c1b 499 } else if (memcmp(dot3, orgid, sizeof(orgid)) == 0) {
a1347cd8 500#ifndef ENABLE_DOT3
a1347cd8
VB
501 hardware->h_rx_unrecognized_cnt++;
502#else
43c02e7b 503 /* Dot3 */
a8105c1b 504 switch (tlv_subtype) {
43c02e7b 505 case LLDP_TLV_DOT3_MAC:
a8105c1b
VB
506 CHECK_TLV_SIZE(9, "MAC/PHY");
507 port->p_autoneg_support = PEEK_UINT8;
43c02e7b 508 port->p_autoneg_enabled =
a8105c1b
VB
509 port->p_autoneg_support && 0x2;
510 port->p_autoneg_support =
511 port->p_autoneg_support && 0x1;
43c02e7b 512 port->p_autoneg_advertised =
a8105c1b
VB
513 PEEK_UINT16;
514 port->p_mau_type = PEEK_UINT16;
43c02e7b
VB
515 break;
516 case LLDP_TLV_DOT3_LA:
a8105c1b 517 CHECK_TLV_SIZE(9, "Link aggregation");
a204514f 518 PEEK_DISCARD_UINT8;
a8105c1b 519 port->p_aggregid = PEEK_UINT32;
43c02e7b 520 break;
548109b2 521 case LLDP_TLV_DOT3_MFS:
a8105c1b
VB
522 CHECK_TLV_SIZE(6, "MFS");
523 port->p_mfs = PEEK_UINT16;
548109b2 524 break;
43c02e7b
VB
525 default:
526 /* Unknown Dot3 TLV, ignore it */
37387046 527 hardware->h_rx_unrecognized_cnt++;
43c02e7b 528 }
a1347cd8 529#endif
a8105c1b 530 } else if (memcmp(med, orgid, sizeof(orgid)) == 0) {
6772b237
VB
531 /* LLDP-MED */
532#ifndef ENABLE_LLDPMED
6772b237
VB
533 hardware->h_rx_unrecognized_cnt++;
534#else
e3a44efb
VB
535 u_int32_t policy;
536 int loctype;
a8105c1b 537 int power;
e3a44efb 538
a8105c1b 539 switch (tlv_subtype) {
6772b237 540 case LLDP_TLV_MED_CAP:
a8105c1b
VB
541 CHECK_TLV_SIZE(7, "LLDP-MED capabilities");
542 chassis->c_med_cap_available = PEEK_UINT16;
543 chassis->c_med_type = PEEK_UINT8;
740593ff 544 port->p_med_cap_enabled |=
40ecae87 545 LLDPMED_CAP_CAP;
6772b237 546 break;
efe3f9b0 547 case LLDP_TLV_MED_POLICY:
a8105c1b
VB
548 CHECK_TLV_SIZE(8, "LLDP-MED policy");
549 policy = PEEK_UINT32;
e3a44efb
VB
550 if (((policy >> 24) < 1) ||
551 ((policy >> 24) > LLDPMED_APPTYPE_LAST)) {
552 LLOG_INFO("unknown policy field %d "
553 "received on %s",
554 hardware->h_ifname);
e3a44efb
VB
555 break;
556 }
740593ff 557 port->p_med_policy[(policy >> 24) - 1].type =
e3a44efb 558 (policy >> 24);
740593ff 559 port->p_med_policy[(policy >> 24) - 1].unknown =
e3a44efb 560 ((policy & 0x800000) != 0);
740593ff 561 port->p_med_policy[(policy >> 24) - 1].tagged =
e3a44efb 562 ((policy & 0x400000) != 0);
740593ff 563 port->p_med_policy[(policy >> 24) - 1].vid =
e3a44efb 564 (policy & 0x001FFE00) >> 9;
740593ff 565 port->p_med_policy[(policy >> 24) - 1].priority =
e3a44efb 566 (policy & 0x1C0) >> 6;
740593ff 567 port->p_med_policy[(policy >> 24) - 1].dscp =
e3a44efb 568 policy & 0x3F;
740593ff 569 port->p_med_cap_enabled |=
40ecae87 570 LLDPMED_CAP_POLICY;
efe3f9b0
VB
571 break;
572 case LLDP_TLV_MED_LOCATION:
a8105c1b
VB
573 CHECK_TLV_SIZE(5, "LLDP-MED Location");
574 loctype = PEEK_UINT8;
575 if ((loctype < 1) ||
576 (loctype > LLDPMED_LOCFORMAT_LAST)) {
e3a44efb
VB
577 LLOG_INFO("unknown location type "
578 "received on %s",
579 hardware->h_ifname);
e3a44efb
VB
580 break;
581 }
740593ff 582 if ((port->p_med_location[loctype - 1].data =
a8105c1b 583 (char*)malloc(tlv_size - 5)) == NULL) {
efe3f9b0
VB
584 LLOG_WARN("unable to allocate memory "
585 "for LLDP-MED location for "
586 "frame received on %s",
587 hardware->h_ifname);
588 goto malformed;
589 }
a8105c1b
VB
590 PEEK_BYTES(port->p_med_location[loctype - 1].data,
591 tlv_size - 5);
740593ff 592 port->p_med_location[loctype - 1].data_len =
a8105c1b 593 tlv_size - 5;
740593ff 594 port->p_med_location[loctype - 1].format = loctype;
740593ff 595 port->p_med_cap_enabled |=
40ecae87 596 LLDPMED_CAP_LOCATION;
efe3f9b0
VB
597 break;
598 case LLDP_TLV_MED_MDI:
a8105c1b
VB
599 CHECK_TLV_SIZE(7, "LLDP-MED PoE-MDI");
600 power = PEEK_UINT8;
601 switch (power & 0xC0) {
994812b9 602 case 0x0:
740593ff
VB
603 port->p_med_pow_devicetype = LLDPMED_POW_TYPE_PSE;
604 port->p_med_cap_enabled |=
a49b3a79 605 LLDPMED_CAP_MDI_PSE;
a8105c1b 606 switch (power & 0x30) {
994812b9 607 case 0x0:
740593ff 608 port->p_med_pow_source =
994812b9
VB
609 LLDPMED_POW_SOURCE_UNKNOWN;
610 break;
611 case 0x10:
740593ff 612 port->p_med_pow_source =
994812b9
VB
613 LLDPMED_POW_SOURCE_PRIMARY;
614 break;
615 case 0x20:
740593ff 616 port->p_med_pow_source =
994812b9
VB
617 LLDPMED_POW_SOURCE_BACKUP;
618 break;
619 default:
740593ff 620 port->p_med_pow_source =
994812b9
VB
621 LLDPMED_POW_SOURCE_RESERVED;
622 }
623 break;
624 case 0x40:
740593ff
VB
625 port->p_med_pow_devicetype = LLDPMED_POW_TYPE_PD;
626 port->p_med_cap_enabled |=
a49b3a79 627 LLDPMED_CAP_MDI_PD;
a8105c1b 628 switch (power & 0x30) {
994812b9 629 case 0x0:
740593ff 630 port->p_med_pow_source =
994812b9
VB
631 LLDPMED_POW_SOURCE_UNKNOWN;
632 break;
633 case 0x10:
740593ff 634 port->p_med_pow_source =
994812b9
VB
635 LLDPMED_POW_SOURCE_PSE;
636 break;
637 case 0x20:
740593ff 638 port->p_med_pow_source =
994812b9
VB
639 LLDPMED_POW_SOURCE_LOCAL;
640 break;
641 default:
740593ff 642 port->p_med_pow_source =
994812b9
VB
643 LLDPMED_POW_SOURCE_BOTH;
644 }
645 break;
646 default:
740593ff 647 port->p_med_pow_devicetype =
994812b9
VB
648 LLDPMED_POW_TYPE_RESERVED;
649 }
a8105c1b 650 switch (power & 0x0F) {
994812b9 651 case 0x0:
740593ff 652 port->p_med_pow_priority =
994812b9
VB
653 LLDPMED_POW_PRIO_UNKNOWN;
654 break;
655 case 0x1:
740593ff 656 port->p_med_pow_priority =
994812b9
VB
657 LLDPMED_POW_PRIO_CRITICAL;
658 break;
659 case 0x2:
740593ff 660 port->p_med_pow_priority =
994812b9
VB
661 LLDPMED_POW_PRIO_HIGH;
662 break;
663 case 0x3:
740593ff 664 port->p_med_pow_priority =
994812b9
VB
665 LLDPMED_POW_PRIO_LOW;
666 break;
667 default:
740593ff 668 port->p_med_pow_priority =
994812b9
VB
669 LLDPMED_POW_PRIO_UNKNOWN;
670 }
a8105c1b 671 port->p_med_pow_val = PEEK_UINT16;
efe3f9b0 672 break;
6772b237
VB
673 case LLDP_TLV_MED_IV_HW:
674 case LLDP_TLV_MED_IV_SW:
675 case LLDP_TLV_MED_IV_FW:
676 case LLDP_TLV_MED_IV_SN:
677 case LLDP_TLV_MED_IV_MANUF:
678 case LLDP_TLV_MED_IV_MODEL:
679 case LLDP_TLV_MED_IV_ASSET:
a8105c1b 680 if (tlv_size <= 4)
6772b237
VB
681 b = NULL;
682 else {
a8105c1b 683 if ((b = (char*)malloc(tlv_size - 3)) ==
efe3f9b0
VB
684 NULL) {
685 LLOG_WARN("unable to allocate "
686 "memory for LLDP-MED "
687 "inventory for frame "
688 "received on %s",
689 hardware->h_ifname);
690 goto malformed;
691 }
a8105c1b
VB
692 PEEK_BYTES(b, tlv_size - 4);
693 b[tlv_size - 4] = '\0';
6772b237 694 }
a8105c1b 695 switch (tlv_subtype) {
6772b237
VB
696 case LLDP_TLV_MED_IV_HW:
697 chassis->c_med_hw = b;
698 break;
699 case LLDP_TLV_MED_IV_FW:
700 chassis->c_med_fw = b;
701 break;
702 case LLDP_TLV_MED_IV_SW:
703 chassis->c_med_sw = b;
704 break;
705 case LLDP_TLV_MED_IV_SN:
706 chassis->c_med_sn = b;
707 break;
708 case LLDP_TLV_MED_IV_MANUF:
709 chassis->c_med_manuf = b;
710 break;
711 case LLDP_TLV_MED_IV_MODEL:
397dee69 712 chassis->c_med_model = b;
6772b237
VB
713 break;
714 case LLDP_TLV_MED_IV_ASSET:
72c4c96f 715 chassis->c_med_asset = b;
6772b237
VB
716 break;
717 default:
718 LLOG_WARNX("should not be there!");
719 free(b);
720 break;
721 }
740593ff 722 port->p_med_cap_enabled |=
40ecae87 723 LLDPMED_CAP_IV;
6772b237
VB
724 break;
725 default:
726 /* Unknown LLDP MED, ignore it */
6772b237
VB
727 hardware->h_rx_unrecognized_cnt++;
728 }
729#endif /* ENABLE_LLDPMED */
43c02e7b 730 } else {
9ca19b69 731 LLOG_INFO("unknown org tlv received on %s",
43c02e7b 732 hardware->h_ifname);
37387046 733 hardware->h_rx_unrecognized_cnt++;
43c02e7b
VB
734 }
735 break;
736 default:
737 LLOG_WARNX("unknown tlv (%d) received on %s",
a8105c1b
VB
738 tlv_type, hardware->h_ifname);
739 goto malformed;
740 }
741 if (pos > tlv + tlv_size) {
742 LLOG_WARNX("BUG: already past TLV!");
43c02e7b
VB
743 goto malformed;
744 }
a8105c1b 745 PEEK_DISCARD(tlv + tlv_size - pos);
43c02e7b
VB
746 }
747
748 /* Some random check */
749 if ((chassis->c_id == NULL) ||
750 (port->p_id == NULL) ||
751 (chassis->c_ttl == 0) ||
752 (gotend == 0)) {
753 LLOG_WARNX("some mandatory tlv are missing for frame received on %s",
754 hardware->h_ifname);
755 goto malformed;
756 }
757#define NOTRECEIVED "Not received"
758 if (chassis->c_name == NULL) {
759 if ((chassis->c_name = (char *)calloc(1, strlen(NOTRECEIVED) + 1)) == NULL) {
760 LLOG_WARNX("unable to allocate null chassis name");
761 goto malformed;
762 }
763 memcpy(chassis->c_name, NOTRECEIVED, strlen(NOTRECEIVED));
764 }
765 if (chassis->c_descr == NULL) {
766 if ((chassis->c_descr = (char *)calloc(1, strlen(NOTRECEIVED) + 1)) == NULL) {
767 LLOG_WARNX("unable to allocate null chassis description");
768 goto malformed;
769 }
770 memcpy(chassis->c_descr, NOTRECEIVED, strlen(NOTRECEIVED));
771 }
772 if (port->p_descr == NULL) {
773 if ((port->p_descr = (char *)calloc(1, strlen(NOTRECEIVED) + 1)) == NULL) {
774 LLOG_WARNX("unable to allocate null port description");
775 goto malformed;
776 }
777 memcpy(port->p_descr, NOTRECEIVED, strlen(NOTRECEIVED));
778 }
779 *newchassis = chassis;
780 *newport = port;
781 return 1;
782malformed:
d3322e23 783 lldpd_chassis_cleanup(chassis);
a0edeaf8 784 lldpd_port_cleanup(port, 1);
43c02e7b
VB
785 return -1;
786}