diff options
Diffstat (limited to 'src/daemon/lldpd.h')
-rw-r--r-- | src/daemon/lldpd.h | 429 |
1 files changed, 429 insertions, 0 deletions
diff --git a/src/daemon/lldpd.h b/src/daemon/lldpd.h new file mode 100644 index 0000000..2fc381b --- /dev/null +++ b/src/daemon/lldpd.h @@ -0,0 +1,429 @@ +/* -*- 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. + */ + +#ifndef _LLDPD_H +#define _LLDPD_H + +#if HAVE_CONFIG_H +# include <config.h> +#endif + +#ifdef HAVE_VALGRIND_VALGRIND_H +# include <valgrind/valgrind.h> +#else +# define RUNNING_ON_VALGRIND 0 +#endif + +#include <stdlib.h> +#include <stddef.h> +#include <string.h> +#include <sys/queue.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <net/if_arp.h> +#include <netinet/if_ether.h> +#include <sys/un.h> + +#include "lldp-tlv.h" +#if defined ENABLE_CDP || defined ENABLE_FDP +# include "protocols/cdp.h" +#endif +#ifdef ENABLE_SONMP +# include "protocols/sonmp.h" +#endif +#ifdef ENABLE_EDP +# include "protocols/edp.h" +#endif + +#include "../compat/compat.h" +#include "../marshal.h" +#include "../log.h" +#include "../ctl.h" +#include "../lldpd-structs.h" + +/* We don't want to import event2/event.h. We only need those as + opaque structs. */ +struct event; +struct event_base; + +#define PROCFS_SYS_NET "/proc/sys/net/" +#define SYSFS_CLASS_NET "/sys/class/net/" +#define SYSFS_CLASS_DMI "/sys/class/dmi/id/" +#define LLDPD_TX_INTERVAL 30 +#define LLDPD_TX_HOLD 4 +#define LLDPD_TTL LLDPD_TX_INTERVAL *LLDPD_TX_HOLD +#define LLDPD_TX_MSGDELAY 1 +#define LLDPD_MAX_NEIGHBORS 32 +#define LLDPD_FAST_TX_INTERVAL 1 +#define LLDPD_FAST_INIT 4 + +#define USING_AGENTX_SUBAGENT_MODULE 1 + +#define PROTO_SEND_SIG struct lldpd *, struct lldpd_hardware * +#define PROTO_DECODE_SIG \ + struct lldpd *, char *, int, struct lldpd_hardware *, struct lldpd_chassis **, \ + struct lldpd_port ** +#define PROTO_GUESS_SIG char *, int + +#define ALIGNED_CAST(TYPE, ATTR) ((TYPE)(void *)(ATTR)) + +struct protocol { + int mode; /* > 0 mode identifier (unique per protocol) */ + int enabled; /* Is this protocol enabled? */ + const char *name; /* Name of protocol */ + char arg; /* Argument to enable this protocol */ + int (*send)(PROTO_SEND_SIG); /* How to send a frame */ + int (*decode)(PROTO_DECODE_SIG); /* How to decode a frame */ + int (*guess)(PROTO_GUESS_SIG); /* Can be NULL, use MAC address in this case */ + u_int8_t mac[3][ETHER_ADDR_LEN]; /* Destination MAC addresses used by this + protocol */ +}; + +#define SMART_HIDDEN(port) (port->p_hidden_in) + +struct lldpd; + +/* lldpd.c */ +struct lldpd_hardware *lldpd_get_hardware(struct lldpd *, char *, int); +struct lldpd_hardware *lldpd_alloc_hardware(struct lldpd *, char *, int); +void lldpd_hardware_cleanup(struct lldpd *, struct lldpd_hardware *); +struct lldpd_mgmt *lldpd_alloc_mgmt(int family, void *addr, size_t addrsize, + u_int32_t iface); +void lldpd_recv(struct lldpd *, struct lldpd_hardware *, int); +void lldpd_send(struct lldpd_hardware *); +void lldpd_loop(struct lldpd *); +int lldpd_main(int, char **, char **); +void lldpd_update_localports(struct lldpd *); +void lldpd_update_localchassis(struct lldpd *); +void lldpd_cleanup(struct lldpd *); + +/* frame.c */ +u_int16_t frame_checksum(const u_int8_t *, int, int); + +/* event.c */ +void levent_loop(struct lldpd *); +void levent_shutdown(struct lldpd *); +void levent_hardware_init(struct lldpd_hardware *); +void levent_hardware_add_fd(struct lldpd_hardware *, int); +void levent_hardware_release(struct lldpd_hardware *); +void levent_ctl_notify(char *, int, struct lldpd_port *); +void levent_send_now(struct lldpd *); +void levent_update_now(struct lldpd *); +int levent_iface_subscribe(struct lldpd *, int); +void levent_schedule_pdu(struct lldpd_hardware *); +void levent_schedule_cleanup(struct lldpd *); +int levent_make_socket_nonblocking(int); +int levent_make_socket_blocking(int); +#ifdef HOST_OS_LINUX +void levent_recv_error(int, const char *); +#endif + +/* lldp.c */ +int lldp_send_shutdown(PROTO_SEND_SIG); +int lldp_send(PROTO_SEND_SIG); +int lldp_decode(PROTO_DECODE_SIG); + +/* cdp.c */ +#ifdef ENABLE_CDP +int cdpv1_send(PROTO_SEND_SIG); +int cdpv2_send(PROTO_SEND_SIG); +int cdpv1_guess(PROTO_GUESS_SIG); +int cdpv2_guess(PROTO_GUESS_SIG); +#endif +#if defined ENABLE_CDP || defined ENABLE_FDP +int cdp_decode(PROTO_DECODE_SIG); +#endif +#ifdef ENABLE_FDP +int fdp_send(PROTO_SEND_SIG); +#endif + +#ifdef ENABLE_SONMP +/* sonmp.c */ +int sonmp_send(PROTO_SEND_SIG); +int sonmp_decode(PROTO_DECODE_SIG); +#endif + +#ifdef ENABLE_EDP +/* edp.c */ +int edp_send(PROTO_SEND_SIG); +int edp_decode(PROTO_DECODE_SIG); +#endif + +/* dmi.c */ +#ifdef ENABLE_LLDPMED +char *dmi_hw(void); +char *dmi_fw(void); +char *dmi_sn(void); +char *dmi_manuf(void); +char *dmi_model(void); +char *dmi_asset(void); +#endif + +#ifdef USE_SNMP +/* agent.c */ +void agent_shutdown(void); +void agent_init(struct lldpd *, const char *); +void agent_notify(struct lldpd_hardware *, int, struct lldpd_port *); +#endif + +#ifdef ENABLE_PRIVSEP +/* agent_priv.c */ +void agent_priv_register_domain(void); +#endif + +/* client.c */ +int client_handle_client(struct lldpd *cfg, + ssize_t (*send)(void *, int, void *, size_t), void *, enum hmsg_type type, + void *buffer, size_t n, int *); + +/* priv.c */ +#ifdef ENABLE_PRIVSEP +void priv_init(const char *, int, uid_t, gid_t); +#else +void priv_init(void); +#endif +void priv_wait(void); +void priv_ctl_cleanup(const char *ctlname); +char *priv_gethostname(void); +#ifdef HOST_OS_LINUX +int priv_open(const char *); +void asroot_open(void); +#endif +int priv_iface_init(int, char *); +int asroot_iface_init_os(int, char *, int *); +int priv_iface_multicast(const char *, const u_int8_t *, int); +int priv_iface_description(const char *, const char *); +int asroot_iface_description_os(const char *, const char *); +int priv_iface_promisc(const char *); +int asroot_iface_promisc_os(const char *); +int priv_snmp_socket(struct sockaddr_un *); + +enum priv_cmd { + PRIV_PING, + PRIV_DELETE_CTL_SOCKET, + PRIV_GET_HOSTNAME, + PRIV_OPEN, + PRIV_IFACE_INIT, + PRIV_IFACE_MULTICAST, + PRIV_IFACE_DESCRIPTION, + PRIV_IFACE_PROMISC, + PRIV_SNMP_SOCKET, +}; + +/* priv-seccomp.c */ +#if defined USE_SECCOMP && defined ENABLE_PRIVSEP +int priv_seccomp_init(int, int); +#endif + +/* privsep_io.c */ +enum priv_context { PRIV_PRIVILEGED, PRIV_UNPRIVILEGED }; +int may_read(enum priv_context, void *, size_t); +void must_read(enum priv_context, void *, size_t); +void must_write(enum priv_context, const void *, size_t); +void priv_privileged_fd(int); +void priv_unprivileged_fd(int); +int priv_fd(enum priv_context); +int receive_fd(enum priv_context); +void send_fd(enum priv_context, int); + +/* interfaces-*.c */ + +/* BPF filter to get revelant information from interfaces */ +/* LLDP: "ether proto 0x88cc and ether dst 01:80:c2:00:00:0e" */ +/* FDP: "ether dst 01:e0:52:cc:cc:cc" */ +/* CDP: "ether dst 01:00:0c:cc:cc:cc" */ +/* SONMP: "ether dst 01:00:81:00:01:00" */ +/* EDP: "ether dst 00:e0:2b:00:00:00" */ +/* For optimization purpose, we first check if the first bit of the + first byte is 1. if not, this can only be an EDP packet: + + tcpdump -dd "(ether[0] & 1 = 1 and + ((ether proto 0x88cc and (ether dst 01:80:c2:00:00:0e or + ether dst 01:80:c2:00:00:03 or + ether dst 01:80:c2:00:00:00)) or + (ether dst 01:e0:52:cc:cc:cc) or + (ether dst 01:00:0c:cc:cc:cc) or + (ether dst 01:00:81:00:01:00))) or + (ether dst 00:e0:2b:00:00:00)" +*/ + +#ifndef ETH_P_LLDP +# define ETH_P_LLDP 0x88cc +#endif +#define LLDPD_FILTER_F \ + { 0x30, 0, 0, 0x00000000 }, { 0x54, 0, 0, 0x00000001 }, { 0x15, 0, 16, 0x00000001 }, \ + { 0x28, 0, 0, 0x0000000c }, { 0x15, 0, 6, ETH_P_LLDP }, \ + { 0x20, 0, 0, 0x00000002 }, { 0x15, 2, 0, 0xc200000e }, \ + { 0x15, 1, 0, 0xc2000003 }, { 0x15, 0, 2, 0xc2000000 }, \ + { 0x28, 0, 0, 0x00000000 }, { 0x15, 12, 13, 0x00000180 }, \ + { 0x20, 0, 0, 0x00000002 }, { 0x15, 0, 2, 0x52cccccc }, \ + { 0x28, 0, 0, 0x00000000 }, { 0x15, 8, 9, 0x000001e0 }, \ + { 0x15, 1, 0, 0x0ccccccc }, { 0x15, 0, 2, 0x81000100 }, \ + { 0x28, 0, 0, 0x00000000 }, { 0x15, 4, 5, 0x00000100 }, \ + { 0x20, 0, 0, 0x00000002 }, { 0x15, 0, 3, 0x2b000000 }, \ + { 0x28, 0, 0, 0x00000000 }, { 0x15, 0, 1, 0x000000e0 }, \ + { 0x6, 0, 0, 0x00040000 }, \ + { \ + 0x6, 0, 0, 0x00000000 \ + } + +/* This function is responsible to refresh information about interfaces. It is + * OS specific but should be present for each OS. It can use the functions in + * `interfaces.c` as helper by providing a list of OS-independent interface + * devices. */ +void interfaces_update(struct lldpd *); + +/* interfaces.c */ +/* An interface cannot be both physical and (bridge or bond or vlan) */ +#define IFACE_PHYSICAL_T (1 << 0) /* Physical interface */ +#define IFACE_BRIDGE_T (1 << 1) /* Bridge interface */ +#define IFACE_BOND_T (1 << 2) /* Bond interface */ +#define IFACE_VLAN_T (1 << 3) /* VLAN interface */ +#define IFACE_WIRELESS_T (1 << 4) /* Wireless interface */ +#define IFACE_BRIDGE_VLAN_T (1 << 5) /* Bridge-aware VLAN interface */ + +#define MAX_VLAN 4096 +#define VLAN_BITMAP_LEN (MAX_VLAN / 32) +struct interfaces_device { + TAILQ_ENTRY(interfaces_device) next; + int ignore; /* Ignore this interface */ + int index; /* Index */ + char *name; /* Name */ + char *alias; /* Alias */ + char *address; /* MAC address */ + char *driver; /* Driver */ + int flags; /* Flags (IFF_*) */ + int mtu; /* MTU */ + int type; /* Type (see IFACE_*_T) */ + uint32_t vlan_bmap[VLAN_BITMAP_LEN]; /* If a VLAN, what are the VLAN ID? */ + int pvid; /* If a VLAN, what is the default VLAN? */ + struct interfaces_device *lower; /* Lower interface (for a VLAN for example) */ + struct interfaces_device *upper; /* Upper interface (for a bridge or a bond) */ + + /* The following are OS specific. Should be static (no free function) */ +#ifdef HOST_OS_LINUX + int lower_idx; /* Index to lower interface */ + int upper_idx; /* Index to upper interface */ +#endif +}; +struct interfaces_address { + TAILQ_ENTRY(interfaces_address) next; + int index; /* Index */ + int flags; /* Flags */ + struct sockaddr_storage address; /* Address */ + + /* The following are OS specific. */ + /* Nothing yet. */ +}; +TAILQ_HEAD(interfaces_device_list, interfaces_device); +TAILQ_HEAD(interfaces_address_list, interfaces_address); +void interfaces_free_device(struct interfaces_device *); +void interfaces_free_address(struct interfaces_address *); +void interfaces_free_devices(struct interfaces_device_list *); +void interfaces_free_addresses(struct interfaces_address_list *); +struct interfaces_device *interfaces_indextointerface(struct interfaces_device_list *, + int); +struct interfaces_device *interfaces_nametointerface(struct interfaces_device_list *, + const char *); + +void interfaces_helper_promisc(struct lldpd *, struct lldpd_hardware *); +void interfaces_helper_allowlist(struct lldpd *, struct interfaces_device_list *); +void interfaces_helper_chassis(struct lldpd *, struct interfaces_device_list *); +void interfaces_helper_add_hardware(struct lldpd *, struct lldpd_hardware *); +void interfaces_helper_physical(struct lldpd *, struct interfaces_device_list *, + struct lldpd_ops *, int (*init)(struct lldpd *, struct lldpd_hardware *)); +void interfaces_helper_port_name_desc(struct lldpd *, struct lldpd_hardware *, + struct interfaces_device *); +void interfaces_helper_mgmt(struct lldpd *, struct interfaces_address_list *, + struct interfaces_device_list *); +#ifdef ENABLE_DOT1 +void interfaces_helper_vlan(struct lldpd *, struct interfaces_device_list *); +#endif +int interfaces_send_helper(struct lldpd *, struct lldpd_hardware *, char *, size_t); + +void interfaces_setup_multicast(struct lldpd *, const char *, int); +int interfaces_routing_enabled(struct lldpd *); +void interfaces_cleanup(struct lldpd *); + +#ifdef HOST_OS_LINUX +/* netlink.c */ +struct interfaces_device_list *netlink_get_interfaces(struct lldpd *); +struct interfaces_address_list *netlink_get_addresses(struct lldpd *); +void netlink_cleanup(struct lldpd *); +struct lldpd_netlink; +#endif + +#ifndef HOST_OS_LINUX +/* interfaces-bpf.c */ +int ifbpf_phys_init(struct lldpd *, struct lldpd_hardware *); +#endif + +/* pattern.c */ +enum pattern_match_result { + PATTERN_MATCH_DENIED, + PATTERN_MATCH_ALLOWED, + PATTERN_MATCH_ALLOWED_EXACT +}; +enum pattern_match_result pattern_match(char *, char *, int); + +/* bitmap.c */ +void bitmap_set(uint32_t *bmap, uint16_t vlan_id); +int bitmap_isempty(uint32_t *bmap); +unsigned int bitmap_numbits(uint32_t *bmap); + +struct lldpd { + int g_sock; + struct event_base *g_base; +#ifdef USE_SNMP +#endif + + struct lldpd_config g_config; + + struct protocol *g_protocols; + int g_lastrid; + struct event *g_main_loop; + struct event *g_cleanup_timer; +#ifdef USE_SNMP + int g_snmp; + struct event *g_snmp_timeout; + void *g_snmp_fds; + const char *g_snmp_agentx; +#endif /* USE_SNMP */ + + /* Unix socket handling */ + const char *g_ctlname; + int g_ctl; + struct event *g_iface_event; /* Triggered when there is an interface change */ + struct event + *g_iface_timer_event; /* Triggered one second after last interface change */ + void (*g_iface_cb)( + struct lldpd *); /* Called when there is an interface change */ + + char *g_lsb_release; + +#ifdef HOST_OS_LINUX + struct lldpd_netlink *g_netlink; +#endif + + struct lldpd_port *g_default_local_port; +#define LOCAL_CHASSIS(cfg) ((struct lldpd_chassis *)(TAILQ_FIRST(&cfg->g_chassis))) + TAILQ_HEAD(, lldpd_chassis) g_chassis; + TAILQ_HEAD(, lldpd_hardware) g_hardware; +}; + +#endif /* _LLDPD_H */ |