1 /* -*- mode: c; c-file-style: "openbsd" -*- */
3 * Copyright (c) 2008 Vincent Bernat <bernat@luffy.cx>
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.
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.
26 #include <arpa/inet.h>
28 static struct sonmp_chassis sonmp_chassis_types
[] = {
29 {1, "unknown (via SONMP)"},
41 {13, "Nortel 2813SA"},
42 {14, "Nortel 2814SA"},
44 {16, "Nortel EtherCell"},
46 {18, "Alcatel Ethernet workgroup conc."},
47 {20, "Nortel 2715SA"},
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"},
59 {32, "Nortel Centillion"},
60 {33, "Nortel Centillion"},
61 {34, "Nortel Centillion"},
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"},
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"},
180 {0, "unknown (via SONMP)"},
184 sonmp_send(struct lldpd
*global
,
185 struct lldpd_hardware
*hardware
)
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
;
193 struct in_addr address
;
195 log_debug("sonmp", "send SONMP PDU to %s",
198 chassis
= hardware
->h_lport
.p_chassis
;
199 length
= hardware
->h_mtu
;
200 if ((packet
= (u_int8_t
*)calloc(1, length
)) == NULL
)
204 /* Ethernet header */
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
)))
217 POKE_UINT8(0xaa) && POKE_UINT8(0xaa) &&
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
)))
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
;
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 */
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 */
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",
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 */
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",
274 hardware
->h_tx_cnt
++;
282 sonmp_decode(struct lldpd
*cfg
, char *frame
, int s
,
283 struct lldpd_hardware
*hardware
,
284 struct lldpd_chassis
**newchassis
, struct lldpd_port
**newport
)
286 const u_int8_t mcastaddr
[] = SONMP_MULTICAST_ADDR
;
287 struct lldpd_chassis
*chassis
;
288 struct lldpd_port
*port
;
289 struct lldpd_mgmt
*mgmt
;
292 u_int8_t seg
[3], rchassis
;
293 struct in_addr address
;
295 log_debug("sonmp", "decode SONMP PDU from %s",
298 if ((chassis
= calloc(1, sizeof(struct lldpd_chassis
))) == NULL
) {
299 log_warn("sonmp", "failed to allocate remote chassis");
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");
309 TAILQ_INIT(&port
->p_vlans
);
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
);
318 if (PEEK_CMP(mcastaddr
, sizeof(mcastaddr
)) != 0)
319 /* There is two multicast address. We just handle only one of
322 /* We skip to LLC PID */
323 PEEK_DISCARD(ETHER_ADDR_LEN
); PEEK_DISCARD_UINT16
;
325 if (PEEK_UINT16
!= LLC_PID_SONMP_HELLO
) {
326 log_debug("sonmp", "incorrect LLC protocol ID received for SONMP on %s",
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",
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",
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
)
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",
358 mgmt
= lldpd_alloc_mgmt(LLDPD_AF_IPV4
, &address
, sizeof(struct in_addr
), 0);
361 log_warn("sonmp", "unable to allocate memory for management address");
363 log_warn("sonmp", "too large management address received on %s",
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
):
370 port
->p_ttl
= (port
->p_ttl
+ 999) / 1000;
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",
379 port
->p_id_len
= strlen(port
->p_id
);
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",
385 log_warnx("sonmp", "unable to write port description for %s",
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",
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",
404 *newchassis
= chassis
;
409 lldpd_chassis_cleanup(chassis
, 1);
410 lldpd_port_cleanup(port
, 1);
415 #endif /* ENABLE_SONMP */