]> git.ipfire.org Git - thirdparty/lldpd.git/blob - src/daemon/protocols/sonmp.c
Allow configuring tx-interval in milliseconds
[thirdparty/lldpd.git] / src / daemon / protocols / sonmp.c
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_SONMP
22
23 #include <stdio.h>
24 #include <unistd.h>
25 #include <errno.h>
26 #include <arpa/inet.h>
27
28 static struct sonmp_chassis sonmp_chassis_types[] = {
29 {1, "unknown (via SONMP)"},
30 {2, "Nortel 3000"},
31 {3, "Nortel 3030"},
32 {4, "Nortel 2310"},
33 {5, "Nortel 2810"},
34 {6, "Nortel 2912"},
35 {7, "Nortel 2914"},
36 {8, "Nortel 271x"},
37 {9, "Nortel 2813"},
38 {10, "Nortel 2814"},
39 {11, "Nortel 2915"},
40 {12, "Nortel 5000"},
41 {13, "Nortel 2813SA"},
42 {14, "Nortel 2814SA"},
43 {15, "Nortel 810M"},
44 {16, "Nortel EtherCell"},
45 {17, "Nortel 5005"},
46 {18, "Alcatel Ethernet workgroup conc."},
47 {20, "Nortel 2715SA"},
48 {21, "Nortel 2486"},
49 {22, "Nortel 28000 series"},
50 {23, "Nortel 23000 series"},
51 {24, "Nortel 5DN00x series"},
52 {25, "BayStack Ethernet"},
53 {26, "Nortel 23100 series"},
54 {27, "Nortel 100Base-T Hub"},
55 {28, "Nortel 3000 Fast Ethernet"},
56 {29, "Nortel Orion switch"},
57 {30, "unknown"},
58 {31, "Nortel DDS "},
59 {32, "Nortel Centillion"},
60 {33, "Nortel Centillion"},
61 {34, "Nortel Centillion"},
62 {35, "BayStack 301"},
63 {36, "BayStack TokenRing Hub"},
64 {37, "Nortel FVC Multimedia Switch"},
65 {38, "Nortel Switch Node"},
66 {39, "BayStack 302 Switch"},
67 {40, "BayStack 350 Switch"},
68 {41, "BayStack 150 Ethernet Hub"},
69 {42, "Nortel Centillion 50N switch"},
70 {43, "Nortel Centillion 50T switch"},
71 {44, "BayStack 303 and 304 Switches"},
72 {45, "BayStack 200 Ethernet Hub"},
73 {46, "BayStack 250 10/100 Ethernet Hub"},
74 {48, "BayStack 450 10/100/1000 Switches"},
75 {49, "BayStack 410 10/100 Switches"},
76 {50, "Nortel Ethernet Routing 1200 L3 Switch"},
77 {51, "Nortel Ethernet Routing 1250 L3 Switch"},
78 {52, "Nortel Ethernet Routing 1100 L3 Switch"},
79 {53, "Nortel Ethernet Routing 1150 L3 Switch"},
80 {54, "Nortel Ethernet Routing 1050 L3 Switch"},
81 {55, "Nortel Ethernet Routing 1051 L3 Switch"},
82 {56, "Nortel Ethernet Routing 8610 L3 Switch"},
83 {57, "Nortel Ethernet Routing 8606 L3 Switch"},
84 {58, "Nortel Ethernet Routing Switch 8010"},
85 {59, "Nortel Ethernet Routing Switch 8006"},
86 {60, "BayStack 670 wireless access point"},
87 {61, "Nortel Ethernet Routing Switch 740 "},
88 {62, "Nortel Ethernet Routing Switch 750 "},
89 {63, "Nortel Ethernet Routing Switch 790"},
90 {64, "Nortel Business Policy Switch 2000 10/100 Switches"},
91 {65, "Nortel Ethernet Routing 8110 L2 Switch"},
92 {66, "Nortel Ethernet Routing 8106 L2 Switch"},
93 {67, "BayStack 3580 Gig Switch"},
94 {68, "BayStack 10 Power Supply Unit"},
95 {69, "BayStack 420 10/100 Switch"},
96 {70, "OPTera Metro 1200 Ethernet Service Module"},
97 {71, "Nortel Ethernet Routing Switch 8010co"},
98 {72, "Nortel Ethernet Routing 8610co L3 switch"},
99 {73, "Nortel Ethernet Routing 8110co L2 switch"},
100 {74, "Nortel Ethernet Routing 8003"},
101 {75, "Nortel Ethernet Routing 8603 L3 switch"},
102 {76, "Nortel Ethernet Routing 8103 L2 switch"},
103 {77, "BayStack 380 10/100/1000 Switch"},
104 {78, "Nortel Ethernet Switch 470-48T"},
105 {79, "OPTera Metro 1450 Ethernet Service Module"},
106 {80, "OPTera Metro 1400 Ethernet Service Module"},
107 {81, "Alteon Switch Family"},
108 {82, "Ethernet Switch 460-24T-PWR"},
109 {83, "OPTera Metro 8010 OPM L2 Switch"},
110 {84, "OPTera Metro 8010co OPM L2 Switch"},
111 {85, "OPTera Metro 8006 OPM L2 Switch"},
112 {86, "OPTera Metro 8003 OPM L2 Switch"},
113 {87, "Alteon 180e"},
114 {88, "Alteon AD3"},
115 {89, "Alteon 184"},
116 {90, "Alteon AD4"},
117 {91, "Nortel Ethernet Routing 1424 L3 switch"},
118 {92, "Nortel Ethernet Routing 1648 L3 switch"},
119 {93, "Nortel Ethernet Routing 1612 L3 switch"},
120 {94, "Nortel Ethernet Routing 1624 L3 switch "},
121 {95, "BayStack 380-24F Fiber 1000 Switch"},
122 {96, "Nortel Ethernet Routing Switch 5510-24T"},
123 {97, "Nortel Ethernet Routing Switch 5510-48T"},
124 {98, "Nortel Ethernet Switch 470-24T"},
125 {99, "Nortel Networks Wireless LAN Access Point 2220"},
126 {100, "Ethernet Routing RBS 2402 L3 switch"},
127 {101, "Alteon Application Switch 2424 "},
128 {102, "Alteon Application Switch 2224 "},
129 {103, "Alteon Application Switch 2208 "},
130 {104, "Alteon Application Switch 2216"},
131 {105, "Alteon Application Switch 3408"},
132 {106, "Alteon Application Switch 3416"},
133 {107, "Nortel Networks Wireless LAN SecuritySwitch 2250"},
134 {108, "Ethernet Switch 425-48T"},
135 {109, "Ethernet Switch 425-24T"},
136 {110, "Nortel Networks Wireless LAN Access Point 2221"},
137 {111, "Nortel Metro Ethernet Service Unit 24-T SPF switch"},
138 {112, "Nortel Metro Ethernet Service Unit 24-T LX DC switch"},
139 {113, "Nortel Ethernet Routing Switch 8300 10-slot chassis"},
140 {114, "Nortel Ethernet Routing Switch 8300 6-slot chassis"},
141 {115, "Nortel Ethernet Routing Switch 5520-24T-PWR"},
142 {116, "Nortel Ethernet Routing Switch 5520-48T-PWR"},
143 {117, "Nortel Networks VPN Gateway 3050"},
144 {118, "Alteon SSL 310 10/100"},
145 {119, "Alteon SSL 310 10/100 Fiber"},
146 {120, "Alteon SSL 310 10/100 FIPS"},
147 {121, "Alteon SSL 410 10/100/1000"},
148 {122, "Alteon SSL 410 10/100/1000 Fiber"},
149 {123, "Alteon Application Switch 2424-SSL"},
150 {124, "Nortel Ethernet Switch 325-24T"},
151 {125, "Nortel Ethernet Switch 325-24G"},
152 {126, "Nortel Networks Wireless LAN Access Point 2225"},
153 {127, "Nortel Networks Wireless LAN SecuritySwitch 2270"},
154 {128, "Nortel 24-port Ethernet Switch 470-24T-PWR"},
155 {129, "Nortel 48-port Ethernet Switch 470-48T-PWR"},
156 {130, "Nortel Ethernet Routing Switch 5530-24TFD"},
157 {131, "Nortel Ethernet Switch 3510-24T"},
158 {132, "Nortel Metro Ethernet Service Unit 12G AC L3 switch"},
159 {133, "Nortel Metro Ethernet Service Unit 12G DC L3 switch"},
160 {134, "Nortel Secure Access Switch"},
161 {135, "Networks VPN Gateway 3070"},
162 {136, "OPTera Metro 3500"},
163 {137, "SMB BES 1010 24T"},
164 {138, "SMB BES 1010 48T"},
165 {139, "SMB BES 1020 24T PWR"},
166 {140, "SMB BES 1020 48T PWR"},
167 {141, "SMB BES 2010 24T"},
168 {142, "SMB BES 2010 48T"},
169 {143, "SMB BES 2020 24T PWR"},
170 {144, "SMB BES 2020 48T PWR"},
171 {145, "SMB BES 110 24T"},
172 {146, "SMB BES 110 48T"},
173 {147, "SMB BES 120 24T PWR"},
174 {148, "SMB BES 120 48T PWR"},
175 {149, "SMB BES 210 24T"},
176 {150, "SMB BES 210 48T"},
177 {151, "SMB BES 220 24T PWR"},
178 {152, "SMB BES 220 48T PWR"},
179 {153, "OME 6500"},
180 {0, "unknown (via SONMP)"},
181 };
182
183 int
184 sonmp_send(struct lldpd *global,
185 struct lldpd_hardware *hardware)
186 {
187 const u_int8_t mcastaddr[] = SONMP_MULTICAST_ADDR;
188 const u_int8_t llcorg[] = LLC_ORG_NORTEL;
189 struct lldpd_chassis *chassis;
190 struct lldpd_mgmt *mgmt;
191 u_int8_t *packet, *pos, *pos_pid, *end;
192 int length;
193 struct in_addr address;
194
195 log_debug("sonmp", "send SONMP PDU to %s",
196 hardware->h_ifname);
197
198 chassis = hardware->h_lport.p_chassis;
199 length = hardware->h_mtu;
200 if ((packet = (u_int8_t*)calloc(1, length)) == NULL)
201 return ENOMEM;
202 pos = packet;
203
204 /* Ethernet header */
205 if (!(
206 /* SONMP multicast address as target */
207 POKE_BYTES(mcastaddr, sizeof(mcastaddr)) &&
208 /* Source MAC addresss */
209 POKE_BYTES(&hardware->h_lladdr, ETHER_ADDR_LEN) &&
210 /* SONMP frame is of fixed size */
211 POKE_UINT16(SONMP_SIZE)))
212 goto toobig;
213
214 /* LLC header */
215 if (!(
216 /* DSAP and SSAP */
217 POKE_UINT8(0xaa) && POKE_UINT8(0xaa) &&
218 /* Control field */
219 POKE_UINT8(0x03) &&
220 /* ORG */
221 POKE_BYTES(llcorg, sizeof(llcorg)) &&
222 POKE_SAVE(pos_pid) && /* We will modify PID later to
223 create a new frame */
224 POKE_UINT16(LLC_PID_SONMP_HELLO)))
225 goto toobig;
226
227
228 address.s_addr = htonl(INADDR_ANY);
229 TAILQ_FOREACH(mgmt, &chassis->c_mgmt, m_entries) {
230 if (mgmt->m_family == LLDPD_AF_IPV4) {
231 address.s_addr = mgmt->m_addr.inet.s_addr;
232 }
233 break;
234 }
235
236 /* SONMP */
237 if (!(
238 /* Our IP address */
239 POKE_BYTES(&address, sizeof(struct in_addr)) &&
240 /* Segment on three bytes, we don't have slots, so we
241 skip the first two bytes */
242 POKE_UINT16(0) &&
243 POKE_UINT8(hardware->h_ifindex) &&
244 POKE_UINT8(1) && /* Chassis: Other */
245 POKE_UINT8(12) && /* Back: Ethernet, Fast Ethernet and Gigabit */
246 POKE_UINT8(SONMP_TOPOLOGY_NEW) && /* Should work. We have no state */
247 POKE_UINT8(1) && /* Links: Dunno what it is */
248 POKE_SAVE(end)))
249 goto toobig;
250
251 if (interfaces_send_helper(global, hardware,
252 (char *)packet, end - packet) == -1) {
253 log_warn("sonmp", "unable to send packet on real device for %s",
254 hardware->h_ifname);
255 free(packet);
256 return ENETDOWN;
257 }
258
259 POKE_RESTORE(pos_pid); /* Modify LLC PID */
260 (void)POKE_UINT16(LLC_PID_SONMP_FLATNET);
261 POKE_RESTORE(packet); /* Go to the beginning */
262 PEEK_DISCARD(ETHER_ADDR_LEN - 1); /* Modify the last byte of the MAC address */
263 (void)POKE_UINT8(1);
264
265 if (interfaces_send_helper(global, hardware,
266 (char *)packet, end - packet) == -1) {
267 log_warn("sonmp", "unable to send second SONMP packet on real device for %s",
268 hardware->h_ifname);
269 free(packet);
270 return ENETDOWN;
271 }
272
273 free(packet);
274 hardware->h_tx_cnt++;
275 return 0;
276 toobig:
277 free(packet);
278 return -1;
279 }
280
281 int
282 sonmp_decode(struct lldpd *cfg, char *frame, int s,
283 struct lldpd_hardware *hardware,
284 struct lldpd_chassis **newchassis, struct lldpd_port **newport)
285 {
286 const u_int8_t mcastaddr[] = SONMP_MULTICAST_ADDR;
287 struct lldpd_chassis *chassis;
288 struct lldpd_port *port;
289 struct lldpd_mgmt *mgmt;
290 int length, i;
291 u_int8_t *pos;
292 u_int8_t seg[3], rchassis;
293 struct in_addr address;
294
295 log_debug("sonmp", "decode SONMP PDU from %s",
296 hardware->h_ifname);
297
298 if ((chassis = calloc(1, sizeof(struct lldpd_chassis))) == NULL) {
299 log_warn("sonmp", "failed to allocate remote chassis");
300 return -1;
301 }
302 TAILQ_INIT(&chassis->c_mgmt);
303 if ((port = calloc(1, sizeof(struct lldpd_port))) == NULL) {
304 log_warn("sonmp", "failed to allocate remote port");
305 free(chassis);
306 return -1;
307 }
308 #ifdef ENABLE_DOT1
309 TAILQ_INIT(&port->p_vlans);
310 #endif
311
312 length = s;
313 pos = (u_int8_t*)frame;
314 if (length < SONMP_SIZE) {
315 log_warnx("sonmp", "too short SONMP frame received on %s", hardware->h_ifname);
316 goto malformed;
317 }
318 if (PEEK_CMP(mcastaddr, sizeof(mcastaddr)) != 0)
319 /* There is two multicast address. We just handle only one of
320 * them. */
321 goto malformed;
322 /* We skip to LLC PID */
323 PEEK_DISCARD(ETHER_ADDR_LEN); PEEK_DISCARD_UINT16;
324 PEEK_DISCARD(6);
325 if (PEEK_UINT16 != LLC_PID_SONMP_HELLO) {
326 log_debug("sonmp", "incorrect LLC protocol ID received for SONMP on %s",
327 hardware->h_ifname);
328 goto malformed;
329 }
330
331 chassis->c_id_subtype = LLDP_CHASSISID_SUBTYPE_ADDR;
332 if ((chassis->c_id = calloc(1, sizeof(struct in_addr) + 1)) == NULL) {
333 log_warn("sonmp", "unable to allocate memory for chassis id on %s",
334 hardware->h_ifname);
335 goto malformed;
336 }
337 chassis->c_id_len = sizeof(struct in_addr) + 1;
338 chassis->c_id[0] = 1;
339 PEEK_BYTES(&address, sizeof(struct in_addr));
340 memcpy(chassis->c_id + 1, &address, sizeof(struct in_addr));
341 if (asprintf(&chassis->c_name, "%s", inet_ntoa(address)) == -1) {
342 log_warnx("sonmp", "unable to write chassis name for %s",
343 hardware->h_ifname);
344 goto malformed;
345 }
346 PEEK_BYTES(seg, sizeof(seg));
347 rchassis = PEEK_UINT8;
348 for (i=0; sonmp_chassis_types[i].type != 0; i++) {
349 if (sonmp_chassis_types[i].type == rchassis)
350 break;
351 }
352 if (asprintf(&chassis->c_descr, "%s",
353 sonmp_chassis_types[i].description) == -1) {
354 log_warnx("sonmp", "unable to write chassis description for %s",
355 hardware->h_ifname);
356 goto malformed;
357 }
358 mgmt = lldpd_alloc_mgmt(LLDPD_AF_IPV4, &address, sizeof(struct in_addr), 0);
359 if (mgmt == NULL) {
360 if (errno == ENOMEM)
361 log_warn("sonmp", "unable to allocate memory for management address");
362 else
363 log_warn("sonmp", "too large management address received on %s",
364 hardware->h_ifname);
365 goto malformed;
366 }
367 TAILQ_INSERT_TAIL(&chassis->c_mgmt, mgmt, m_entries);
368 port->p_ttl = cfg?(cfg->g_config.c_tx_interval * cfg->g_config.c_tx_hold):
369 LLDPD_TTL;
370 port->p_ttl = (port->p_ttl + 999) / 1000;
371
372 port->p_id_subtype = LLDP_PORTID_SUBTYPE_LOCAL;
373 if (asprintf(&port->p_id, "%02x-%02x-%02x",
374 seg[0], seg[1], seg[2]) == -1) {
375 log_warn("sonmp", "unable to allocate memory for port id on %s",
376 hardware->h_ifname);
377 goto malformed;
378 }
379 port->p_id_len = strlen(port->p_id);
380
381 /* Port description depend on the number of segments */
382 if ((seg[0] == 0) && (seg[1] == 0)) {
383 if (asprintf(&port->p_descr, "port %d",
384 seg[2]) == -1) {
385 log_warnx("sonmp", "unable to write port description for %s",
386 hardware->h_ifname);
387 goto malformed;
388 }
389 } else if (seg[0] == 0) {
390 if (asprintf(&port->p_descr, "port %d/%d",
391 seg[1], seg[2]) == -1) {
392 log_warnx("sonmp", "unable to write port description for %s",
393 hardware->h_ifname);
394 goto malformed;
395 }
396 } else {
397 if (asprintf(&port->p_descr, "port %x:%x:%x",
398 seg[0], seg[1], seg[2]) == -1) {
399 log_warnx("sonmp", "unable to write port description for %s",
400 hardware->h_ifname);
401 goto malformed;
402 }
403 }
404 *newchassis = chassis;
405 *newport = port;
406 return 1;
407
408 malformed:
409 lldpd_chassis_cleanup(chassis, 1);
410 lldpd_port_cleanup(port, 1);
411 free(port);
412 return -1;
413 }
414
415 #endif /* ENABLE_SONMP */