From 690b944cc01bd3d3b7d2587c7d6a4ed533f348ef Mon Sep 17 00:00:00 2001 From: Vincent Bernat Date: Thu, 27 Dec 2012 23:25:26 +0100 Subject: [PATCH] OpenBSD support. With VLAN, bonding and bridge support as well. Tested with OpenBSD 5.2. To ease porting, we also shop `netinet/if_ether.h` which is a stripped down version of the one contained in OpenBSD (without kernel and ARP stuff). Including correctly this header has always been a pain, even when supporting only Linux. --- .gitignore | 2 +- NEWS | 4 +- configure.ac | 3 - include/netinet/if_ether.h | 92 +++++++++++++++++++ m4/os.m4 | 1 + src/compat/compat.h | 4 - src/ctl.c | 3 +- src/daemon/Makefile.am | 5 +- ...{interfaces-freebsd.c => interfaces-bsd.c} | 69 ++++++++------ src/daemon/lldp-tlv.h | 5 - src/daemon/lldpd.c | 9 +- src/daemon/lldpd.h | 2 +- src/daemon/priv.c | 9 +- src/lldpd-structs.h | 2 +- 14 files changed, 157 insertions(+), 53 deletions(-) create mode 100644 include/netinet/if_ether.h rename src/daemon/{interfaces-freebsd.c => interfaces-bsd.c} (94%) diff --git a/.gitignore b/.gitignore index 3e5acad7..bf795e60 100644 --- a/.gitignore +++ b/.gitignore @@ -3,7 +3,7 @@ *.lo *.a *.la -/build/ +/build*/ # autotools stuff /m4/lt*.m4 diff --git a/NEWS b/NEWS index cf88c852..e5405f75 100644 --- a/NEWS +++ b/NEWS @@ -1,6 +1,8 @@ lldpd (0.6.2) - * Features: + * Global changes: + FreeBSD support. + + OpenBSD support. + * Features: + Allow to disable LLDP protocol (with `-ll`). In this case, the first enabled protocol will be used when no neighbor is detected. + Allow to filter debug logs using tokens. Add more debug logs. diff --git a/configure.ac b/configure.ac index 8ec60e02..11fa363d 100644 --- a/configure.ac +++ b/configure.ac @@ -80,9 +80,6 @@ AC_CACHE_SAVE AC_HEADER_RESOLV AC_CHECK_HEADERS([valgrind/valgrind.h]) -# Check for ETHERTYPE_VLAN, put it in compat.h if not defined -AC_CHECK_DECLS([ETHERTYPE_VLAN],[],[],[[@%:@include ]]) - AC_CACHE_SAVE # Checks for typedefs, structures, and compiler characteristics. diff --git a/include/netinet/if_ether.h b/include/netinet/if_ether.h new file mode 100644 index 00000000..fa65914c --- /dev/null +++ b/include/netinet/if_ether.h @@ -0,0 +1,92 @@ +/* $OpenBSD: if_ether.h,v 1.47 2010/02/08 13:32:50 claudio Exp $ */ +/* $NetBSD: if_ether.h,v 1.22 1996/05/11 13:00:00 mycroft Exp $ */ + +/* + * Copyright (c) 1982, 1986, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)if_ether.h 8.1 (Berkeley) 6/10/93 + */ + +#ifndef _NETINET_IF_ETHER_H_ +#define _NETINET_IF_ETHER_H_ + +/* + * Some basic Ethernet constants. + */ +#define ETHER_ADDR_LEN 6 /* Ethernet address length */ +#define ETHER_TYPE_LEN 2 /* Ethernet type field length */ +#define ETHER_CRC_LEN 4 /* Ethernet CRC length */ +#define ETHER_HDR_LEN ((ETHER_ADDR_LEN * 2) + ETHER_TYPE_LEN) +#define ETHER_MIN_LEN 64 /* Minimum frame length, CRC included */ +#define ETHER_MAX_LEN 1518 /* Maximum frame length, CRC included */ +#define ETHER_MAX_DIX_LEN 1536 /* Maximum DIX frame length */ + +/* + * Some Ethernet extensions. + */ +#define ETHER_VLAN_ENCAP_LEN 4 /* len of 802.1Q VLAN encapsulation */ + +/* + * Mbuf adjust factor to force 32-bit alignment of IP header. + * Drivers should do m_adj(m, ETHER_ALIGN) when setting up a + * receive so the upper layers get the IP header properly aligned + * past the 14-byte Ethernet header. + */ +#define ETHER_ALIGN 2 /* driver adjust for IP hdr alignment */ + +/* + * Ethernet address - 6 octets + */ +struct ether_addr { + u_int8_t ether_addr_octet[ETHER_ADDR_LEN]; +}; + +/* + * The length of the combined header. + */ +struct ether_header { + u_int8_t ether_dhost[ETHER_ADDR_LEN]; + u_int8_t ether_shost[ETHER_ADDR_LEN]; + u_int16_t ether_type; +}; + +#define ETHERTYPE_VLAN 0x8100 /* IEEE 802.1Q VLAN tagging (XXX conflicts) */ +#define ETHERTYPE_LLDP 0x88CC /* Link Layer Discovery Protocol */ + +#define ETHER_IS_MULTICAST(addr) (*(addr) & 0x01) /* is address mcast/bcast? */ + +#define ETHERMTU (ETHER_MAX_LEN - ETHER_HDR_LEN - ETHER_CRC_LEN) +#define ETHERMIN (ETHER_MIN_LEN - ETHER_HDR_LEN - ETHER_CRC_LEN) + +/* + * Ethernet CRC32 polynomials (big- and little-endian verions). + */ +#define ETHER_CRC_POLY_LE 0xedb88320 +#define ETHER_CRC_POLY_BE 0x04c11db6 + +#endif /* _NETINET_IF_ETHER_H_ */ diff --git a/m4/os.m4 b/m4/os.m4 index dfb69650..0f3dbb17 100644 --- a/m4/os.m4 +++ b/m4/os.m4 @@ -19,6 +19,7 @@ AC_DEFUN([lldp_CHECK_OS], [ lldp_DEFINE_OS(linux*, Linux, LINUX) lldp_DEFINE_OS(freebsd*|kfreebsd*, FreeBSD, FREEBSD) + lldp_DEFINE_OS(openbsd*, OpenBSD, OPENBSD) if test x$os = x; then AC_MSG_RESULT(no) diff --git a/src/compat/compat.h b/src/compat/compat.h index 74e35a78..9f432866 100644 --- a/src/compat/compat.h +++ b/src/compat/compat.h @@ -35,10 +35,6 @@ #include -#if !HAVE_DECL_ETHERTYPE_VLAN -#define ETHERTYPE_VLAN 0x8100 -#endif - #if !HAVE_STRLCPY size_t strlcpy(char *, const char *, size_t); #endif diff --git a/src/ctl.c b/src/ctl.c index 8562720b..1d8cae65 100644 --- a/src/ctl.c +++ b/src/ctl.c @@ -29,7 +29,8 @@ #include "log.h" #include "compat/compat.h" -#define UNIX_PATH_MAX 108 +/* Linux: 108. OpenBSD: 104. */ +#define UNIX_PATH_MAX 104 /** * Create a new listening Unix socket for control protocol. diff --git a/src/daemon/Makefile.am b/src/daemon/Makefile.am index b8385014..7c269e37 100644 --- a/src/daemon/Makefile.am +++ b/src/daemon/Makefile.am @@ -28,7 +28,10 @@ liblldpd_la_SOURCES += \ netlink.c endif if HOST_OS_FREEBSD -liblldpd_la_SOURCES += interfaces-freebsd.c +liblldpd_la_SOURCES += interfaces-bsd.c +endif +if HOST_OS_OPENBSD +liblldpd_la_SOURCES += interfaces-bsd.c endif # Add SNMP support if needed diff --git a/src/daemon/interfaces-freebsd.c b/src/daemon/interfaces-bsd.c similarity index 94% rename from src/daemon/interfaces-freebsd.c rename to src/daemon/interfaces-bsd.c index 0d4cb117..d60fc573 100644 --- a/src/daemon/interfaces-freebsd.c +++ b/src/daemon/interfaces-bsd.c @@ -19,46 +19,26 @@ #include #include +#include #include #include #include #include -#include #include #include -#include -#include #include +#if defined HOST_OS_FREEBSD +# include +# include +#elif defined HOST_OS_OPENBSD +# include +# include +#endif #ifndef IFDESCRSIZE #define IFDESCRSIZE 64 #endif -static int -ifbsd_check_driver(struct lldpd *cfg, - struct ifaddrs *ifaddr, - struct interfaces_device *iface) -{ - int name[6]; - char dname[IFNAMSIZ+1] = {}; - size_t len = IFNAMSIZ; - - name[0] = CTL_NET; - name[1] = PF_LINK; - name[2] = NETLINK_GENERIC; - name[3] = IFMIB_IFDATA; - name[4] = iface->index; - name[5] = IFDATA_DRIVERNAME; - - if (sysctl(name, 6, dname, &len, 0, 0) == -1 || len == 0) { - log_info("interfaces", "unable to get driver name for %s", - iface->name); - return -1; - } - iface->driver = strdup(dname); - return 0; -} - static int ifbsd_check_wireless(struct lldpd *cfg, struct ifaddrs *ifaddr, @@ -83,6 +63,8 @@ ifbsd_check_bridge(struct lldpd *cfg, .ifbic_len = sizeof(req), .ifbic_req = req }; + +#if defined HOST_OS_FREEBSD struct ifdrv ifd = { .ifd_cmd = BRDGGIFS, .ifd_len = sizeof(bifc), @@ -95,6 +77,16 @@ ifbsd_check_bridge(struct lldpd *cfg, "%s is not a bridge", master->name); return; } +#elif defined HOST_OS_OPENBSD + strlcpy(bifc.ifbic_name, master->name, sizeof(bifc.ifbic_name)); + if (ioctl(cfg->g_sock, SIOCBRDGIFS, (caddr_t)&bifc) < 0) { + log_debug("interfaces", + "%s is not a bridge", master->name); + return; + } +#else +# error Unsupported OS +#endif if (bifc.ifbic_len >= sizeof(req)) { log_warnx("interfaces", "%s is a bridge too big. Please, report the problem", @@ -124,6 +116,13 @@ ifbsd_check_bond(struct lldpd *cfg, struct interfaces_device_list *interfaces, struct interfaces_device *master) { +#if defined HOST_OS_OPENBSD +/* OpenBSD is the same as FreeBSD, just lagg->trunk */ +# define lagg_reqport trunk_reqport +# define lagg_reqall trunk_reqall +# define SIOCGLAGG SIOCGTRUNK +# define LAGG_MAX_PORTS TRUNK_MAX_PORTS +#endif struct lagg_reqport rpbuf[LAGG_MAX_PORTS]; struct lagg_reqall ra = { .ra_size = sizeof(rpbuf), @@ -246,10 +245,16 @@ ifbsd_extract_device(struct lldpd *cfg, /* Grab description */ iface->alias = malloc(IFDESCRSIZE); if (iface->alias) { +#ifdef HOST_OS_FREEBSD struct ifreq ifr = { .ifr_buffer = { .buffer = iface->alias, .length = IFDESCRSIZE } }; +#else + struct ifreq ifr = { + .ifr_data = (caddr_t)iface->alias + }; +#endif strlcpy(ifr.ifr_name, ifaddr->ifa_name, sizeof(ifr.ifr_name)); if (ioctl(cfg->g_sock, SIOCGIFDESCR, (caddr_t)&ifr) < 0) { free(iface->alias); @@ -257,8 +262,7 @@ ifbsd_extract_device(struct lldpd *cfg, } } - if (ifbsd_check_driver(cfg, ifaddr, iface) == -1 || - ifbsd_check_wireless(cfg, ifaddr, iface) == -1) { + if (ifbsd_check_wireless(cfg, ifaddr, iface) == -1) { interfaces_free_device(iface); return NULL; } @@ -523,9 +527,14 @@ ifbsd_phys_init(struct lldpd *cfg, goto end; } +#ifdef HOST_OS_FREEBSD /* We only want to receive incoming packets */ enable = BPF_D_IN; if (ioctl(fd, BIOCSDIRECTION, (caddr_t)&enable) < 0) { +#else + enable = BPF_DIRECTION_IN; + if (ioctl(fd, BIOCSDIRFILT, (caddr_t)&enable) < 0) { +#endif log_warn("interfaces", "unable to set packet direction for BPF filter on %s", hardware->h_ifname); diff --git a/src/daemon/lldp-tlv.h b/src/daemon/lldp-tlv.h index ab24486f..1af76f58 100644 --- a/src/daemon/lldp-tlv.h +++ b/src/daemon/lldp-tlv.h @@ -18,11 +18,6 @@ #ifndef _LLDP_TLV_H #define _LLDP_TLV_H -/* Should be defined in net/ethertypes.h */ -#ifndef ETHERTYPE_LLDP -#define ETHERTYPE_LLDP 0x88cc -#endif - #define LLDP_MULTICAST_ADDR { \ 0x01, 0x80, 0xc2, 0x00, 0x00, 0x0e \ } diff --git a/src/daemon/lldpd.c b/src/daemon/lldpd.c index b52eceda..a3bcede9 100644 --- a/src/daemon/lldpd.c +++ b/src/daemon/lldpd.c @@ -34,10 +34,11 @@ #include #include #include -#include +#include #include #include -#ifdef HOST_OS_FREEBSD +#if defined HOST_OS_FREEBSD || defined HOST_OS_OPENBSD +# include # include #endif @@ -852,7 +853,7 @@ lldpd_update_localchassis(struct lldpd *cfg) LOCAL_CHASSIS(cfg)->c_cap_enabled &= ~LLDP_CAP_ROUTER; close(f); } -#elif defined HOST_OS_FREEBSD +#elif defined HOST_OS_FREEBSD || defined HOST_OS_OPENBSD int n, mib[4] = { CTL_NET, PF_INET, @@ -867,6 +868,8 @@ lldpd_update_localchassis(struct lldpd *cfg) } else LOCAL_CHASSIS(cfg)->c_cap_enabled &= ~LLDP_CAP_ROUTER; } +#else +#error Unsupported OS #endif else log_debug("localchassis", "unable to check if forwarding is enabled"); diff --git a/src/daemon/lldpd.h b/src/daemon/lldpd.h index baf8d28b..1a042623 100644 --- a/src/daemon/lldpd.h +++ b/src/daemon/lldpd.h @@ -34,7 +34,7 @@ #include #include #include -#include +#include #include #include diff --git a/src/daemon/priv.c b/src/daemon/priv.c index 65a60637..b63000d6 100644 --- a/src/daemon/priv.c +++ b/src/daemon/priv.c @@ -42,7 +42,7 @@ #ifdef HOST_OS_FREEBSD # include #endif -#include +#include /* Use resolv.h */ #ifdef HAVE_SYS_TYPES_H @@ -345,7 +345,7 @@ asroot_iface_init() must_write(remote, &rc, sizeof(rc)); send_fd(remote, s); close(s); -#elif defined HOST_OS_FREEBSD +#elif defined HOST_OS_FREEBSD || defined HOST_OS_OPENBSD int fd = -1, rc = 0, n = 0; char dev[20]; int ifindex; @@ -391,6 +391,11 @@ asroot_iface_multicast() dlp->sdl_alen = ETHER_ADDR_LEN; dlp->sdl_slen = 0; must_read(remote, LLADDR(dlp), ETHER_ADDR_LEN); +#elif defined HOST_OS_OPENBSD + struct sockaddr *sap = (struct sockaddr *)&ifr.ifr_addr; + sap->sa_len = sizeof(struct sockaddr); + sap->sa_family = AF_UNSPEC; + must_read(remote, sap->sa_data, ETHER_ADDR_LEN); #else #error Unsupported OS #endif diff --git a/src/lldpd-structs.h b/src/lldpd-structs.h index 37e6e247..1f65de93 100644 --- a/src/lldpd-structs.h +++ b/src/lldpd-structs.h @@ -34,7 +34,7 @@ # include #endif -#include +#include #include #include -- 2.39.5