diff options
Diffstat (limited to '')
-rw-r--r-- | src/daemon/protocols/sonmp.c | 410 |
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 */ |