Coverage Report

Created: 2026-01-09 07:09

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