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