]> git.ipfire.org Git - thirdparty/lldpd.git/blame - src/daemon/protocols/lldp.c
daemon: do not explicitely inline functions
[thirdparty/lldpd.git] / src / daemon / protocols / lldp.c
CommitLineData
4b292b55 1/* -*- mode: c; c-file-style: "openbsd" -*- */
43c02e7b
VB
2/*
3 * Copyright (c) 2008 Vincent Bernat <bernat@luffy.cx>
4 *
51434125 5 * Permission to use, copy, modify, and/or distribute this software for any
43c02e7b
VB
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18#include "lldpd.h"
a8105c1b 19#include "frame.h"
43c02e7b
VB
20
21#include <unistd.h>
22#include <errno.h>
23#include <time.h>
24#include <sys/types.h>
25#include <sys/socket.h>
26#include <sys/ioctl.h>
43c02e7b 27
e86777ab 28static int
e6b36c87
JV
29lldpd_af_to_lldp_proto(int af)
30{
31 switch (af) {
32 case LLDPD_AF_IPV4:
33 return LLDP_MGMT_ADDR_IP4;
34 case LLDPD_AF_IPV6:
35 return LLDP_MGMT_ADDR_IP6;
36 default:
37 return LLDP_MGMT_ADDR_NONE;
38 }
39}
40
e86777ab 41static int
e6b36c87
JV
42lldpd_af_from_lldp_proto(int proto)
43{
44 switch (proto) {
45 case LLDP_MGMT_ADDR_IP4:
46 return LLDPD_AF_IPV4;
47 case LLDP_MGMT_ADDR_IP6:
48 return LLDPD_AF_IPV6;
49 default:
50 return LLDPD_AF_UNSPEC;
51 }
52}
53
acb5f65b
VB
54static int _lldp_send(struct lldpd *global,
55 struct lldpd_hardware *hardware,
56 u_int8_t c_id_subtype,
57 char *c_id,
58 int c_id_len,
59 u_int8_t p_id_subtype,
60 char *p_id,
61 int p_id_len,
62 int shutdown)
43c02e7b 63{
a8105c1b 64 struct lldpd_port *port;
77507b69 65 struct lldpd_chassis *chassis;
a8105c1b
VB
66 struct lldpd_frame *frame;
67 int length;
68 u_int8_t *packet, *pos, *tlv;
e6b36c87
JV
69 struct lldpd_mgmt *mgmt;
70 int proto;
a8105c1b 71
1eadc9a1
VB
72 u_int8_t mcastaddr_regular[] = LLDP_ADDR_NEAREST_BRIDGE;
73 u_int8_t mcastaddr_nontpmr[] = LLDP_ADDR_NEAREST_NONTPMR_BRIDGE;
74 u_int8_t mcastaddr_customer[] = LLDP_ADDR_NEAREST_CUSTOMER_BRIDGE;
75 u_int8_t *mcastaddr;
a1347cd8
VB
76#ifdef ENABLE_DOT1
77 const u_int8_t dot1[] = LLDP_TLV_ORG_DOT1;
a1347cd8 78 struct lldpd_vlan *vlan;
9757bfbc
SK
79 struct lldpd_ppvid *ppvid;
80 struct lldpd_pi *pi;
a1347cd8
VB
81#endif
82#ifdef ENABLE_DOT3
83 const u_int8_t dot3[] = LLDP_TLV_ORG_DOT3;
a1347cd8 84#endif
89840df0 85#ifdef ENABLE_LLDPMED
115ff55c 86 int i;
89840df0 87 const u_int8_t med[] = LLDP_TLV_ORG_MED;
89840df0 88#endif
fb1b78bb 89#ifdef ENABLE_CUSTOM
cd5de7a2 90 struct lldpd_custom *custom;
fb1b78bb 91#endif
a8105c1b 92 port = &hardware->h_lport;
77507b69 93 chassis = port->p_chassis;
a8105c1b 94 length = hardware->h_mtu;
b0cb07f7 95 if ((packet = (u_int8_t*)calloc(1, length)) == NULL)
a8105c1b 96 return ENOMEM;
a8105c1b 97 pos = packet;
43c02e7b
VB
98
99 /* Ethernet header */
1eadc9a1
VB
100 switch (global->g_config.c_lldp_agent_type) {
101 case LLDP_AGENT_TYPE_NEAREST_NONTPMR_BRIDGE: mcastaddr = mcastaddr_nontpmr; break;
102 case LLDP_AGENT_TYPE_NEAREST_CUSTOMER_BRIDGE: mcastaddr = mcastaddr_customer; break;
103 case LLDP_AGENT_TYPE_NEAREST_BRIDGE:
104 default: mcastaddr = mcastaddr_regular; break;
105 }
a8105c1b
VB
106 if (!(
107 /* LLDP multicast address */
1eadc9a1 108 POKE_BYTES(mcastaddr, ETHER_ADDR_LEN) &&
a8105c1b 109 /* Source MAC address */
ed409ccd 110 POKE_BYTES(&hardware->h_lladdr, ETHER_ADDR_LEN) &&
a8105c1b
VB
111 /* LLDP frame */
112 POKE_UINT16(ETHERTYPE_LLDP)))
113 goto toobig;
43c02e7b
VB
114
115 /* Chassis ID */
a8105c1b
VB
116 if (!(
117 POKE_START_LLDP_TLV(LLDP_TLV_CHASSIS_ID) &&
acb5f65b
VB
118 POKE_UINT8(c_id_subtype) &&
119 POKE_BYTES(c_id, c_id_len) &&
a8105c1b
VB
120 POKE_END_LLDP_TLV))
121 goto toobig;
43c02e7b
VB
122
123 /* Port ID */
a8105c1b
VB
124 if (!(
125 POKE_START_LLDP_TLV(LLDP_TLV_PORT_ID) &&
acb5f65b
VB
126 POKE_UINT8(p_id_subtype) &&
127 POKE_BYTES(p_id, p_id_len) &&
a8105c1b
VB
128 POKE_END_LLDP_TLV))
129 goto toobig;
43c02e7b
VB
130
131 /* Time to live */
a8105c1b
VB
132 if (!(
133 POKE_START_LLDP_TLV(LLDP_TLV_TTL) &&
71b0f981 134 POKE_UINT16(shutdown?0:(global?global->g_config.c_ttl:180)) &&
a8105c1b
VB
135 POKE_END_LLDP_TLV))
136 goto toobig;
43c02e7b 137
acb5f65b
VB
138 if (shutdown)
139 goto end;
140
43c02e7b 141 /* System name */
12313820
VB
142 if (chassis->c_name && *chassis->c_name != '\0') {
143 if (!(
144 POKE_START_LLDP_TLV(LLDP_TLV_SYSTEM_NAME) &&
145 POKE_BYTES(chassis->c_name, strlen(chassis->c_name)) &&
146 POKE_END_LLDP_TLV))
147 goto toobig;
148 }
43c02e7b 149
d7985042
VB
150 /* System description (skip it if empty) */
151 if (chassis->c_descr && *chassis->c_descr != '\0') {
152 if (!(
153 POKE_START_LLDP_TLV(LLDP_TLV_SYSTEM_DESCR) &&
154 POKE_BYTES(chassis->c_descr, strlen(chassis->c_descr)) &&
155 POKE_END_LLDP_TLV))
156 goto toobig;
157 }
43c02e7b
VB
158
159 /* System capabilities */
ca838758 160 if (global->g_config.c_cap_advertise && chassis->c_cap_available) {
7d678398
AA
161 if (!(
162 POKE_START_LLDP_TLV(LLDP_TLV_SYSTEM_CAP) &&
163 POKE_UINT16(chassis->c_cap_available) &&
164 POKE_UINT16(chassis->c_cap_enabled) &&
165 POKE_END_LLDP_TLV))
166 goto toobig;
167 }
43c02e7b 168
e6b36c87
JV
169 /* Management addresses */
170 TAILQ_FOREACH(mgmt, &chassis->c_mgmt, m_entries) {
171 proto = lldpd_af_to_lldp_proto(mgmt->m_family);
9221b5c2 172 if (proto == LLDP_MGMT_ADDR_NONE) continue;
a8105c1b 173 if (!(
e6b36c87
JV
174 POKE_START_LLDP_TLV(LLDP_TLV_MGMT_ADDR) &&
175 /* Size of the address, including its type */
176 POKE_UINT8(mgmt->m_addrsize + 1) &&
177 POKE_UINT8(proto) &&
178 POKE_BYTES(&mgmt->m_addr, mgmt->m_addrsize)))
a8105c1b 179 goto toobig;
43c02e7b
VB
180
181 /* Interface port type, OID */
e6b36c87 182 if (mgmt->m_iface == 0) {
a8105c1b 183 if (!(
e6b36c87
JV
184 /* We don't know the management interface */
185 POKE_UINT8(LLDP_MGMT_IFACE_UNKNOWN) &&
186 POKE_UINT32(0)))
a8105c1b
VB
187 goto toobig;
188 } else {
189 if (!(
e6b36c87
JV
190 /* We have the index of the management interface */
191 POKE_UINT8(LLDP_MGMT_IFACE_IFINDEX) &&
192 POKE_UINT32(mgmt->m_iface)))
a8105c1b 193 goto toobig;
43c02e7b 194 }
a8105c1b 195 if (!(
e6b36c87
JV
196 /* We don't provide an OID for management */
197 POKE_UINT8(0) &&
198 POKE_END_LLDP_TLV))
a8105c1b 199 goto toobig;
43c02e7b
VB
200 }
201
202 /* Port description */
12313820
VB
203 if (port->p_descr && *port->p_descr != '\0') {
204 if (!(
205 POKE_START_LLDP_TLV(LLDP_TLV_PORT_DESCR) &&
206 POKE_BYTES(port->p_descr, strlen(port->p_descr)) &&
207 POKE_END_LLDP_TLV))
208 goto toobig;
209 }
43c02e7b 210
a1347cd8 211#ifdef ENABLE_DOT1
9757bfbc
SK
212 /* Port VLAN ID */
213 if(port->p_pvid != 0) {
214 if (!(
215 POKE_START_LLDP_TLV(LLDP_TLV_ORG) &&
216 POKE_BYTES(dot1, sizeof(dot1)) &&
217 POKE_UINT8(LLDP_TLV_DOT1_PVID) &&
218 POKE_UINT16(port->p_pvid) &&
219 POKE_END_LLDP_TLV)) {
220 goto toobig;
221 }
222 }
223 /* Port and Protocol VLAN IDs */
224 TAILQ_FOREACH(ppvid, &port->p_ppvids, p_entries) {
225 if (!(
226 POKE_START_LLDP_TLV(LLDP_TLV_ORG) &&
227 POKE_BYTES(dot1, sizeof(dot1)) &&
228 POKE_UINT8(LLDP_TLV_DOT1_PPVID) &&
229 POKE_UINT8(ppvid->p_cap_status) &&
230 POKE_UINT16(ppvid->p_ppvid) &&
231 POKE_END_LLDP_TLV)) {
232 goto toobig;
233 }
234 }
43c02e7b 235 /* VLANs */
a8105c1b
VB
236 TAILQ_FOREACH(vlan, &port->p_vlans, v_entries) {
237 if (!(
238 POKE_START_LLDP_TLV(LLDP_TLV_ORG) &&
239 POKE_BYTES(dot1, sizeof(dot1)) &&
240 POKE_UINT8(LLDP_TLV_DOT1_VLANNAME) &&
241 POKE_UINT16(vlan->v_vid) &&
242 POKE_UINT8(strlen(vlan->v_name)) &&
243 POKE_BYTES(vlan->v_name, strlen(vlan->v_name)) &&
244 POKE_END_LLDP_TLV))
245 goto toobig;
43c02e7b 246 }
9757bfbc
SK
247 /* Protocol Identities */
248 TAILQ_FOREACH(pi, &port->p_pids, p_entries) {
249 if (!(
250 POKE_START_LLDP_TLV(LLDP_TLV_ORG) &&
251 POKE_BYTES(dot1, sizeof(dot1)) &&
252 POKE_UINT8(LLDP_TLV_DOT1_PI) &&
48acfcaf
VB
253 POKE_UINT8(pi->p_pi_len) &&
254 POKE_BYTES(pi->p_pi, pi->p_pi_len) &&
9757bfbc
SK
255 POKE_END_LLDP_TLV))
256 goto toobig;
257 }
a1347cd8 258#endif
43c02e7b 259
a1347cd8 260#ifdef ENABLE_DOT3
43c02e7b 261 /* Aggregation status */
a8105c1b
VB
262 if (!(
263 POKE_START_LLDP_TLV(LLDP_TLV_ORG) &&
264 POKE_BYTES(dot3, sizeof(dot3)) &&
265 POKE_UINT8(LLDP_TLV_DOT3_LA) &&
266 /* Bit 0 = capability ; Bit 1 = status */
267 POKE_UINT8((port->p_aggregid) ? 3:1) &&
268 POKE_UINT32(port->p_aggregid) &&
269 POKE_END_LLDP_TLV))
270 goto toobig;
43c02e7b
VB
271
272 /* MAC/PHY */
a8105c1b
VB
273 if (!(
274 POKE_START_LLDP_TLV(LLDP_TLV_ORG) &&
275 POKE_BYTES(dot3, sizeof(dot3)) &&
276 POKE_UINT8(LLDP_TLV_DOT3_MAC) &&
3fd015c0
VB
277 POKE_UINT8(port->p_macphy.autoneg_support |
278 (port->p_macphy.autoneg_enabled << 1)) &&
279 POKE_UINT16(port->p_macphy.autoneg_advertised) &&
280 POKE_UINT16(port->p_macphy.mau_type) &&
a8105c1b
VB
281 POKE_END_LLDP_TLV))
282 goto toobig;
548109b2
VB
283
284 /* MFS */
683b1710
VB
285 if (port->p_mfs) {
286 if (!(
287 POKE_START_LLDP_TLV(LLDP_TLV_ORG) &&
288 POKE_BYTES(dot3, sizeof(dot3)) &&
289 POKE_UINT8(LLDP_TLV_DOT3_MFS) &&
290 POKE_UINT16(port->p_mfs) &&
291 POKE_END_LLDP_TLV))
292 goto toobig;
293 }
42ee7382
VB
294 /* Power */
295 if (port->p_power.devicetype) {
296 if (!(
297 POKE_START_LLDP_TLV(LLDP_TLV_ORG) &&
298 POKE_BYTES(dot3, sizeof(dot3)) &&
299 POKE_UINT8(LLDP_TLV_DOT3_POWER) &&
300 POKE_UINT8((
301 (((2 - port->p_power.devicetype) %(1<< 1))<<0) |
302 (( port->p_power.supported %(1<< 1))<<1) |
303 (( port->p_power.enabled %(1<< 1))<<2) |
304 (( port->p_power.paircontrol %(1<< 1))<<3))) &&
305 POKE_UINT8(port->p_power.pairs) &&
608cb51c
VB
306 POKE_UINT8(port->p_power.class)))
307 goto toobig;
308 /* 802.3at */
309 if (port->p_power.powertype != LLDP_DOT3_POWER_8023AT_OFF) {
310 if (!(
311 POKE_UINT8((
312 (((port->p_power.powertype ==
313 LLDP_DOT3_POWER_8023AT_TYPE1)?1:0) << 7) |
314 (((port->p_power.devicetype ==
315 LLDP_DOT3_POWER_PSE)?0:1) << 6) |
316 ((port->p_power.source %(1<< 2))<<4) |
317 ((port->p_power.priority %(1<< 2))<<0))) &&
318 POKE_UINT16(port->p_power.requested) &&
319 POKE_UINT16(port->p_power.allocated)))
320 goto toobig;
321 }
322 if (!(POKE_END_LLDP_TLV))
42ee7382
VB
323 goto toobig;
324 }
a1347cd8 325#endif
43c02e7b 326
89840df0 327#ifdef ENABLE_LLDPMED
740593ff 328 if (port->p_med_cap_enabled) {
89840df0 329 /* LLDP-MED cap */
03d178b6
VB
330 if (port->p_med_cap_enabled & LLDP_MED_CAP_CAP) {
331 if (!(
332 POKE_START_LLDP_TLV(LLDP_TLV_ORG) &&
333 POKE_BYTES(med, sizeof(med)) &&
334 POKE_UINT8(LLDP_TLV_MED_CAP) &&
335 POKE_UINT16(chassis->c_med_cap_available) &&
336 POKE_UINT8(chassis->c_med_type) &&
337 POKE_END_LLDP_TLV))
338 goto toobig;
339 }
89840df0
VB
340
341 /* LLDP-MED inventory */
a8105c1b 342#define LLDP_INVENTORY(value, subtype) \
89840df0 343 if (value) { \
a8105c1b
VB
344 if (!( \
345 POKE_START_LLDP_TLV(LLDP_TLV_ORG) && \
346 POKE_BYTES(med, sizeof(med)) && \
347 POKE_UINT8(subtype) && \
348 POKE_BYTES(value, \
349 (strlen(value)>32)?32:strlen(value)) && \
350 POKE_END_LLDP_TLV)) \
351 goto toobig; \
89840df0 352 }
e809a587 353
4b292b55 354 if (port->p_med_cap_enabled & LLDP_MED_CAP_IV) {
a8105c1b
VB
355 LLDP_INVENTORY(chassis->c_med_hw,
356 LLDP_TLV_MED_IV_HW);
357 LLDP_INVENTORY(chassis->c_med_fw,
358 LLDP_TLV_MED_IV_FW);
359 LLDP_INVENTORY(chassis->c_med_sw,
360 LLDP_TLV_MED_IV_SW);
361 LLDP_INVENTORY(chassis->c_med_sn,
362 LLDP_TLV_MED_IV_SN);
363 LLDP_INVENTORY(chassis->c_med_manuf,
364 LLDP_TLV_MED_IV_MANUF);
365 LLDP_INVENTORY(chassis->c_med_model,
366 LLDP_TLV_MED_IV_MODEL);
367 LLDP_INVENTORY(chassis->c_med_asset,
368 LLDP_TLV_MED_IV_ASSET);
e809a587 369 }
115ff55c
VB
370
371 /* LLDP-MED location */
4b292b55 372 for (i = 0; i < LLDP_MED_LOCFORMAT_LAST; i++) {
740593ff 373 if (port->p_med_location[i].format == i + 1) {
a8105c1b
VB
374 if (!(
375 POKE_START_LLDP_TLV(LLDP_TLV_ORG) &&
376 POKE_BYTES(med, sizeof(med)) &&
377 POKE_UINT8(LLDP_TLV_MED_LOCATION) &&
378 POKE_UINT8(port->p_med_location[i].format) &&
379 POKE_BYTES(port->p_med_location[i].data,
380 port->p_med_location[i].data_len) &&
381 POKE_END_LLDP_TLV))
382 goto toobig;
115ff55c
VB
383 }
384 }
86f24df3
VB
385
386 /* LLDP-MED network policy */
4b292b55 387 for (i = 0; i < LLDP_MED_APPTYPE_LAST; i++) {
86f24df3
VB
388 if (port->p_med_policy[i].type == i + 1) {
389 if (!(
390 POKE_START_LLDP_TLV(LLDP_TLV_ORG) &&
391 POKE_BYTES(med, sizeof(med)) &&
392 POKE_UINT8(LLDP_TLV_MED_POLICY) &&
393 POKE_UINT32((
394 ((port->p_med_policy[i].type %(1<< 8))<<24) |
395 ((port->p_med_policy[i].unknown %(1<< 1))<<23) |
396 ((port->p_med_policy[i].tagged %(1<< 1))<<22) |
397 /*((0 %(1<< 1))<<21) |*/
398 ((port->p_med_policy[i].vid %(1<<12))<< 9) |
399 ((port->p_med_policy[i].priority %(1<< 3))<< 6) |
400 ((port->p_med_policy[i].dscp %(1<< 6))<< 0) )) &&
401 POKE_END_LLDP_TLV))
402 goto toobig;
403 }
404 }
009ddd23
VB
405
406 /* LLDP-MED POE-MDI */
4b292b55
VB
407 if ((port->p_med_power.devicetype == LLDP_MED_POW_TYPE_PSE) ||
408 (port->p_med_power.devicetype == LLDP_MED_POW_TYPE_PD)) {
009ddd23
VB
409 int devicetype = 0, source = 0;
410 if (!(
411 POKE_START_LLDP_TLV(LLDP_TLV_ORG) &&
412 POKE_BYTES(med, sizeof(med)) &&
413 POKE_UINT8(LLDP_TLV_MED_MDI)))
414 goto toobig;
415 switch (port->p_med_power.devicetype) {
4b292b55 416 case LLDP_MED_POW_TYPE_PSE:
009ddd23
VB
417 devicetype = 0;
418 switch (port->p_med_power.source) {
4b292b55
VB
419 case LLDP_MED_POW_SOURCE_PRIMARY: source = 1; break;
420 case LLDP_MED_POW_SOURCE_BACKUP: source = 2; break;
421 case LLDP_MED_POW_SOURCE_RESERVED: source = 3; break;
009ddd23
VB
422 default: source = 0; break;
423 }
424 break;
4b292b55 425 case LLDP_MED_POW_TYPE_PD:
009ddd23
VB
426 devicetype = 1;
427 switch (port->p_med_power.source) {
4b292b55
VB
428 case LLDP_MED_POW_SOURCE_PSE: source = 1; break;
429 case LLDP_MED_POW_SOURCE_LOCAL: source = 2; break;
430 case LLDP_MED_POW_SOURCE_BOTH: source = 3; break;
009ddd23
VB
431 default: source = 0; break;
432 }
433 break;
434 }
435 if (!(
436 POKE_UINT8((
437 ((devicetype %(1<< 2))<<6) |
438 ((source %(1<< 2))<<4) |
439 ((port->p_med_power.priority %(1<< 4))<<0) )) &&
440 POKE_UINT16(port->p_med_power.val) &&
441 POKE_END_LLDP_TLV))
442 goto toobig;
443 }
89840df0
VB
444 }
445#endif
446
fb1b78bb 447#ifdef ENABLE_CUSTOM
cd5de7a2
AA
448 TAILQ_FOREACH(custom, &port->p_custom_list, next) {
449 if (!(
450 POKE_START_LLDP_TLV(LLDP_TLV_ORG) &&
451 POKE_BYTES(custom->oui, sizeof(custom->oui)) &&
452 POKE_UINT8(custom->subtype) &&
453 POKE_BYTES(custom->oui_info, custom->oui_info_len) &&
454 POKE_END_LLDP_TLV))
455 goto toobig;
456 }
fb1b78bb 457#endif
cd5de7a2 458
acb5f65b 459end:
43c02e7b 460 /* END */
a8105c1b
VB
461 if (!(
462 POKE_START_LLDP_TLV(LLDP_TLV_END) &&
463 POKE_END_LLDP_TLV))
464 goto toobig;
43c02e7b 465
5347914e 466 if (interfaces_send_helper(global, hardware,
6e75df87 467 (char *)packet, pos - packet) == -1) {
6f8925be 468 log_warn("lldp", "unable to send packet on real device for %s",
f2dcb180
VB
469 hardware->h_ifname);
470 free(packet);
471 return ENETDOWN;
43c02e7b
VB
472 }
473
f2dcb180
VB
474 hardware->h_tx_cnt++;
475
a8105c1b 476 /* We assume that LLDP frame is the reference */
acb5f65b 477 if (!shutdown && (frame = (struct lldpd_frame*)malloc(
a8105c1b
VB
478 sizeof(int) + pos - packet)) != NULL) {
479 frame->size = pos - packet;
480 memcpy(&frame->frame, packet, frame->size);
77507b69
VB
481 if ((hardware->h_lport.p_lastframe == NULL) ||
482 (hardware->h_lport.p_lastframe->size != frame->size) ||
483 (memcmp(hardware->h_lport.p_lastframe->frame, frame->frame,
a8105c1b 484 frame->size) != 0)) {
77507b69 485 free(hardware->h_lport.p_lastframe);
acb5f65b
VB
486 hardware->h_lport.p_lastframe = frame;
487 hardware->h_lport.p_lastchange = time(NULL);
488 } else free(frame);
43c02e7b
VB
489 }
490
a8105c1b 491 free(packet);
43c02e7b 492 return 0;
a8105c1b
VB
493
494toobig:
495 free(packet);
496 return E2BIG;
43c02e7b
VB
497}
498
e770b720
VB
499/* Send a shutdown LLDPDU. */
500int
acb5f65b
VB
501lldp_send_shutdown(struct lldpd *global,
502 struct lldpd_hardware *hardware)
503{
e770b720
VB
504 if (hardware->h_lchassis_previous_id == NULL ||
505 hardware->h_lport_previous_id == NULL)
506 return 0;
acb5f65b
VB
507 return _lldp_send(global, hardware,
508 hardware->h_lchassis_previous_id_subtype,
509 hardware->h_lchassis_previous_id,
510 hardware->h_lchassis_previous_id_len,
511 hardware->h_lport_previous_id_subtype,
512 hardware->h_lport_previous_id,
513 hardware->h_lport_previous_id_len,
514 1);
515}
516
517int
518lldp_send(struct lldpd *global,
519 struct lldpd_hardware *hardware)
520{
521 struct lldpd_port *port = &hardware->h_lport;
522 struct lldpd_chassis *chassis = port->p_chassis;
523 int ret;
524
525 /* Check if we have a change. */
526 if (hardware->h_lchassis_previous_id != NULL &&
527 hardware->h_lport_previous_id != NULL &&
528 (hardware->h_lchassis_previous_id_subtype != chassis->c_id_subtype ||
529 hardware->h_lchassis_previous_id_len != chassis->c_id_len ||
530 hardware->h_lport_previous_id_subtype != port->p_id_subtype ||
531 hardware->h_lport_previous_id_len != port->p_id_len ||
532 memcmp(hardware->h_lchassis_previous_id,
533 chassis->c_id, chassis->c_id_len) ||
534 memcmp(hardware->h_lport_previous_id,
535 port->p_id, port->p_id_len))) {
536 log_info("lldp", "MSAP has changed for port %s, sending a shutdown LLDPDU",
537 hardware->h_ifname);
538 if ((ret = lldp_send_shutdown(global, hardware)) != 0)
539 return ret;
540 }
541
542 log_debug("lldp", "send LLDP PDU to %s",
543 hardware->h_ifname);
544
545 if ((ret = _lldp_send(global, hardware,
546 chassis->c_id_subtype,
547 chassis->c_id,
548 chassis->c_id_len,
549 port->p_id_subtype,
550 port->p_id,
551 port->p_id_len,
552 0)) != 0)
553 return ret;
554
555 /* Record current chassis and port ID */
556 free(hardware->h_lchassis_previous_id);
557 hardware->h_lchassis_previous_id_subtype = chassis->c_id_subtype;
558 hardware->h_lchassis_previous_id_len = chassis->c_id_len;
559 if ((hardware->h_lchassis_previous_id = malloc(chassis->c_id_len)) != NULL)
560 memcpy(hardware->h_lchassis_previous_id, chassis->c_id,
561 chassis->c_id_len);
562 free(hardware->h_lport_previous_id);
563 hardware->h_lport_previous_id_subtype = port->p_id_subtype;
564 hardware->h_lport_previous_id_len = port->p_id_len;
565 if ((hardware->h_lport_previous_id = malloc(port->p_id_len)) != NULL)
566 memcpy(hardware->h_lport_previous_id, port->p_id,
567 port->p_id_len);
568
569 return 0;
570}
571
a8105c1b
VB
572#define CHECK_TLV_SIZE(x, name) \
573 do { if (tlv_size < (x)) { \
6f8925be 574 log_warnx("lldp", name " TLV too short received on %s", \
a8105c1b
VB
575 hardware->h_ifname); \
576 goto malformed; \
577 } } while (0)
578
43c02e7b
VB
579int
580lldp_decode(struct lldpd *cfg, char *frame, int s,
581 struct lldpd_hardware *hardware,
582 struct lldpd_chassis **newchassis, struct lldpd_port **newport)
583{
584 struct lldpd_chassis *chassis;
585 struct lldpd_port *port;
a98ed042 586 char lldpaddr[ETHER_ADDR_LEN];
43c02e7b
VB
587 const char dot1[] = LLDP_TLV_ORG_DOT1;
588 const char dot3[] = LLDP_TLV_ORG_DOT3;
6772b237 589 const char med[] = LLDP_TLV_ORG_MED;
5317a14a 590 const char dcbx[] = LLDP_TLV_ORG_DCBX;
a3cae2a7 591 unsigned char orgid[3];
5a215d4b 592 int length, gotend = 0, ttl_received = 0;
a8105c1b
VB
593 int tlv_size, tlv_type, tlv_subtype;
594 u_int8_t *pos, *tlv;
43c02e7b 595 char *b;
a8105c1b 596#ifdef ENABLE_DOT1
506273e9 597 struct lldpd_vlan *vlan = NULL;
75b3469d 598 int vlan_len;
9757bfbc 599 struct lldpd_ppvid *ppvid;
506273e9 600 struct lldpd_pi *pi = NULL;
a8105c1b 601#endif
e6b36c87
JV
602 struct lldpd_mgmt *mgmt;
603 int af;
604 u_int8_t addr_str_length, addr_str_buffer[32];
605 u_int8_t addr_family, addr_length, *addr_ptr, iface_subtype;
606 u_int32_t iface_number, iface;
fb1b78bb 607#ifdef ENABLE_CUSTOM
1cce9f1a 608 struct lldpd_custom *custom = NULL;
fb1b78bb 609#endif
43c02e7b 610
6f8925be
VB
611 log_debug("lldp", "receive LLDP PDU on %s",
612 hardware->h_ifname);
613
43c02e7b 614 if ((chassis = calloc(1, sizeof(struct lldpd_chassis))) == NULL) {
6f8925be 615 log_warn("lldp", "failed to allocate remote chassis");
43c02e7b
VB
616 return -1;
617 }
e6b36c87 618 TAILQ_INIT(&chassis->c_mgmt);
43c02e7b 619 if ((port = calloc(1, sizeof(struct lldpd_port))) == NULL) {
6f8925be 620 log_warn("lldp", "failed to allocate remote port");
43c02e7b
VB
621 free(chassis);
622 return -1;
623 }
a1347cd8 624#ifdef ENABLE_DOT1
43c02e7b 625 TAILQ_INIT(&port->p_vlans);
9757bfbc
SK
626 TAILQ_INIT(&port->p_ppvids);
627 TAILQ_INIT(&port->p_pids);
a1347cd8 628#endif
fb1b78bb 629#ifdef ENABLE_CUSTOM
cd5de7a2 630 TAILQ_INIT(&port->p_custom_list);
fb1b78bb 631#endif
43c02e7b 632
a8105c1b
VB
633 length = s;
634 pos = (u_int8_t*)frame;
635
4e5f34c5 636 if (length < 2*ETHER_ADDR_LEN + sizeof(u_int16_t)) {
6f8925be 637 log_warnx("lldp", "too short frame received on %s", hardware->h_ifname);
43c02e7b
VB
638 goto malformed;
639 }
a98ed042
VB
640 PEEK_BYTES(lldpaddr, ETHER_ADDR_LEN);
641 if (memcmp(lldpaddr, (const char [])LLDP_ADDR_NEAREST_BRIDGE, ETHER_ADDR_LEN) &&
642 memcmp(lldpaddr, (const char [])LLDP_ADDR_NEAREST_NONTPMR_BRIDGE, ETHER_ADDR_LEN) &&
643 memcmp(lldpaddr, (const char [])LLDP_ADDR_NEAREST_CUSTOMER_BRIDGE, ETHER_ADDR_LEN)) {
6f8925be 644 log_info("lldp", "frame not targeted at LLDP multicast address received on %s",
43c02e7b
VB
645 hardware->h_ifname);
646 goto malformed;
647 }
4e5f34c5 648 PEEK_DISCARD(ETHER_ADDR_LEN); /* Skip source address */
a8105c1b 649 if (PEEK_UINT16 != ETHERTYPE_LLDP) {
6f8925be 650 log_info("lldp", "non LLDP frame received on %s",
43c02e7b
VB
651 hardware->h_ifname);
652 goto malformed;
653 }
654
a8105c1b
VB
655 while (length && (!gotend)) {
656 if (length < 2) {
6f8925be 657 log_warnx("lldp", "tlv header too short received on %s",
43c02e7b
VB
658 hardware->h_ifname);
659 goto malformed;
660 }
a8105c1b
VB
661 tlv_size = PEEK_UINT16;
662 tlv_type = tlv_size >> 9;
663 tlv_size = tlv_size & 0x1ff;
2d1fe392 664 (void)PEEK_SAVE(tlv);
a8105c1b 665 if (length < tlv_size) {
6f8925be 666 log_warnx("lldp", "frame too short for tlv received on %s",
43c02e7b
VB
667 hardware->h_ifname);
668 goto malformed;
669 }
a8105c1b 670 switch (tlv_type) {
43c02e7b 671 case LLDP_TLV_END:
a8105c1b 672 if (tlv_size != 0) {
6f8925be 673 log_warnx("lldp", "lldp end received with size not null on %s",
43c02e7b
VB
674 hardware->h_ifname);
675 goto malformed;
676 }
a8105c1b 677 if (length)
6f8925be 678 log_debug("lldp", "extra data after lldp end on %s",
43c02e7b
VB
679 hardware->h_ifname);
680 gotend = 1;
681 break;
682 case LLDP_TLV_CHASSIS_ID:
683 case LLDP_TLV_PORT_ID:
a8105c1b
VB
684 CHECK_TLV_SIZE(2, "Port Id");
685 tlv_subtype = PEEK_UINT8;
686 if ((tlv_subtype == 0) || (tlv_subtype > 7)) {
6f8925be 687 log_warnx("lldp", "unknown subtype for tlv id received on %s",
43c02e7b
VB
688 hardware->h_ifname);
689 goto malformed;
690 }
a8105c1b 691 if ((b = (char *)calloc(1, tlv_size - 1)) == NULL) {
6f8925be 692 log_warn("lldp", "unable to allocate memory for id tlv "
43c02e7b
VB
693 "received on %s",
694 hardware->h_ifname);
695 goto malformed;
696 }
a8105c1b
VB
697 PEEK_BYTES(b, tlv_size - 1);
698 if (tlv_type == LLDP_TLV_PORT_ID) {
699 port->p_id_subtype = tlv_subtype;
43c02e7b 700 port->p_id = b;
a8105c1b 701 port->p_id_len = tlv_size - 1;
43c02e7b 702 } else {
a8105c1b 703 chassis->c_id_subtype = tlv_subtype;
43c02e7b 704 chassis->c_id = b;
a8105c1b 705 chassis->c_id_len = tlv_size - 1;
43c02e7b 706 }
43c02e7b
VB
707 break;
708 case LLDP_TLV_TTL:
a8105c1b 709 CHECK_TLV_SIZE(2, "TTL");
78346c89 710 port->p_ttl = PEEK_UINT16;
5a215d4b 711 ttl_received = 1;
43c02e7b
VB
712 break;
713 case LLDP_TLV_PORT_DESCR:
714 case LLDP_TLV_SYSTEM_NAME:
715 case LLDP_TLV_SYSTEM_DESCR:
a8105c1b 716 if (tlv_size < 1) {
6f8925be 717 log_debug("lldp", "empty tlv received on %s",
43c02e7b 718 hardware->h_ifname);
a700e935 719 break;
43c02e7b 720 }
a8105c1b 721 if ((b = (char *)calloc(1, tlv_size + 1)) == NULL) {
6f8925be 722 log_warn("lldp", "unable to allocate memory for string tlv "
43c02e7b
VB
723 "received on %s",
724 hardware->h_ifname);
725 goto malformed;
726 }
a8105c1b
VB
727 PEEK_BYTES(b, tlv_size);
728 if (tlv_type == LLDP_TLV_PORT_DESCR)
43c02e7b 729 port->p_descr = b;
a8105c1b 730 else if (tlv_type == LLDP_TLV_SYSTEM_NAME)
43c02e7b
VB
731 chassis->c_name = b;
732 else chassis->c_descr = b;
733 break;
734 case LLDP_TLV_SYSTEM_CAP:
a8105c1b
VB
735 CHECK_TLV_SIZE(4, "System capabilities");
736 chassis->c_cap_available = PEEK_UINT16;
737 chassis->c_cap_enabled = PEEK_UINT16;
43c02e7b
VB
738 break;
739 case LLDP_TLV_MGMT_ADDR:
e6b36c87
JV
740 CHECK_TLV_SIZE(1, "Management address");
741 addr_str_length = PEEK_UINT8;
dd4f16e7
VB
742 if (addr_str_length > sizeof(addr_str_buffer)) {
743 log_warnx("lldp", "too large management address on %s",
744 hardware->h_ifname);
745 goto malformed;
746 }
feed548d 747 CHECK_TLV_SIZE(1 + addr_str_length, "Management address");
e6b36c87
JV
748 PEEK_BYTES(addr_str_buffer, addr_str_length);
749 addr_length = addr_str_length - 1;
750 addr_family = addr_str_buffer[0];
751 addr_ptr = &addr_str_buffer[1];
feed548d 752 CHECK_TLV_SIZE(1 + addr_str_length + 5, "Management address");
e6b36c87
JV
753 iface_subtype = PEEK_UINT8;
754 iface_number = PEEK_UINT32;
dd4f16e7 755
e6b36c87
JV
756 af = lldpd_af_from_lldp_proto(addr_family);
757 if (af == LLDPD_AF_UNSPEC)
758 break;
759 if (iface_subtype == LLDP_MGMT_IFACE_IFINDEX)
760 iface = iface_number;
761 else
762 iface = 0;
763 mgmt = lldpd_alloc_mgmt(af, addr_ptr, addr_length, iface);
764 if (mgmt == NULL) {
9221b5c2
VB
765 if (errno == ENOMEM)
766 log_warn("lldp", "unable to allocate memory "
767 "for management address");
768 else
769 log_warn("lldp", "too large management address "
770 "received on %s", hardware->h_ifname);
ff75b38e 771 goto malformed;
43c02e7b 772 }
e6b36c87 773 TAILQ_INSERT_TAIL(&chassis->c_mgmt, mgmt, m_entries);
43c02e7b
VB
774 break;
775 case LLDP_TLV_ORG:
dd4f16e7 776 CHECK_TLV_SIZE(1 + (int)sizeof(orgid), "Organisational");
a8105c1b
VB
777 PEEK_BYTES(orgid, sizeof(orgid));
778 tlv_subtype = PEEK_UINT8;
779 if (memcmp(dot1, orgid, sizeof(orgid)) == 0) {
a1347cd8 780#ifndef ENABLE_DOT1
a1347cd8
VB
781 hardware->h_rx_unrecognized_cnt++;
782#else
43c02e7b 783 /* Dot1 */
a8105c1b 784 switch (tlv_subtype) {
75b3469d 785 case LLDP_TLV_DOT1_VLANNAME:
a8105c1b 786 CHECK_TLV_SIZE(7, "VLAN");
43c02e7b
VB
787 if ((vlan = (struct lldpd_vlan *)calloc(1,
788 sizeof(struct lldpd_vlan))) == NULL) {
6f8925be 789 log_warn("lldp", "unable to alloc vlan "
efe3f9b0 790 "structure for "
43c02e7b
VB
791 "tlv received on %s",
792 hardware->h_ifname);
793 goto malformed;
794 }
a8105c1b
VB
795 vlan->v_vid = PEEK_UINT16;
796 vlan_len = PEEK_UINT8;
797 CHECK_TLV_SIZE(7 + vlan_len, "VLAN");
43c02e7b
VB
798 if ((vlan->v_name =
799 (char *)calloc(1, vlan_len + 1)) == NULL) {
6f8925be 800 log_warn("lldp", "unable to alloc vlan name for "
43c02e7b
VB
801 "tlv received on %s",
802 hardware->h_ifname);
803 goto malformed;
804 }
a8105c1b 805 PEEK_BYTES(vlan->v_name, vlan_len);
43c02e7b
VB
806 TAILQ_INSERT_TAIL(&port->p_vlans,
807 vlan, v_entries);
506273e9 808 vlan = NULL;
75b3469d
VB
809 break;
810 case LLDP_TLV_DOT1_PVID:
a8105c1b
VB
811 CHECK_TLV_SIZE(6, "PVID");
812 port->p_pvid = PEEK_UINT16;
75b3469d 813 break;
9757bfbc
SK
814 case LLDP_TLV_DOT1_PPVID:
815 CHECK_TLV_SIZE(7, "PPVID");
816 /* validation needed */
817 /* PPVID has to be unique if more than
818 one PPVID TLVs are received -
819 discard if duplicate */
820 /* if support bit is not set and
821 enabled bit is set - PPVID TLV is
822 considered error and discarded */
823 /* if PPVID > 4096 - bad and discard */
824 if ((ppvid = (struct lldpd_ppvid *)calloc(1,
825 sizeof(struct lldpd_ppvid))) == NULL) {
6f8925be 826 log_warn("lldp", "unable to alloc ppvid "
9757bfbc
SK
827 "structure for "
828 "tlv received on %s",
829 hardware->h_ifname);
830 goto malformed;
831 }
832 ppvid->p_cap_status = PEEK_UINT8;
833 ppvid->p_ppvid = PEEK_UINT16;
834 TAILQ_INSERT_TAIL(&port->p_ppvids,
835 ppvid, p_entries);
836 break;
837 case LLDP_TLV_DOT1_PI:
838 /* validation needed */
839 /* PI has to be unique if more than
840 one PI TLVs are received - discard
841 if duplicate ?? */
842 CHECK_TLV_SIZE(5, "PI");
843 if ((pi = (struct lldpd_pi *)calloc(1,
844 sizeof(struct lldpd_pi))) == NULL) {
6f8925be 845 log_warn("lldp", "unable to alloc PI "
9757bfbc
SK
846 "structure for "
847 "tlv received on %s",
848 hardware->h_ifname);
849 goto malformed;
850 }
48acfcaf 851 pi->p_pi_len = PEEK_UINT8;
78e82fcf 852 CHECK_TLV_SIZE(5 + pi->p_pi_len, "PI");
9757bfbc 853 if ((pi->p_pi =
48acfcaf 854 (char *)calloc(1, pi->p_pi_len)) == NULL) {
6f8925be 855 log_warn("lldp", "unable to alloc pid name for "
9757bfbc
SK
856 "tlv received on %s",
857 hardware->h_ifname);
858 goto malformed;
859 }
48acfcaf 860 PEEK_BYTES(pi->p_pi, pi->p_pi_len);
9757bfbc
SK
861 TAILQ_INSERT_TAIL(&port->p_pids,
862 pi, p_entries);
506273e9 863 pi = NULL;
9757bfbc 864 break;
75b3469d 865 default:
43c02e7b 866 /* Unknown Dot1 TLV, ignore it */
a1347cd8
VB
867 hardware->h_rx_unrecognized_cnt++;
868 }
869#endif
a8105c1b 870 } else if (memcmp(dot3, orgid, sizeof(orgid)) == 0) {
a1347cd8 871#ifndef ENABLE_DOT3
a1347cd8
VB
872 hardware->h_rx_unrecognized_cnt++;
873#else
43c02e7b 874 /* Dot3 */
a8105c1b 875 switch (tlv_subtype) {
43c02e7b 876 case LLDP_TLV_DOT3_MAC:
a8105c1b 877 CHECK_TLV_SIZE(9, "MAC/PHY");
3fd015c0
VB
878 port->p_macphy.autoneg_support = PEEK_UINT8;
879 port->p_macphy.autoneg_enabled =
0a36d97b 880 (port->p_macphy.autoneg_support & 0x2) >> 1;
3fd015c0 881 port->p_macphy.autoneg_support =
befbdf89 882 port->p_macphy.autoneg_support & 0x1;
3fd015c0 883 port->p_macphy.autoneg_advertised =
a8105c1b 884 PEEK_UINT16;
3fd015c0 885 port->p_macphy.mau_type = PEEK_UINT16;
43c02e7b
VB
886 break;
887 case LLDP_TLV_DOT3_LA:
a8105c1b 888 CHECK_TLV_SIZE(9, "Link aggregation");
a204514f 889 PEEK_DISCARD_UINT8;
a8105c1b 890 port->p_aggregid = PEEK_UINT32;
43c02e7b 891 break;
548109b2 892 case LLDP_TLV_DOT3_MFS:
a8105c1b
VB
893 CHECK_TLV_SIZE(6, "MFS");
894 port->p_mfs = PEEK_UINT16;
548109b2 895 break;
befbdf89
VB
896 case LLDP_TLV_DOT3_POWER:
897 CHECK_TLV_SIZE(7, "Power");
898 port->p_power.devicetype = PEEK_UINT8;
899 port->p_power.supported =
0a36d97b 900 (port->p_power.devicetype & 0x2) >> 1;
befbdf89 901 port->p_power.enabled =
0a36d97b 902 (port->p_power.devicetype & 0x4) >> 2;
befbdf89 903 port->p_power.paircontrol =
181351d6 904 (port->p_power.devicetype & 0x8) >> 3;
befbdf89
VB
905 port->p_power.devicetype =
906 (port->p_power.devicetype & 0x1)?
907 LLDP_DOT3_POWER_PSE:LLDP_DOT3_POWER_PD;
908 port->p_power.pairs = PEEK_UINT8;
909 port->p_power.class = PEEK_UINT8;
608cb51c
VB
910 /* 802.3at? */
911 if (tlv_size >= 12) {
912 port->p_power.powertype = PEEK_UINT8;
913 port->p_power.source =
914 (port->p_power.powertype & (1<<5 | 1<<4)) >> 4;
915 port->p_power.priority =
916 (port->p_power.powertype & (1<<1 | 1<<0));
917 port->p_power.powertype =
918 (port->p_power.powertype & (1<<7))?
919 LLDP_DOT3_POWER_8023AT_TYPE1:
920 LLDP_DOT3_POWER_8023AT_TYPE2;
921 port->p_power.requested = PEEK_UINT16;
922 port->p_power.allocated = PEEK_UINT16;
923 } else
924 port->p_power.powertype =
925 LLDP_DOT3_POWER_8023AT_OFF;
befbdf89 926 break;
43c02e7b
VB
927 default:
928 /* Unknown Dot3 TLV, ignore it */
37387046 929 hardware->h_rx_unrecognized_cnt++;
43c02e7b 930 }
a1347cd8 931#endif
a8105c1b 932 } else if (memcmp(med, orgid, sizeof(orgid)) == 0) {
6772b237
VB
933 /* LLDP-MED */
934#ifndef ENABLE_LLDPMED
6772b237
VB
935 hardware->h_rx_unrecognized_cnt++;
936#else
e3a44efb 937 u_int32_t policy;
cdece23a
VB
938 unsigned loctype;
939 unsigned power;
e3a44efb 940
a8105c1b 941 switch (tlv_subtype) {
6772b237 942 case LLDP_TLV_MED_CAP:
a8105c1b
VB
943 CHECK_TLV_SIZE(7, "LLDP-MED capabilities");
944 chassis->c_med_cap_available = PEEK_UINT16;
945 chassis->c_med_type = PEEK_UINT8;
740593ff 946 port->p_med_cap_enabled |=
4b292b55 947 LLDP_MED_CAP_CAP;
6772b237 948 break;
efe3f9b0 949 case LLDP_TLV_MED_POLICY:
a8105c1b
VB
950 CHECK_TLV_SIZE(8, "LLDP-MED policy");
951 policy = PEEK_UINT32;
e3a44efb 952 if (((policy >> 24) < 1) ||
4b292b55 953 ((policy >> 24) > LLDP_MED_APPTYPE_LAST)) {
6f8925be 954 log_info("lldp", "unknown policy field %d "
e3a44efb 955 "received on %s",
e51da5ec 956 policy,
e3a44efb 957 hardware->h_ifname);
e3a44efb
VB
958 break;
959 }
740593ff 960 port->p_med_policy[(policy >> 24) - 1].type =
e3a44efb 961 (policy >> 24);
740593ff 962 port->p_med_policy[(policy >> 24) - 1].unknown =
e3a44efb 963 ((policy & 0x800000) != 0);
740593ff 964 port->p_med_policy[(policy >> 24) - 1].tagged =
e3a44efb 965 ((policy & 0x400000) != 0);
740593ff 966 port->p_med_policy[(policy >> 24) - 1].vid =
e3a44efb 967 (policy & 0x001FFE00) >> 9;
740593ff 968 port->p_med_policy[(policy >> 24) - 1].priority =
e3a44efb 969 (policy & 0x1C0) >> 6;
740593ff 970 port->p_med_policy[(policy >> 24) - 1].dscp =
e3a44efb 971 policy & 0x3F;
740593ff 972 port->p_med_cap_enabled |=
4b292b55 973 LLDP_MED_CAP_POLICY;
efe3f9b0
VB
974 break;
975 case LLDP_TLV_MED_LOCATION:
a8105c1b
VB
976 CHECK_TLV_SIZE(5, "LLDP-MED Location");
977 loctype = PEEK_UINT8;
978 if ((loctype < 1) ||
4b292b55 979 (loctype > LLDP_MED_LOCFORMAT_LAST)) {
6f8925be 980 log_info("lldp", "unknown location type "
e3a44efb
VB
981 "received on %s",
982 hardware->h_ifname);
e3a44efb
VB
983 break;
984 }
740593ff 985 if ((port->p_med_location[loctype - 1].data =
a8105c1b 986 (char*)malloc(tlv_size - 5)) == NULL) {
6f8925be 987 log_warn("lldp", "unable to allocate memory "
efe3f9b0
VB
988 "for LLDP-MED location for "
989 "frame received on %s",
990 hardware->h_ifname);
991 goto malformed;
992 }
a8105c1b
VB
993 PEEK_BYTES(port->p_med_location[loctype - 1].data,
994 tlv_size - 5);
740593ff 995 port->p_med_location[loctype - 1].data_len =
a8105c1b 996 tlv_size - 5;
740593ff 997 port->p_med_location[loctype - 1].format = loctype;
740593ff 998 port->p_med_cap_enabled |=
4b292b55 999 LLDP_MED_CAP_LOCATION;
efe3f9b0
VB
1000 break;
1001 case LLDP_TLV_MED_MDI:
a8105c1b
VB
1002 CHECK_TLV_SIZE(7, "LLDP-MED PoE-MDI");
1003 power = PEEK_UINT8;
1004 switch (power & 0xC0) {
994812b9 1005 case 0x0:
4b292b55 1006 port->p_med_power.devicetype = LLDP_MED_POW_TYPE_PSE;
740593ff 1007 port->p_med_cap_enabled |=
4b292b55 1008 LLDP_MED_CAP_MDI_PSE;
a8105c1b 1009 switch (power & 0x30) {
994812b9 1010 case 0x0:
6d08df0e 1011 port->p_med_power.source =
4b292b55 1012 LLDP_MED_POW_SOURCE_UNKNOWN;
994812b9
VB
1013 break;
1014 case 0x10:
6d08df0e 1015 port->p_med_power.source =
4b292b55 1016 LLDP_MED_POW_SOURCE_PRIMARY;
994812b9
VB
1017 break;
1018 case 0x20:
6d08df0e 1019 port->p_med_power.source =
4b292b55 1020 LLDP_MED_POW_SOURCE_BACKUP;
994812b9
VB
1021 break;
1022 default:
6d08df0e 1023 port->p_med_power.source =
4b292b55 1024 LLDP_MED_POW_SOURCE_RESERVED;
994812b9
VB
1025 }
1026 break;
1027 case 0x40:
4b292b55 1028 port->p_med_power.devicetype = LLDP_MED_POW_TYPE_PD;
740593ff 1029 port->p_med_cap_enabled |=
4b292b55 1030 LLDP_MED_CAP_MDI_PD;
a8105c1b 1031 switch (power & 0x30) {
994812b9 1032 case 0x0:
6d08df0e 1033 port->p_med_power.source =
4b292b55 1034 LLDP_MED_POW_SOURCE_UNKNOWN;
994812b9
VB
1035 break;
1036 case 0x10:
6d08df0e 1037 port->p_med_power.source =
4b292b55 1038 LLDP_MED_POW_SOURCE_PSE;
994812b9
VB
1039 break;
1040 case 0x20:
6d08df0e 1041 port->p_med_power.source =
4b292b55 1042 LLDP_MED_POW_SOURCE_LOCAL;
994812b9
VB
1043 break;
1044 default:
6d08df0e 1045 port->p_med_power.source =
4b292b55 1046 LLDP_MED_POW_SOURCE_BOTH;
994812b9
VB
1047 }
1048 break;
1049 default:
6d08df0e 1050 port->p_med_power.devicetype =
4b292b55 1051 LLDP_MED_POW_TYPE_RESERVED;
994812b9 1052 }
cdece23a 1053 if ((power & 0x0F) > LLDP_MED_POW_PRIO_LOW)
6d08df0e 1054 port->p_med_power.priority =
4b292b55 1055 LLDP_MED_POW_PRIO_UNKNOWN;
009ddd23 1056 else
6d08df0e 1057 port->p_med_power.priority =
009ddd23 1058 power & 0x0F;
6d08df0e 1059 port->p_med_power.val = PEEK_UINT16;
efe3f9b0 1060 break;
6772b237
VB
1061 case LLDP_TLV_MED_IV_HW:
1062 case LLDP_TLV_MED_IV_SW:
1063 case LLDP_TLV_MED_IV_FW:
1064 case LLDP_TLV_MED_IV_SN:
1065 case LLDP_TLV_MED_IV_MANUF:
1066 case LLDP_TLV_MED_IV_MODEL:
1067 case LLDP_TLV_MED_IV_ASSET:
a8105c1b 1068 if (tlv_size <= 4)
5ecdbc53 1069 b = NULL;
6772b237 1070 else {
a8105c1b 1071 if ((b = (char*)malloc(tlv_size - 3)) ==
efe3f9b0 1072 NULL) {
6f8925be 1073 log_warn("lldp", "unable to allocate "
efe3f9b0
VB
1074 "memory for LLDP-MED "
1075 "inventory for frame "
1076 "received on %s",
1077 hardware->h_ifname);
1078 goto malformed;
1079 }
a8105c1b
VB
1080 PEEK_BYTES(b, tlv_size - 4);
1081 b[tlv_size - 4] = '\0';
6772b237 1082 }
a8105c1b 1083 switch (tlv_subtype) {
6772b237
VB
1084 case LLDP_TLV_MED_IV_HW:
1085 chassis->c_med_hw = b;
1086 break;
1087 case LLDP_TLV_MED_IV_FW:
1088 chassis->c_med_fw = b;
1089 break;
1090 case LLDP_TLV_MED_IV_SW:
1091 chassis->c_med_sw = b;
1092 break;
1093 case LLDP_TLV_MED_IV_SN:
1094 chassis->c_med_sn = b;
1095 break;
1096 case LLDP_TLV_MED_IV_MANUF:
1097 chassis->c_med_manuf = b;
1098 break;
1099 case LLDP_TLV_MED_IV_MODEL:
397dee69 1100 chassis->c_med_model = b;
6772b237
VB
1101 break;
1102 case LLDP_TLV_MED_IV_ASSET:
72c4c96f 1103 chassis->c_med_asset = b;
6772b237 1104 break;
6772b237 1105 }
740593ff 1106 port->p_med_cap_enabled |=
4b292b55 1107 LLDP_MED_CAP_IV;
6772b237
VB
1108 break;
1109 default:
1110 /* Unknown LLDP MED, ignore it */
6772b237
VB
1111 hardware->h_rx_unrecognized_cnt++;
1112 }
1113#endif /* ENABLE_LLDPMED */
5317a14a
ST
1114 } else if (memcmp(dcbx, orgid, sizeof(orgid)) == 0) {
1115 log_debug("lldp", "unsupported DCBX tlv received on %s - ignore",
1116 hardware->h_ifname);
1117 hardware->h_rx_unrecognized_cnt++;
43c02e7b 1118 } else {
9c242613 1119 log_debug("lldp", "unknown org tlv [%02x:%02x:%02x] received on %s",
5317a14a 1120 orgid[0], orgid[1], orgid[2],
43c02e7b 1121 hardware->h_ifname);
37387046 1122 hardware->h_rx_unrecognized_cnt++;
fb1b78bb 1123#ifdef ENABLE_CUSTOM
cd5de7a2 1124 custom = (struct lldpd_custom*)calloc(1, sizeof(struct lldpd_custom));
1cce9f1a
VB
1125 if (!custom) {
1126 log_warn("lldp",
1127 "unable to allocate memory for custom TLV");
1128 goto malformed;
1129 }
cd5de7a2
AA
1130 custom->oui_info_len = tlv_size > 4 ? tlv_size - 4 : 0;
1131 memcpy(custom->oui, orgid, sizeof(custom->oui));
1132 custom->subtype = tlv_subtype;
8caf4341
AA
1133 if (custom->oui_info_len > 0) {
1134 custom->oui_info = malloc(custom->oui_info_len);
1cce9f1a
VB
1135 if (!custom->oui_info) {
1136 log_warn("lldp",
1137 "unable to allocate memory for custom TLV data");
1138 goto malformed;
1139 }
cd5de7a2 1140 PEEK_BYTES(custom->oui_info, custom->oui_info_len);
8caf4341 1141 }
cd5de7a2 1142 TAILQ_INSERT_TAIL(&port->p_custom_list, custom, next);
1cce9f1a 1143 custom = NULL;
fb1b78bb 1144#endif
43c02e7b
VB
1145 }
1146 break;
1147 default:
6f8925be 1148 log_warnx("lldp", "unknown tlv (%d) received on %s",
a8105c1b
VB
1149 tlv_type, hardware->h_ifname);
1150 goto malformed;
1151 }
1152 if (pos > tlv + tlv_size) {
6f8925be 1153 log_warnx("lldp", "BUG: already past TLV!");
43c02e7b
VB
1154 goto malformed;
1155 }
a8105c1b 1156 PEEK_DISCARD(tlv + tlv_size - pos);
43c02e7b
VB
1157 }
1158
1159 /* Some random check */
1160 if ((chassis->c_id == NULL) ||
1161 (port->p_id == NULL) ||
5a215d4b 1162 (!ttl_received) ||
43c02e7b 1163 (gotend == 0)) {
6f8925be 1164 log_warnx("lldp", "some mandatory tlv are missing for frame received on %s",
43c02e7b
VB
1165 hardware->h_ifname);
1166 goto malformed;
1167 }
43c02e7b
VB
1168 *newchassis = chassis;
1169 *newport = port;
1170 return 1;
1171malformed:
1cce9f1a
VB
1172#ifdef ENABLE_CUSTOM
1173 free(custom);
1174#endif
506273e9
VB
1175#ifdef ENABLE_DOT1
1176 free(vlan);
1177 free(pi);
1178#endif
77507b69 1179 lldpd_chassis_cleanup(chassis, 1);
4b292b55 1180 lldpd_port_cleanup(port, 1);
4e624dc2 1181 free(port);
43c02e7b
VB
1182 return -1;
1183}