]> git.ipfire.org Git - thirdparty/lldpd.git/blame - src/edp.c
Suppress bond handling.
[thirdparty/lldpd.git] / src / edp.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 19
4bad1937
VB
20#ifdef ENABLE_EDP
21
43c02e7b 22#include <stdio.h>
a8105c1b 23#include <unistd.h>
43c02e7b
VB
24#include <errno.h>
25#include <arpa/inet.h>
26#include <fnmatch.h>
27
8888d191 28static int seq = 0;
43c02e7b
VB
29
30int
31edp_send(struct lldpd *global, struct lldpd_chassis *chassis,
32 struct lldpd_hardware *hardware)
33{
43c02e7b
VB
34 const u_int8_t mcastaddr[] = EDP_MULTICAST_ADDR;
35 const u_int8_t llcorg[] = LLC_ORG_EXTREME;
a8105c1b
VB
36 int length, i, v;
37 u_int8_t *packet, *pos, *pos_llc, *pos_len_eh, *pos_len_edp, *pos_edp, *tlv, *end;
38 u_int16_t checksum;
a1347cd8 39#ifdef ENABLE_DOT1
43c02e7b 40 struct lldpd_vlan *vlan;
a1347cd8
VB
41 unsigned int state = 0;
42#endif
43c02e7b 43 u_int8_t edp_fakeversion[] = {7, 6, 4, 99};
43c02e7b
VB
44 /* Subsequent XXX can be replaced by other values. We place
45 them here to ensure the position of "" to be a bit
46 invariant with version changes. */
47 char *deviceslot[] = { "eth", "veth", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "", NULL };
48
a1347cd8 49#ifdef ENABLE_DOT1
43c02e7b 50 while (state != 2) {
a1347cd8 51#endif
a8105c1b
VB
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;
57 v = 0;
58
59 /* Ethernet header */
60 if (!(
61 POKE_BYTES(mcastaddr, sizeof(mcastaddr)) &&
62 POKE_BYTES(&hardware->h_lladdr, sizeof(hardware->h_lladdr)) &&
63 POKE_SAVE(pos_len_eh) && /* We compute the len later */
64 POKE_UINT16(0)))
65 goto toobig;
43c02e7b 66
a8105c1b
VB
67 /* LLC */
68 if (!(
69 POKE_SAVE(pos_llc) && /* We need to save our
70 current position to
71 compute ethernet len */
72 /* SSAP and DSAP */
73 POKE_UINT8(0xaa) && POKE_UINT8(0xaa) &&
74 /* Control field */
75 POKE_UINT8(0x03) &&
76 /* ORG */
77 POKE_BYTES(llcorg, sizeof(llcorg)) &&
78 POKE_UINT16(LLC_PID_EDP)))
79 goto toobig;
43c02e7b
VB
80
81 /* EDP header */
43c02e7b
VB
82 if ((chassis->c_id_len != ETH_ALEN) ||
83 (chassis->c_id_subtype != LLDP_CHASSISID_SUBTYPE_LLADDR)) {
84 LLOG_WARNX("local chassis does not use MAC address as chassis ID!?");
a8105c1b 85 free(packet);
43c02e7b
VB
86 return EINVAL;
87 }
a8105c1b
VB
88 if (!(
89 POKE_SAVE(pos_edp) && /* Save the start of EDP frame */
90 POKE_UINT8(1) && POKE_UINT8(0) &&
91 POKE_SAVE(pos_len_edp) && /* We compute the len
92 and the checksum
93 later */
94 POKE_UINT32(0) && /* Len + Checksum */
95 POKE_UINT16(seq) &&
96 POKE_UINT16(0) &&
98faedcf 97 POKE_BYTES(chassis->c_id, ETH_ALEN)))
a8105c1b
VB
98 goto toobig;
99 seq++;
43c02e7b 100
a1347cd8 101#ifdef ENABLE_DOT1
43c02e7b
VB
102 switch (state) {
103 case 0:
a1347cd8 104#endif
43c02e7b 105 /* Display TLV */
a8105c1b
VB
106 if (!(
107 POKE_START_EDP_TLV(EDP_TLV_DISPLAY) &&
108 POKE_BYTES(chassis->c_name, strlen(chassis->c_name)) &&
109 POKE_UINT8(0) && /* Add a NULL character
110 for better
111 compatibility */
112 POKE_END_EDP_TLV))
113 goto toobig;
43c02e7b
VB
114
115 /* Info TLV */
a8105c1b
VB
116 if (!(
117 POKE_START_EDP_TLV(EDP_TLV_INFO)))
118 goto toobig;
119 /* We try to emulate the slot thing */
43c02e7b
VB
120 for (i=0; deviceslot[i] != NULL; i++) {
121 if (strncmp(hardware->h_ifname, deviceslot[i],
122 strlen(deviceslot[i])) == 0) {
a8105c1b
VB
123 if (!(
124 POKE_UINT16(i) &&
125 POKE_UINT16(atoi(hardware->h_ifname +
126 strlen(deviceslot[i])))))
127 goto toobig;
43c02e7b
VB
128 break;
129 }
130 }
a8105c1b
VB
131 /* If we don't find a "slot", we say that the
132 interface is in slot 8 */
ae8f3104 133 if (deviceslot[i] == NULL) {
a8105c1b
VB
134 if (!(
135 POKE_UINT16(8) &&
136 POKE_UINT16(if_nametoindex(hardware->h_ifname))))
137 goto toobig;
43c02e7b 138 }
a8105c1b
VB
139 if (!(
140 POKE_UINT16(0) && /* vchassis */
141 POKE_UINT32(0) && POKE_UINT16(0) && /* Reserved */
142 /* Version */
143 POKE_BYTES(edp_fakeversion, sizeof(edp_fakeversion)) &&
144 /* Connections, we say that we won't
145 have more interfaces than this
146 mask. */
147 POKE_UINT32(0xffffffff) &&
148 POKE_UINT32(0) && POKE_UINT32(0) && POKE_UINT32(0) &&
149 POKE_END_EDP_TLV))
150 goto toobig;
151
a1347cd8 152#ifdef ENABLE_DOT1
43c02e7b
VB
153 break;
154 case 1:
43c02e7b
VB
155 TAILQ_FOREACH(vlan, &hardware->h_lport.p_vlans,
156 v_entries) {
a8105c1b
VB
157 v++;
158 if (!(
159 POKE_START_EDP_TLV(EDP_TLV_VLAN) &&
160 POKE_UINT8(0) && /* Flags: no IP address */
161 POKE_UINT8(0) && /* Reserved */
162 POKE_UINT16(vlan->v_vid) &&
163 POKE_UINT32(0) && /* Reserved */
164 POKE_UINT32(0) && /* IP address */
165 /* VLAN name */
166 POKE_BYTES(vlan->v_name, strlen(vlan->v_name)) &&
167 POKE_UINT8(0) &&
168 POKE_END_EDP_TLV))
169 goto toobig;
43c02e7b
VB
170 }
171 break;
172 }
173
7c11435e 174 if ((state == 1) && (v == 0)) /* No VLAN, no need to send another TLV */
43c02e7b 175 break;
a1347cd8 176#endif
43c02e7b
VB
177
178 /* Null TLV */
a8105c1b
VB
179 if (!(
180 POKE_START_EDP_TLV(EDP_TLV_NULL) &&
181 POKE_END_EDP_TLV &&
182 POKE_SAVE(end)))
183 goto toobig;
43c02e7b
VB
184
185 /* Compute len and checksum */
a8105c1b
VB
186 i = end - pos_llc; /* Ethernet length */
187 v = end - pos_edp; /* EDP length */
188 POKE_RESTORE(pos_len_eh);
189 if (!(POKE_UINT16(i))) goto toobig;
190 POKE_RESTORE(pos_len_edp);
191 if (!(POKE_UINT16(v))) goto toobig;
192 checksum = frame_checksum(pos_edp, v, 0);
193 if (!(POKE_UINT16(ntohs(checksum)))) goto toobig;
43c02e7b 194
0bc32943 195 if (write(hardware->h_raw, packet, end - packet) == -1) {
43c02e7b
VB
196 LLOG_WARN("unable to send packet on real device for %s",
197 hardware->h_ifname);
a8105c1b 198 free(packet);
43c02e7b
VB
199 return ENETDOWN;
200 }
a8105c1b 201 free(packet);
a1347cd8
VB
202
203#ifdef ENABLE_DOT1
43c02e7b
VB
204 state++;
205 }
a1347cd8 206#endif
43c02e7b
VB
207
208 hardware->h_tx_cnt++;
43c02e7b 209 return 0;
a8105c1b
VB
210 toobig:
211 free(packet);
212 return E2BIG;
43c02e7b
VB
213}
214
a8105c1b
VB
215#define CHECK_TLV_SIZE(x, name) \
216 do { if (tlv_len < (x)) { \
217 LLOG_WARNX(name " EDP TLV too short received on %s",\
218 hardware->h_ifname); \
219 goto malformed; \
220 } } while (0)
221
43c02e7b
VB
222int
223edp_decode(struct lldpd *cfg, char *frame, int s,
224 struct lldpd_hardware *hardware,
225 struct lldpd_chassis **newchassis, struct lldpd_port **newport)
226{
227 struct lldpd_chassis *chassis;
228 struct lldpd_port *port;
a1347cd8 229#ifdef ENABLE_DOT1
a8105c1b 230 struct lldpd_vlan *lvlan = NULL, *lvlan_next;
a1347cd8 231#endif
43c02e7b 232 const unsigned char edpaddr[] = EDP_MULTICAST_ADDR;
a8105c1b
VB
233 int length, gotend = 0, gotvlans = 0, edp_len, tlv_len, tlv_type;
234 int edp_port, edp_slot;
235 u_int8_t *pos, *pos_edp, *tlv;
236 u_int8_t version[4];
237 struct in_addr address;
43c02e7b
VB
238
239 if ((chassis = calloc(1, sizeof(struct lldpd_chassis))) == NULL) {
240 LLOG_WARN("failed to allocate remote chassis");
241 return -1;
242 }
243 if ((port = calloc(1, sizeof(struct lldpd_port))) == NULL) {
244 LLOG_WARN("failed to allocate remote port");
245 free(chassis);
246 return -1;
247 }
a1347cd8 248#ifdef ENABLE_DOT1
43c02e7b 249 TAILQ_INIT(&port->p_vlans);
a1347cd8 250#endif
43c02e7b 251
a8105c1b
VB
252 length = s;
253 pos = (u_int8_t*)frame;
254
255 if (length < 2*ETH_ALEN + sizeof(u_int16_t) + 8 /* LLC */ +
256 10 + ETH_ALEN /* EDP header */) {
257 LLOG_WARNX("too short EDP frame received on %s", hardware->h_ifname);
43c02e7b
VB
258 goto malformed;
259 }
260
a8105c1b 261 if (PEEK_CMP(edpaddr, sizeof(edpaddr)) != 0) {
43c02e7b
VB
262 LLOG_INFO("frame not targeted at EDP multicast address received on %s",
263 hardware->h_ifname);
264 goto malformed;
265 }
a8105c1b
VB
266 PEEK_DISCARD(ETH_ALEN); PEEK_DISCARD_UINT16;
267 PEEK_DISCARD(6); /* LLC: DSAP + SSAP + control + org */
268 if (PEEK_UINT16 != LLC_PID_EDP) {
43c02e7b
VB
269 LLOG_DEBUG("incorrect LLC protocol ID received on %s",
270 hardware->h_ifname);
271 goto malformed;
272 }
273
a8105c1b
VB
274 PEEK_SAVE(pos_edp); /* Save the start of EDP packet */
275 if (PEEK_UINT8 != 1) {
276 LLOG_WARNX("incorrect EDP version for frame received on %s",
277 hardware->h_ifname);
43c02e7b
VB
278 goto malformed;
279 }
a8105c1b
VB
280 PEEK_DISCARD_UINT8; /* Reserved */
281 edp_len = PEEK_UINT16;
282 PEEK_DISCARD_UINT16; /* Checksum */
283 PEEK_DISCARD_UINT16; /* Sequence */
284 if (PEEK_UINT16 != 0) { /* ID Type = 0 = MAC */
43c02e7b
VB
285 LLOG_WARNX("incorrect device id type for frame received on %s",
286 hardware->h_ifname);
287 goto malformed;
288 }
a8105c1b 289 if (edp_len > length + 10) {
43c02e7b
VB
290 LLOG_WARNX("incorrect size for EDP frame received on %s",
291 hardware->h_ifname);
292 goto malformed;
293 }
294 chassis->c_ttl = LLDPD_TTL;
295 chassis->c_id_subtype = LLDP_CHASSISID_SUBTYPE_LLADDR;
296 chassis->c_id_len = ETH_ALEN;
297 if ((chassis->c_id = (char *)malloc(ETH_ALEN)) == NULL) {
298 LLOG_WARN("unable to allocate memory for chassis ID");
299 goto malformed;
300 }
a8105c1b
VB
301 PEEK_BYTES(chassis->c_id, ETH_ALEN);
302
303 /* Let's check checksum */
304 if (frame_checksum(pos_edp, edp_len, 0) != 0) {
43c02e7b
VB
305 LLOG_WARNX("incorrect EDP checksum for frame received on %s",
306 hardware->h_ifname);
307 goto malformed;
308 }
309
a8105c1b
VB
310 while (length && !gotend) {
311 if (length < 4) {
43c02e7b
VB
312 LLOG_WARNX("EDP TLV header is too large for "
313 "frame received on %s",
314 hardware->h_ifname);
315 goto malformed;
316 }
a8105c1b
VB
317 if (PEEK_UINT8 != EDP_TLV_MARKER) {
318 LLOG_WARNX("incorrect marker starting EDP TLV header for frame "
319 "received on %s",
320 hardware->h_ifname);
321 goto malformed;
322 }
323 tlv_type = PEEK_UINT8;
324 tlv_len = PEEK_UINT16 - 4;
325 PEEK_SAVE(tlv);
326 if ((tlv_len < 0) || (tlv_len > length)) {
43c02e7b
VB
327 LLOG_DEBUG("incorrect size in EDP TLV header for frame "
328 "received on %s",
329 hardware->h_ifname);
330 /* Some poor old Extreme Summit are quite bogus */
331 gotend = 1;
332 break;
333 }
a8105c1b 334 switch (tlv_type) {
43c02e7b 335 case EDP_TLV_INFO:
a8105c1b 336 CHECK_TLV_SIZE(32, "Info");
43c02e7b 337 port->p_id_subtype = LLDP_PORTID_SUBTYPE_IFNAME;
a8105c1b 338 edp_slot = PEEK_UINT16; edp_port = PEEK_UINT16;
43c02e7b 339 if (asprintf(&port->p_id, "%d/%d",
a8105c1b 340 edp_slot + 1, edp_port + 1) == -1) {
43c02e7b
VB
341 LLOG_WARN("unable to allocate memory for "
342 "port ID");
343 goto malformed;
344 }
345 port->p_id_len = strlen(port->p_id);
346 if (asprintf(&port->p_descr, "Slot %d / Port %d",
a8105c1b 347 edp_slot + 1, edp_port + 1) == -1) {
43c02e7b
VB
348 LLOG_WARN("unable to allocate memory for "
349 "port description");
350 goto malformed;
351 }
a8105c1b
VB
352 PEEK_DISCARD_UINT16; /* vchassis */
353 PEEK_DISCARD(6); /* Reserved */
354 PEEK_BYTES(version, 4);
43c02e7b
VB
355 if (asprintf(&chassis->c_descr,
356 "EDP enabled device, version %d.%d.%d.%d",
a8105c1b
VB
357 version[0], version[1],
358 version[2], version[3]) == -1) {
43c02e7b
VB
359 LLOG_WARN("unable to allocate memory for "
360 "chassis description");
361 goto malformed;
362 }
363 break;
364 case EDP_TLV_DISPLAY:
a8105c1b 365 if ((chassis->c_name = (char *)calloc(1, tlv_len + 1)) == NULL) {
43c02e7b
VB
366 LLOG_WARN("unable to allocate memory for chassis "
367 "name");
368 goto malformed;
369 }
370 /* TLV display contains a lot of garbage */
a8105c1b 371 PEEK_BYTES(chassis->c_name, tlv_len);
43c02e7b
VB
372 break;
373 case EDP_TLV_NULL:
a8105c1b 374 if (tlv_len != 0) {
43c02e7b
VB
375 LLOG_WARNX("null tlv with incorrect size in frame "
376 "received on %s",
377 hardware->h_ifname);
378 goto malformed;
379 }
a8105c1b 380 if (length)
43c02e7b
VB
381 LLOG_DEBUG("extra data after edp frame on %s",
382 hardware->h_ifname);
383 gotend = 1;
384 break;
385 case EDP_TLV_VLAN:
a1347cd8 386#ifdef ENABLE_DOT1
a8105c1b 387 CHECK_TLV_SIZE(12, "VLAN");
43c02e7b
VB
388 if ((lvlan = (struct lldpd_vlan *)calloc(1,
389 sizeof(struct lldpd_vlan))) == NULL) {
390 LLOG_WARN("unable to allocate vlan");
391 goto malformed;
392 }
a8105c1b
VB
393 PEEK_DISCARD_UINT16; /* Flags + reserved */
394 lvlan->v_vid = PEEK_UINT16; /* VID */
395 PEEK_DISCARD(4); /* Reserved */
396 PEEK_BYTES(&address, sizeof(address));
397
398 if ((lvlan->v_name = (char *)calloc(1,
399 tlv_len + 1 - 12)) == NULL) {
43c02e7b 400 LLOG_WARN("unable to allocate vlan name");
a8105c1b 401 free(lvlan);
43c02e7b
VB
402 goto malformed;
403 }
a8105c1b
VB
404 PEEK_BYTES(lvlan->v_name, tlv_len - 12);
405
406 if (address.s_addr != INADDR_ANY) {
43c02e7b 407 if (chassis->c_mgmt.s_addr == INADDR_ANY)
a8105c1b 408 chassis->c_mgmt.s_addr = address.s_addr;
43c02e7b
VB
409 else
410 /* We need to guess the good one */
411 if (cfg->g_mgmt_pattern != NULL) {
412 /* We can try to use this to prefer an address */
413 char *ip;
a8105c1b 414 ip = inet_ntoa(address);
43c02e7b
VB
415 if (fnmatch(cfg->g_mgmt_pattern,
416 ip, 0) == 0)
a8105c1b 417 chassis->c_mgmt.s_addr = address.s_addr;
43c02e7b
VB
418 }
419 }
420 TAILQ_INSERT_TAIL(&port->p_vlans,
421 lvlan, v_entries);
a1347cd8 422#endif
43c02e7b
VB
423 gotvlans = 1;
424 break;
425 default:
426 LLOG_DEBUG("unknown EDP TLV type (%d) received on %s",
a8105c1b 427 tlv_type, hardware->h_ifname);
37387046 428 hardware->h_rx_unrecognized_cnt++;
43c02e7b 429 }
a8105c1b 430 PEEK_DISCARD(tlv + tlv_len - pos);
43c02e7b
VB
431 }
432 if ((chassis->c_id == NULL) ||
433 (port->p_id == NULL) ||
434 (chassis->c_name == NULL) ||
435 (chassis->c_descr == NULL) ||
436 (port->p_descr == NULL) ||
437 (gotend == 0)) {
a1347cd8 438#ifdef ENABLE_DOT1
43c02e7b
VB
439 if (gotvlans && gotend) {
440 /* VLAN can be sent in a separate frames. We need to add
441 * those vlans to an existing chassis */
442 if (hardware->h_rchassis &&
443 (hardware->h_rchassis->c_id_subtype == chassis->c_id_subtype) &&
444 (hardware->h_rchassis->c_id_len == chassis->c_id_len) &&
445 (memcmp(hardware->h_rchassis->c_id, chassis->c_id,
446 chassis->c_id_len) == 0)) {
447 /* We attach the VLANs to current hardware */
448 lldpd_vlan_cleanup(hardware->h_rport);
449 for (lvlan = TAILQ_FIRST(&port->p_vlans);
450 lvlan != NULL;
451 lvlan = lvlan_next) {
452 lvlan_next = TAILQ_NEXT(lvlan, v_entries);
453 TAILQ_REMOVE(&port->p_vlans, lvlan, v_entries);
454 TAILQ_INSERT_TAIL(&hardware->h_rport->p_vlans,
455 lvlan, v_entries);
456 }
457 /* And the IP address */
458 hardware->h_rchassis->c_mgmt.s_addr =
459 chassis->c_mgmt.s_addr;
460 }
461 /* We discard the remaining frame */
462 goto malformed;
463 }
a1347cd8
VB
464#else
465 if (gotvlans)
466 goto malformed;
467#endif
43c02e7b
VB
468 LLOG_WARNX("some mandatory tlv are missing for frame received on %s",
469 hardware->h_ifname);
470 goto malformed;
471 }
472 *newchassis = chassis;
473 *newport = port;
474 return 1;
475
476malformed:
d3322e23 477 lldpd_chassis_cleanup(chassis);
a0edeaf8 478 lldpd_port_cleanup(port, 1);
43c02e7b
VB
479 return -1;
480}
4bad1937
VB
481
482#endif /* ENABLE_EDP */