summaryrefslogtreecommitdiffstats
path: root/src/daemon/protocols/sonmp.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/daemon/protocols/sonmp.c')
-rw-r--r--src/daemon/protocols/sonmp.c410
1 files changed, 410 insertions, 0 deletions
diff --git a/src/daemon/protocols/sonmp.c b/src/daemon/protocols/sonmp.c
new file mode 100644
index 0000000..34ebcd7
--- /dev/null
+++ b/src/daemon/protocols/sonmp.c
@@ -0,0 +1,410 @@
+/* -*- mode: c; c-file-style: "openbsd" -*- */
+/*
+ * Copyright (c) 2008 Vincent Bernat <bernat@luffy.cx>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "../lldpd.h"
+#include "../frame.h"
+
+#ifdef ENABLE_SONMP
+
+# include <stdio.h>
+# include <unistd.h>
+# include <errno.h>
+# include <arpa/inet.h>
+
+static struct sonmp_chassis sonmp_chassis_types[] = {
+ { 1, "unknown (via SONMP)" },
+ { 2, "Nortel 3000" },
+ { 3, "Nortel 3030" },
+ { 4, "Nortel 2310" },
+ { 5, "Nortel 2810" },
+ { 6, "Nortel 2912" },
+ { 7, "Nortel 2914" },
+ { 8, "Nortel 271x" },
+ { 9, "Nortel 2813" },
+ { 10, "Nortel 2814" },
+ { 11, "Nortel 2915" },
+ { 12, "Nortel 5000" },
+ { 13, "Nortel 2813SA" },
+ { 14, "Nortel 2814SA" },
+ { 15, "Nortel 810M" },
+ { 16, "Nortel EtherCell" },
+ { 17, "Nortel 5005" },
+ { 18, "Alcatel Ethernet workgroup conc." },
+ { 20, "Nortel 2715SA" },
+ { 21, "Nortel 2486" },
+ { 22, "Nortel 28000 series" },
+ { 23, "Nortel 23000 series" },
+ { 24, "Nortel 5DN00x series" },
+ { 25, "BayStack Ethernet" },
+ { 26, "Nortel 23100 series" },
+ { 27, "Nortel 100Base-T Hub" },
+ { 28, "Nortel 3000 Fast Ethernet" },
+ { 29, "Nortel Orion switch" },
+ { 30, "unknown" },
+ { 31, "Nortel DDS " },
+ { 32, "Nortel Centillion" },
+ { 33, "Nortel Centillion" },
+ { 34, "Nortel Centillion" },
+ { 35, "BayStack 301" },
+ { 36, "BayStack TokenRing Hub" },
+ { 37, "Nortel FVC Multimedia Switch" },
+ { 38, "Nortel Switch Node" },
+ { 39, "BayStack 302 Switch" },
+ { 40, "BayStack 350 Switch" },
+ { 41, "BayStack 150 Ethernet Hub" },
+ { 42, "Nortel Centillion 50N switch" },
+ { 43, "Nortel Centillion 50T switch" },
+ { 44, "BayStack 303 and 304 Switches" },
+ { 45, "BayStack 200 Ethernet Hub" },
+ { 46, "BayStack 250 10/100 Ethernet Hub" },
+ { 48, "BayStack 450 10/100/1000 Switches" },
+ { 49, "BayStack 410 10/100 Switches" },
+ { 50, "Nortel Ethernet Routing 1200 L3 Switch" },
+ { 51, "Nortel Ethernet Routing 1250 L3 Switch" },
+ { 52, "Nortel Ethernet Routing 1100 L3 Switch" },
+ { 53, "Nortel Ethernet Routing 1150 L3 Switch" },
+ { 54, "Nortel Ethernet Routing 1050 L3 Switch" },
+ { 55, "Nortel Ethernet Routing 1051 L3 Switch" },
+ { 56, "Nortel Ethernet Routing 8610 L3 Switch" },
+ { 57, "Nortel Ethernet Routing 8606 L3 Switch" },
+ { 58, "Nortel Ethernet Routing Switch 8010" },
+ { 59, "Nortel Ethernet Routing Switch 8006" },
+ { 60, "BayStack 670 wireless access point" },
+ { 61, "Nortel Ethernet Routing Switch 740 " },
+ { 62, "Nortel Ethernet Routing Switch 750 " },
+ { 63, "Nortel Ethernet Routing Switch 790" },
+ { 64, "Nortel Business Policy Switch 2000 10/100 Switches" },
+ { 65, "Nortel Ethernet Routing 8110 L2 Switch" },
+ { 66, "Nortel Ethernet Routing 8106 L2 Switch" },
+ { 67, "BayStack 3580 Gig Switch" },
+ { 68, "BayStack 10 Power Supply Unit" },
+ { 69, "BayStack 420 10/100 Switch" },
+ { 70, "OPTera Metro 1200 Ethernet Service Module" },
+ { 71, "Nortel Ethernet Routing Switch 8010co" },
+ { 72, "Nortel Ethernet Routing 8610co L3 switch" },
+ { 73, "Nortel Ethernet Routing 8110co L2 switch" },
+ { 74, "Nortel Ethernet Routing 8003" },
+ { 75, "Nortel Ethernet Routing 8603 L3 switch" },
+ { 76, "Nortel Ethernet Routing 8103 L2 switch" },
+ { 77, "BayStack 380 10/100/1000 Switch" },
+ { 78, "Nortel Ethernet Switch 470-48T" },
+ { 79, "OPTera Metro 1450 Ethernet Service Module" },
+ { 80, "OPTera Metro 1400 Ethernet Service Module" },
+ { 81, "Alteon Switch Family" },
+ { 82, "Ethernet Switch 460-24T-PWR" },
+ { 83, "OPTera Metro 8010 OPM L2 Switch" },
+ { 84, "OPTera Metro 8010co OPM L2 Switch" },
+ { 85, "OPTera Metro 8006 OPM L2 Switch" },
+ { 86, "OPTera Metro 8003 OPM L2 Switch" },
+ { 87, "Alteon 180e" },
+ { 88, "Alteon AD3" },
+ { 89, "Alteon 184" },
+ { 90, "Alteon AD4" },
+ { 91, "Nortel Ethernet Routing 1424 L3 switch" },
+ { 92, "Nortel Ethernet Routing 1648 L3 switch" },
+ { 93, "Nortel Ethernet Routing 1612 L3 switch" },
+ { 94, "Nortel Ethernet Routing 1624 L3 switch " },
+ { 95, "BayStack 380-24F Fiber 1000 Switch" },
+ { 96, "Nortel Ethernet Routing Switch 5510-24T" },
+ { 97, "Nortel Ethernet Routing Switch 5510-48T" },
+ { 98, "Nortel Ethernet Switch 470-24T" },
+ { 99, "Nortel Networks Wireless LAN Access Point 2220" },
+ { 100, "Ethernet Routing RBS 2402 L3 switch" },
+ { 101, "Alteon Application Switch 2424 " },
+ { 102, "Alteon Application Switch 2224 " },
+ { 103, "Alteon Application Switch 2208 " },
+ { 104, "Alteon Application Switch 2216" },
+ { 105, "Alteon Application Switch 3408" },
+ { 106, "Alteon Application Switch 3416" },
+ { 107, "Nortel Networks Wireless LAN SecuritySwitch 2250" },
+ { 108, "Ethernet Switch 425-48T" },
+ { 109, "Ethernet Switch 425-24T" },
+ { 110, "Nortel Networks Wireless LAN Access Point 2221" },
+ { 111, "Nortel Metro Ethernet Service Unit 24-T SPF switch" },
+ { 112, "Nortel Metro Ethernet Service Unit 24-T LX DC switch" },
+ { 113, "Nortel Ethernet Routing Switch 8300 10-slot chassis" },
+ { 114, "Nortel Ethernet Routing Switch 8300 6-slot chassis" },
+ { 115, "Nortel Ethernet Routing Switch 5520-24T-PWR" },
+ { 116, "Nortel Ethernet Routing Switch 5520-48T-PWR" },
+ { 117, "Nortel Networks VPN Gateway 3050" },
+ { 118, "Alteon SSL 310 10/100" },
+ { 119, "Alteon SSL 310 10/100 Fiber" },
+ { 120, "Alteon SSL 310 10/100 FIPS" },
+ { 121, "Alteon SSL 410 10/100/1000" },
+ { 122, "Alteon SSL 410 10/100/1000 Fiber" },
+ { 123, "Alteon Application Switch 2424-SSL" },
+ { 124, "Nortel Ethernet Switch 325-24T" },
+ { 125, "Nortel Ethernet Switch 325-24G" },
+ { 126, "Nortel Networks Wireless LAN Access Point 2225" },
+ { 127, "Nortel Networks Wireless LAN SecuritySwitch 2270" },
+ { 128, "Nortel 24-port Ethernet Switch 470-24T-PWR" },
+ { 129, "Nortel 48-port Ethernet Switch 470-48T-PWR" },
+ { 130, "Nortel Ethernet Routing Switch 5530-24TFD" },
+ { 131, "Nortel Ethernet Switch 3510-24T" },
+ { 132, "Nortel Metro Ethernet Service Unit 12G AC L3 switch" },
+ { 133, "Nortel Metro Ethernet Service Unit 12G DC L3 switch" },
+ { 134, "Nortel Secure Access Switch" },
+ { 135, "Networks VPN Gateway 3070" },
+ { 136, "OPTera Metro 3500" },
+ { 137, "SMB BES 1010 24T" },
+ { 138, "SMB BES 1010 48T" },
+ { 139, "SMB BES 1020 24T PWR" },
+ { 140, "SMB BES 1020 48T PWR" },
+ { 141, "SMB BES 2010 24T" },
+ { 142, "SMB BES 2010 48T" },
+ { 143, "SMB BES 2020 24T PWR" },
+ { 144, "SMB BES 2020 48T PWR" },
+ { 145, "SMB BES 110 24T" },
+ { 146, "SMB BES 110 48T" },
+ { 147, "SMB BES 120 24T PWR" },
+ { 148, "SMB BES 120 48T PWR" },
+ { 149, "SMB BES 210 24T" },
+ { 150, "SMB BES 210 48T" },
+ { 151, "SMB BES 220 24T PWR" },
+ { 152, "SMB BES 220 48T PWR" },
+ { 153, "OME 6500" },
+ { 0, "unknown (via SONMP)" },
+};
+
+int
+sonmp_send(struct lldpd *global, struct lldpd_hardware *hardware)
+{
+ const u_int8_t mcastaddr[] = SONMP_MULTICAST_ADDR;
+ const u_int8_t llcorg[] = LLC_ORG_NORTEL;
+ struct lldpd_chassis *chassis;
+ struct lldpd_mgmt *mgmt;
+ u_int8_t *packet, *pos, *pos_pid, *end;
+ int length;
+ struct in_addr address;
+
+ log_debug("sonmp", "send SONMP PDU to %s", hardware->h_ifname);
+
+ chassis = hardware->h_lport.p_chassis;
+ length = hardware->h_mtu;
+ if ((packet = (u_int8_t *)calloc(1, length)) == NULL) return ENOMEM;
+ pos = packet;
+
+ /* Ethernet header */
+ if (!(
+ /* SONMP multicast address as target */
+ POKE_BYTES(mcastaddr, sizeof(mcastaddr)) &&
+ /* Source MAC addresss */
+ POKE_BYTES(&hardware->h_lladdr, ETHER_ADDR_LEN) &&
+ /* SONMP frame is of fixed size */
+ POKE_UINT16(SONMP_SIZE)))
+ goto toobig;
+
+ /* LLC header */
+ if (!(
+ /* DSAP and SSAP */
+ POKE_UINT8(0xaa) && POKE_UINT8(0xaa) &&
+ /* Control field */
+ POKE_UINT8(0x03) &&
+ /* ORG */
+ POKE_BYTES(llcorg, sizeof(llcorg)) &&
+ POKE_SAVE(pos_pid) && /* We will modify PID later to
+ create a new frame */
+ POKE_UINT16(LLC_PID_SONMP_HELLO)))
+ goto toobig;
+
+ address.s_addr = htonl(INADDR_ANY);
+ TAILQ_FOREACH (mgmt, &chassis->c_mgmt, m_entries) {
+ if (mgmt->m_family == LLDPD_AF_IPV4) {
+ address.s_addr = mgmt->m_addr.inet.s_addr;
+ }
+ break;
+ }
+
+ /* SONMP */
+ if (!(
+ /* Our IP address */
+ POKE_BYTES(&address, sizeof(struct in_addr)) &&
+ /* Segment on three bytes, we don't have slots, so we
+ skip the first two bytes */
+ POKE_UINT16(0) && POKE_UINT8(hardware->h_ifindex) &&
+ POKE_UINT8(1) && /* Chassis: Other */
+ POKE_UINT8(12) && /* Back: Ethernet, Fast Ethernet and Gigabit */
+ POKE_UINT8(SONMP_TOPOLOGY_NEW) && /* Should work. We have no state */
+ POKE_UINT8(1) && /* Links: Dunno what it is */
+ POKE_SAVE(end)))
+ goto toobig;
+
+ if (interfaces_send_helper(global, hardware, (char *)packet, end - packet) ==
+ -1) {
+ log_warn("sonmp", "unable to send packet on real device for %s",
+ hardware->h_ifname);
+ free(packet);
+ return ENETDOWN;
+ }
+
+ POKE_RESTORE(pos_pid); /* Modify LLC PID */
+ (void)POKE_UINT16(LLC_PID_SONMP_FLATNET);
+ POKE_RESTORE(packet); /* Go to the beginning */
+ PEEK_DISCARD(ETHER_ADDR_LEN - 1); /* Modify the last byte of the MAC address */
+ (void)POKE_UINT8(1);
+
+ if (interfaces_send_helper(global, hardware, (char *)packet, end - packet) ==
+ -1) {
+ log_warn("sonmp",
+ "unable to send second SONMP packet on real device for %s",
+ hardware->h_ifname);
+ free(packet);
+ return ENETDOWN;
+ }
+
+ free(packet);
+ hardware->h_tx_cnt++;
+ return 0;
+toobig:
+ free(packet);
+ return -1;
+}
+
+int
+sonmp_decode(struct lldpd *cfg, char *frame, int s, struct lldpd_hardware *hardware,
+ struct lldpd_chassis **newchassis, struct lldpd_port **newport)
+{
+ const u_int8_t mcastaddr[] = SONMP_MULTICAST_ADDR;
+ struct lldpd_chassis *chassis;
+ struct lldpd_port *port;
+ struct lldpd_mgmt *mgmt;
+ int length, i;
+ u_int8_t *pos;
+ u_int8_t seg[3], rchassis;
+ struct in_addr address;
+
+ log_debug("sonmp", "decode SONMP PDU from %s", hardware->h_ifname);
+
+ if ((chassis = calloc(1, sizeof(struct lldpd_chassis))) == NULL) {
+ log_warn("sonmp", "failed to allocate remote chassis");
+ return -1;
+ }
+ TAILQ_INIT(&chassis->c_mgmt);
+ if ((port = calloc(1, sizeof(struct lldpd_port))) == NULL) {
+ log_warn("sonmp", "failed to allocate remote port");
+ free(chassis);
+ return -1;
+ }
+# ifdef ENABLE_DOT1
+ TAILQ_INIT(&port->p_vlans);
+# endif
+
+ length = s;
+ pos = (u_int8_t *)frame;
+ if (length < SONMP_SIZE + 2 * ETHER_ADDR_LEN + sizeof(u_int16_t)) {
+ log_warnx("sonmp", "too short SONMP frame received on %s",
+ hardware->h_ifname);
+ goto malformed;
+ }
+ if (PEEK_CMP(mcastaddr, sizeof(mcastaddr)) != 0)
+ /* There is two multicast address. We just handle only one of
+ * them. */
+ goto malformed;
+ /* We skip to LLC PID */
+ PEEK_DISCARD(ETHER_ADDR_LEN);
+ PEEK_DISCARD_UINT16;
+ PEEK_DISCARD(6);
+ if (PEEK_UINT16 != LLC_PID_SONMP_HELLO) {
+ log_debug("sonmp", "incorrect LLC protocol ID received for SONMP on %s",
+ hardware->h_ifname);
+ goto malformed;
+ }
+
+ chassis->c_id_subtype = LLDP_CHASSISID_SUBTYPE_ADDR;
+ if ((chassis->c_id = calloc(1, sizeof(struct in_addr) + 1)) == NULL) {
+ log_warn("sonmp", "unable to allocate memory for chassis id on %s",
+ hardware->h_ifname);
+ goto malformed;
+ }
+ chassis->c_id_len = sizeof(struct in_addr) + 1;
+ chassis->c_id[0] = 1;
+ PEEK_BYTES(&address, sizeof(struct in_addr));
+ memcpy(chassis->c_id + 1, &address, sizeof(struct in_addr));
+ if (asprintf(&chassis->c_name, "%s", inet_ntoa(address)) == -1) {
+ log_warnx("sonmp", "unable to write chassis name for %s",
+ hardware->h_ifname);
+ goto malformed;
+ }
+ PEEK_BYTES(seg, sizeof(seg));
+ rchassis = PEEK_UINT8;
+ for (i = 0; sonmp_chassis_types[i].type != 0; i++) {
+ if (sonmp_chassis_types[i].type == rchassis) break;
+ }
+ if (asprintf(&chassis->c_descr, "%s", sonmp_chassis_types[i].description) ==
+ -1) {
+ log_warnx("sonmp", "unable to write chassis description for %s",
+ hardware->h_ifname);
+ goto malformed;
+ }
+ mgmt = lldpd_alloc_mgmt(LLDPD_AF_IPV4, &address, sizeof(struct in_addr), 0);
+ if (mgmt == NULL) {
+ if (errno == ENOMEM)
+ log_warn("sonmp",
+ "unable to allocate memory for management address");
+ else
+ log_warn("sonmp", "too large management address received on %s",
+ hardware->h_ifname);
+ goto malformed;
+ }
+ TAILQ_INSERT_TAIL(&chassis->c_mgmt, mgmt, m_entries);
+ port->p_ttl =
+ cfg ? (cfg->g_config.c_tx_interval * cfg->g_config.c_tx_hold) : LLDPD_TTL;
+ port->p_ttl = (port->p_ttl + 999) / 1000;
+
+ port->p_id_subtype = LLDP_PORTID_SUBTYPE_LOCAL;
+
+ port->p_id_len =
+ asprintf(&port->p_id, "%02x-%02x-%02x", seg[0], seg[1], seg[2]);
+ if (port->p_id_len == -1) {
+ log_warn("sonmp", "unable to allocate memory for port id on %s",
+ hardware->h_ifname);
+ goto malformed;
+ }
+
+ /* Port description depend on the number of segments */
+ if ((seg[0] == 0) && (seg[1] == 0)) {
+ if (asprintf(&port->p_descr, "port %d", seg[2]) == -1) {
+ log_warnx("sonmp", "unable to write port description for %s",
+ hardware->h_ifname);
+ goto malformed;
+ }
+ } else if (seg[0] == 0) {
+ if (asprintf(&port->p_descr, "port %d/%d", seg[1], seg[2]) == -1) {
+ log_warnx("sonmp", "unable to write port description for %s",
+ hardware->h_ifname);
+ goto malformed;
+ }
+ } else {
+ if (asprintf(&port->p_descr, "port %x:%x:%x", seg[0], seg[1], seg[2]) ==
+ -1) {
+ log_warnx("sonmp", "unable to write port description for %s",
+ hardware->h_ifname);
+ goto malformed;
+ }
+ }
+ *newchassis = chassis;
+ *newport = port;
+ return 1;
+
+malformed:
+ lldpd_chassis_cleanup(chassis, 1);
+ lldpd_port_cleanup(port, 1);
+ free(port);
+ return -1;
+}
+
+#endif /* ENABLE_SONMP */