summaryrefslogtreecommitdiff
path: root/src/ipcpd
diff options
context:
space:
mode:
Diffstat (limited to 'src/ipcpd')
-rw-r--r--src/ipcpd/CMakeLists.txt5
-rw-r--r--src/ipcpd/broadcast/main.c13
-rw-r--r--src/ipcpd/common/connmgr.c93
-rw-r--r--src/ipcpd/common/connmgr.h17
-rw-r--r--src/ipcpd/config.h.in25
-rw-r--r--src/ipcpd/eth/CMakeLists.txt21
-rw-r--r--src/ipcpd/eth/eth.c2468
-rw-r--r--src/ipcpd/eth/llc.c26
-rw-r--r--src/ipcpd/ipcp.c305
-rw-r--r--src/ipcpd/ipcp.h13
-rw-r--r--src/ipcpd/local/CMakeLists.txt1
-rw-r--r--src/ipcpd/local/main.c32
-rw-r--r--src/ipcpd/local/reg.c217
-rw-r--r--src/ipcpd/local/reg.h (renamed from src/ipcpd/eth/dix.c)27
-rw-r--r--src/ipcpd/shim-data.c582
-rw-r--r--src/ipcpd/shim-data.h109
-rw-r--r--src/ipcpd/udp/CMakeLists.txt14
-rw-r--r--src/ipcpd/udp/udp.c1333
-rw-r--r--src/ipcpd/udp/udp4.c42
-rw-r--r--src/ipcpd/udp/udp6.c42
-rw-r--r--src/ipcpd/unicast/fa.c8
-rw-r--r--src/ipcpd/unicast/main.c9
22 files changed, 631 insertions, 4771 deletions
diff --git a/src/ipcpd/CMakeLists.txt b/src/ipcpd/CMakeLists.txt
index 609da54a..a84e5369 100644
--- a/src/ipcpd/CMakeLists.txt
+++ b/src/ipcpd/CMakeLists.txt
@@ -4,7 +4,6 @@
# Common sources shared by all IPCPs (absolute paths for subdirectories)
set(IPCP_SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/ipcp.c
- ${CMAKE_CURRENT_SOURCE_DIR}/shim-data.c
)
set(COMMON_SOURCES
@@ -24,7 +23,3 @@ configure_file("${CMAKE_CURRENT_SOURCE_DIR}/config.h.in"
add_subdirectory(local)
add_subdirectory(broadcast)
add_subdirectory(unicast)
-if(HAVE_ETH)
- add_subdirectory(eth)
-endif()
-add_subdirectory(udp)
diff --git a/src/ipcpd/broadcast/main.c b/src/ipcpd/broadcast/main.c
index d18cac82..22b34a76 100644
--- a/src/ipcpd/broadcast/main.c
+++ b/src/ipcpd/broadcast/main.c
@@ -37,6 +37,7 @@
#include <ouroboros/logs.h>
#include <ouroboros/notifier.h>
#include <ouroboros/np1_flow.h>
+#include <ouroboros/qos.h>
#include <ouroboros/random.h>
#include <ouroboros/rib.h>
#include <ouroboros/time.h>
@@ -100,12 +101,14 @@ static void stop_components(void)
enroll_stop();
}
-static int broadcast_ipcp_enroll(const char * dst,
- struct layer_info * info)
+static int broadcast_ipcp_enroll(const char * dst,
+ const struct poa_addr * addr,
+ struct layer_info * info)
{
struct ipcp_config * conf;
- struct conn conn;
- uint8_t id[ENROLL_ID_LEN];
+ struct conn conn;
+ uint8_t id[ENROLL_ID_LEN];
+ qosspec_t qs = qos_msg;
if (random_buffer(id, ENROLL_ID_LEN) < 0) {
log_err("Failed to generate enrollment ID.");
@@ -114,7 +117,7 @@ static int broadcast_ipcp_enroll(const char * dst,
log_info_id(id, "Requesting enrollment.");
- if (connmgr_alloc(COMPID_ENROLL, dst, NULL, &conn) < 0) {
+ if (connmgr_alloc(COMPID_ENROLL, dst, &qs, addr, &conn) < 0) {
log_err_id(id, "Failed to get connection.");
goto fail_id;
}
diff --git a/src/ipcpd/common/connmgr.c b/src/ipcpd/common/connmgr.c
index 6384a45c..e0ad80cb 100644
--- a/src/ipcpd/common/connmgr.c
+++ b/src/ipcpd/common/connmgr.c
@@ -26,6 +26,7 @@
#include <ouroboros/dev.h>
#include <ouroboros/errno.h>
#include <ouroboros/fccntl.h>
+#include <ouroboros/ipcp-dev.h>
#include <ouroboros/list.h>
#include <ouroboros/logs.h>
#include <ouroboros/notifier.h>
@@ -39,6 +40,10 @@
#include <stdlib.h>
#include <string.h>
+#define CONNMGR_ETH_PROBE_TIMEO 20 /* ms, one query attempt */
+#define CONNMGR_ETH_RETRY_TIMEO 1500 /* ms, the remaining tries */
+#define CONNMGR_DHT_TIMEO 1000 /* ms, bounded lower-layer */
+
struct conn_el {
struct list_head next;
struct conn conn;
@@ -60,6 +65,14 @@ struct {
pthread_t acceptor;
} connmgr;
+static bool is_eth_query(const struct poa_addr * addr)
+{
+ static const uint8_t zero[POA_MAC_SIZE] = { 0 };
+
+ return addr->type == POA_ETH &&
+ memcmp(addr->eth.dst.mac, zero, POA_MAC_SIZE) == 0;
+}
+
static int get_id_by_name(const char * name)
{
enum comp_id i;
@@ -121,6 +134,7 @@ static int add_comp_conn(enum comp_id id,
return 0;
}
+/* qs is also an in-parameter, and flow_accept writes it back. */
static void * flow_acceptor(void * o)
{
int fd;
@@ -323,9 +337,10 @@ void connmgr_comp_fini(enum comp_id id)
memset(&connmgr.comps[id].info, 0, sizeof(connmgr.comps[id].info));
}
-int connmgr_ipcp_connect(const char * dst,
- const char * component,
- qosspec_t qs)
+int connmgr_ipcp_connect(const char * dst,
+ const char * component,
+ qosspec_t qs,
+ const struct poa_addr * addr)
{
struct conn_el * ce;
int id;
@@ -334,6 +349,11 @@ int connmgr_ipcp_connect(const char * dst,
assert(dst);
assert(component);
+ if (qs.service == SVC_STREAM) {
+ log_err("No stream service on component flows.");
+ return -ENOTSUP;
+ }
+
ce = malloc(sizeof(*ce));
if (ce == NULL) {
log_err("Out of memory.");
@@ -348,7 +368,7 @@ int connmgr_ipcp_connect(const char * dst,
pthread_cleanup_push(free, ce);
- ret = connmgr_alloc(id, dst, &qs, &ce->conn);
+ ret = connmgr_alloc(id, dst, &qs, addr, &ce->conn);
pthread_cleanup_pop(false);
@@ -414,10 +434,46 @@ int connmgr_ipcp_disconnect(const char * dst,
return 0;
}
-int connmgr_alloc(enum comp_id id,
- const char * dst,
- qosspec_t * qs,
- struct conn * conn)
+/*
+ * Without an address, a peer may be on the wire or reachable through
+ * the layer below. A PoA query is cheap and creates no flow, so it
+ * goes first; the layer below gets a bounded try before the query
+ * retries, and the last try is unbounded.
+ */
+static int alloc_any(const char * dst,
+ qosspec_t * qs)
+{
+ struct timespec probe = TIMESPEC_INIT_MS(CONNMGR_ETH_PROBE_TIMEO);
+ struct timespec retry = TIMESPEC_INIT_MS(CONNMGR_ETH_RETRY_TIMEO);
+ struct timespec below = TIMESPEC_INIT_MS(CONNMGR_DHT_TIMEO);
+ struct poa_addr addr;
+ int fd;
+
+ if (poa_query(dst, &probe, &addr) == 0) {
+ fd = poa_flow_alloc(dst, &addr, qs, NULL);
+ if (fd >= 0)
+ return fd;
+ }
+
+ fd = flow_alloc(dst, qs, &below);
+ if (fd >= 0)
+ return fd;
+
+ if (poa_query(dst, &retry, &addr) == 0) {
+ fd = poa_flow_alloc(dst, &addr, qs, NULL);
+ if (fd >= 0)
+ return fd;
+ }
+
+ return flow_alloc(dst, qs, NULL);
+}
+
+/* A literal peer address bypasses the layer below. */
+int connmgr_alloc(enum comp_id id,
+ const char * dst,
+ qosspec_t * qs,
+ const struct poa_addr * addr,
+ struct conn * conn)
{
struct comp * comp;
int fd;
@@ -428,7 +484,26 @@ int connmgr_alloc(enum comp_id id,
comp = connmgr.comps + id;
- fd = flow_alloc(dst, qs, NULL);
+ if (addr != NULL)
+ fd = poa_flow_alloc(dst, addr, qs, NULL);
+ else
+ fd = alloc_any(dst, qs);
+
+ if (fd == -EPERM && addr != NULL) {
+ log_err("No PoA attached to reach %s.", dst);
+ goto fail_alloc;
+ }
+
+ if (fd == -EINVAL && addr != NULL) {
+ log_err("More than one PoA could reach %s", dst);
+ goto fail_alloc;
+ }
+
+ if (fd == -ETIMEDOUT && addr != NULL && is_eth_query(addr)) {
+ log_err("No answer to name query for %s.", dst);
+ goto fail_alloc;
+ }
+
if (fd < 0) {
log_err("Failed to allocate flow to %s.", dst);
goto fail_alloc;
diff --git a/src/ipcpd/common/connmgr.h b/src/ipcpd/common/connmgr.h
index f48ecd1b..86f80fb0 100644
--- a/src/ipcpd/common/connmgr.h
+++ b/src/ipcpd/common/connmgr.h
@@ -24,6 +24,7 @@
#define OUROBOROS_IPCPD_COMMON_CONNMGR_H
#include <ouroboros/cep.h>
+#include <ouroboros/ipcp.h>
#include <ouroboros/qos.h>
#include "comp.h"
@@ -53,17 +54,19 @@ int connmgr_comp_init(enum comp_id id,
void connmgr_comp_fini(enum comp_id id);
-int connmgr_ipcp_connect(const char * dst,
- const char * component,
- qosspec_t qs);
+int connmgr_ipcp_connect(const char * dst,
+ const char * component,
+ qosspec_t qs,
+ const struct poa_addr * addr);
int connmgr_ipcp_disconnect(const char * dst,
const char * component);
-int connmgr_alloc(enum comp_id id,
- const char * dst,
- qosspec_t * qs,
- struct conn * conn);
+int connmgr_alloc(enum comp_id id,
+ const char * dst,
+ qosspec_t * qs,
+ const struct poa_addr * addr,
+ struct conn * conn);
int connmgr_dealloc(enum comp_id id,
struct conn * conn);
diff --git a/src/ipcpd/config.h.in b/src/ipcpd/config.h.in
index 517016cc..55b0120c 100644
--- a/src/ipcpd/config.h.in
+++ b/src/ipcpd/config.h.in
@@ -25,6 +25,7 @@
#define SYS_MAX_FLOWS @SYS_MAX_FLOWS@
#define PROC_RES_FDS @PROC_RES_FDS@
#define PROC_MAX_FLOWS @PROC_MAX_FLOWS@
+#define POA_MAX_POAS @POA_MAX_POAS@
#define SOCKET_TIMEOUT @SOCKET_TIMEOUT@
#define CONNECT_TIMEOUT @CONNECT_TIMEOUT@
@@ -54,7 +55,6 @@
#cmakedefine DISABLE_CORE_LOCK
#cmakedefine BUILD_CONTAINER
#cmakedefine IPCP_FLOW_STATS
-#cmakedefine IPCP_ETH_FLOW_STATS
#cmakedefine IPCP_DEBUG_LOCAL
#ifdef CONFIG_OUROBOROS_DEBUG
#cmakedefine DEBUG_PROTO_DHT
@@ -62,29 +62,6 @@
#cmakedefine DEBUG_PROTO_LS
#endif
-/* udp */
-#cmakedefine HAVE_DDNS
-#define NSUPDATE_EXEC "@NSUPDATE_EXECUTABLE@"
-#define NSLOOKUP_EXEC "@NSLOOKUP_EXECUTABLE@"
-#define IPCP_UDP_RD_THR @IPCP_UDP_RD_THR@
-#define IPCP_UDP_WR_THR @IPCP_UDP_WR_THR@
-#define IPCP_UDP_MPL @IPCP_UDP_MPL@
-#define IPCP_UDP4_MTU @IPCP_UDP4_MTU@
-#define IPCP_UDP6_MTU @IPCP_UDP6_MTU@
-
-/* eth */
-#cmakedefine HAVE_NETMAP
-#cmakedefine HAVE_BPF
-#cmakedefine HAVE_RAW_SOCKETS
-#cmakedefine IPCP_ETH_QDISC_BYPASS
-#define IPCP_ETH_RD_THR @IPCP_ETH_RD_THR@
-#define IPCP_ETH_WR_THR @IPCP_ETH_WR_THR@
-#define IPCP_ETH_LO_MTU @IPCP_ETH_LO_MTU@
-#define IPCP_ETH_MGMT_FRAME_SIZE @IPCP_ETH_MGMT_FRAME_SIZE@
-#define IPCP_ETH_MPL @IPCP_ETH_MPL@
-#define IPCP_ETH_SNDBUF @IPCP_ETH_SNDBUF@
-#define IPCP_ETH_RCVBUF @IPCP_ETH_RCVBUF@
-
/* local */
#define IPCP_LOCAL_MPL @IPCP_LOCAL_MPL@
#define IPCP_LOCAL_MTU @IPCP_LOCAL_MTU@
diff --git a/src/ipcpd/eth/CMakeLists.txt b/src/ipcpd/eth/CMakeLists.txt
deleted file mode 100644
index 5a36352d..00000000
--- a/src/ipcpd/eth/CMakeLists.txt
+++ /dev/null
@@ -1,21 +0,0 @@
-# Ethernet IPCPs build configuration (LLC and DIX)
-# HAVE_ETH detection is in cmake/dependencies.cmake
-
-add_executable(${IPCP_ETH_LLC_TARGET} llc.c ${IPCP_SOURCES})
-add_executable(${IPCP_ETH_DIX_TARGET} dix.c ${IPCP_SOURCES})
-
-foreach(target ${IPCP_ETH_LLC_TARGET} ${IPCP_ETH_DIX_TARGET})
- target_include_directories(${target} PRIVATE ${IPCP_INCLUDE_DIRS})
- if(HAVE_BPF AND NOT APPLE)
- target_include_directories(${target} PRIVATE ${BPF_C_INCLUDE_DIR})
- endif()
- if(HAVE_NETMAP AND NOT APPLE)
- target_compile_options(${target} PRIVATE -std=c99)
- target_include_directories(${target} PRIVATE ${NETMAP_C_INCLUDE_DIR})
- endif()
- target_link_libraries(${target} PRIVATE ouroboros-dev)
- ouroboros_target_debug_definitions(${target})
-endforeach()
-
-install(TARGETS ${IPCP_ETH_LLC_TARGET} ${IPCP_ETH_DIX_TARGET}
- RUNTIME DESTINATION ${CMAKE_INSTALL_SBINDIR})
diff --git a/src/ipcpd/eth/eth.c b/src/ipcpd/eth/eth.c
deleted file mode 100644
index 2d3bd249..00000000
--- a/src/ipcpd/eth/eth.c
+++ /dev/null
@@ -1,2468 +0,0 @@
-/*
- * Ouroboros - Copyright (C) 2016 - 2026
- *
- * IPC processes over Ethernet
- *
- * Dimitri Staessens <dimitri@ouroboros.rocks>
- * Sander Vrijders <sander@ouroboros.rocks>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., http://www.fsf.org/about/contact/.
- */
-
-#if !defined(BUILD_ETH_DIX) && !defined(BUILD_ETH_LLC)
-#error Define BUILD_ETH_DIX or BUILD_ETH_LLC to build an Ethernet IPCP
-#endif
-
-#if defined(__APPLE__)
-#define _BSD_SOURCE
-#define _DARWIN_C_SOURCE
-#elif defined(__FreeBSD__)
-#define __BSD_VISIBLE 1
-#elif defined (__linux__) || defined (__CYGWIN__)
-#define _DEFAULT_SOURCE
-#else
-#define _POSIX_C_SOURCE 200112L
-#endif
-
-#include "config.h"
-
-#include <ouroboros/atomics.h>
-#include <ouroboros/endian.h>
-#include <ouroboros/hash.h>
-#include <ouroboros/errno.h>
-#include <ouroboros/list.h>
-#include <ouroboros/utils.h>
-#include <ouroboros/bitmap.h>
-#include <ouroboros/crc8.h>
-#include <ouroboros/dev.h>
-#include <ouroboros/ipcp-dev.h>
-#include <ouroboros/fqueue.h>
-#include <ouroboros/logs.h>
-#include <ouroboros/np1_flow.h>
-#include <ouroboros/time.h>
-#include <ouroboros/fccntl.h>
-#include <ouroboros/pthread.h>
-#include <ouroboros/rib.h>
-
-#ifndef IPCP_ETH_FLOW_STATS
-#undef FETCH_ADD_RELAXED
-#define FETCH_ADD_RELAXED(p, v) ((void) 0)
-#undef FETCH_SUB_RELAXED
-#define FETCH_SUB_RELAXED(p, v) ((void) 0)
-#endif
-
-#include "ipcp.h"
-#include "np1.h"
-#include "shim-data.h"
-
-#include <signal.h>
-#include <stdlib.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <string.h>
-#include <sys/socket.h>
-#include <sys/types.h>
-#include <sys/ioctl.h>
-
-#include <net/if.h>
-#include <netinet/in.h>
-
-#ifdef __linux__
-#include <linux/if_packet.h>
-#include <linux/if_ether.h>
-#include <linux/netlink.h>
-#include <linux/rtnetlink.h>
-#include <linux/sockios.h>
-#endif
-
-#ifdef __FreeBSD__
-#include <net/if_dl.h>
-#include <netinet/if_ether.h>
-#include <ifaddrs.h>
-#endif
-
-#ifdef __APPLE__
-#include <net/if_dl.h>
-#include <ifaddrs.h>
-#endif
-
-#include <poll.h>
-#include <sys/mman.h>
-
-#if defined(HAVE_NETMAP)
- #define NETMAP_WITH_LIBS
- #include <net/netmap_user.h>
-#elif defined(HAVE_BPF)
- #define BPF_DEV_MAX 256
- #define BPF_BLEN sysconf(_SC_PAGESIZE)
- #include <net/bpf.h>
-#endif
-
-#define MAC_FMT "%02x:%02x:%02x:%02x:%02x:%02x"
-#define MAC_VAL(a) \
- (uint8_t)(a)[0], (uint8_t)(a)[1], (uint8_t)(a)[2], \
- (uint8_t)(a)[3], (uint8_t)(a)[4], (uint8_t)(a)[5]
-
-
-#ifndef ETH_MAX_MTU /* In if_ether.h as of Linux 4.10. */
- #define ETH_MAX_MTU 0xFFFFU
-#endif /* ETH_MAX_MTU */
-#ifdef BUILD_ETH_DIX
- #define ETH_MTU eth_data.mtu
- #define ETH_MTU_MAX ETH_MAX_MTU
-#else
- #define ETH_MTU eth_data.mtu
- #define ETH_MTU_MAX 1500
-#endif /* BUILD_ETH_DIX */
-
-#define ETH_TYPE_LENGTH_SIZE sizeof(uint16_t)
-#define ETH_HEADER_SIZE (2 * MAC_SIZE + ETH_TYPE_LENGTH_SIZE)
-
-#if defined(BUILD_ETH_DIX)
-#define THIS_TYPE IPCP_ETH_DIX
-#define MGMT_EID 0
-#define DIX_EID_SIZE sizeof(uint16_t)
-#define DIX_LENGTH_SIZE sizeof(uint16_t)
-#define DIX_HCS_SIZE CRC8_HASH_LEN
-#define DIX_HEADER_SIZE (DIX_EID_SIZE + DIX_LENGTH_SIZE + DIX_HCS_SIZE)
-#define ETH_HEADER_TOT_SIZE (ETH_HEADER_SIZE + DIX_HEADER_SIZE)
-#define MAX_EIDS (1 << (8 * DIX_EID_SIZE))
-#define ETH_MAX_PACKET_SIZE (ETH_MTU - DIX_HEADER_SIZE)
-#define ETH_FRAME_SIZE (ETH_HEADER_SIZE + ETH_MTU_MAX)
-#elif defined(BUILD_ETH_LLC)
-#define THIS_TYPE IPCP_ETH_LLC
-#define MGMT_SAP 0x01
-#define LLC_FIELDS_SIZE 3
-#define LLC_HCS_SIZE CRC8_HASH_LEN
-#define LLC_HEADER_SIZE (LLC_FIELDS_SIZE + LLC_HCS_SIZE)
-#define ETH_HEADER_TOT_SIZE (ETH_HEADER_SIZE + LLC_HEADER_SIZE)
-#define MAX_SAPS 64
-#define ETH_MAX_PACKET_SIZE (ETH_MTU - LLC_HEADER_SIZE)
-#define ETH_FRAME_SIZE (ETH_HEADER_SIZE + ETH_MTU_MAX)
-#endif
-
-#define NAME_QUERY_TIMEO 1900 /* ms total budget */
-#define NAME_QUERY_RETRIES 3 /* retransmits, 4 attempts total */
-#define MGMT_TIMEO 100 /* ms */
-#define MGMT_FRAME_SIZE IPCP_ETH_MGMT_FRAME_SIZE
-#define ETH_RIB_PATH "eth"
-
-#define FLOW_REQ 0
-#define FLOW_REPLY 1
-#define NAME_QUERY_REQ 2
-#define NAME_QUERY_REPLY 3
-#define FLOW_IRM_UPDATE 4
-
-struct mgmt_msg {
-#if defined(BUILD_ETH_DIX)
- uint16_t seid;
- uint16_t deid;
-#elif defined(BUILD_ETH_LLC)
- uint8_t ssap;
- uint8_t dsap;
- /* QoS here for alignment */
- uint8_t code;
- uint8_t availability;
-#endif
- /* QoS parameters from spec, aligned */
- uint32_t loss;
- uint64_t bandwidth;
- uint32_t ber;
- uint32_t max_gap;
- uint32_t delay;
- uint32_t timeout;
- int32_t response;
- uint8_t service;
-#if defined (BUILD_ETH_DIX)
- uint8_t code;
- uint8_t availability;
-#endif
-} __attribute__((packed));
-
-struct eth_frame {
- uint8_t dst_hwaddr[MAC_SIZE];
- uint8_t src_hwaddr[MAC_SIZE];
-#if defined(BUILD_ETH_DIX)
- uint16_t ethertype;
- uint16_t eid;
- uint16_t length;
-#elif defined(BUILD_ETH_LLC)
- uint16_t length;
- uint8_t dsap;
- uint8_t ssap;
- uint8_t cf;
-#endif
- uint8_t hcs;
- uint8_t payload;
-} __attribute__((packed));
-
-struct ef {
-#if defined(BUILD_ETH_DIX)
- int32_t r_eid;
-#elif defined(BUILD_ETH_LLC)
- int8_t sap;
- int8_t r_sap;
-#endif
- uint8_t r_addr[MAC_SIZE];
-#ifdef IPCP_ETH_FLOW_STATS
- struct {
- time_t stamp;
- size_t p_rcv;
- size_t b_rcv;
- size_t p_dlv_f;
- size_t p_snd;
- size_t b_snd;
- size_t p_snd_f;
- } stat;
-#endif
-};
-
-struct mgmt_frame {
- struct list_head next;
- uint8_t r_addr[MAC_SIZE];
- uint8_t buf[MGMT_FRAME_SIZE];
- size_t len;
-};
-
-struct {
- struct shim_data * shim_data;
-
- int mtu;
-#ifdef __linux__
- int if_idx;
-#endif
-#if defined(HAVE_NETMAP)
- struct nm_desc * nmd;
- uint8_t hw_addr[MAC_SIZE];
- struct pollfd poll_in;
- struct pollfd poll_out;
-#elif defined(HAVE_BPF)
- int bpf;
- uint8_t hw_addr[MAC_SIZE];
-#elif defined(HAVE_RAW_SOCKETS)
- int s_fd;
- struct sockaddr_ll device;
-#endif /* HAVE_NETMAP */
-#if defined (BUILD_ETH_DIX)
- uint16_t ethertype;
-#elif defined(BUILD_ETH_LLC)
- struct bmp * saps;
- int * ef_to_fd;
-#endif
- struct ef * fd_to_ef;
- fset_t * np1_flows;
- pthread_rwlock_t flows_lock;
-#ifdef IPCP_ETH_FLOW_STATS
- struct {
- size_t n_flows;
- size_t n_rcv;
- size_t n_snd;
- size_t n_mgmt_rcv;
- size_t n_mgmt_snd;
- size_t n_bad_id;
- size_t n_dlv_f;
- size_t n_buf_f;
- size_t n_rcv_f;
- size_t n_snd_f;
- size_t kern_rcv;
- size_t kern_drp;
- } stat;
-#endif
-
- pthread_t packet_writer[IPCP_ETH_WR_THR];
- pthread_t packet_reader[IPCP_ETH_RD_THR];
-
-#ifdef __linux__
- pthread_t if_monitor;
-#endif
-
- /* Handle mgmt frames in a different thread */
- pthread_t mgmt_handler;
- pthread_mutex_t mgmt_lock;
- pthread_cond_t mgmt_cond;
- struct list_head mgmt_frames;
-} eth_data;
-
-static int eth_data_init(void)
-{
- int i;
- int ret = -ENOMEM;
- pthread_condattr_t cattr;
-
- eth_data.fd_to_ef =
- malloc(sizeof(*eth_data.fd_to_ef) * SYS_MAX_FLOWS);
- if (eth_data.fd_to_ef == NULL)
- goto fail_fd_to_ef;
-
-#ifdef BUILD_ETH_LLC
- eth_data.ef_to_fd =
- malloc(sizeof(*eth_data.ef_to_fd) * MAX_SAPS);
- if (eth_data.ef_to_fd == NULL)
- goto fail_ef_to_fd;
-
- for (i = 0; i < MAX_SAPS; ++i)
- eth_data.ef_to_fd[i] = -1;
-
- eth_data.saps = bmp_create(MAX_SAPS, 2);
- if (eth_data.saps == NULL)
- goto fail_saps;
-#endif
- eth_data.np1_flows = fset_create();
- if (eth_data.np1_flows == NULL)
- goto fail_np1_flows;
-
- for (i = 0; i < SYS_MAX_FLOWS; ++i) {
-#if defined(BUILD_ETH_DIX)
- eth_data.fd_to_ef[i].r_eid = -1;
-#elif defined(BUILD_ETH_LLC)
- eth_data.fd_to_ef[i].sap = -1;
- eth_data.fd_to_ef[i].r_sap = -1;
-#endif
- memset(&eth_data.fd_to_ef[i].r_addr, 0, MAC_SIZE);
-#ifdef IPCP_ETH_FLOW_STATS
- memset(&eth_data.fd_to_ef[i].stat, 0,
- sizeof(eth_data.fd_to_ef[i].stat));
-#endif
- }
-#ifdef IPCP_ETH_FLOW_STATS
- memset(&eth_data.stat, 0, sizeof(eth_data.stat));
-#endif
-
- eth_data.shim_data = shim_data_create();
- if (eth_data.shim_data == NULL)
- goto fail_shim_data;
-
- ret = -1;
-
- if (pthread_rwlock_init(&eth_data.flows_lock, NULL))
- goto fail_flows_lock;
-
- if (pthread_mutex_init(&eth_data.mgmt_lock, NULL))
- goto fail_mgmt_lock;
-
- if (pthread_condattr_init(&cattr))
- goto fail_condattr;
-
-#ifndef __APPLE__
- pthread_condattr_setclock(&cattr, PTHREAD_COND_CLOCK);
-#endif
-
- if (pthread_cond_init(&eth_data.mgmt_cond, &cattr))
- goto fail_mgmt_cond;
-
- pthread_condattr_destroy(&cattr);
-
- list_head_init(&eth_data.mgmt_frames);
-
- return 0;
-
- fail_mgmt_cond:
- pthread_condattr_destroy(&cattr);
- fail_condattr:
- pthread_mutex_destroy(&eth_data.mgmt_lock);
- fail_mgmt_lock:
- pthread_rwlock_destroy(&eth_data.flows_lock);
- fail_flows_lock:
- shim_data_destroy(eth_data.shim_data);
- fail_shim_data:
- fset_destroy(eth_data.np1_flows);
- fail_np1_flows:
-#ifdef BUILD_ETH_LLC
- bmp_destroy(eth_data.saps);
- fail_saps:
- free(eth_data.ef_to_fd);
- fail_ef_to_fd:
-#endif
- free(eth_data.fd_to_ef);
- fail_fd_to_ef:
- return ret;
-}
-
-static void eth_data_fini(void)
-{
-#if defined(HAVE_NETMAP)
- nm_close(eth_data.nmd);
-#elif defined(HAVE_BPF)
- close(eth_data.bpf);
-#elif defined(HAVE_RAW_SOCKETS)
- close(eth_data.s_fd);
-#endif
- pthread_cond_destroy(&eth_data.mgmt_cond);
- pthread_mutex_destroy(&eth_data.mgmt_lock);
- pthread_rwlock_destroy(&eth_data.flows_lock);
- shim_data_destroy(eth_data.shim_data);
- fset_destroy(eth_data.np1_flows);
-#ifdef BUILD_ETH_LLC
- bmp_destroy(eth_data.saps);
- free(eth_data.ef_to_fd);
-#endif
- free(eth_data.fd_to_ef);
-}
-
-#ifdef IPCP_ETH_FLOW_STATS
-static int eth_rib_read(const char * path,
- char * buf,
- size_t len)
-{
- struct ef * flow;
- int fd;
- char tmstr[RIB_TM_STRLEN];
- struct tm * tm;
- time_t stamp;
- char * entry;
-
- entry = strstr(path, RIB_SEPARATOR) + 1;
- assert(entry);
-
- if (len < 2048)
- return 0;
-
- buf[0] = '\0';
-
- if (strcmp(entry, "summary") == 0) {
- int n;
-#if defined(HAVE_RAW_SOCKETS)
- int rcvbuf = 0;
- int sndbuf = 0;
- int queued = 0;
- socklen_t optlen = sizeof(rcvbuf);
-# if defined(__linux__)
- int outq = 0;
- struct tpacket_stats tp_stats;
- socklen_t tp_len = sizeof(tp_stats);
-# endif
-
- getsockopt(eth_data.s_fd, SOL_SOCKET,
- SO_RCVBUF, &rcvbuf, &optlen);
- optlen = sizeof(sndbuf);
- getsockopt(eth_data.s_fd, SOL_SOCKET,
- SO_SNDBUF, &sndbuf, &optlen);
- ioctl(eth_data.s_fd, FIONREAD, &queued);
-# if defined(__linux__)
- ioctl(eth_data.s_fd, SIOCOUTQ, &outq);
- if (getsockopt(eth_data.s_fd, SOL_PACKET,
- PACKET_STATISTICS,
- &tp_stats, &tp_len) == 0) {
- FETCH_ADD_RELAXED(&eth_data.stat.kern_rcv,
- tp_stats.tp_packets);
- FETCH_ADD_RELAXED(&eth_data.stat.kern_drp,
- tp_stats.tp_drops);
- }
-# endif
-#endif
- n = sprintf(buf,
- "Active flows: %20zu\n"
- "Total frames received: %20zu\n"
- "Total frames sent: %20zu\n"
- "Management frames received: %20zu\n"
- "Management frames sent: %20zu\n"
- "Bad EID/SAP frames: %20zu\n"
- "Delivery (N+1) failures: %20zu\n"
- "Buffer alloc failures: %20zu\n"
- "Frame read failures: %20zu\n"
- "Frame send failures: %20zu\n",
- LOAD_RELAXED(&eth_data.stat.n_flows),
- LOAD_RELAXED(&eth_data.stat.n_rcv),
- LOAD_RELAXED(&eth_data.stat.n_snd),
- LOAD_RELAXED(&eth_data.stat.n_mgmt_rcv),
- LOAD_RELAXED(&eth_data.stat.n_mgmt_snd),
- LOAD_RELAXED(&eth_data.stat.n_bad_id),
- LOAD_RELAXED(&eth_data.stat.n_dlv_f),
- LOAD_RELAXED(&eth_data.stat.n_buf_f),
- LOAD_RELAXED(&eth_data.stat.n_rcv_f),
- LOAD_RELAXED(&eth_data.stat.n_snd_f));
-#if defined(HAVE_RAW_SOCKETS)
- n += sprintf(buf + n,
- "Socket rcvbuf (bytes): %20d\n"
- "Socket sndbuf (bytes): %20d\n"
- "Socket ingress (bytes): %20d\n",
- rcvbuf, sndbuf, queued);
-# if defined(__linux__)
- n += sprintf(buf + n,
- "Socket egress (bytes): %20d\n"
- "Kernel frames received: %20zu\n"
- "Kernel frames dropped: %20zu\n",
- outq,
- LOAD_RELAXED(&eth_data.stat.kern_rcv),
- LOAD_RELAXED(&eth_data.stat.kern_drp));
-# endif
-#endif
- return n;
- }
-
- fd = atoi(entry);
-
- if (fd < 0 || fd >= SYS_MAX_FLOWS)
- return -1;
-
- flow = &eth_data.fd_to_ef[fd];
-
- pthread_rwlock_rdlock(&eth_data.flows_lock);
-
- stamp = flow->stat.stamp;
- if (stamp == 0) {
- pthread_rwlock_unlock(&eth_data.flows_lock);
- return 0;
- }
-
- pthread_rwlock_unlock(&eth_data.flows_lock);
-
- tm = gmtime(&stamp);
- strftime(tmstr, sizeof(tmstr), RIB_TM_FORMAT, tm);
-
- sprintf(buf,
- "Flow established at: %20s\n"
- "Sent (packets): %20zu\n"
- "Sent (bytes): %20zu\n"
- "Send failed (packets): %20zu\n"
- "Received (packets): %20zu\n"
- "Received (bytes): %20zu\n"
- "Delivery (N+1) failures: %20zu\n",
- tmstr,
- LOAD_RELAXED(&flow->stat.p_snd),
- LOAD_RELAXED(&flow->stat.b_snd),
- LOAD_RELAXED(&flow->stat.p_snd_f),
- LOAD_RELAXED(&flow->stat.p_rcv),
- LOAD_RELAXED(&flow->stat.b_rcv),
- LOAD_RELAXED(&flow->stat.p_dlv_f));
-
- return strlen(buf);
-}
-
-static int eth_rib_readdir(char *** buf)
-{
- char entry[RIB_PATH_LEN + 1];
- size_t i;
- int idx = 0;
- int n_entries;
-
- pthread_rwlock_rdlock(&eth_data.flows_lock);
-
- n_entries = (int) LOAD_RELAXED(&eth_data.stat.n_flows) + 1;
-
- *buf = malloc(sizeof(**buf) * n_entries);
- if (*buf == NULL)
- goto fail_entries;
-
- (*buf)[idx] = malloc(strlen("summary") + 1);
- if ((*buf)[idx] == NULL)
- goto fail_entry;
-
- strcpy((*buf)[idx++], "summary");
-
- for (i = 0; i < SYS_MAX_FLOWS && idx < n_entries; ++i) {
- if (eth_data.fd_to_ef[i].stat.stamp == 0)
- continue;
-
- sprintf(entry, "%zu", i);
-
- (*buf)[idx] = malloc(strlen(entry) + 1);
- if ((*buf)[idx] == NULL)
- goto fail_entry;
-
- strcpy((*buf)[idx++], entry);
- }
-
- pthread_rwlock_unlock(&eth_data.flows_lock);
-
- return idx;
-
- fail_entry:
- while (idx-- > 0)
- free((*buf)[idx]);
-
- free(*buf);
- fail_entries:
- pthread_rwlock_unlock(&eth_data.flows_lock);
- return -ENOMEM;
-}
-
-static int eth_rib_getattr(const char * path,
- struct rib_attr * attr)
-{
- int fd;
- char * entry;
- struct ef * flow;
-
- entry = strstr(path, RIB_SEPARATOR) + 1;
- assert(entry);
-
- if (strcmp(entry, "summary") == 0) {
- attr->size = 2048;
- attr->mtime = 0;
- return 0;
- }
-
- fd = atoi(entry);
-
- if (fd < 0 || fd >= SYS_MAX_FLOWS) {
- attr->size = 0;
- attr->mtime = 0;
- return 0;
- }
-
- flow = &eth_data.fd_to_ef[fd];
-
- pthread_rwlock_rdlock(&eth_data.flows_lock);
-
- if (flow->stat.stamp != 0) {
- attr->size = 2048;
- attr->mtime = flow->stat.stamp;
- } else {
- attr->size = 0;
- attr->mtime = 0;
- }
-
- pthread_rwlock_unlock(&eth_data.flows_lock);
-
- return 0;
-}
-
-static struct rib_ops eth_r_ops = {
- .read = eth_rib_read,
- .readdir = eth_rib_readdir,
- .getattr = eth_rib_getattr
-};
-#endif /* IPCP_ETH_FLOW_STATS */
-
-#ifdef BUILD_ETH_LLC
-static uint8_t reverse_bits(uint8_t b)
-{
- b = (b & 0xF0) >> 4 | (b & 0x0F) << 4;
- b = (b & 0xCC) >> 2 | (b & 0x33) << 2;
- b = (b & 0xAA) >> 1 | (b & 0x55) << 1;
-
- return b;
-}
-#endif
-
-/* Pass a buffer that contains space for the header. */
-static int eth_ipcp_send_frame(const uint8_t * dst_addr,
-#if defined(BUILD_ETH_DIX)
- uint16_t deid,
-#elif defined(BUILD_ETH_LLC)
- uint8_t dsap,
- uint8_t ssap,
-#endif
- const uint8_t * frame,
- size_t len)
-{
- uint32_t frame_len = 0;
-#ifdef BUILD_ETH_LLC
- uint8_t cf = 0x03;
-#endif
- struct eth_frame * e_frame;
-#ifdef HAVE_RAW_SOCKETS
- fd_set fds;
-
- FD_ZERO(&fds);
-#endif
-
- assert(frame);
-
- if (len > (size_t) ETH_MAX_PACKET_SIZE)
- return -1;
-
- e_frame = (struct eth_frame *) frame;
-
- memcpy(e_frame->dst_hwaddr, dst_addr, MAC_SIZE);
- memcpy(e_frame->src_hwaddr,
-#if defined(HAVE_NETMAP) || defined(HAVE_BPF)
- eth_data.hw_addr,
-#elif defined(HAVE_RAW_SOCKETS)
- eth_data.device.sll_addr,
-#endif /* HAVE_NETMAP */
- MAC_SIZE);
-#if defined(BUILD_ETH_DIX)
- e_frame->ethertype = eth_data.ethertype;
- e_frame->eid = htons(deid);
- e_frame->length = htons(len);
- mem_hash(HASH_CRC8, &e_frame->hcs,
- (uint8_t *) &e_frame->eid,
- DIX_EID_SIZE + DIX_LENGTH_SIZE);
- frame_len = ETH_HEADER_TOT_SIZE + len;
-#elif defined(BUILD_ETH_LLC)
- e_frame->length = htons(LLC_HEADER_SIZE + len);
- e_frame->dsap = dsap;
- e_frame->ssap = ssap;
- e_frame->cf = cf;
- mem_hash(HASH_CRC8, &e_frame->hcs,
- (uint8_t *) &e_frame->dsap,
- LLC_FIELDS_SIZE);
- frame_len = ETH_HEADER_TOT_SIZE + len;
-#endif
-
-#if defined(HAVE_NETMAP)
- if (poll(&eth_data.poll_out, 1, -1) < 0)
- return -1;
-
- if (nm_inject(eth_data.nmd, frame, frame_len) != (int) frame_len) {
- log_dbg("Failed to send message.");
- return -1;
- }
-#elif defined(HAVE_BPF)
- if (write(eth_data.bpf, frame, frame_len) < 0) {
- log_dbg("Failed to send message.");
- return -1;
- }
-
-#elif defined(HAVE_RAW_SOCKETS)
- FD_SET(eth_data.s_fd, &fds);
- if (select(eth_data.s_fd + 1, NULL, &fds, NULL, NULL) < 0) {
- log_dbg("Select() failed: %s.", strerror(errno));
- return -1;
- }
- assert(FD_ISSET(eth_data.s_fd, &fds));
-
- if (sendto(eth_data.s_fd, frame, frame_len, 0,
- (struct sockaddr *) &eth_data.device,
- sizeof(eth_data.device)) <= 0) {
- log_dbg("Failed to send message: %s.", strerror(errno));
- return -1;
- }
-#endif /* HAVE_NETMAP */
-
- FETCH_ADD_RELAXED(&eth_data.stat.n_snd, 1);
-
- return 0;
-}
-
-static int eth_ipcp_alloc(const uint8_t * dst_addr,
-#if defined(BUILD_ETH_DIX)
- uint16_t eid,
-#elif defined(BUILD_ETH_LLC)
- uint8_t ssap,
-#endif
- const uint8_t * hash,
- qosspec_t qs,
- const buffer_t * data)
-{
- uint8_t * buf;
- struct mgmt_msg * msg;
- size_t len;
- int ret;
-
- len = sizeof(*msg) + ipcp_dir_hash_len();
-
- buf = malloc(len + ETH_HEADER_TOT_SIZE + data->len);
- if (buf == NULL)
- return -1;
-
- memset(buf, 0, len + ETH_HEADER_TOT_SIZE + data->len);
-
- msg = (struct mgmt_msg *) (buf + ETH_HEADER_TOT_SIZE);
- msg->code = FLOW_REQ;
-#if defined(BUILD_ETH_DIX)
- msg->seid = htons(eid);
-#elif defined(BUILD_ETH_LLC)
- msg->ssap = ssap;
-#endif
-
- msg->delay = hton32(qs.delay);
- msg->bandwidth = hton64(qs.bandwidth);
- msg->availability = qs.availability;
- msg->loss = hton32(qs.loss);
- msg->ber = hton32(qs.ber);
- msg->service = qs.service;
- msg->max_gap = hton32(qs.max_gap);
- msg->timeout = hton32(qs.timeout);
-
- memcpy(msg + 1, hash, ipcp_dir_hash_len());
- if (data->len > 0)
- memcpy(buf + len + ETH_HEADER_TOT_SIZE, data->data, data->len);
-
- ret = eth_ipcp_send_frame(dst_addr,
-#if defined(BUILD_ETH_DIX)
- MGMT_EID,
-#elif defined(BUILD_ETH_LLC)
- reverse_bits(MGMT_SAP),
- reverse_bits(MGMT_SAP),
-#endif
- buf, len + data->len);
- free(buf);
-
- if (ret == 0)
- FETCH_ADD_RELAXED(&eth_data.stat.n_mgmt_snd, 1);
-
- return ret;
-}
-
-static int eth_ipcp_alloc_resp(uint8_t * dst_addr,
-#if defined(BUILD_ETH_DIX)
- uint16_t seid,
- uint16_t deid,
-#elif defined(BUILD_ETH_LLC)
- uint8_t ssap,
- uint8_t dsap,
-#endif
- int response,
- const buffer_t * data)
-{
- struct mgmt_msg * msg;
- uint8_t * buf;
-
- buf = malloc(sizeof(*msg) + ETH_HEADER_TOT_SIZE + data->len);
- if (buf == NULL)
- return -1;
-
- memset(buf, 0, sizeof(*msg) + ETH_HEADER_TOT_SIZE + data->len);
-
- msg = (struct mgmt_msg *) (buf + ETH_HEADER_TOT_SIZE);
-
- msg->code = FLOW_REPLY;
-#if defined(BUILD_ETH_DIX)
- msg->seid = htons(seid);
- msg->deid = htons(deid);
-#elif defined(BUILD_ETH_LLC)
- msg->ssap = ssap;
- msg->dsap = dsap;
-#endif
- msg->response = hton32(response);
-
- if (data->len > 0)
- memcpy(msg + 1, data->data, data->len);
-
- if (eth_ipcp_send_frame(dst_addr,
-#if defined(BUILD_ETH_DIX)
- MGMT_EID,
-#elif defined(BUILD_ETH_LLC)
- reverse_bits(MGMT_SAP),
- reverse_bits(MGMT_SAP),
-#endif
- buf, sizeof(*msg) + data->len)) {
- free(buf);
- return -1;
- }
-
- FETCH_ADD_RELAXED(&eth_data.stat.n_mgmt_snd, 1);
-
- free(buf);
-
- return 0;
-}
-
-static int eth_ipcp_flow_update(int fd,
- const buffer_t * data)
-{
- struct mgmt_msg * msg;
- struct ef * flow;
- uint8_t * buf;
- uint8_t r_addr[MAC_SIZE];
- int ret;
-
- buf = malloc(sizeof(*msg) + ETH_HEADER_TOT_SIZE + data->len);
- if (buf == NULL)
- return -1;
-
- memset(buf, 0, sizeof(*msg) + ETH_HEADER_TOT_SIZE + data->len);
-
- msg = (struct mgmt_msg *) (buf + ETH_HEADER_TOT_SIZE);
-
- msg->code = FLOW_IRM_UPDATE;
-
- pthread_rwlock_rdlock(&eth_data.flows_lock);
-
- flow = &eth_data.fd_to_ef[fd];
-#if defined(BUILD_ETH_DIX)
- msg->seid = htons((uint16_t) fd);
- msg->deid = htons((uint16_t) flow->r_eid);
-#elif defined(BUILD_ETH_LLC)
- msg->ssap = flow->sap;
- msg->dsap = (uint8_t) flow->r_sap;
-#endif
- memcpy(r_addr, flow->r_addr, MAC_SIZE);
-
- pthread_rwlock_unlock(&eth_data.flows_lock);
-
- if (data->len > 0)
- memcpy(msg + 1, data->data, data->len);
-
- ret = eth_ipcp_send_frame(r_addr,
-#if defined(BUILD_ETH_DIX)
- MGMT_EID,
-#elif defined(BUILD_ETH_LLC)
- reverse_bits(MGMT_SAP),
- reverse_bits(MGMT_SAP),
-#endif
- buf, sizeof(*msg) + data->len);
- free(buf);
-
- if (ret == 0)
- FETCH_ADD_RELAXED(&eth_data.stat.n_mgmt_snd, 1);
-
- return ret;
-}
-
-static int eth_ipcp_req(uint8_t * r_addr,
-#if defined(BUILD_ETH_DIX)
- uint16_t r_eid,
-#elif defined(BUILD_ETH_LLC)
- uint8_t r_sap,
-#endif
- const uint8_t * dst,
- qosspec_t qs,
- const buffer_t * data)
-{
- int fd;
-
- fd = ipcp_wait_flow_req_arr(dst, qs, IPCP_ETH_MPL,
- ETH_MAX_PACKET_SIZE, data);
- if (fd < 0) {
- log_err("Could not get new flow from IRMd.");
- return -1;
- }
-
- pthread_rwlock_wrlock(&eth_data.flows_lock);
-#if defined(BUILD_ETH_DIX)
- eth_data.fd_to_ef[fd].r_eid = r_eid;
-#elif defined(BUILD_ETH_LLC)
- eth_data.fd_to_ef[fd].r_sap = r_sap;
-#endif
- memcpy(eth_data.fd_to_ef[fd].r_addr, r_addr, MAC_SIZE);
-
- pthread_rwlock_unlock(&eth_data.flows_lock);
-
-#if defined(BUILD_ETH_DIX)
- log_dbg("New flow request, fd %d, remote endpoint %d.", fd, r_eid);
-#elif defined(BUILD_ETH_LLC)
- log_dbg("New flow request, fd %d, remote SAP %d.", fd, r_sap);
-#endif
- return 0;
-}
-
-static int eth_ipcp_alloc_reply(uint8_t * r_addr,
-#if defined(BUILD_ETH_DIX)
- uint16_t seid,
- uint16_t deid,
-#elif defined(BUILD_ETH_LLC)
- uint8_t ssap,
- int dsap,
-#endif
- int response,
- const buffer_t * data)
-{
- int ret = 0;
- int fd = -1;
- time_t mpl = IPCP_ETH_MPL;
-
- pthread_rwlock_wrlock(&eth_data.flows_lock);
-
-#if defined(BUILD_ETH_DIX)
- fd = deid;
-#elif defined(BUILD_ETH_LLC)
- fd = eth_data.ef_to_fd[dsap];
-#endif
- if (fd < 0) {
- pthread_rwlock_unlock(&eth_data.flows_lock);
- log_err("No flow found with that SAP.");
- return -1; /* -EFLOWNOTFOUND */
- }
-
- if (response) {
-#ifdef BUILD_ETH_LLC
- bmp_release(eth_data.saps, eth_data.fd_to_ef[fd].sap);
-#endif
- } else {
-#if defined(BUILD_ETH_DIX)
- eth_data.fd_to_ef[fd].r_eid = seid;
-#elif defined(BUILD_ETH_LLC)
- eth_data.fd_to_ef[fd].r_sap = ssap;
-#endif
- memcpy(eth_data.fd_to_ef[fd].r_addr, r_addr, MAC_SIZE);
- }
-
- pthread_rwlock_unlock(&eth_data.flows_lock);
-
-#if defined(BUILD_ETH_DIX)
- log_dbg("Flow reply, fd %d, src eid %d, dst eid %d.", fd, seid, deid);
-#elif defined(BUILD_ETH_LLC)
- log_dbg("Flow reply, fd %d, SSAP %d, DSAP %d.", fd, ssap, dsap);
-#endif
- if ((ret = ipcp_flow_alloc_reply(fd, response, mpl,
- ETH_MAX_PACKET_SIZE, data)) < 0) {
- log_err("Failed to reply to flow allocation.");
- return -1;
- }
-
- return ret;
-}
-
-static int eth_ipcp_name_query_req(const uint8_t * hash,
- uint8_t * r_addr)
-{
- uint8_t * buf;
- struct mgmt_msg * msg;
- size_t len;
-
- if (shim_data_reg_has(eth_data.shim_data, hash)) {
- len = sizeof(*msg) + ipcp_dir_hash_len();
-
- buf = malloc(len + ETH_HEADER_TOT_SIZE);
- if (buf == NULL)
- return -1;
-
- memset(buf, 0, len + ETH_HEADER_TOT_SIZE);
-
- msg = (struct mgmt_msg *) (buf + ETH_HEADER_TOT_SIZE);
- msg->code = NAME_QUERY_REPLY;
-
- memcpy(msg + 1, hash, ipcp_dir_hash_len());
-
- if (eth_ipcp_send_frame(r_addr,
-#if defined(BUILD_ETH_DIX)
- MGMT_EID,
-#elif defined(BUILD_ETH_LLC)
- reverse_bits(MGMT_SAP),
- reverse_bits(MGMT_SAP),
-#endif
- buf, len)) {
- log_err("Failed to send management frame.");
- free(buf);
- return -1;
- }
-
- FETCH_ADD_RELAXED(&eth_data.stat.n_mgmt_snd, 1);
-
- free(buf);
- }
-
- return 0;
-}
-
-static int eth_ipcp_name_query_reply(const uint8_t * hash,
- uint8_t * r_addr)
-{
- struct addr addr;
-
- memcpy(&addr.mac, r_addr, MAC_SIZE);
-
- shim_data_dir_add_entry(eth_data.shim_data, hash, addr);
-
- shim_data_dir_query_respond(eth_data.shim_data, hash);
-
- return 0;
-}
-
-static int eth_ipcp_flow_update_arr(const uint8_t * buf,
- size_t len)
-{
- struct mgmt_msg * msg;
- buffer_t data;
- int fd;
- int flow_id;
-
- msg = (struct mgmt_msg *) buf;
-
- data.data = (uint8_t *) buf + sizeof(*msg);
- data.len = len - sizeof(*msg);
-
- pthread_rwlock_rdlock(&eth_data.flows_lock);
-#if defined(BUILD_ETH_DIX)
- fd = ntohs(msg->deid);
-#elif defined(BUILD_ETH_LLC)
- fd = eth_data.ef_to_fd[msg->dsap];
-#endif
- pthread_rwlock_unlock(&eth_data.flows_lock);
-
- if (fd < 0 || fd >= SYS_MAX_FLOWS) {
- log_err("Flow update for unknown endpoint.");
- return -1;
- }
-
- flow_id = np1_flow_id(fd);
- if (flow_id < 0)
- return -1;
-
- if (ipcp_flow_update_arr(flow_id, &data) < 0) {
- log_err("Failed to relay flow update on fd %d.", fd);
- return -1;
- }
-
- return 0;
-}
-
-static int eth_ipcp_mgmt_frame(const uint8_t * buf,
- size_t len,
- uint8_t * r_addr)
-{
- struct mgmt_msg * msg;
- size_t msg_len;
- qosspec_t qs;
- buffer_t data;
-
- if (len < sizeof(*msg))
- return -1;
-
- msg = (struct mgmt_msg *) buf;
-
- switch (msg->code) {
- case FLOW_REQ:
- msg_len = sizeof(*msg) + ipcp_dir_hash_len();
-
- if (len < msg_len)
- return -1;
-
- qs.delay = ntoh32(msg->delay);
- qs.bandwidth = ntoh64(msg->bandwidth);
- qs.availability = msg->availability;
- qs.loss = ntoh32(msg->loss);
- qs.ber = ntoh32(msg->ber);
- qs.service = msg->service;
- qs.max_gap = ntoh32(msg->max_gap);
- qs.timeout = ntoh32(msg->timeout);
-
- data.data = (uint8_t *) buf + msg_len;
- data.len = len - msg_len;
-
- if (shim_data_reg_has(eth_data.shim_data,
- buf + sizeof(*msg))) {
- eth_ipcp_req(r_addr,
-#if defined(BUILD_ETH_DIX)
- ntohs(msg->seid),
-#elif defined(BUILD_ETH_LLC)
- msg->ssap,
-#endif
- buf + sizeof(*msg),
- qs,
- &data);
- }
- break;
- case FLOW_REPLY:
- data.data = (uint8_t *) buf + sizeof(*msg);
- data.len = len - sizeof(*msg);
-
- eth_ipcp_alloc_reply(r_addr,
-#if defined(BUILD_ETH_DIX)
- ntohs(msg->seid),
- ntohs(msg->deid),
-#elif defined(BUILD_ETH_LLC)
- msg->ssap,
- msg->dsap,
-#endif
- ntoh32(msg->response),
- &data);
- break;
- case FLOW_IRM_UPDATE:
- eth_ipcp_flow_update_arr(buf, len);
- break;
- case NAME_QUERY_REQ:
- if (len < sizeof(*msg) + ipcp_dir_hash_len())
- return -1;
- eth_ipcp_name_query_req(buf + sizeof(*msg), r_addr);
- break;
- case NAME_QUERY_REPLY:
- if (len < sizeof(*msg) + ipcp_dir_hash_len())
- return -1;
- eth_ipcp_name_query_reply(buf + sizeof(*msg), r_addr);
- break;
- default:
- log_err("Unknown message received %d.", msg->code);
- return -1;
- }
-
- return 0;
-}
-
-static void * eth_ipcp_mgmt_handler(void * o)
-{
- (void) o;
-
- pthread_cleanup_push(__cleanup_mutex_unlock, &eth_data.mgmt_lock);
-
- while (true) {
- int ret = 0;
- struct timespec timeout = TIMESPEC_INIT_MS(MGMT_TIMEO);
- struct timespec abstime;
- struct mgmt_frame * frame = NULL;
-
- clock_gettime(PTHREAD_COND_CLOCK, &abstime);
- ts_add(&abstime, &timeout, &abstime);
-
- pthread_mutex_lock(&eth_data.mgmt_lock);
-
- while (list_is_empty(&eth_data.mgmt_frames) &&
- ret != -ETIMEDOUT)
- ret = -pthread_cond_timedwait(&eth_data.mgmt_cond,
- &eth_data.mgmt_lock,
- &abstime);
- if (ret != -ETIMEDOUT)
- frame = list_first_entry((&eth_data.mgmt_frames),
- struct mgmt_frame, next);
- if (frame != NULL)
- list_del(&frame->next);
-
- pthread_mutex_unlock(&eth_data.mgmt_lock);
-
- if (frame == NULL)
- continue;
-
- eth_ipcp_mgmt_frame(frame->buf, frame->len, frame->r_addr);
-
- free(frame);
- }
-
- pthread_cleanup_pop(false);
-
- return (void *) 0;
-}
-
-static void * eth_ipcp_packet_reader(void * o)
-{
- uint8_t br_addr[MAC_SIZE];
-#if defined(BUILD_ETH_DIX)
- uint16_t deid;
-#elif defined(BUILD_ETH_LLC)
- uint8_t dsap;
- uint8_t ssap;
-#endif
- uint16_t length;
- int fd;
- uint8_t * buf;
-#if defined(HAVE_NETMAP)
- struct nm_pkthdr hdr;
-#else
- struct ssm_pk_buff * spb;
- fd_set fds;
- int frame_len;
-#endif
-#if defined(HAVE_RAW_SOCKETS)
- struct sockaddr_ll src;
- socklen_t slen;
-#endif
- size_t eth_len;
- uint8_t hcs;
- struct eth_frame * e_frame;
- struct mgmt_frame * frame;
-
- (void) o;
-
- ipcp_lock_to_core();
-
- memset(br_addr, 0xff, MAC_SIZE * sizeof(uint8_t));
-
- while (true) {
-#if defined(HAVE_NETMAP)
- if (poll(&eth_data.poll_in, 1, -1) < 0)
- continue;
- if (eth_data.poll_in.revents == 0) /* TIMED OUT */
- continue;
-
- buf = nm_nextpkt(eth_data.nmd, &hdr);
- if (buf == NULL) {
- log_dbg("Bad read from netmap device.");
- continue;
- }
-#else
- FD_ZERO(&fds);
- #if defined(HAVE_BPF)
- FD_SET(eth_data.bpf, &fds);
- if (select(eth_data.bpf + 1, &fds, NULL, NULL, NULL))
- continue;
- assert(FD_ISSET(eth_data.bpf, &fds));
- if (ipcp_spb_reserve(&spb, BPF_LEN))
- continue;
- buf = ssm_pk_buff_head(spb);
- frame_len = read(eth_data.bpf, buf, BPF_BLEN);
- #elif defined(HAVE_RAW_SOCKETS)
- FD_SET(eth_data.s_fd, &fds);
- if (select(eth_data.s_fd + 1, &fds, NULL, NULL, NULL) < 0)
- continue;
- assert(FD_ISSET(eth_data.s_fd, &fds));
- if (ipcp_spb_reserve(&spb, ETH_MTU)) {
- FETCH_ADD_RELAXED(&eth_data.stat.n_buf_f, 1);
- continue;
- }
- buf = ssm_pk_buff_push(spb, ETH_HEADER_TOT_SIZE);
- if (buf == NULL) {
- log_dbg("Failed to allocate header.");
- ipcp_spb_release(spb);
- FETCH_ADD_RELAXED(&eth_data.stat.n_buf_f, 1);
- continue;
- }
- slen = sizeof(src);
- /* MSG_DONTWAIT: RD_THR>1 race-loser bails with EAGAIN. */
- frame_len = recvfrom(eth_data.s_fd, buf,
- ETH_MTU + ETH_HEADER_TOT_SIZE,
- MSG_DONTWAIT,
- (struct sockaddr *) &src, &slen);
- #endif
- if (frame_len == 0) {
- ipcp_spb_release(spb);
- continue; /* Spurious */
- }
-
- if (frame_len < 0) {
- ipcp_spb_release(spb);
-
- if (errno == EAGAIN || errno == EWOULDBLOCK)
- continue;
-
- log_dbg("Failed to rcv frame: %s.", strerror(errno));
- FETCH_ADD_RELAXED(&eth_data.stat.n_rcv_f, 1);
- continue;
- }
-#endif
-
-#if defined(HAVE_NETMAP)
- eth_len = hdr.len;
-#elif defined(HAVE_BPF)
- eth_len = ((struct bpf_hdr *) buf)->bh_caplen;
-#else
- eth_len = (size_t) frame_len;
-#endif
- /* Defense in depth: reject before parsing dereferences. */
- if (eth_len < ETH_HEADER_TOT_SIZE)
- goto fail_frame;
-
-#if defined(HAVE_RAW_SOCKETS)
- /* Drop our own egress. */
- if (src.sll_pkttype == PACKET_OUTGOING)
- goto fail_frame;
-#endif
-
-#if defined(HAVE_BPF) && !defined(HAVE_NETMAP)
- e_frame = (struct eth_frame *)
- (buf + ((struct bpf_hdr *) buf)->bh_hdrlen);
-#else
- e_frame = (struct eth_frame *) buf;
-#endif
- assert(e_frame->dst_hwaddr);
-
-#if !defined(HAVE_BPF)
- #if defined(HAVE_NETMAP)
- if (memcmp(eth_data.hw_addr,
- #elif defined(HAVE_RAW_SOCKETS)
- if (memcmp(eth_data.device.sll_addr,
- #endif /* HAVE_NETMAP */
- e_frame->dst_hwaddr,
- MAC_SIZE) &&
- memcmp(br_addr, e_frame->dst_hwaddr, MAC_SIZE)) {
- FETCH_ADD_RELAXED(&eth_data.stat.n_bad_id, 1);
- goto fail_frame;
- }
-#endif
- length = ntohs(e_frame->length);
-#if defined(BUILD_ETH_DIX)
- if (e_frame->ethertype != eth_data.ethertype)
- goto fail_frame;
-
- if (length > ETH_MTU)
- goto fail_frame;
-
- deid = ntohs(e_frame->eid);
-#elif defined (BUILD_ETH_LLC)
- if (length > 0x05FF) /* DIX */
- goto fail_frame;
-
- if (length < LLC_HEADER_SIZE || length > ETH_MTU)
- goto fail_frame;
-
- length -= LLC_HEADER_SIZE;
-
- dsap = reverse_bits(e_frame->dsap);
- ssap = reverse_bits(e_frame->ssap);
-#endif
-
- if (eth_len < ETH_HEADER_TOT_SIZE + (size_t) length)
- goto fail_frame;
-
-#if defined(BUILD_ETH_DIX)
- mem_hash(HASH_CRC8, &hcs,
- (uint8_t *) &e_frame->eid,
- DIX_EID_SIZE + DIX_LENGTH_SIZE);
-#elif defined(BUILD_ETH_LLC)
- mem_hash(HASH_CRC8, &hcs,
- (uint8_t *) &e_frame->dsap,
- LLC_FIELDS_SIZE);
-#endif
- if (hcs != e_frame->hcs)
- goto fail_frame;
-
-#if defined(BUILD_ETH_DIX)
- if (deid == MGMT_EID) {
-#elif defined (BUILD_ETH_LLC)
- if (ssap == MGMT_SAP && dsap == MGMT_SAP) {
-#endif
- ipcp_spb_release(spb); /* No need for the N+1 buffer. */
-
- if (length > MGMT_FRAME_SIZE) {
- log_warn("Management frame size %u exceeds %u.",
- length, MGMT_FRAME_SIZE);
- continue;
- }
-
- frame = malloc(sizeof(*frame));
- if (frame == NULL) {
- log_err("Failed to allocate frame.");
- continue;
- }
-
- memcpy(frame->buf, &e_frame->payload, length);
- memcpy(frame->r_addr, e_frame->src_hwaddr, MAC_SIZE);
- frame->len = length;
-
- pthread_mutex_lock(&eth_data.mgmt_lock);
- list_add(&frame->next, &eth_data.mgmt_frames);
- pthread_cond_signal(&eth_data.mgmt_cond);
- pthread_mutex_unlock(&eth_data.mgmt_lock);
- FETCH_ADD_RELAXED(&eth_data.stat.n_rcv, 1);
- FETCH_ADD_RELAXED(&eth_data.stat.n_mgmt_rcv, 1);
- } else {
- pthread_rwlock_rdlock(&eth_data.flows_lock);
-
-#if defined(BUILD_ETH_DIX)
- fd = deid;
-#elif defined(BUILD_ETH_LLC)
- fd = eth_data.ef_to_fd[dsap];
-#endif
- if (fd < 0) {
- pthread_rwlock_unlock(&eth_data.flows_lock);
- FETCH_ADD_RELAXED(&eth_data.stat.n_bad_id, 1);
- goto fail_frame;
- }
-
-#ifdef BUILD_ETH_LLC
- if (eth_data.fd_to_ef[fd].r_sap != ssap
- || memcmp(eth_data.fd_to_ef[fd].r_addr,
- e_frame->src_hwaddr, MAC_SIZE)) {
- pthread_rwlock_unlock(&eth_data.flows_lock);
- FETCH_ADD_RELAXED(&eth_data.stat.n_bad_id, 1);
- goto fail_frame;
- }
-#endif
- FETCH_ADD_RELAXED(&eth_data.fd_to_ef[fd].stat.p_rcv, 1);
- FETCH_ADD_RELAXED(&eth_data.fd_to_ef[fd].stat.b_rcv,
- length);
- FETCH_ADD_RELAXED(&eth_data.stat.n_rcv, 1);
- pthread_rwlock_unlock(&eth_data.flows_lock);
-
-#ifndef HAVE_NETMAP
- ssm_pk_buff_pop(spb, ETH_HEADER_TOT_SIZE);
- ssm_pk_buff_truncate(spb, length);
-#else
- if (ipcp_spb_reserve(&spb, length))
- continue;
-
- buf = ssm_pk_buff_head(spb);
- memcpy(buf, &e_frame->payload, length);
-#endif
- if (np1_flow_write(fd, spb, NP1_GET_POOL(fd)) < 0) {
- ipcp_spb_release(spb);
- FETCH_ADD_RELAXED(
- &eth_data.fd_to_ef[fd].stat.p_dlv_f,
- 1);
- FETCH_ADD_RELAXED(&eth_data.stat.n_dlv_f, 1);
- }
-
- continue;
- fail_frame:
-#ifndef HAVE_NETMAP
- ipcp_spb_release(spb);
-#endif
- }
- }
-
- return (void *) 0;
-}
-
-static void cleanup_writer(void * o)
-{
- fqueue_destroy((fqueue_t *) o);
-}
-
-static void * eth_ipcp_packet_writer(void * o)
-{
- int fd;
- struct ssm_pk_buff * spb;
- size_t len;
-#if defined(BUILD_ETH_DIX)
- uint16_t deid;
-#elif defined(BUILD_ETH_LLC)
- uint8_t dsap;
- uint8_t ssap;
-#endif
- uint8_t r_addr[MAC_SIZE];
-
- fqueue_t * fq;
-
- fq = fqueue_create();
- if (fq == NULL)
- return (void *) -1;
-
- (void) o;
-
- ipcp_lock_to_core();
-
- pthread_cleanup_push(cleanup_writer, fq);
-
- while (true) {
- fevent(eth_data.np1_flows, fq, NULL);
- while ((fd = fqueue_next(fq)) >= 0) {
- if (fqueue_type(fq) != FLOW_PKT)
- continue;
-
- if (np1_flow_read(fd, &spb, NP1_GET_POOL(fd))) {
- log_dbg("Bad read from fd %d.", fd);
- continue;
- }
-
- len = ssm_pk_buff_len(spb);
-
- if (ssm_pk_buff_push(spb, ETH_HEADER_TOT_SIZE)
- == NULL) {
- log_dbg("Failed to allocate header.");
- ipcp_spb_release(spb);
- FETCH_ADD_RELAXED(&eth_data.stat.n_buf_f, 1);
- continue;
- }
-
- pthread_rwlock_rdlock(&eth_data.flows_lock);
-#if defined(BUILD_ETH_DIX)
- deid = eth_data.fd_to_ef[fd].r_eid;
-#elif defined(BUILD_ETH_LLC)
- dsap = reverse_bits(eth_data.fd_to_ef[fd].r_sap);
- ssap = reverse_bits(eth_data.fd_to_ef[fd].sap);
-#endif
- memcpy(r_addr,
- eth_data.fd_to_ef[fd].r_addr,
- MAC_SIZE);
-
- pthread_rwlock_unlock(&eth_data.flows_lock);
-
- if (eth_ipcp_send_frame(r_addr,
-#if defined(BUILD_ETH_DIX)
- deid,
-#elif defined(BUILD_ETH_LLC)
- dsap, ssap,
-#endif
- ssm_pk_buff_head(spb),
- len)) {
- log_dbg("Failed to send frame.");
- FETCH_ADD_RELAXED(
- &eth_data.fd_to_ef[fd].stat.p_snd_f,
- 1);
- FETCH_ADD_RELAXED(&eth_data.stat.n_snd_f, 1);
- } else {
- FETCH_ADD_RELAXED(
- &eth_data.fd_to_ef[fd].stat.p_snd,
- 1);
- FETCH_ADD_RELAXED(
- &eth_data.fd_to_ef[fd].stat.b_snd,
- len);
- }
- ipcp_spb_release(spb);
- }
- }
-
- pthread_cleanup_pop(true);
-
- return (void *) 1;
-}
-
-#ifdef __linux__
-static int open_netlink_socket(void)
-{
- struct sockaddr_nl sa;
- int fd;
-
- memset(&sa, 0, sizeof(sa));
- sa.nl_family = AF_NETLINK;
- sa.nl_pid = getpid();
- sa.nl_groups = RTMGRP_LINK;
-
- fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
- if (fd < 0)
- return -1;
-
- if (bind(fd, (struct sockaddr *) &sa, sizeof(sa))) {
- close(fd);
- return -1;
- }
-
- return fd;
-}
-
-static void change_flows_state(bool up)
-{
- int i;
- uint32_t flags;
-
- pthread_rwlock_rdlock(&eth_data.flows_lock);
-
-#if defined(BUILD_ETH_DIX)
- for (i = 0; i < SYS_MAX_FLOWS; ++i)
- if (eth_data.fd_to_ef[i].r_eid != -1) {
- fccntl(i, FLOWGFLAGS, &flags);
- if (up)
- fccntl(i, FLOWSFLAGS, flags & ~FLOWFDOWN);
- else
- fccntl(i, FLOWSFLAGS, flags | FLOWFDOWN);
- }
-#elif defined(BUILD_ETH_LLC)
- for (i = 0; i < MAX_SAPS; i++)
- if (eth_data.ef_to_fd[i] != -1) {
- fccntl(eth_data.ef_to_fd[i], FLOWGFLAGS, &flags);
- if (up)
- fccntl(eth_data.ef_to_fd[i],
- FLOWSFLAGS, flags & ~FLOWFDOWN);
- else
- fccntl(eth_data.ef_to_fd[i],
- FLOWSFLAGS, flags | FLOWFDOWN);
- }
-#endif
-
- pthread_rwlock_unlock(&eth_data.flows_lock);
-}
-
-static void * eth_ipcp_if_monitor(void * o)
-{
- int fd;
- int status;
- char buf[4096];
- struct iovec iov = {buf, sizeof(buf)};
- struct sockaddr_nl snl;
- struct msghdr msg = {(void *) &snl, sizeof(snl),
- &iov, 1, NULL, 0, 0};
- struct nlmsghdr * h;
- struct ifinfomsg * ifi;
-
- (void ) o;
-
- fd = open_netlink_socket();
- if (fd < 0) {
- log_err("Failed to open socket.");
- return (void *) -1;
- }
-
- pthread_cleanup_push(__cleanup_close_ptr, &fd);
-
- while (true) {
- status = recvmsg(fd, &msg, 0);
- if (status < 0)
- continue;
-
- for (h = (struct nlmsghdr *) buf;
- NLMSG_OK(h, (unsigned int) status);
- h = NLMSG_NEXT(h, status)) {
-
- /* Finish reading */
- if (h->nlmsg_type == NLMSG_DONE)
- break;
-
- /* Message is some kind of error */
- if (h->nlmsg_type == NLMSG_ERROR)
- continue;
-
- /* Only interested in link up/down */
- if (h->nlmsg_type != RTM_NEWLINK)
- continue;
-
- ifi = NLMSG_DATA(h);
-
- /* Not our interface */
- if (ifi->ifi_index != eth_data.if_idx)
- continue;
-
- if (ifi->ifi_flags & IFF_UP) {
- change_flows_state(true);
- log_dbg("Interface up.");
- } else {
- change_flows_state(false);
- log_dbg("Interface down.");
- }
- }
- }
-
- pthread_cleanup_pop(true);
-
- return (void *) 0;
-}
-#endif
-
-#if defined (HAVE_BPF) && !defined(HAVE_NETMAP)
-static int open_bpf_device(void)
-{
- char dev[32];
- size_t i = 0;
-
- for (i = 0; i < BPF_DEV_MAX; i++) {
- int fd = -1;
-
- snprintf(dev, sizeof(dev), "/dev/bpf%zu", i);
-
- fd = open(dev, O_RDWR);
- if (fd > -1)
- return fd;
- }
-
- return -1;
-}
-#endif
-
-#if defined(__FreeBSD__) || defined(__APPLE__)
-static int ifr_hwaddr_from_ifaddrs(struct ifreq * ifr)
-{
- struct ifaddrs * ifaddr;
- struct ifaddrs * ifa;
- int idx;
-
- if (getifaddrs(&ifaddr) < 0) {
- log_err("Could not get interfaces.");
- goto fail_ifaddrs;
- }
-
- for (ifa = ifaddr, idx = 0; ifa != NULL; ifa = ifa->ifa_next, ++idx) {
- if (strcmp(ifa->ifa_name, ifr->ifr_name) == 0)
- break;
- }
-
- if (ifa == NULL) {
- log_err("Interface not found.");
- goto fail_ifa;
- }
-
- memcpy(&ifr->ifr_addr, ifa->ifa_addr, sizeof(*ifa->ifa_addr));
-
- log_dbg("Interface %s hwaddr " MAC_FMT ".", ifr->ifr_name,
- MAC_VAL(ifr->ifr_addr.sa_data));
-
- freeifaddrs(ifaddr);
-
- return 0;
- fail_ifa:
- freeifaddrs(ifaddr);
- fail_ifaddrs:
- return -1;
-
-}
-#elif defined(__linux__)
-static int ifr_hwaddr_from_socket(struct ifreq * ifr)
-{
- int skfd;
-
- skfd = socket(AF_UNIX, SOCK_STREAM, 0);
- if (skfd < 0) {
- log_err("Failed to open socket.");
- goto fail_socket;
- }
-
- if (ioctl(skfd, SIOCGIFHWADDR, ifr)) {
- log_err("Failed to get hwaddr.");
- goto fail_ifr;
- }
-
- log_dbg("Interface %s hwaddr " MAC_FMT ".", ifr->ifr_name,
- MAC_VAL(ifr->ifr_hwaddr.sa_data));
-
- close(skfd);
-
- return 0;
-
- fail_ifr:
- close(skfd);
- fail_socket:
- return -1;
-}
-#endif
-
-static int eth_ifr_hwaddr(struct ifreq * ifr)
-{
-#if defined(__FreeBSD__) || defined(__APPLE__)
- return ifr_hwaddr_from_ifaddrs(ifr);
-#elif defined(__linux__)
- return ifr_hwaddr_from_socket(ifr);
-#else
- return -1;
-#endif
-}
-
-static int eth_ifr_mtu(struct ifreq * ifr)
-{
- int skfd;
-
- skfd = socket(AF_UNIX, SOCK_STREAM, 0);
- if (skfd < 0) {
- log_err("Failed to open socket.");
- goto fail_socket;
- }
-
- if (ioctl(skfd, SIOCGIFMTU, ifr) < 0) {
- log_err("Failed to get MTU.");
- goto fail_mtu;
- }
- close(skfd);
-
- return 0;
-
- fail_mtu:
- close(skfd);
- fail_socket:
- return -1;
-}
-
-static int eth_set_mtu(struct ifreq * ifr)
-{
- if (eth_ifr_mtu(ifr) < 0) {
- log_err("Failed to get interface MTU.");
- return -1;
- }
-
- log_dbg("Device MTU is %d.", ifr->ifr_mtu);
-
- eth_data.mtu = MIN((int) ETH_MTU_MAX, ifr->ifr_mtu);
- if (memcmp(ifr->ifr_name, "lo", 2) == 0 &&
- eth_data.mtu > IPCP_ETH_LO_MTU) {
- log_dbg("Using loopback interface. MTU restricted to %d.",
- IPCP_ETH_LO_MTU);
- eth_data.mtu = IPCP_ETH_LO_MTU;
- }
-
- log_dbg("Layer MTU is %d.", eth_data.mtu);
-
- return 0;
-}
-#if defined(HAVE_NETMAP)
-static int eth_init_nmd(struct ifreq * ifr)
-{
- strcpy(ifn, "netmap:");
- strcat(ifn, ifr->ifr_name);
-
- eth_data.nmd = nm_open(ifn, NULL, 0, NULL);
- if (eth_data.nmd == NULL) {
- log_err("Failed to open netmap device.");
- goto fail_nmd;
- }
-
- memset(&eth_data.poll_in, 0, sizeof(eth_data.poll_in));
- memset(&eth_data.poll_out, 0, sizeof(eth_data.poll_out));
-
- eth_data.poll_in.fd = NETMAP_FD(eth_data.nmd);
- eth_data.poll_in.events = POLLIN;
- eth_data.poll_out.fd = NETMAP_FD(eth_data.nmd);
- eth_data.poll_out.events = POLLOUT;
-
- log_info("Using netmap device.");
-
- return 0;
- fail_nmd:
- return -1;
-}
-#elif defined (HAVE_BPF)
-static int eth_init_bpf(struct ifreq * ifr)
-{
- int enable = 1;
- int disable = 0;
- int blen;
-
- eth_data.bpf = open_bpf_device();
- if (eth_data.bpf < 0) {
- log_err("Failed to open bpf device.");
- goto fail_bpf;
- }
-
- ioctl(eth_data.bpf, BIOCGBLEN, &blen);
- if (BPF_BLEN < blen) {
- log_err("BPF buffer too small (is: %ld must be: %d).",
- BPF_BLEN, blen);
- goto fail_device;
- }
-
- if (ioctl(eth_data.bpf, BIOCSETIF, ifr) < 0) {
- log_err("Failed to set interface.");
- goto fail_device;
- }
-
- if (ioctl(eth_data.bpf, BIOCSHDRCMPLT, &enable) < 0) {
- log_err("Failed to set BIOCSHDRCMPLT.");
- goto fail_device;
- }
-
- if (ioctl(eth_data.bpf, BIOCSSEESENT, &disable) < 0) {
- log_err("Failed to set BIOCSSEESENT.");
- goto fail_device;
- }
-
- if (ioctl(eth_data.bpf, BIOCIMMEDIATE, &enable) < 0) {
- log_err("Failed to set BIOCIMMEDIATE.");
- goto fail_device;
- }
-
- log_info("Using Berkeley Packet Filter.");
-
- return 0;
-
- fail_device:
- close(eth_data.bpf);
- fail_bpf:
- return -1;
-}
-#elif defined(HAVE_RAW_SOCKETS)
-#define SOCKOPT()
-static int eth_init_raw_socket(struct ifreq * ifr)
-{
- int idx;
- int sndbuf;
- int rcvbuf;
-#if defined(IPCP_ETH_QDISC_BYPASS)
- int qdisc_bypass = 1;
-#endif /* ENABLE_QDISC_BYPASS */
-
- idx = if_nametoindex(ifr->ifr_name);
- if (idx == 0) {
- log_err("Failed to retrieve interface index.");
- return -1;
- }
-
- memset(&(eth_data.device), 0, sizeof(eth_data.device));
- eth_data.device.sll_ifindex = idx;
- eth_data.device.sll_family = AF_PACKET;
- memcpy(eth_data.device.sll_addr, ifr->ifr_hwaddr.sa_data, MAC_SIZE);
- eth_data.device.sll_halen = MAC_SIZE;
- eth_data.device.sll_protocol = htons(ETH_P_ALL);
-#if defined (BUILD_ETH_DIX)
- eth_data.s_fd = socket(AF_PACKET, SOCK_RAW, eth_data.ethertype);
-#elif defined (BUILD_ETH_LLC)
- eth_data.s_fd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_802_2));
-#endif
- if (eth_data.s_fd < 0) {
- log_err("Failed to create socket.");
- goto fail_socket;
- }
-
-#if defined(IPCP_ETH_QDISC_BYPASS)
- if (setsockopt(eth_data.s_fd, SOL_PACKET, PACKET_QDISC_BYPASS,
- &qdisc_bypass, sizeof(qdisc_bypass))) {
- log_info("Qdisc bypass not supported.");
- }
-#endif
-
- sndbuf = IPCP_ETH_SNDBUF;
- if (sndbuf > 0) {
- /* Never below one frame or sendto() cannot fit an SDU. */
- sndbuf = MAX(sndbuf, (int) (ETH_HEADER_TOT_SIZE + ETH_MTU));
- if (setsockopt(eth_data.s_fd, SOL_SOCKET, SO_SNDBUF,
- &sndbuf, sizeof(sndbuf)))
- log_info("Failed to set SO_SNDBUF to %d.", sndbuf);
- }
-
- rcvbuf = IPCP_ETH_RCVBUF;
- if (rcvbuf > 0) {
- /* SO_RCVBUFFORCE bypasses rmem_max; SO_RCVBUF is fallback. */
- if (setsockopt(eth_data.s_fd, SOL_SOCKET, SO_RCVBUFFORCE,
- &rcvbuf, sizeof(rcvbuf))
- && setsockopt(eth_data.s_fd, SOL_SOCKET, SO_RCVBUF,
- &rcvbuf, sizeof(rcvbuf)))
- log_info("Failed to set SO_RCVBUF to %d.", rcvbuf);
- }
-
- if (bind(eth_data.s_fd, (struct sockaddr *) &eth_data.device,
- sizeof(eth_data.device)) < 0) {
- log_err("Failed to bind socket to interface.");
- goto fail_device;
- }
-#ifdef __linux__
- eth_data.if_idx = idx;
-#endif
- log_info("Using raw socket device.");
-
- return 0;
- fail_device:
- close(eth_data.s_fd);
- fail_socket:
- return -1;
-}
-#endif
-
-static int eth_ipcp_bootstrap(struct ipcp_config * conf)
-{
- struct ifreq ifr;
- int i;
-#if defined(HAVE_NETMAP)
- char ifn[IFNAMSIZ];
-#endif /* HAVE_NETMAP */
-
- assert(conf);
- assert(conf->type == THIS_TYPE);
-
- memset(&ifr, 0, sizeof(ifr));
- strcpy(ifr.ifr_name, conf->eth.dev);
-
- if (strlen(conf->eth.dev) >= IFNAMSIZ) {
- log_err("Invalid device name: %s.", conf->eth.dev);
- return -1;
- }
-#ifdef BUILD_ETH_DIX
- if (conf->eth.ethertype < 0x0600 || conf->eth.ethertype == 0xFFFF) {
- log_err("Invalid Ethertype: %d.", conf->eth.ethertype);
- return -1;
- }
- eth_data.ethertype = htons(conf->eth.ethertype);
-#endif
- if (eth_set_mtu(&ifr) < 0) {
- log_err("Failed to set MTU.");
- return -1;
- }
-
- if (eth_ifr_hwaddr(&ifr) < 0) {
- log_err("Failed to get hardware addr.");
- return -1;
- }
-#if defined(HAVE_NETMAP) || defined(HAVE_BPF)
- memcpy(eth_data.hw_addr, LLADDR((struct sockaddr_dl *) &ifr.ifr_addr),
- MAC_SIZE);
-#endif
-#if defined(HAVE_NETMAP)
- if (eth_init_nmd(&ifr) < 0) {
- log_err("Failed to initialize netmap device.");
- return -1;
- }
-#elif defined(HAVE_BPF) /* !HAVE_NETMAP */
- if (eth_init_bpf(&ifr) < 0) {
- log_err("Failed to initialize BPF device.");
- return -1;
- }
-#elif defined(HAVE_RAW_SOCKETS)
- if (eth_init_raw_socket(&ifr) < 0) {
- log_err("Failed to initialize raw socket device.");
- return -1;
- }
-#endif /* HAVE_NETMAP */
-#ifdef IPCP_ETH_FLOW_STATS
- if (rib_reg(ETH_RIB_PATH, &eth_r_ops)) {
- log_err("Failed to register RIB.");
- goto fail_rib_reg;
- }
-#endif
-#if defined(__linux__)
- if (pthread_create(&eth_data.if_monitor, NULL,
- eth_ipcp_if_monitor, NULL)) {
- log_err("Failed to create monitor thread: %s.",
- strerror(errno));
- goto fail_monitor;
- }
-#endif
- if (pthread_create(&eth_data.mgmt_handler, NULL,
- eth_ipcp_mgmt_handler, NULL)) {
- log_err("Failed to create mgmt handler thread: %s.",
- strerror(errno));
- goto fail_mgmt_handler;
- }
-
- for (i = 0; i < IPCP_ETH_RD_THR; i++) {
- if (pthread_create(&eth_data.packet_reader[i], NULL,
- eth_ipcp_packet_reader, NULL)) {
- log_err("Failed to create packet reader thread: %s",
- strerror(errno));
- goto fail_packet_reader;
- }
- }
-
- for (i = 0; i < IPCP_ETH_WR_THR; i++) {
- if (pthread_create(&eth_data.packet_writer[i], NULL,
- eth_ipcp_packet_writer, NULL)) {
- log_err("Failed to create packet writer thread: %s",
- strerror(errno));
- goto fail_packet_writer;
- }
- }
-
-#if defined(BUILD_ETH_DIX)
- log_dbg("Bootstrapped IPCP over DIX Ethernet with pid %d "
- "and Ethertype 0x%X.", getpid(), conf->eth.ethertype);
-#elif defined(BUILD_ETH_LLC)
- log_dbg("Bootstrapped IPCP over Ethernet with LLC with pid %d.",
- getpid());
-#endif
- return 0;
-
- fail_packet_writer:
- while (i-- > 0) {
- pthread_cancel(eth_data.packet_writer[i]);
- pthread_join(eth_data.packet_writer[i], NULL);
- }
- i = IPCP_ETH_RD_THR;
- fail_packet_reader:
- while (i-- > 0) {
- pthread_cancel(eth_data.packet_reader[i]);
- pthread_join(eth_data.packet_reader[i], NULL);
- }
- pthread_cancel(eth_data.mgmt_handler);
- pthread_join(eth_data.mgmt_handler, NULL);
- fail_mgmt_handler:
-#if defined(__linux__)
- pthread_cancel(eth_data.if_monitor);
- pthread_join(eth_data.if_monitor, NULL);
-#endif
-#if defined(__linux__)
- fail_monitor:
-#endif
-#ifdef IPCP_ETH_FLOW_STATS
- rib_unreg(ETH_RIB_PATH);
- fail_rib_reg:
-#endif
-#if defined(HAVE_NETMAP)
- nm_close(eth_data.nmd);
-#elif defined(HAVE_BPF)
- close(eth_data.bpf);
-#elif defined(HAVE_RAW_SOCKETS)
- close(eth_data.s_fd);
-#endif
- return -1;
-}
-
-static int eth_ipcp_reg(const uint8_t * hash)
-{
- if (shim_data_reg_add_entry(eth_data.shim_data, hash)) {
- log_err("Failed to add " HASH_FMT32 " to local registry.",
- HASH_VAL32(hash));
- return -1;
- }
-
- return 0;
-}
-
-static int eth_ipcp_unreg(const uint8_t * hash)
-{
- shim_data_reg_del_entry(eth_data.shim_data, hash);
-
- return 0;
-}
-
-static int eth_ipcp_query(const uint8_t * hash)
-{
- uint8_t r_addr[MAC_SIZE];
- struct timespec timeout;
- struct dir_query * query;
- int ret;
- int attempt;
- uint8_t * buf;
- struct mgmt_msg * msg;
- size_t len;
- long per_ms;
-
- if (shim_data_dir_has(eth_data.shim_data, hash))
- return 0;
-
- len = sizeof(*msg) + ipcp_dir_hash_len();
-
- buf = malloc(len + ETH_HEADER_TOT_SIZE);
- if (buf == NULL)
- return -1;
-
- memset(buf, 0, len + ETH_HEADER_TOT_SIZE);
-
- msg = (struct mgmt_msg *) (buf + ETH_HEADER_TOT_SIZE);
- msg->code = NAME_QUERY_REQ;
-
- memcpy(msg + 1, hash, ipcp_dir_hash_len());
-
- memset(r_addr, 0xff, MAC_SIZE);
-
- per_ms = NAME_QUERY_TIMEO / (NAME_QUERY_RETRIES + 1);
-
- ret = -1;
- for (attempt = 0; attempt <= NAME_QUERY_RETRIES; ++attempt) {
- query = shim_data_dir_query_create(eth_data.shim_data, hash);
- if (query == NULL) {
- ret = -1;
- break;
- }
-
- if (eth_ipcp_send_frame(r_addr,
-#if defined(BUILD_ETH_DIX)
- MGMT_EID,
-#elif defined(BUILD_ETH_LLC)
- reverse_bits(MGMT_SAP),
- reverse_bits(MGMT_SAP),
-#endif
- buf, len)) {
- log_err("Failed to send management frame.");
- shim_data_dir_query_destroy(eth_data.shim_data,
- query);
- ret = -1;
- break;
- }
-
- FETCH_ADD_RELAXED(&eth_data.stat.n_mgmt_snd, 1);
-
- timeout.tv_sec = per_ms / 1000;
- timeout.tv_nsec = (per_ms % 1000) * 1000000L;
-
- ret = shim_data_dir_query_wait(query, &timeout);
-
- shim_data_dir_query_destroy(eth_data.shim_data, query);
-
- if (ret != -ETIMEDOUT)
- break;
- }
-
- free(buf);
-
- return ret;
-}
-
-static int eth_ipcp_flow_alloc(int fd,
- const uint8_t * hash,
- qosspec_t qs,
- const buffer_t * data)
-{
-#ifdef BUILD_ETH_LLC
- uint8_t ssap = 0;
-#endif
- uint8_t r_addr[MAC_SIZE];
- struct addr addr;
-
- assert(hash);
-
- if (!shim_data_dir_has(eth_data.shim_data, hash)) {
- log_err("Destination "HASH_FMT32 "unreachable.",
- HASH_VAL32(hash));
- return -1;
- }
-
- addr = shim_data_dir_get_addr(eth_data.shim_data, hash);
- memcpy(r_addr, &addr.mac, MAC_SIZE);
-
-#ifdef BUILD_ETH_LLC
- pthread_rwlock_wrlock(&eth_data.flows_lock);
- ssap = bmp_allocate(eth_data.saps);
- if (!bmp_is_id_valid(eth_data.saps, ssap)) {
- pthread_rwlock_unlock(&eth_data.flows_lock);
- log_err("Failed to allocate SSAP.");
- return -1;
- }
-
- eth_data.fd_to_ef[fd].sap = ssap;
- eth_data.ef_to_fd[ssap] = fd;
- pthread_rwlock_unlock(&eth_data.flows_lock);
-#endif
-
- if (eth_ipcp_alloc(r_addr,
-#if defined(BUILD_ETH_DIX)
- fd,
-#elif defined(BUILD_ETH_LLC)
- ssap,
-#endif
- hash,
- qs,
- data) < 0) {
-#ifdef BUILD_ETH_LLC
- pthread_rwlock_wrlock(&eth_data.flows_lock);
- bmp_release(eth_data.saps, eth_data.fd_to_ef[fd].sap);
- eth_data.fd_to_ef[fd].sap = -1;
- eth_data.ef_to_fd[ssap] = -1;
- pthread_rwlock_unlock(&eth_data.flows_lock);
- log_err("Failed to allocate with peer.");
-#endif
- return -1;
- }
-
- fset_add(eth_data.np1_flows, fd);
-#ifdef IPCP_ETH_FLOW_STATS
- pthread_rwlock_wrlock(&eth_data.flows_lock);
- memset(&eth_data.fd_to_ef[fd].stat, 0,
- sizeof(eth_data.fd_to_ef[fd].stat));
- eth_data.fd_to_ef[fd].stat.stamp = time(NULL);
- FETCH_ADD_RELAXED(&eth_data.stat.n_flows, 1);
- pthread_rwlock_unlock(&eth_data.flows_lock);
-#endif
-#if defined(BUILD_ETH_LLC)
- log_dbg("Assigned SAP %d for fd %d.", ssap, fd);
-#endif
- return 0;
-}
-
-static int eth_ipcp_flow_alloc_resp(int fd,
- int response,
- const buffer_t * data)
-{
-#if defined(BUILD_ETH_DIX)
- uint16_t r_eid;
-#elif defined(BUILD_ETH_LLC)
- uint8_t ssap;
- uint8_t r_sap;
-#endif
- uint8_t r_addr[MAC_SIZE];
-
- if (ipcp_wait_flow_resp(fd) < 0) {
- log_err("Failed to wait for flow response.");
- return -1;
- }
-
- pthread_rwlock_wrlock(&eth_data.flows_lock);
-#if defined(BUILD_ETH_DIX)
- r_eid = eth_data.fd_to_ef[fd].r_eid;
-#elif defined(BUILD_ETH_LLC)
- ssap = bmp_allocate(eth_data.saps);
- if (!bmp_is_id_valid(eth_data.saps, ssap)) {
- pthread_rwlock_unlock(&eth_data.flows_lock);
- log_err("Failed to allocate SSAP.");
- return -1;
- }
-
- eth_data.fd_to_ef[fd].sap = ssap;
- r_sap = eth_data.fd_to_ef[fd].r_sap;
- eth_data.ef_to_fd[ssap] = fd;
-#endif
- memcpy(r_addr, eth_data.fd_to_ef[fd].r_addr, MAC_SIZE);
-
- pthread_rwlock_unlock(&eth_data.flows_lock);
-
- if (eth_ipcp_alloc_resp(r_addr,
-#if defined(BUILD_ETH_DIX)
- fd, r_eid,
-#elif defined(BUILD_ETH_LLC)
- ssap, r_sap,
-#endif
- response,
- data) < 0) {
-#ifdef BUILD_ETH_LLC
- pthread_rwlock_wrlock(&eth_data.flows_lock);
- bmp_release(eth_data.saps, eth_data.fd_to_ef[fd].sap);
- pthread_rwlock_unlock(&eth_data.flows_lock);
-#endif
- log_err("Failed to respond to peer.");
- return -1;
- }
-
- fset_add(eth_data.np1_flows, fd);
-#ifdef IPCP_ETH_FLOW_STATS
- pthread_rwlock_wrlock(&eth_data.flows_lock);
- memset(&eth_data.fd_to_ef[fd].stat, 0,
- sizeof(eth_data.fd_to_ef[fd].stat));
- eth_data.fd_to_ef[fd].stat.stamp = time(NULL);
- FETCH_ADD_RELAXED(&eth_data.stat.n_flows, 1);
- pthread_rwlock_unlock(&eth_data.flows_lock);
-#endif
-#if defined(BUILD_ETH_LLC)
- log_dbg("Assigned SAP %d for fd %d.", ssap, fd);
-#endif
- return 0;
-}
-
-static int eth_ipcp_flow_dealloc(int fd)
-{
-#ifdef BUILD_ETH_LLC
- uint8_t sap;
-#endif
- ipcp_flow_fini(fd);
-
- fset_del(eth_data.np1_flows, fd);
-
- pthread_rwlock_wrlock(&eth_data.flows_lock);
-
-#if defined(BUILD_ETH_DIX)
- eth_data.fd_to_ef[fd].r_eid = -1;
-#elif defined BUILD_ETH_LLC
- sap = eth_data.fd_to_ef[fd].sap;
- bmp_release(eth_data.saps, sap);
- eth_data.fd_to_ef[fd].sap = -1;
- eth_data.fd_to_ef[fd].r_sap = -1;
- eth_data.ef_to_fd[sap] = -1;
-#endif
- memset(&eth_data.fd_to_ef[fd].r_addr, 0, MAC_SIZE);
-
-#ifdef IPCP_ETH_FLOW_STATS
- memset(&eth_data.fd_to_ef[fd].stat, 0,
- sizeof(eth_data.fd_to_ef[fd].stat));
- FETCH_SUB_RELAXED(&eth_data.stat.n_flows, 1);
-#endif
-
- pthread_rwlock_unlock(&eth_data.flows_lock);
-
- ipcp_flow_dealloc(fd);
-
- return 0;
-}
-
-static struct ipcp_ops eth_ops = {
- .ipcp_bootstrap = eth_ipcp_bootstrap,
- .ipcp_enroll = NULL,
- .ipcp_connect = NULL,
- .ipcp_disconnect = NULL,
- .ipcp_reg = eth_ipcp_reg,
- .ipcp_unreg = eth_ipcp_unreg,
- .ipcp_query = eth_ipcp_query,
- .ipcp_flow_alloc = eth_ipcp_flow_alloc,
- .ipcp_flow_join = NULL,
- .ipcp_flow_alloc_resp = eth_ipcp_flow_alloc_resp,
- .ipcp_flow_dealloc = eth_ipcp_flow_dealloc,
- .ipcp_flow_update = eth_ipcp_flow_update
-};
-
-int main(int argc,
- char * argv[])
-{
- int i;
-
- if (eth_data_init() < 0) {
-#if defined(BUILD_ETH_DIX)
- log_err("Failed to init eth-llc data.");
-#elif defined(BUILD_ETH_LLC)
- log_err("Failed to init eth-dix data.");
-#endif
- goto fail_data_init;
- }
-
- if (ipcp_init(argc, argv, &eth_ops, THIS_TYPE) < 0) {
- log_err("Failed to initialize IPCP.");
- goto fail_init;
- }
-
- if (ipcp_start() < 0) {
- log_err("Failed to start IPCP.");
- goto fail_start;
- }
-
- ipcp_sigwait();
-
- if (ipcp_get_state() == IPCP_SHUTDOWN) {
- for (i = 0; i < IPCP_ETH_WR_THR; ++i)
- pthread_cancel(eth_data.packet_writer[i]);
- for (i = 0; i < IPCP_ETH_RD_THR; ++i)
- pthread_cancel(eth_data.packet_reader[i]);
-
- pthread_cancel(eth_data.mgmt_handler);
-#ifdef __linux__
- pthread_cancel(eth_data.if_monitor);
-#endif
- for (i = 0; i < IPCP_ETH_WR_THR; ++i)
- pthread_join(eth_data.packet_writer[i], NULL);
- for (i = 0; i < IPCP_ETH_RD_THR; ++i)
- pthread_join(eth_data.packet_reader[i], NULL);
-
- pthread_join(eth_data.mgmt_handler, NULL);
-#ifdef __linux__
- pthread_join(eth_data.if_monitor, NULL);
-#endif
-#ifdef IPCP_ETH_FLOW_STATS
- rib_unreg(ETH_RIB_PATH);
-#endif
- }
-
- ipcp_stop();
-
- ipcp_fini();
-
- eth_data_fini();
-
- exit(EXIT_SUCCESS);
-
- fail_start:
- ipcp_fini();
- fail_init:
- eth_data_fini();
- fail_data_init:
- exit(EXIT_FAILURE);
-}
diff --git a/src/ipcpd/eth/llc.c b/src/ipcpd/eth/llc.c
deleted file mode 100644
index a772e86e..00000000
--- a/src/ipcpd/eth/llc.c
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Ouroboros - Copyright (C) 2016 - 2026
- *
- * IPC processes over Ethernet - LLC
- *
- * Dimitri Staessens <dimitri@ouroboros.rocks>
- * Sander Vrijders <sander@ouroboros.rocks>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., http://www.fsf.org/about/contact/.
- */
-
-#define BUILD_ETH_LLC
-#define OUROBOROS_PREFIX "ipcpd/eth-llc"
-
-#include "eth.c"
diff --git a/src/ipcpd/ipcp.c b/src/ipcpd/ipcp.c
index dcee4b9c..b25b7d04 100644
--- a/src/ipcpd/ipcp.c
+++ b/src/ipcpd/ipcp.c
@@ -36,6 +36,7 @@
#define OUROBOROS_PREFIX "ipcpd/ipcp"
#define IPCP_INFO "info"
#define ALLOC_TIMEOUT 50 /* ms */
+#define HAS_POA (ipcpd.type != IPCP_LOCAL)
#include <ouroboros/bitmap.h>
#include <ouroboros/dev.h>
@@ -54,6 +55,7 @@
#include "ipcp.h"
#include "np1.h"
+#include <arpa/inet.h>
#include <signal.h>
#include <string.h>
#include <sys/socket.h>
@@ -69,14 +71,14 @@
#define CLOCK_REALTIME_COARSE CLOCK_REALTIME
#endif
+/* Fits "eth <dev> 0x<type>", the longest PoA rendering. */
+/* Matches src/tools/irm/irm_utils.h; keep in sync. */
+#define POA_STRLEN (DEV_NAME_SIZE + 11)
+
static char * ipcp_type_str[] = {
"local",
"unicast",
- "broadcast",
- "eth-llc",
- "eth-dix",
- "udp4",
- "udp6"
+ "broadcast"
};
static char * dir_hash_str[] = {
@@ -237,14 +239,6 @@ static int ipcp_rib_read(const char * path,
strcpy(buf, "unicast\n");
else if (ipcpd.type == IPCP_BROADCAST)
strcpy(buf, "broadcast\n");
- else if (ipcpd.type == IPCP_ETH_LLC)
- strcpy(buf, "eth-llc\n");
- else if (ipcpd.type == IPCP_ETH_DIX)
- strcpy(buf, "eth-dix\n");
- else if (ipcpd.type == IPCP_UDP4)
- strcpy(buf, "udp4\n");
- else if (ipcpd.type == IPCP_UDP6)
- strcpy(buf, "udp6\n");
else
strcpy(buf, "bug\n");
}
@@ -316,8 +310,7 @@ static void * acceptloop(void * o)
(void) o;
- while (ipcp_get_state() != IPCP_SHUTDOWN &&
- ipcp_get_state() != IPCP_INIT) {
+ while (ipcp_get_state() != IPCP_SHUTDOWN) {
struct cmd * cmd;
csockfd = accept(ipcpd.sockfd, 0, 0);
@@ -471,11 +464,6 @@ static void do_bootstrap(ipcp_config_msg_t * conf_msg,
conf = ipcp_config_msg_to_s(conf_msg);
switch(conf.type) { /* FIXED algorithms */
- case IPCP_UDP4:
- /* FALLTHRU */
- case IPCP_UDP6:
- conf.layer_info.dir_hash_algo = (enum pol_dir_hash) HASH_MD5;
- break;
case IPCP_BROADCAST:
conf.layer_info.dir_hash_algo = DIR_HASH_SHA3_256;
break;
@@ -493,6 +481,8 @@ static void do_bootstrap(ipcp_config_msg_t * conf_msg,
strcpy(ipcpd.layer_name, info->name);
ipcpd.dir_hash_algo = (enum hash_algo) info->dir_hash_algo;
+ if (poa_set_layer(info->name) < 0)
+ log_warn("Failed to set layer name for PoA queries.");
ret_msg->layer_info = layer_info_s_to_msg(info);
ipcp_set_state(IPCP_OPERATIONAL);
@@ -503,10 +493,13 @@ static void do_bootstrap(ipcp_config_msg_t * conf_msg,
ipcp_dir_hash_len());
}
-static void do_enroll(const char * dst,
- ipcp_msg_t * ret_msg)
+static void do_enroll(const char * dst,
+ const poa_addr_msg_t * peer,
+ ipcp_msg_t * ret_msg)
{
struct layer_info info;
+ struct poa_addr addr;
+ struct poa_addr * pa = NULL;
log_info("Enrolling with %s...", dst);
@@ -524,7 +517,16 @@ static void do_enroll(const char * dst,
return;
}
- ret_msg->result = ipcpd.ops->ipcp_enroll(dst, &info);
+ if (peer != NULL) {
+ addr = poa_addr_msg_to_s(peer);
+ if (addr.type == POA_INVALID || addr.type == POA_UDP) {
+ ret_msg->result = -EINVAL;
+ return;
+ }
+ pa = &addr;
+ }
+
+ ret_msg->result = ipcpd.ops->ipcp_enroll(dst, pa, &info);
if (ret_msg->result < 0) {
log_err("Failed to bootstrap IPCP.");
return;
@@ -532,6 +534,8 @@ static void do_enroll(const char * dst,
strcpy(ipcpd.layer_name, info.name);
ipcpd.dir_hash_algo = (enum hash_algo) info.dir_hash_algo;
+ if (poa_set_layer(info.name) < 0)
+ log_warn("Failed to set layer name for PoA queries.");
ret_msg->layer_info = layer_info_s_to_msg(&info);
ipcp_set_state(IPCP_OPERATIONAL);
@@ -542,11 +546,136 @@ static void do_enroll(const char * dst,
ipcp_dir_hash_len());
}
-static void do_connect(const char * dst,
- const char * comp,
- qosspec_t qs,
- ipcp_msg_t * ret_msg)
+/* Bounded so one oversized reply cannot be built; 64 is generous. */
+#define POA_LIST_MAX 64
+
+static void do_list_poas(ipcp_msg_t * ret_msg)
+{
+ struct poa_spec eps[POA_LIST_MAX];
+ ssize_t n;
+ ssize_t i;
+
+ if (ipcpd.type != IPCP_UNICAST && ipcpd.type != IPCP_BROADCAST) {
+ ret_msg->result = -ENOTSUP;
+ return;
+ }
+
+ n = poa_list(eps, POA_LIST_MAX);
+ if (n < 0) {
+ ret_msg->result = (int) n;
+ return;
+ }
+
+ if (n > POA_LIST_MAX) {
+ log_warn("Listing %d of %zd PoAs.", POA_LIST_MAX, n);
+
+ n = POA_LIST_MAX;
+ }
+
+ if (n == 0) {
+ ret_msg->result = 0;
+ return;
+ }
+
+ ret_msg->poas = malloc(n * sizeof(*ret_msg->poas));
+ if (ret_msg->poas == NULL) {
+ ret_msg->result = -ENOMEM;
+ return;
+ }
+
+ for (i = 0; i < n; i++) {
+ ret_msg->poas[i] = poa_spec_s_to_msg(&eps[i]);
+ if (ret_msg->poas[i] == NULL) {
+ ret_msg->result = -ENOMEM;
+ return;
+ }
+ ret_msg->n_poas++;
+ }
+
+ ret_msg->result = 0;
+}
+
+/* Names a PoA the way "irm ipcp poa list" prints it. */
+/* Matches src/tools/irm/irm_utils.c; keep in sync. */
+static void poa_spec_str(const struct poa_spec * poa,
+ char * buf,
+ size_t len)
+{
+ char addr[INET6_ADDRSTRLEN];
+
+ switch (poa->type) {
+ case POA_UDP4:
+ if (inet_ntop(AF_INET, &poa->udp4.ip_addr,
+ addr, sizeof(addr)) == NULL)
+ break;
+
+ snprintf(buf, len, "udp4 %s:%u", addr, poa->udp4.port);
+ return;
+ case POA_UDP6:
+ if (inet_ntop(AF_INET6, &poa->udp6.ip_addr,
+ addr, sizeof(addr)) == NULL)
+ break;
+
+ snprintf(buf, len, "udp6 [%s]:%u", addr, poa->udp6.port);
+ return;
+ case POA_ETH:
+ snprintf(buf, len, "eth %s 0x%04X", poa->eth.dev,
+ poa->eth.ethertype);
+ return;
+ default:
+ break;
+ }
+
+ snprintf(buf, len, "(unknown)");
+}
+
+static void do_attach(poa_spec_msg_t * msg,
+ ipcp_msg_t * ret_msg)
{
+ struct poa_spec poa;
+ char str[POA_STRLEN + 1];
+
+ poa = poa_spec_msg_to_s(msg);
+
+ poa_spec_str(&poa, str, sizeof(str));
+
+ ret_msg->result = poa_attach(&poa);
+ if (ret_msg->result < 0) {
+ log_err("Failed to attach %s.", str);
+ return;
+ }
+
+ log_info("Attached %s.", str);
+}
+
+static void do_detach(poa_spec_msg_t * msg,
+ ipcp_msg_t * ret_msg)
+{
+ struct poa_spec poa;
+ char str[POA_STRLEN + 1];
+
+ poa = poa_spec_msg_to_s(msg);
+
+ poa_spec_str(&poa, str, sizeof(str));
+
+ ret_msg->result = poa_detach(&poa);
+ if (ret_msg->result < 0) {
+ log_err("Failed to detach %s.", str);
+ return;
+ }
+
+ log_info("Detached %s.", str);
+}
+
+static void do_connect(const char * dst,
+ const char * comp,
+ qosspec_t qs,
+ const poa_addr_msg_t * peer,
+ ipcp_msg_t * ret_msg)
+{
+ struct poa_addr addr;
+ struct poa_addr * pa = NULL;
+
log_info("Connecting %s to %s...", comp, dst);
if (ipcpd.ops->ipcp_connect == NULL) {
@@ -555,7 +684,16 @@ static void do_connect(const char * dst,
return;
}
- ret_msg->result = ipcpd.ops->ipcp_connect(dst, comp, qs);
+ if (peer != NULL) {
+ addr = poa_addr_msg_to_s(peer);
+ if (addr.type == POA_INVALID || addr.type == POA_UDP) {
+ ret_msg->result = -EINVAL;
+ return;
+ }
+ pa = &addr;
+ }
+
+ ret_msg->result = ipcpd.ops->ipcp_connect(dst, comp, qs, pa);
log_info("Finished connecting.");
}
@@ -734,9 +872,14 @@ static void do_flow_join(pid_t pid,
log_info("Finished joining layer " HASH_FMT32 ".", HASH_VAL32(dst));
}
+/*
+ * The IRMd says whether the flow is on a PoA, as it may not be known
+ * here yet. PoA flows answer without the IPCP type's flow machinery.
+ */
static void do_flow_alloc_resp(int resp,
int flow_id,
uid_t uid,
+ bool is_poa,
const buffer_t * data,
ipcp_msg_t * ret_msg)
{
@@ -745,13 +888,6 @@ static void do_flow_alloc_resp(int resp,
log_info("Responding %d to alloc on flow_id %d.", resp, flow_id);
- if (ipcpd.ops->ipcp_flow_alloc_resp == NULL) {
- log_err("Failed to respond on flow %d: operation unsupported.",
- flow_id);
- ret_msg->result = -ENOTSUP;
- return;
- }
-
if (ipcp_get_state() != IPCP_OPERATIONAL) {
log_err("Failed to respond to flow %d:"
"IPCP in state <%s>, need <%s>.",
@@ -762,6 +898,20 @@ static void do_flow_alloc_resp(int resp,
return;
}
+ if (is_poa) {
+ ret_msg->result = poa_flow_alloc_resp(flow_id, resp, data);
+ log_info("Finished responding %d on PoA flow %d.",
+ ret_msg->result, flow_id);
+ return;
+ }
+
+ if (ipcpd.ops->ipcp_flow_alloc_resp == NULL) {
+ log_err("Failed to respond on flow %d: operation unsupported.",
+ flow_id);
+ ret_msg->result = -ENOTSUP;
+ return;
+ }
+
fd = np1_flow_resp(flow_id, resp);
if (fd < 0) {
log_warn("Flow_id %d is not known.", flow_id);
@@ -788,18 +938,13 @@ static void do_flow_alloc_resp(int resp,
static void do_flow_dealloc(int flow_id,
int timeo_sec,
+ bool is_poa,
ipcp_msg_t * ret_msg)
{
int fd;
log_info("Deallocating flow %d.", flow_id);
- if (ipcpd.ops->ipcp_flow_dealloc == NULL) {
- log_err("Failed to dealloc: operation unsupported.");
- ret_msg->result = -ENOTSUP;
- return;
- }
-
if (ipcp_get_state() != IPCP_OPERATIONAL) {
log_err("Failed to enroll: IPCP in state <%s>, need <%s>.",
ipcp_state_str[ipcp_get_state()],
@@ -808,6 +953,20 @@ static void do_flow_dealloc(int flow_id,
return;
}
+ if (is_poa) {
+ ret_msg->result = poa_flow_dealloc(flow_id);
+
+ log_info("Finished deallocating PoA flow %d.", flow_id);
+ return;
+ }
+
+ if (ipcpd.ops->ipcp_flow_dealloc == NULL) {
+ log_err("Failed to dealloc: operation unsupported.");
+
+ ret_msg->result = -ENOTSUP;
+ return;
+ }
+
fd = np1_flow_dealloc(flow_id, timeo_sec);
if (fd < 0) {
log_warn("Could not deallocate flow_id %d.", flow_id);
@@ -822,18 +981,25 @@ static void do_flow_dealloc(int flow_id,
static void do_flow_update(int flow_id,
const buffer_t * data,
+ bool is_poa,
ipcp_msg_t * ret_msg)
{
int fd;
- if (ipcpd.ops->ipcp_flow_update == NULL) {
- log_err("Failed to update flow: operation unsupported.");
- ret_msg->result = -ENOTSUP;
+ if (ipcp_get_state() != IPCP_OPERATIONAL) {
+ ret_msg->result = -EIPCPSTATE;
return;
}
- if (ipcp_get_state() != IPCP_OPERATIONAL) {
- ret_msg->result = -EIPCPSTATE;
+ if (is_poa) {
+ ret_msg->result = poa_flow_update(flow_id, data);
+ return;
+ }
+
+ if (ipcpd.ops->ipcp_flow_update == NULL) {
+ log_err("Failed to update flow: operation unsupported.");
+
+ ret_msg->result = -ENOTSUP;
return;
}
@@ -881,6 +1047,7 @@ static void * mainloop(void * o)
free(cmd);
if (msg == NULL) {
+ log_err("Failed to unpack command message.");
close(sfd);
continue;
}
@@ -897,11 +1064,23 @@ static void * mainloop(void * o)
do_bootstrap(msg->conf, &ret_msg);
break;
case IPCP_MSG_CODE__IPCP_ENROLL:
- do_enroll(msg->dst, &ret_msg);
+ do_enroll(msg->dst, msg->peer, &ret_msg);
+ break;
+ case IPCP_MSG_CODE__IPCP_ATTACH:
+ assert(HAS_POA);
+ do_attach(msg->poa, &ret_msg);
+ break;
+ case IPCP_MSG_CODE__IPCP_DETACH:
+ assert(HAS_POA);
+ do_detach(msg->poa, &ret_msg);
+ break;
+ case IPCP_MSG_CODE__IPCP_LIST_POAS:
+ do_list_poas(&ret_msg);
break;
case IPCP_MSG_CODE__IPCP_CONNECT:
qs = qos_spec_msg_to_s(msg->qosspec);
- do_connect(msg->dst, msg->comp, qs, &ret_msg);
+ do_connect(msg->dst, msg->comp, qs, msg->peer,
+ &ret_msg);
break;
case IPCP_MSG_CODE__IPCP_DISCONNECT:
do_disconnect(msg->dst, msg->comp, &ret_msg);
@@ -940,17 +1119,20 @@ static void * mainloop(void * o)
data.len = msg->pk.len;
data.data = msg->pk.data;
do_flow_alloc_resp(msg->response, msg->flow_id,
- msg->uid, &data, &ret_msg);
+ msg->uid, msg->is_poa,
+ &data, &ret_msg);
break;
case IPCP_MSG_CODE__IPCP_FLOW_DEALLOC:
- do_flow_dealloc(msg->flow_id, msg->timeo_sec, &ret_msg);
+ do_flow_dealloc(msg->flow_id, msg->timeo_sec,
+ msg->is_poa, &ret_msg);
break;
case IPCP_MSG_CODE__IPCP_FLOW_UPDATE:
assert(msg->pk.len > 0 ? msg->pk.data != NULL
: msg->pk.data == NULL);
data.len = msg->pk.len;
data.data = msg->pk.data;
- do_flow_update(msg->flow_id, &data, &ret_msg);
+ do_flow_update(msg->flow_id, &data, msg->is_poa,
+ &ret_msg);
break;
default:
ret_msg.result = -1;
@@ -988,7 +1170,7 @@ static void * mainloop(void * o)
if (write(sfd, buffer.data, buffer.len) == -1)
log_warn("Failed to send reply message");
- pthread_cleanup_pop(true); /* close sfd */
+ pthread_cleanup_pop(true); /* close sfd */
pthread_cleanup_pop(true); /* free buffer.data */
tpm_end_work(ipcpd.tpm);
@@ -1101,6 +1283,11 @@ int ipcp_init(int argc,
goto fail_rib_reg;
}
+ if (poa_init(ipcpd.name) < 0) {
+ log_err("Failed to initialize PoAs.");
+ goto fail_poa_init;
+ }
+
list_head_init(&ipcpd.cmds);
ipcpd.tpm = tpm_create(IPCP_MIN_THREADS, IPCP_ADD_THREADS,
@@ -1124,6 +1311,8 @@ int ipcp_init(int argc,
return 0;
fail_tpm_create:
+ poa_fini();
+ fail_poa_init:
rib_unreg(IPCP_INFO);
fail_rib_reg:
rib_fini();
@@ -1149,6 +1338,7 @@ int ipcp_init(int argc,
return -1;
}
+/* Enrolment runs over a PoA, so poa_start() precedes any RPC. */
int ipcp_start(void)
{
sigset_t sigset;
@@ -1169,6 +1359,11 @@ int ipcp_start(void)
ipcp_set_state(IPCP_BOOT);
+ if (poa_start() < 0) {
+ log_err("Failed to start PoAs.");
+ goto fail_poa_start;
+ }
+
if (tpm_start(ipcpd.tpm)) {
log_err("Failed to start threadpool manager.");
goto fail_tpm_start;
@@ -1192,6 +1387,8 @@ int ipcp_start(void)
fail_acceptor:
tpm_stop(ipcpd.tpm);
fail_tpm_start:
+ poa_stop();
+ fail_poa_start:
tpm_destroy(ipcpd.tpm);
ipcp_set_state(IPCP_INIT);
ipcp_create_r(&info);
@@ -1263,6 +1460,8 @@ void ipcp_stop(void)
tpm_stop(ipcpd.tpm);
+ poa_stop();
+
ipcp_set_state(IPCP_INIT);
}
@@ -1271,6 +1470,8 @@ void ipcp_fini(void)
tpm_destroy(ipcpd.tpm);
+ poa_fini();
+
rib_unreg(IPCP_INFO);
rib_fini();
diff --git a/src/ipcpd/ipcp.h b/src/ipcpd/ipcp.h
index 210157ec..e0aab291 100644
--- a/src/ipcpd/ipcp.h
+++ b/src/ipcpd/ipcp.h
@@ -36,15 +36,18 @@
#define ipcp_dir_hash_strlen() (ipcp_dir_hash_len() * 2)
+/* Attach or release one flow PoA on a unicast or broadcast IPCP. */
struct ipcp_ops {
int (* ipcp_bootstrap)(struct ipcp_config * conf);
- int (* ipcp_enroll)(const char * dst,
- struct layer_info * info);
+ int (* ipcp_enroll)(const char * dst,
+ const struct poa_addr * addr,
+ struct layer_info * info);
- int (* ipcp_connect)(const char * dst,
- const char * component,
- qosspec_t qs);
+ int (* ipcp_connect)(const char * dst,
+ const char * component,
+ qosspec_t qs,
+ const struct poa_addr * addr);
int (* ipcp_disconnect)(const char * dst,
const char * component);
diff --git a/src/ipcpd/local/CMakeLists.txt b/src/ipcpd/local/CMakeLists.txt
index 91f300a3..af433d01 100644
--- a/src/ipcpd/local/CMakeLists.txt
+++ b/src/ipcpd/local/CMakeLists.txt
@@ -2,6 +2,7 @@
add_executable(${IPCP_LOCAL_TARGET}
main.c
+ reg.c
${IPCP_SOURCES}
)
diff --git a/src/ipcpd/local/main.c b/src/ipcpd/local/main.c
index c0aeb51e..69eac8a6 100644
--- a/src/ipcpd/local/main.c
+++ b/src/ipcpd/local/main.c
@@ -42,7 +42,7 @@
#include "ipcp.h"
#include "np1.h"
-#include "shim-data.h"
+#include "reg.h"
#include <string.h>
#include <stdlib.h>
@@ -53,14 +53,14 @@
#define THIS_TYPE IPCP_LOCAL
struct {
- struct shim_data * shim_data;
+ struct reg * reg;
- int in_out[SYS_MAX_FLOWS];
- fset_t * flows;
- fqueue_t * fq;
+ int in_out[SYS_MAX_FLOWS];
+ fset_t * flows;
+ fqueue_t * fq;
- pthread_rwlock_t lock;
- pthread_t packet_loop;
+ pthread_rwlock_t lock;
+ pthread_t packet_loop;
} local_data;
static int local_data_init(void)
@@ -77,9 +77,9 @@ static int local_data_init(void)
if (local_data.fq == NULL)
goto fail_fqueue;
- local_data.shim_data = shim_data_create();
- if (local_data.shim_data == NULL)
- goto fail_shim_data;
+ local_data.reg = reg_create();
+ if (local_data.reg == NULL)
+ goto fail_reg;
if (pthread_rwlock_init(&local_data.lock, NULL) < 0)
goto fail_rwlock_init;
@@ -87,8 +87,8 @@ static int local_data_init(void)
return 0;
fail_rwlock_init:
- shim_data_destroy(local_data.shim_data);
- fail_shim_data:
+ reg_destroy(local_data.reg);
+ fail_reg:
fqueue_destroy(local_data.fq);
fail_fqueue:
fset_destroy(local_data.flows);
@@ -98,7 +98,7 @@ static int local_data_init(void)
static void local_data_fini(void){
pthread_rwlock_destroy(&local_data.lock);
- shim_data_destroy(local_data.shim_data);
+ reg_destroy(local_data.reg);
fqueue_destroy(local_data.fq);
fset_destroy(local_data.flows);
}
@@ -166,7 +166,7 @@ static int local_ipcp_bootstrap(struct ipcp_config * conf)
static int local_ipcp_reg(const uint8_t * hash)
{
- if (shim_data_reg_add_entry(local_data.shim_data, hash)) {
+ if (reg_add(local_data.reg, hash) < 0) {
log_err("Failed to add " HASH_FMT32 " to local registry.",
HASH_VAL32(hash));
return -1;
@@ -177,7 +177,7 @@ static int local_ipcp_reg(const uint8_t * hash)
static int local_ipcp_unreg(const uint8_t * hash)
{
- shim_data_reg_del_entry(local_data.shim_data, hash);
+ reg_del(local_data.reg, hash);
log_info("Unregistered " HASH_FMT32 ".", HASH_VAL32(hash));
@@ -188,7 +188,7 @@ static int local_ipcp_query(const uint8_t * hash)
{
int ret;
- ret = (shim_data_reg_has(local_data.shim_data, hash) ? 0 : -1);
+ ret = (reg_has(local_data.reg, hash) ? 0 : -1);
return ret;
}
diff --git a/src/ipcpd/local/reg.c b/src/ipcpd/local/reg.c
new file mode 100644
index 00000000..36f19b16
--- /dev/null
+++ b/src/ipcpd/local/reg.c
@@ -0,0 +1,217 @@
+/*
+ * Ouroboros - Copyright (C) 2016 - 2026
+ *
+ * Names registered with the local IPCP
+ *
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., http://www.fsf.org/about/contact/.
+ */
+
+#if defined(__linux__) || defined(__CYGWIN__)
+#define _DEFAULT_SOURCE
+#else
+#define _POSIX_C_SOURCE 200112L
+#endif
+
+#define OUROBOROS_PREFIX "local-reg"
+
+#include <ouroboros/hash.h>
+#include <ouroboros/list.h>
+#include <ouroboros/logs.h>
+
+#include "reg.h"
+#include "ipcp.h"
+
+#include <assert.h>
+#include <pthread.h>
+#include <stdlib.h>
+#include <string.h>
+
+struct reg_entry {
+ struct list_head list;
+ uint8_t * hash;
+};
+
+struct reg {
+ struct list_head names;
+ pthread_rwlock_t lock;
+};
+
+static struct reg_entry * reg_entry_create(uint8_t * hash)
+{
+ struct reg_entry * entry;
+
+ entry = malloc(sizeof(*entry));
+ if (entry == NULL)
+ return NULL;
+
+ list_head_init(&entry->list);
+
+ entry->hash = hash;
+
+ return entry;
+}
+
+static void reg_entry_destroy(struct reg_entry * entry)
+{
+ assert(entry);
+
+ free(entry->hash);
+ free(entry);
+}
+
+/* Call with the lock held. */
+static struct reg_entry * reg_find(struct reg * reg,
+ const uint8_t * hash)
+{
+ struct list_head * p;
+
+ list_for_each(p, &reg->names) {
+ struct reg_entry * e;
+
+ e = list_entry(p, struct reg_entry, list);
+ if (memcmp(e->hash, hash, ipcp_dir_hash_len()) == 0)
+ return e;
+ }
+
+ return NULL;
+}
+
+struct reg * reg_create(void)
+{
+ struct reg * reg;
+
+ reg = malloc(sizeof(*reg));
+ if (reg == NULL)
+ goto fail_malloc;
+
+ list_head_init(&reg->names);
+
+ if (pthread_rwlock_init(&reg->lock, NULL) < 0)
+ goto fail_lock;
+
+ return reg;
+
+ fail_lock:
+ free(reg);
+ fail_malloc:
+ return NULL;
+}
+
+void reg_destroy(struct reg * reg)
+{
+ if (reg == NULL)
+ return;
+
+ pthread_rwlock_wrlock(&reg->lock);
+
+ while (!list_is_empty(&reg->names)) {
+ struct reg_entry * e;
+
+ e = list_first_entry(&reg->names, struct reg_entry, list);
+
+ list_del(&e->list);
+
+ reg_entry_destroy(e);
+ }
+
+ pthread_rwlock_unlock(&reg->lock);
+
+ pthread_rwlock_destroy(&reg->lock);
+
+ free(reg);
+}
+
+int reg_add(struct reg * reg,
+ const uint8_t * hash)
+{
+ struct reg_entry * entry;
+ uint8_t * dup;
+
+ assert(reg);
+ assert(hash);
+
+ pthread_rwlock_wrlock(&reg->lock);
+
+ if (reg_find(reg, hash) != NULL) {
+ pthread_rwlock_unlock(&reg->lock);
+ log_dbg(HASH_FMT32 " was already registered.",
+ HASH_VAL32(hash));
+ return 0;
+ }
+
+ dup = ipcp_hash_dup(hash);
+ if (dup == NULL)
+ goto fail;
+
+ entry = reg_entry_create(dup);
+ if (entry == NULL) {
+ free(dup);
+ goto fail;
+ }
+
+ list_add(&entry->list, &reg->names);
+
+ pthread_rwlock_unlock(&reg->lock);
+
+ return 0;
+
+ fail:
+ pthread_rwlock_unlock(&reg->lock);
+ return -1;
+}
+
+int reg_del(struct reg * reg,
+ const uint8_t * hash)
+{
+ struct reg_entry * e;
+
+ if (reg == NULL)
+ return -1;
+
+ pthread_rwlock_wrlock(&reg->lock);
+
+ e = reg_find(reg, hash);
+ if (e == NULL) {
+ pthread_rwlock_unlock(&reg->lock);
+ return 0; /* nothing to do */
+ }
+
+ list_del(&e->list);
+
+ pthread_rwlock_unlock(&reg->lock);
+
+ reg_entry_destroy(e);
+
+ return 0;
+}
+
+bool reg_has(struct reg * reg,
+ const uint8_t * hash)
+{
+ bool ret;
+
+ assert(reg);
+ assert(hash);
+
+ pthread_rwlock_rdlock(&reg->lock);
+
+ ret = reg_find(reg, hash) != NULL;
+
+ pthread_rwlock_unlock(&reg->lock);
+
+ return ret;
+}
diff --git a/src/ipcpd/eth/dix.c b/src/ipcpd/local/reg.h
index cf8253bd..2c6142bb 100644
--- a/src/ipcpd/eth/dix.c
+++ b/src/ipcpd/local/reg.h
@@ -1,7 +1,7 @@
/*
* Ouroboros - Copyright (C) 2016 - 2026
*
- * IPC processes over Ethernet - DIX
+ * Names registered with the local IPCP
*
* Dimitri Staessens <dimitri@ouroboros.rocks>
* Sander Vrijders <sander@ouroboros.rocks>
@@ -20,7 +20,26 @@
* Foundation, Inc., http://www.fsf.org/about/contact/.
*/
-#define BUILD_ETH_DIX
-#define OUROBOROS_PREFIX "ipcpd/eth-dix"
+#ifndef OUROBOROS_IPCPD_LOCAL_REG_H
+#define OUROBOROS_IPCPD_LOCAL_REG_H
-#include "eth.c"
+#include <stdbool.h>
+#include <stdint.h>
+
+/* The hashes of the names registered with this IPCP. */
+struct reg;
+
+struct reg * reg_create(void);
+
+void reg_destroy(struct reg * reg);
+
+int reg_add(struct reg * reg,
+ const uint8_t * hash);
+
+int reg_del(struct reg * reg,
+ const uint8_t * hash);
+
+bool reg_has(struct reg * reg,
+ const uint8_t * hash);
+
+#endif /* OUROBOROS_IPCPD_LOCAL_REG_H */
diff --git a/src/ipcpd/shim-data.c b/src/ipcpd/shim-data.c
deleted file mode 100644
index 90a676da..00000000
--- a/src/ipcpd/shim-data.c
+++ /dev/null
@@ -1,582 +0,0 @@
-/*
- * Ouroboros - Copyright (C) 2016 - 2026
- *
- * IPC process utilities
- *
- * Dimitri Staessens <dimitri@ouroboros.rocks>
- * Sander Vrijders <sander@ouroboros.rocks>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., http://www.fsf.org/about/contact/.
- */
-
-#if defined(__linux__) || defined(__CYGWIN__)
-#define _DEFAULT_SOURCE
-#else
-#define _POSIX_C_SOURCE 200112L
-#endif
-
-#include "config.h"
-
-#define OUROBOROS_PREFIX "shim-data"
-
-#include <ouroboros/errno.h>
-#include <ouroboros/hash.h>
-#include <ouroboros/list.h>
-#include <ouroboros/logs.h>
-#include <ouroboros/time.h>
-
-#include "shim-data.h"
-#include "ipcp.h"
-
-#include <assert.h>
-#include <stdlib.h>
-#include <string.h>
-
-struct reg_entry {
- struct list_head list;
- uint8_t * hash;
-};
-
-struct dir_entry {
- struct list_head list;
- uint8_t * hash;
- struct addr addr;
-};
-
-static void destroy_dir_query(struct dir_query * query)
-{
- assert(query);
-
- pthread_mutex_lock(&query->lock);
-
- switch (query->state) {
- case QUERY_INIT:
- query->state = QUERY_DONE;
- break;
- case QUERY_PENDING:
- query->state = QUERY_DESTROY;
- pthread_cond_broadcast(&query->cond);
- break;
- case QUERY_RESPONSE:
- case QUERY_DONE:
- break;
- case QUERY_DESTROY:
- pthread_mutex_unlock(&query->lock);
- return;
- default:
- assert(false);
- return;
- }
-
- while (query->state != QUERY_DONE)
- pthread_cond_wait(&query->cond, &query->lock);
-
- pthread_mutex_unlock(&query->lock);
-
- pthread_cond_destroy(&query->cond);
- pthread_mutex_destroy(&query->lock);
-
- free(query->hash);
- free(query);
-}
-
-static struct reg_entry * reg_entry_create(uint8_t * hash)
-{
- struct reg_entry * entry = malloc(sizeof(*entry));
- if (entry == NULL)
- return NULL;
-
- assert(hash);
-
- entry->hash = hash;
-
- return entry;
-}
-
-static void reg_entry_destroy(struct reg_entry * entry)
-{
- assert(entry);
-
- free(entry->hash);
- free(entry);
-}
-
-static struct dir_entry * dir_entry_create(uint8_t * hash,
- struct addr addr)
-{
- struct dir_entry * entry = malloc(sizeof(*entry));
- if (entry == NULL)
- return NULL;
-
- assert(hash);
-
- entry->addr = addr;
- entry->hash = hash;
-
- return entry;
-}
-
-static void dir_entry_destroy(struct dir_entry * entry)
-{
- assert(entry);
-
- free(entry->hash);
- free(entry);
-}
-
-struct shim_data * shim_data_create(void)
-{
- struct shim_data * sd;
-
- sd = malloc(sizeof(*sd));
- if (sd == NULL)
- return NULL;
-
- /* init the lists */
- list_head_init(&sd->registry);
- list_head_init(&sd->directory);
- list_head_init(&sd->dir_queries);
-
- /* init the locks */
- if (pthread_rwlock_init(&sd->reg_lock, NULL) < 0)
- goto fail_reg_lock_init;
-
- if (pthread_rwlock_init(&sd->dir_lock, NULL) < 0)
- goto fail_dir_lock_init;
-
- if (pthread_mutex_init(&sd->dir_queries_lock, NULL) < 0)
- goto fail_mutex_init;
-
- return sd;
-
- fail_mutex_init:
- pthread_rwlock_destroy(&sd->dir_lock);
- fail_dir_lock_init:
- pthread_rwlock_destroy(&sd->reg_lock);
- fail_reg_lock_init:
- return NULL;
-}
-
-static void clear_registry(struct shim_data * data)
-{
- struct list_head * h;
- struct list_head * t;
-
- assert(data);
-
- list_for_each_safe(h, t, &data->registry) {
- struct reg_entry * e = list_entry(h, struct reg_entry, list);
- list_del(&e->list);
- reg_entry_destroy(e);
- }
-}
-
-static void clear_directory(struct shim_data * data)
-{
- struct list_head * h;
- struct list_head * t;
-
- assert(data);
-
- list_for_each_safe(h, t, &data->directory) {
- struct dir_entry * e = list_entry(h, struct dir_entry, list);
- list_del(&e->list);
- dir_entry_destroy(e);
- }
-}
-
-static void clear_dir_queries(struct shim_data * data)
-{
- struct list_head * h;
- struct list_head * t;
-
- assert(data);
-
- list_for_each_safe(h, t, &data->dir_queries) {
- struct dir_query * e = list_entry(h, struct dir_query, next);
- list_del(&e->next);
- destroy_dir_query(e);
- }
-}
-
-void shim_data_destroy(struct shim_data * data)
-{
- if (data == NULL)
- return;
-
- /* clear the lists */
- pthread_rwlock_wrlock(&data->reg_lock);
- clear_registry(data);
- pthread_rwlock_unlock(&data->reg_lock);
-
- pthread_rwlock_wrlock(&data->dir_lock);
- clear_directory(data);
- pthread_rwlock_unlock(&data->dir_lock);
-
- pthread_mutex_lock(&data->dir_queries_lock);
- clear_dir_queries(data);
- pthread_mutex_unlock(&data->dir_queries_lock);
-
- pthread_rwlock_destroy(&data->dir_lock);
- pthread_rwlock_destroy(&data->reg_lock);
- pthread_mutex_destroy(&data->dir_queries_lock);
-
- free(data);
-}
-
-static struct reg_entry * find_reg_entry_by_hash(struct shim_data * data,
- const uint8_t * hash)
-{
- struct list_head * h;
-
- assert(data);
- assert(hash);
-
- list_for_each(h, &data->registry) {
- struct reg_entry * e = list_entry(h, struct reg_entry, list);
- if (!memcmp(e->hash, hash, ipcp_dir_hash_len()))
- return e;
- }
-
- return NULL;
-}
-
-static struct dir_entry * find_dir_entry(struct shim_data * data,
- const uint8_t * hash,
- struct addr addr)
-{
- struct list_head * h;
- list_for_each(h, &data->directory) {
- struct dir_entry * e = list_entry(h, struct dir_entry, list);
- if (memcmp(&e->addr, &addr, sizeof(addr)) != 0)
- continue;
-
- if (memcmp(e->hash, hash, ipcp_dir_hash_len()) == 0)
- return e;
- }
-
- return NULL;
-}
-
-static struct dir_entry * find_dir_entry_any(struct shim_data * data,
- const uint8_t * hash)
-{
- struct list_head * h;
- list_for_each(h, &data->directory) {
- struct dir_entry * e = list_entry(h, struct dir_entry, list);
- if (!memcmp(e->hash, hash, ipcp_dir_hash_len()))
- return e;
- }
-
- return NULL;
-}
-
-int shim_data_reg_add_entry(struct shim_data * data,
- const uint8_t * hash)
-{
- struct reg_entry * entry;
- uint8_t * hash_dup;
-
- assert(data);
- assert(hash);
-
- pthread_rwlock_wrlock(&data->reg_lock);
-
- if (find_reg_entry_by_hash(data, hash)) {
- pthread_rwlock_unlock(&data->reg_lock);
- log_dbg(HASH_FMT32 " was already in the directory.",
- HASH_VAL32(hash));
- return 0;
- }
-
- hash_dup = ipcp_hash_dup(hash);
- if (hash_dup == NULL) {
- pthread_rwlock_unlock(&data->reg_lock);
- return -1;
- }
-
- entry = reg_entry_create(hash_dup);
- if (entry == NULL) {
- pthread_rwlock_unlock(&data->reg_lock);
- return -1;
- }
-
- list_add(&entry->list, &data->registry);
-
- pthread_rwlock_unlock(&data->reg_lock);
-
- return 0;
-}
-
-int shim_data_reg_del_entry(struct shim_data * data,
- const uint8_t * hash)
-{
- struct reg_entry * e;
- if (data == NULL)
- return -1;
-
- pthread_rwlock_wrlock(&data->reg_lock);
-
- e = find_reg_entry_by_hash(data, hash);
- if (e == NULL) {
- pthread_rwlock_unlock(&data->reg_lock);
- return 0; /* nothing to do */
- }
-
- list_del(&e->list);
-
- pthread_rwlock_unlock(&data->reg_lock);
-
- reg_entry_destroy(e);
-
- return 0;
-}
-
-bool shim_data_reg_has(struct shim_data * data,
- const uint8_t * hash)
-{
- bool ret = false;
-
- assert(data);
- assert(hash);
-
- pthread_rwlock_rdlock(&data->reg_lock);
-
- ret = (find_reg_entry_by_hash(data, hash) != NULL);
-
- pthread_rwlock_unlock(&data->reg_lock);
-
- return ret;
-}
-
-int shim_data_dir_add_entry(struct shim_data * data,
- const uint8_t * hash,
- struct addr addr)
-{
- struct dir_entry * entry;
- uint8_t * entry_hash;
-
- assert(data);
- assert(hash);
-
- pthread_rwlock_wrlock(&data->dir_lock);
-
- if (find_dir_entry(data, hash, addr) != NULL) {
- pthread_rwlock_unlock(&data->dir_lock);
- return -1;
- }
-
- entry_hash = ipcp_hash_dup(hash);
- if (entry_hash == NULL) {
- pthread_rwlock_unlock(&data->dir_lock);
- return -1;
- }
-
- entry = dir_entry_create(entry_hash, addr);
- if (entry == NULL) {
- pthread_rwlock_unlock(&data->dir_lock);
- return -1;
- }
-
- list_add(&entry->list,&data->directory);
-
- pthread_rwlock_unlock(&data->dir_lock);
-
- return 0;
-}
-
-int shim_data_dir_del_entry(struct shim_data * data,
- const uint8_t * hash,
- struct addr addr)
-{
- struct dir_entry * e;
- if (data == NULL)
- return -1;
-
- pthread_rwlock_wrlock(&data->dir_lock);
-
- e = find_dir_entry(data, hash, addr);
- if (e == NULL) {
- pthread_rwlock_unlock(&data->dir_lock);
- return 0; /* nothing to do */
- }
-
- list_del(&e->list);
-
- pthread_rwlock_unlock(&data->dir_lock);
-
- dir_entry_destroy(e);
-
- return 0;
-}
-
-bool shim_data_dir_has(struct shim_data * data,
- const uint8_t * hash)
-{
- bool ret = false;
-
- pthread_rwlock_rdlock(&data->dir_lock);
-
- ret = (find_dir_entry_any(data, hash) != NULL);
-
- pthread_rwlock_unlock(&data->dir_lock);
-
- return ret;
-}
-
-struct addr shim_data_dir_get_addr(struct shim_data * data,
- const uint8_t * hash)
-{
- struct dir_entry * entry;
- struct addr addr = {0};
-
- pthread_rwlock_rdlock(&data->dir_lock);
-
- entry = find_dir_entry_any(data, hash);
- if (entry == NULL) {
- pthread_rwlock_unlock(&data->dir_lock);
- log_warn("No address for " HASH_FMT32 ".", HASH_VAL32(hash));
- return addr; /* undefined behaviour, 0 may be a valid address */
- }
-
- addr = entry->addr;
-
- pthread_rwlock_unlock(&data->dir_lock);
-
- return addr;
-}
-
-struct dir_query * shim_data_dir_query_create(struct shim_data * data,
- const uint8_t * hash)
-{
- struct dir_query * query;
- pthread_condattr_t cattr;
-
- query = malloc(sizeof(*query));
- if (query == NULL)
- return NULL;
-
- query->hash = ipcp_hash_dup(hash);
- if (query->hash == NULL) {
- free(query);
- return NULL;
- }
-
- query->state = QUERY_INIT;
-
- pthread_condattr_init(&cattr);
-#ifndef __APPLE__
- pthread_condattr_setclock(&cattr, PTHREAD_COND_CLOCK);
-#endif
- pthread_cond_init(&query->cond, &cattr);
- pthread_mutex_init(&query->lock, NULL);
-
- list_head_init(&query->next);
-
- pthread_mutex_lock(&data->dir_queries_lock);
- list_add(&query->next, &data->dir_queries);
- pthread_mutex_unlock(&data->dir_queries_lock);
-
- return query;
-}
-
-void shim_data_dir_query_respond(struct shim_data * data,
- const uint8_t * hash)
-{
- struct dir_query * e = NULL;
- struct list_head * pos;
- bool found = false;
-
- pthread_mutex_lock(&data->dir_queries_lock);
-
- list_for_each(pos, &data->dir_queries) {
- e = list_entry(pos, struct dir_query, next);
-
- if (memcmp(e->hash, hash, ipcp_dir_hash_len()) == 0) {
- found = true;
- break;
- }
- }
-
- if (!found) {
- pthread_mutex_unlock(&data->dir_queries_lock);
- return;
- }
-
- pthread_mutex_lock(&e->lock);
-
- if (e->state != QUERY_PENDING) {
- pthread_mutex_unlock(&e->lock);
- pthread_mutex_unlock(&data->dir_queries_lock);
- return;
- }
-
- e->state = QUERY_RESPONSE;
- pthread_cond_broadcast(&e->cond);
-
- while (e->state == QUERY_RESPONSE)
- pthread_cond_wait(&e->cond, &e->lock);
-
- pthread_mutex_unlock(&e->lock);
-
- pthread_mutex_unlock(&data->dir_queries_lock);
-}
-
-void shim_data_dir_query_destroy(struct shim_data * data,
- struct dir_query * query)
-{
- pthread_mutex_lock(&data->dir_queries_lock);
-
- list_del(&query->next);
- destroy_dir_query(query);
-
- pthread_mutex_unlock(&data->dir_queries_lock);
-}
-
-int shim_data_dir_query_wait(struct dir_query * query,
- const struct timespec * timeout)
-{
- struct timespec abstime;
- int ret = 0;
-
- assert(query);
- assert(timeout);
-
- clock_gettime(PTHREAD_COND_CLOCK, &abstime);
- ts_add(&abstime, timeout, &abstime);
-
- pthread_mutex_lock(&query->lock);
-
- if (query->state != QUERY_INIT) {
- pthread_mutex_unlock(&query->lock);
- return -EINVAL;
- }
-
- query->state = QUERY_PENDING;
-
- while (query->state == QUERY_PENDING && ret != -ETIMEDOUT)
- ret = -pthread_cond_timedwait(&query->cond,
- &query->lock,
- &abstime);
-
- if (query->state == QUERY_DESTROY)
- ret = -1;
-
- query->state = QUERY_DONE;
- pthread_cond_broadcast(&query->cond);
-
- pthread_mutex_unlock(&query->lock);
-
- return ret;
-}
diff --git a/src/ipcpd/shim-data.h b/src/ipcpd/shim-data.h
deleted file mode 100644
index fbadb4d4..00000000
--- a/src/ipcpd/shim-data.h
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * Ouroboros - Copyright (C) 2016 - 2026
- *
- * Utitilies for building IPC processes
- *
- * Dimitri Staessens <dimitri@ouroboros.rocks>
- * Sander Vrijders <sander@ouroboros.rocks>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., http://www.fsf.org/about/contact/.
- */
-
-#ifndef OUROBOROS_IPCPD_IPCP_DATA_H
-#define OUROBOROS_IPCPD_IPCP_DATA_H
-
-#include <ouroboros/list.h>
-
-#include <pthread.h>
-#include <stdint.h>
-#include <netinet/in.h>
-#include <sys/types.h>
-
-#define MAC_SIZE 6
-
-enum dir_query_state {
- QUERY_INIT = 0,
- QUERY_PENDING,
- QUERY_RESPONSE,
- QUERY_DONE,
- QUERY_DESTROY
-};
-
-struct dir_query {
- struct list_head next;
- uint8_t * hash;
- enum dir_query_state state;
-
- pthread_mutex_t lock;
- pthread_cond_t cond;
-};
-
-struct addr {
- union {
- uint8_t mac[MAC_SIZE];
- struct in_addr ip4;
- struct in6_addr ip6;
- };
-};
-
-struct shim_data {
- struct list_head registry;
- pthread_rwlock_t reg_lock;
-
- struct list_head directory;
- pthread_rwlock_t dir_lock;
-
- struct list_head dir_queries;
- pthread_mutex_t dir_queries_lock;
-};
-
-struct shim_data * shim_data_create(void);
-
-void shim_data_destroy(struct shim_data * data);
-
-int shim_data_reg_add_entry(struct shim_data * data,
- const uint8_t * hash);
-
-int shim_data_reg_del_entry(struct shim_data * data,
- const uint8_t * hash);
-
-bool shim_data_reg_has(struct shim_data * data,
- const uint8_t * hash);
-
-int shim_data_dir_add_entry(struct shim_data * data,
- const uint8_t * hash,
- struct addr addr);
-
-int shim_data_dir_del_entry(struct shim_data * data,
- const uint8_t * hash,
- struct addr addr);
-
-bool shim_data_dir_has(struct shim_data * data,
- const uint8_t * hash);
-
-struct addr shim_data_dir_get_addr(struct shim_data * data,
- const uint8_t * hash);
-
-struct dir_query * shim_data_dir_query_create(struct shim_data * data,
- const uint8_t * hash);
-
-void shim_data_dir_query_destroy(struct shim_data * data,
- struct dir_query * query);
-
-void shim_data_dir_query_respond(struct shim_data * data,
- const uint8_t * hash);
-
-int shim_data_dir_query_wait(struct dir_query * query,
- const struct timespec * timeout);
-#endif /* OUROBOROS_IPCPD_SHIM_DATA_H */
diff --git a/src/ipcpd/udp/CMakeLists.txt b/src/ipcpd/udp/CMakeLists.txt
deleted file mode 100644
index a98f0919..00000000
--- a/src/ipcpd/udp/CMakeLists.txt
+++ /dev/null
@@ -1,14 +0,0 @@
-# UDP IPCPs build configuration (UDP4 and UDP6)
-# DDNS detection is in cmake/dependencies/udp/ddns.cmake
-
-add_executable(${IPCP_UDP4_TARGET} udp4.c ${IPCP_SOURCES})
-add_executable(${IPCP_UDP6_TARGET} udp6.c ${IPCP_SOURCES})
-
-foreach(target ${IPCP_UDP4_TARGET} ${IPCP_UDP6_TARGET})
- target_include_directories(${target} PRIVATE ${IPCP_INCLUDE_DIRS})
- target_link_libraries(${target} PRIVATE ouroboros-dev)
- ouroboros_target_debug_definitions(${target})
-endforeach()
-
-install(TARGETS ${IPCP_UDP4_TARGET} ${IPCP_UDP6_TARGET}
- RUNTIME DESTINATION ${CMAKE_INSTALL_SBINDIR})
diff --git a/src/ipcpd/udp/udp.c b/src/ipcpd/udp/udp.c
deleted file mode 100644
index db57e2f4..00000000
--- a/src/ipcpd/udp/udp.c
+++ /dev/null
@@ -1,1333 +0,0 @@
-/*
- * Ouroboros - Copyright (C) 2016 - 2026
- *
- * IPC process over UDP
- *
- * Dimitri Staessens <dimitri@ouroboros.rocks>
- * Sander Vrijders <sander@ouroboros.rocks>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., http://www.fsf.org/about/contact/.
- */
-
-#include "config.h"
-
-#include <ouroboros/bitmap.h>
-#include <ouroboros/endian.h>
-#include <ouroboros/hash.h>
-#include <ouroboros/list.h>
-#include <ouroboros/utils.h>
-#include <ouroboros/dev.h>
-#include <ouroboros/ipcp-dev.h>
-#include <ouroboros/np1_flow.h>
-#include <ouroboros/fqueue.h>
-#include <ouroboros/errno.h>
-#include <ouroboros/logs.h>
-#include <ouroboros/pthread.h>
-
-#include "ipcp.h"
-#include "np1.h"
-#include "shim-data.h"
-
-#include <string.h>
-#include <sys/socket.h>
-#include <sys/select.h>
-#include <arpa/inet.h>
-#include <netdb.h>
-#include <netinet/in.h>
-#include <signal.h>
-#include <stdlib.h>
-#include <sys/wait.h>
-#include <fcntl.h>
-#include <unistd.h>
-#if defined(__linux__)
-#include <netinet/ip.h>
-#endif
-
-#define FLOW_REQ 1
-#define FLOW_REPLY 2
-#define FLOW_IRM_UPDATE 3
-
-#define OUR_HEADER_LEN sizeof(uint32_t) /* adds eid */
-
-#define IPCP_UDP_BUF_SIZE IPCP_UDP_MAX_PACKET_SIZE
-#define IPCP_UDP_MSG_SIZE IPCP_UDP_MAX_PACKET_SIZE
-
-#define DNS_TTL 86400
-
-#define SADDR ((struct sockaddr *) &udp_data.s_saddr)
-#define SADDR_SIZE (sizeof(udp_data.s_saddr))
-#define LOCAL_IP (udp_data.s_saddr.sin_addr.s_addr)
-
-#define MGMT_EID 0
-#define MGMT_FRAME_SIZE (sizeof(struct mgmt_msg))
-#define MGMT_FRAME_BUF_SIZE 2048
-
-#ifdef __linux__
-#define SENDTO_FLAGS MSG_CONFIRM
-#else
-#define SENDTO_FLAGS 0
-#endif
-
-/* Keep order for alignment. */
-struct mgmt_msg {
- uint32_t eid;
- uint32_t s_eid;
- uint32_t d_eid;
- int32_t response;
- uint64_t bandwidth;
- uint32_t delay;
- uint32_t loss;
- uint32_t ber;
- uint32_t max_gap;
- uint32_t timeout;
- uint8_t code;
- /* QoS parameters from spec */
- uint8_t availability;
- uint8_t service;
-} __attribute__((packed));
-
-struct mgmt_frame {
- struct list_head next;
- struct __SOCKADDR r_saddr;
- uint8_t buf[MGMT_FRAME_BUF_SIZE];
- size_t len;
-};
-
-/* UDP flow */
-struct uf {
- int d_eid;
- struct __SOCKADDR r_saddr;
-};
-
-struct {
- struct shim_data * shim_data;
-
- struct __ADDR dns_addr;
- struct __SOCKADDR s_saddr;
- int s_fd;
-
- fset_t * np1_flows;
- struct uf fd_to_uf[SYS_MAX_FLOWS];
- pthread_rwlock_t flows_lock;
-
- pthread_t packet_writer[IPCP_UDP_WR_THR];
- pthread_t packet_reader[IPCP_UDP_RD_THR];
-
- /* Handle mgmt frames in a different thread */
- pthread_t mgmt_handler;
- pthread_mutex_t mgmt_lock;
- pthread_cond_t mgmt_cond;
- struct list_head mgmt_frames;
-} udp_data;
-
-static const char * __inet_ntop(const struct __ADDR * addr,
- char * buf)
-{
- return inet_ntop(__AF, addr, buf, __ADDRSTRLEN);
-}
-
-#if defined(BUILD_IPCP_UDP4)
-#define UDP_MTU_FALLBACK IPCP_UDP4_MTU
-#define UDP_IP_OVERHEAD 28U /* IPv4 + UDP */
-#else
-#define UDP_MTU_FALLBACK IPCP_UDP6_MTU
-#define UDP_IP_OVERHEAD 48U /* IPv6 + UDP */
-#endif
-
-static uint32_t udp_query_mtu(const struct __SOCKADDR * saddr)
-{
-#if defined(__linux__) && (defined(IP_MTU) || defined(IPV6_MTU))
- int sock;
- int mtu = 0;
- socklen_t len = sizeof(mtu);
-
- sock = socket(__AF, SOCK_DGRAM, IPPROTO_UDP);
- if (sock < 0)
- return UDP_MTU_FALLBACK;
-
- if (connect(sock, (const struct sockaddr *) saddr,
- sizeof(*saddr)) < 0)
- goto fallback;
-
-#if defined(BUILD_IPCP_UDP4) && defined(IP_MTU)
- if (getsockopt(sock, IPPROTO_IP, IP_MTU, &mtu, &len) < 0)
- goto fallback;
-#elif defined(BUILD_IPCP_UDP6) && defined(IPV6_MTU)
- if (getsockopt(sock, IPPROTO_IPV6, IPV6_MTU, &mtu, &len) < 0)
- goto fallback;
-#else
- goto fallback;
-#endif
- close(sock);
-
- if (mtu <= (int) UDP_IP_OVERHEAD)
- return UDP_MTU_FALLBACK;
-
- return (uint32_t) mtu - UDP_IP_OVERHEAD;
-
- fallback:
- close(sock);
-#else
- (void) saddr;
-#endif
- return UDP_MTU_FALLBACK;
-}
-
-static int udp_data_init(void)
-{
- int i;
- pthread_condattr_t cattr;
-
- if (pthread_rwlock_init(&udp_data.flows_lock, NULL))
- goto fail_rwlock_init;
-
- if (pthread_condattr_init(&cattr))
- goto fail_condattr;
-#ifndef __APPLE__
- pthread_condattr_setclock(&cattr, PTHREAD_COND_CLOCK);
-#endif
- if (pthread_cond_init(&udp_data.mgmt_cond, &cattr))
- goto fail_mgmt_cond;
-
- if (pthread_mutex_init(&udp_data.mgmt_lock, NULL))
- goto fail_mgmt_lock;
-
- for (i = 0; i < SYS_MAX_FLOWS; ++i)
- udp_data.fd_to_uf[i].d_eid = -1;
-
- udp_data.np1_flows = fset_create();
- if (udp_data.np1_flows == NULL)
- goto fail_fset;
-
- udp_data.shim_data = shim_data_create();
- if (udp_data.shim_data == NULL)
- goto fail_data;
-
- pthread_condattr_destroy(&cattr);
-
- list_head_init(&udp_data.mgmt_frames);
-
- return 0;
-
- fail_data:
- fset_destroy(udp_data.np1_flows);
- fail_fset:
- pthread_mutex_destroy(&udp_data.mgmt_lock);
- fail_mgmt_lock:
- pthread_cond_destroy(&udp_data.mgmt_cond);
- fail_mgmt_cond:
- pthread_condattr_destroy(&cattr);
- fail_condattr:
- pthread_rwlock_destroy(&udp_data.flows_lock);
- fail_rwlock_init:
- return -1;
-}
-
-static void udp_data_fini(void)
-{
- shim_data_destroy(udp_data.shim_data);
-
- fset_destroy(udp_data.np1_flows);
-
- pthread_rwlock_destroy(&udp_data.flows_lock);
- pthread_cond_destroy(&udp_data.mgmt_cond);
- pthread_mutex_destroy(&udp_data.mgmt_lock);
-}
-
-static int udp_ipcp_port_alloc(const struct __SOCKADDR * r_saddr,
- uint32_t s_eid,
- const uint8_t * dst,
- qosspec_t qs,
- const buffer_t * data)
-{
- uint8_t * buf;
- struct mgmt_msg * msg;
- size_t len;
-
- assert(data->len > 0 ? data->data != NULL : data->data == NULL);
-
- len = sizeof(*msg) + ipcp_dir_hash_len();
-
- buf = malloc(len + data->len);
- if (buf == NULL)
- return -1;
-
- memset(buf, 0, len + data->len);
-
- msg = (struct mgmt_msg *) buf;
- msg->eid = hton32(MGMT_EID);
- msg->code = FLOW_REQ;
- msg->s_eid = hton32(s_eid);
- msg->delay = hton32(qs.delay);
- msg->bandwidth = hton64(qs.bandwidth);
- msg->availability = qs.availability;
- msg->loss = hton32(qs.loss);
- msg->ber = hton32(qs.ber);
- msg->service = qs.service;
- msg->max_gap = hton32(qs.max_gap);
- msg->timeout = hton32(qs.timeout);
-
- memcpy(msg + 1, dst, ipcp_dir_hash_len());
- if (data->len > 0)
- memcpy(buf + len, data->data, data->len);
-
- if (sendto(udp_data.s_fd, msg, len + data->len,
- SENDTO_FLAGS,
- (const struct sockaddr *) r_saddr, sizeof(*r_saddr)) < 0) {
- log_err("Failed to send flow allocation request: %s.",
- strerror(errno));
- free(buf);
- return -1;
- }
-
- free(buf);
-
- return 0;
-}
-
-static int udp_ipcp_port_alloc_resp(const struct __SOCKADDR * r_saddr,
- uint32_t s_eid,
- uint32_t d_eid,
- int32_t response,
- const buffer_t * data)
-{
- struct mgmt_msg * msg;
-
- msg = malloc(sizeof(*msg) + data->len);
- if (msg == NULL)
- return -1;
-
- memset(msg, 0, sizeof(*msg) + data->len);
-
- msg->eid = hton32(MGMT_EID);
- msg->code = FLOW_REPLY;
- msg->s_eid = hton32(s_eid);
- msg->d_eid = hton32(d_eid);
- msg->response = hton32(response);
-
- if (data->len > 0)
- memcpy(msg + 1, data->data, data->len);
-
- if (sendto(udp_data.s_fd, msg, sizeof(*msg) + data->len,
- SENDTO_FLAGS,
- (const struct sockaddr *) r_saddr, sizeof(*r_saddr)) < 0 ) {
- free(msg);
- return -1;
- }
-
- free(msg);
-
- return 0;
-}
-
-static int udp_ipcp_flow_update(int fd,
- const buffer_t * data)
-{
- struct mgmt_msg * msg;
- struct __SOCKADDR r_saddr;
- uint32_t d_eid;
-
- msg = malloc(sizeof(*msg) + data->len);
- if (msg == NULL)
- return -1;
-
- memset(msg, 0, sizeof(*msg) + data->len);
-
- pthread_rwlock_rdlock(&udp_data.flows_lock);
-
- r_saddr = udp_data.fd_to_uf[fd].r_saddr;
- d_eid = (uint32_t) udp_data.fd_to_uf[fd].d_eid;
-
- pthread_rwlock_unlock(&udp_data.flows_lock);
-
- msg->eid = hton32(MGMT_EID);
- msg->code = FLOW_IRM_UPDATE;
- msg->s_eid = hton32(d_eid);
- msg->d_eid = hton32((uint32_t) fd);
-
- if (data->len > 0)
- memcpy(msg + 1, data->data, data->len);
-
- if (sendto(udp_data.s_fd, msg, sizeof(*msg) + data->len,
- SENDTO_FLAGS,
- (const struct sockaddr *) &r_saddr,
- sizeof(r_saddr)) < 0) {
- log_err("Failed to send flow update: %s.", strerror(errno));
- free(msg);
- return -1;
- }
-
- free(msg);
-
- return 0;
-}
-
-static int udp_ipcp_port_req(struct __SOCKADDR * c_saddr,
- int d_eid,
- const uint8_t * dst,
- qosspec_t qs,
- const buffer_t * data)
-{
- int fd;
-
- fd = ipcp_wait_flow_req_arr(dst, qs, IPCP_UDP_MPL,
- udp_query_mtu(c_saddr), data);
- if (fd < 0) {
- log_err("Could not get new flow from IRMd.");
- return -1;
- }
-
- pthread_rwlock_wrlock(&udp_data.flows_lock);
-
- udp_data.fd_to_uf[fd].r_saddr = *c_saddr;
- udp_data.fd_to_uf[fd].d_eid = d_eid;
-
- pthread_rwlock_unlock(&udp_data.flows_lock);
-
- log_dbg("Pending allocation request, fd %d, remote eid %d.",
- fd, d_eid);
-
- return 0;
-}
-
-static int udp_ipcp_port_alloc_reply(const struct __SOCKADDR * saddr,
- uint32_t s_eid,
- uint32_t d_eid,
- int32_t response,
- const buffer_t * data)
-{
- time_t mpl = IPCP_UDP_MPL;
-
- pthread_rwlock_wrlock(&udp_data.flows_lock);
-
- if (memcmp(&udp_data.fd_to_uf[s_eid].r_saddr, saddr, sizeof(*saddr))) {
- char ipstr[__ADDRSTRLEN];
- pthread_rwlock_unlock(&udp_data.flows_lock);
- #ifdef BUILD_IPCP_UDP4
- __inet_ntop(&saddr->sin_addr, ipstr);
- #else
- __inet_ntop(&saddr->sin6_addr, ipstr);
- #endif
- log_err("Flow allocation reply for %u from wrong source %s.",
- s_eid, ipstr);
- return -1;
- }
-
- if (response == 0)
- udp_data.fd_to_uf[s_eid].d_eid = d_eid;
-
- pthread_rwlock_unlock(&udp_data.flows_lock);
-
- if (ipcp_flow_alloc_reply(s_eid, response, mpl,
- udp_query_mtu(saddr), data) < 0) {
- log_err("Failed to reply to flow allocation.");
- return -1;
- }
-
- log_dbg("Flow allocation completed on eids (%d, %d).",
- s_eid, d_eid);
-
- return 0;
-}
-
-static int udp_ipcp_flow_update_arr(const uint8_t * buf,
- size_t len)
-{
- struct mgmt_msg * msg;
- buffer_t data;
- int fd;
- int flow_id;
-
- msg = (struct mgmt_msg *) buf;
-
- fd = (int) ntoh32(msg->s_eid);
- if (fd < 0 || fd >= SYS_MAX_FLOWS) {
- log_err("Flow update for invalid eid %d.", fd);
- return -1;
- }
-
- data.len = len - sizeof(*msg);
- data.data = (uint8_t *) buf + sizeof(*msg);
-
- flow_id = np1_flow_id(fd);
- if (flow_id < 0)
- return -1;
-
- if (ipcp_flow_update_arr(flow_id, &data) < 0) {
- log_err("Failed to relay flow update on fd %d.", fd);
- return -1;
- }
-
- return 0;
-}
-
-static int udp_ipcp_mgmt_frame(struct __SOCKADDR c_saddr,
- const uint8_t * buf,
- size_t len)
-{
- struct mgmt_msg * msg;
- size_t msg_len;
- qosspec_t qs;
- buffer_t data;
-
- /* Defence against malformed/corrupted wire input. */
- if (len < sizeof(*msg))
- return -1;
-
- msg = (struct mgmt_msg *) buf;
-
- switch (msg->code) {
- case FLOW_REQ:
- msg_len = sizeof(*msg) + ipcp_dir_hash_len();
-
- if (len < msg_len)
- return -1;
-
- data.len = len - msg_len;
- data.data = (uint8_t *) buf + msg_len;
-
-
- qs.delay = ntoh32(msg->delay);
- qs.bandwidth = ntoh64(msg->bandwidth);
- qs.availability = msg->availability;
- qs.loss = ntoh32(msg->loss);
- qs.ber = ntoh32(msg->ber);
- qs.service = msg->service;
- qs.max_gap = ntoh32(msg->max_gap);
- qs.timeout = ntoh32(msg->timeout);
-
- return udp_ipcp_port_req(&c_saddr, ntoh32(msg->s_eid),
- (uint8_t *) (msg + 1), qs,
- &data);
- case FLOW_REPLY:
- data.len = len - sizeof(*msg);
- data.data = (uint8_t *) buf + sizeof(*msg);
-
- return udp_ipcp_port_alloc_reply(&c_saddr,
- ntoh32(msg->s_eid),
- ntoh32(msg->d_eid),
- ntoh32(msg->response),
- &data);
- case FLOW_IRM_UPDATE:
- return udp_ipcp_flow_update_arr(buf, len);
- default:
- log_err("Unknown message received %d.", msg->code);
- return -1;
- }
-}
-
-static void * udp_ipcp_mgmt_handler(void * o)
-{
- (void) o;
-
- pthread_cleanup_push(__cleanup_mutex_unlock, &udp_data.mgmt_lock);
-
- while (true) {
- struct mgmt_frame * frame;
-
- pthread_mutex_lock(&udp_data.mgmt_lock);
-
- while (list_is_empty(&udp_data.mgmt_frames))
- pthread_cond_wait(&udp_data.mgmt_cond,
- &udp_data.mgmt_lock);
-
- frame = list_first_entry((&udp_data.mgmt_frames),
- struct mgmt_frame, next);
- assert(frame != NULL);
- list_del(&frame->next);
-
- pthread_mutex_unlock(&udp_data.mgmt_lock);
-
- udp_ipcp_mgmt_frame(frame->r_saddr, frame->buf, frame->len);
-
- free(frame);
- }
-
- pthread_cleanup_pop(false);
-
- return (void *) 0;
-}
-
-static void * udp_ipcp_packet_reader(void * o)
-{
- uint8_t buf[IPCP_UDP_MAX_PACKET_SIZE];
- uint8_t * data;
- ssize_t n;
- uint32_t eid;
- uint32_t * eid_p;
-
- (void) o;
-
- ipcp_lock_to_core();
-
- data = buf + sizeof(uint32_t);
- eid_p = (uint32_t *) buf;
-
- while (true) {
- struct mgmt_frame * frame;
- struct __SOCKADDR r_saddr;
- socklen_t len;
- struct ssm_pk_buff * spb;
- uint8_t * head;
-
- len = sizeof(r_saddr);
-
- n = recvfrom(udp_data.s_fd, buf, IPCP_UDP_MAX_PACKET_SIZE, 0,
- (struct sockaddr *) &r_saddr, &len);
- if (n < 0)
- continue;
-
- if (n == 0)
- log_dbg("Got a 0 frame.");
-
- if ((size_t) n < sizeof(eid)) {
- log_dbg("Dropped bad frame.");
- continue;
- }
-
- eid = ntoh32(*eid_p);
-
- /* pass onto mgmt queue */
- if (eid == MGMT_EID) {
- if ((size_t) n < MGMT_FRAME_SIZE) {
- log_warn("Dropped runt mgmt frame.");
- continue;
- }
-
- frame = malloc(sizeof(*frame));
- if (frame == NULL)
- continue;
-
- memcpy(frame->buf, buf, n);
- memcpy(&frame->r_saddr, &r_saddr, sizeof(r_saddr));
- frame->len = n;
-
- pthread_mutex_lock(&udp_data.mgmt_lock);
- list_add(&frame->next, &udp_data.mgmt_frames);
- pthread_cond_signal(&udp_data.mgmt_cond);
- pthread_mutex_unlock(&udp_data.mgmt_lock);
- continue;
- }
-
- n-= sizeof(eid);
-
- if (ipcp_spb_reserve(&spb, n))
- continue;
-
- head = ssm_pk_buff_head(spb);
- memcpy(head, data, n);
- if (np1_flow_write(eid, spb, NP1_GET_POOL(eid)) < 0)
- ipcp_spb_release(spb);
- }
-
- return (void *) 0;
-}
-
-static void cleanup_fqueue(void * fq)
-{
- fqueue_destroy((fqueue_t *) fq);
-}
-
-static void cleanup_spb(void * spb)
-{
- ipcp_spb_release((struct ssm_pk_buff *) spb);
-}
-
-static void * udp_ipcp_packet_writer(void * o)
-{
- fqueue_t * fq;
-
- fq = fqueue_create();
- if (fq == NULL)
- return (void *) -1;
-
- (void) o;
-
- ipcp_lock_to_core();
-
- pthread_cleanup_push(cleanup_fqueue, fq);
-
- while (true) {
- struct __SOCKADDR saddr;
- int eid;
- int fd;
- fevent(udp_data.np1_flows, fq, NULL);
- while ((fd = fqueue_next(fq)) >= 0) {
- struct ssm_pk_buff * spb;
- uint8_t * buf;
- uint16_t len;
-
- if (fqueue_type(fq) != FLOW_PKT)
- continue;
-
- if (np1_flow_read(fd, &spb, NP1_GET_POOL(fd))) {
- log_dbg("Bad read from fd %d.", fd);
- continue;
- }
-
- len = ssm_pk_buff_len(spb);
- if (len > IPCP_UDP_MAX_PACKET_SIZE) {
- log_dbg("Packet length exceeds MTU.");
- ipcp_spb_release(spb);
- continue;
- }
-
- buf = ssm_pk_buff_push(spb, OUR_HEADER_LEN);
- if (buf == NULL) {
- log_dbg("Failed to allocate header.");
- ipcp_spb_release(spb);
- continue;
- }
-
- pthread_rwlock_rdlock(&udp_data.flows_lock);
-
- eid = hton32(udp_data.fd_to_uf[fd].d_eid);
- saddr = udp_data.fd_to_uf[fd].r_saddr;
-
- pthread_rwlock_unlock(&udp_data.flows_lock);
-
- memcpy(buf, &eid, sizeof(eid));
-
- pthread_cleanup_push(cleanup_spb, spb);
-
- if (sendto(udp_data.s_fd, buf, len + OUR_HEADER_LEN,
- SENDTO_FLAGS,
- (const struct sockaddr *) &saddr,
- sizeof(saddr)) < 0)
- log_err("Failed to send packet.");
-
- pthread_cleanup_pop(true);
- }
- }
-
- pthread_cleanup_pop(true);
-
- return (void *) 1;
-}
-
-static bool is_addr_specified(const struct __ADDR * addr)
-{
-#ifdef BUILD_IPCP_UDP4
- return addr->s_addr != 0;
-#else
- return !IN6_IS_ADDR_UNSPECIFIED(addr);
-#endif
-}
-
-static int udp_ipcp_bootstrap(struct ipcp_config * conf)
-{
- char ipstr[__ADDRSTRLEN];
- char dnsstr[__ADDRSTRLEN];
- int i = 1;
-#ifdef BUILD_IPCP_UDP4
- struct udp4_config * udp;
- udp = &conf->udp4;
-#else
- struct udp6_config * udp;
- udp = &conf->udp6;
-#endif
-
- assert(conf != NULL);
- assert(conf->type == THIS_TYPE);
- assert(conf->layer_info.dir_hash_algo == (enum pol_dir_hash) HASH_MD5);
-
- if (__inet_ntop(&udp->ip_addr, ipstr) == NULL) {
- log_err("Failed to convert IP address.");
- return -1;
- }
-
- if (is_addr_specified(&udp->dns_addr)) {
- if (__inet_ntop(&udp->dns_addr, dnsstr) == NULL) {
- log_err("Failed to convert DNS address.");
- return -1;
- }
-#ifndef HAVE_DDNS
- log_warn("DNS disabled at compile time, address ignored.");
-#endif
- } else {
- strcpy(dnsstr, "not set");
- }
-
- /* UDP listen server */
- udp_data.s_fd = socket(__AF, SOCK_DGRAM, IPPROTO_UDP);
- if (udp_data.s_fd < 0) {
- log_err("Can't create socket: %s", strerror(errno));
- goto fail_socket;
- }
-
- memset((char *) &udp_data.s_saddr, 0, sizeof(udp_data.s_saddr));
-#ifdef BUILD_IPCP_UDP4
- udp_data.s_saddr.sin_family = AF_INET;
- udp_data.s_saddr.sin_addr = udp->ip_addr;
- udp_data.s_saddr.sin_port = htons(udp->port);
-#else
- udp_data.s_saddr.sin6_family = AF_INET6;
- udp_data.s_saddr.sin6_addr = udp->ip_addr;
- udp_data.s_saddr.sin6_port = htons(udp->port);
-#endif
- if (bind(udp_data.s_fd, SADDR, SADDR_SIZE) < 0) {
- log_err("Couldn't bind to %s:%d. %s.",
- ipstr, udp->port, strerror(errno));
- goto fail_bind;
- }
-
- udp_data.dns_addr = udp->dns_addr;
-
- if (pthread_create(&udp_data.mgmt_handler, NULL,
- udp_ipcp_mgmt_handler, NULL)) {
- log_err("Failed to create management thread.");
- goto fail_bind;
- }
-
- for (i = 0; i < IPCP_UDP_RD_THR; ++i) {
- if (pthread_create(&udp_data.packet_reader[i], NULL,
- udp_ipcp_packet_reader, NULL)) {
- log_err("Failed to create reader thread.");
- goto fail_packet_reader;
- }
- }
-
- for (i = 0; i < IPCP_UDP_WR_THR; ++i) {
- if (pthread_create(&udp_data.packet_writer[i], NULL,
- udp_ipcp_packet_writer, NULL)) {
- log_err("Failed to create writer thread.");
- goto fail_packet_writer;
- }
- }
-
- log_dbg("Bootstrapped " TYPE_STR " with pid %d.", getpid());
- log_dbg("Bound to IP address %s.", ipstr);
- log_dbg("Using port %u.", udp->port);
- if (is_addr_specified(&udp_data.dns_addr))
- log_dbg("DNS server address is %s.", dnsstr);
- else
- log_dbg("DNS server not in use.");
-
- return 0;
-
- fail_packet_writer:
- while (i-- > 0) {
- pthread_cancel(udp_data.packet_writer[i]);
- pthread_join(udp_data.packet_writer[i], NULL);
- }
- i = IPCP_UDP_RD_THR;
- fail_packet_reader:
- while (i-- > 0) {
- pthread_cancel(udp_data.packet_reader[i]);
- pthread_join(udp_data.packet_reader[i], NULL);
- }
- pthread_cancel(udp_data.mgmt_handler);
- pthread_join(udp_data.mgmt_handler, NULL);
- fail_bind:
- close(udp_data.s_fd);
- fail_socket:
- return -1;
-}
-
-#ifdef HAVE_DDNS
-/* FIXME: Dependency on nsupdate to be removed in the end */
-/* NOTE: Disgusted with this crap */
-static int ddns_send(char * cmd)
-{
- pid_t pid;
- int wstatus;
- int pipe_fd[2];
- char * argv[] = {NSUPDATE_EXEC, 0};
- char * envp[] = {0};
-
- if (pipe(pipe_fd)) {
- log_err("Failed to create pipe: %s.", strerror(errno));
- return -1;
- }
-
- pid = fork();
- if (pid == -1) {
- log_err("Failed to fork: %s.", strerror(errno));
- close(pipe_fd[0]);
- close(pipe_fd[1]);
- return -1;
- }
-
- if (pid == 0) {
- close(pipe_fd[1]);
- dup2(pipe_fd[0], 0);
- execve(argv[0], &argv[0], envp);
- log_err("Failed to execute: %s", strerror(errno));
- exit(1);
- }
-
- close(pipe_fd[0]);
-
- if (write(pipe_fd[1], cmd, strlen(cmd)) == -1) {
- log_err("Failed to communicate with nsupdate: %s.",
- strerror(errno));
- close(pipe_fd[1]);
- return -1;
- }
-
- waitpid(pid, &wstatus, 0);
- if (WIFEXITED(wstatus) && WEXITSTATUS(wstatus) == 0)
- log_dbg("Succesfully communicated with DNS server.");
- else
- log_err("Failed to register with DNS server.");
-
- close(pipe_fd[1]);
-
- return 0;
-}
-
-static struct __ADDR ddns_resolve(char * name,
- struct __ADDR dns_addr)
-{
- pid_t pid = -1;
- int wstatus;
- int pipe_fd[2];
- char dnsstr[__ADDRSTRLEN];
- char buf[IPCP_UDP_BUF_SIZE];
- ssize_t count = 0;
- char * substr = NULL;
- char * substr2 = NULL;
- char * addr_str = "Address:";
- struct __ADDR ip_addr = __ADDR_ANY_INIT;
-
- if (__inet_ntop(&dns_addr, dnsstr) == NULL)
- return ip_addr;
-
- if (pipe(pipe_fd)) {
- log_err("Failed to create pipe: %s.", strerror(errno));
- return ip_addr;
- }
-
- pid = fork();
- if (pid == -1) {
- log_err("Failed to fork: %s.", strerror(errno));
- close(pipe_fd[0]);
- close(pipe_fd[1]);
- return ip_addr;
- }
-
- if (pid == 0) {
- char * argv[] = {NSLOOKUP_EXEC, name, dnsstr, 0};
- char * envp[] = {0};
-
- close(pipe_fd[0]);
- dup2(pipe_fd[1], 1);
- execve(argv[0], &argv[0], envp);
- log_err("Failed to execute: %s", strerror(errno));
- exit(1);
- }
-
- close(pipe_fd[1]);
-
- count = read(pipe_fd[0], buf, IPCP_UDP_BUF_SIZE - 1);
- if (count <= 0) {
- log_err("Failed to communicate with nslookup.");
- close(pipe_fd[0]);
- return ip_addr;
- }
-
- close(pipe_fd[0]);
-
- waitpid(pid, &wstatus, 0);
- if (WIFEXITED(wstatus) && WEXITSTATUS(wstatus) == 0 &&
- count != IPCP_UDP_BUF_SIZE - 1)
- log_dbg("Succesfully communicated with nslookup.");
- else
- log_err("Failed to resolve DNS address.");
-
- buf[count] = '\0';
- substr = strtok(buf, "\n");
- while (substr != NULL) {
- substr2 = substr;
- substr = strtok(NULL, "\n");
- }
-
- if (substr2 == NULL || strstr(substr2, addr_str) == NULL) {
- log_err("Failed to resolve DNS address.");
- return ip_addr;
- }
-
- if (inet_pton(__AF, substr2 + strlen(addr_str) + 1, &ip_addr) != 1) {
- log_err("Failed to resolve DNS address.");
- assert(!is_addr_specified(&ip_addr));
- return ip_addr;
- }
-
- return ip_addr;
-}
-#endif
-
-static int udp_ipcp_reg(const uint8_t * hash)
-{
-#ifdef HAVE_DDNS
- char ipstr[__ADDRSTRLEN];
- char dnsstr[__ADDRSTRLEN];
- char cmd[1000];
- struct __ADDR dns_addr;
- struct __ADDR ip_addr;
-#endif
- char * hashstr;
-
- hashstr = malloc(ipcp_dir_hash_strlen() + 1);
- if (hashstr == NULL) {
- log_err("Failed to malloc hashstr.");
- return -1;
- }
-
- assert(hash);
-
- ipcp_hash_str(hashstr, hash);
-
- if (shim_data_reg_add_entry(udp_data.shim_data, hash)) {
- log_err("Failed to add " HASH_FMT32 " to local registry.",
- HASH_VAL32(hash));
- free(hashstr);
- return -1;
- }
-
-#ifdef HAVE_DDNS
- /* register application with DNS server */
-
- dns_addr = udp_data.dns_addr;
-
- if (is_addr_specified(&dns_addr)) {
-#ifdef BUILD_IPCP_UDP4
- ip_addr = udp_data.s_saddr.sin_addr;
-#else
- ip_addr = udp_data.s_saddr.sin6_addr;
-#endif
- if (__inet_ntop(&ip_addr, ipstr) == NULL) {
- log_err("Failed to convert IP address to string.");
- free(hashstr);
- return -1;
- }
-
- if (__inet_ntop(&dns_addr, dnsstr) == NULL) {
- log_err("Failed to convert DNS address to string.");
- free(hashstr);
- return -1;
- }
-
- sprintf(cmd, "server %s\nupdate add %s %d A %s\nsend\nquit\n",
- dnsstr, hashstr, DNS_TTL, ipstr);
-
- if (ddns_send(cmd)) {
- log_err("Failed to send DDNS message.");
- shim_data_reg_del_entry(udp_data.shim_data, hash);
- free(hashstr);
- return -1;
- }
- }
-#endif
- free(hashstr);
-
- return 0;
-}
-
-static int udp_ipcp_unreg(const uint8_t * hash)
-{
-#ifdef HAVE_DDNS
- char dnsstr[__ADDRSTRLEN];
- /* max DNS name length + max IP length + max command length */
- char cmd[100];
- struct __ADDR dns_addr;
-#endif
- char * hashstr;
-
- assert(hash);
-
- hashstr = malloc(ipcp_dir_hash_strlen() + 1);
- if (hashstr == NULL) {
- log_err("Failed to malloc hashstr.");
- return -1;
- }
-
- ipcp_hash_str(hashstr, hash);
-
-#ifdef HAVE_DDNS
- /* unregister application with DNS server */
-
- dns_addr = udp_data.dns_addr;
-
- if (is_addr_specified(&dns_addr)) {
- if (__inet_ntop(&dns_addr, dnsstr) == NULL) {
- log_err("Failed to convert DNS address to string.");
- free(hashstr);
- return -1;
- }
- sprintf(cmd, "server %s\nupdate delete %s A\nsend\nquit\n",
- dnsstr, hashstr);
-
- ddns_send(cmd);
- }
-#endif
-
- shim_data_reg_del_entry(udp_data.shim_data, hash);
-
- free(hashstr);
-
- return 0;
-}
-
-static int udp_ipcp_query(const uint8_t * hash)
-{
- struct addr addr = {};
- char * hashstr;
- struct addrinfo hints;
- struct addrinfo * ai;
-#ifdef HAVE_DDNS
- struct __ADDR dns_addr = __ADDR_ANY_INIT;
- struct __ADDR ip_addr = __ADDR_ANY_INIT;
-#endif
- assert(hash);
-
- hashstr = malloc(ipcp_dir_hash_strlen() + 1);
- if (hashstr == NULL) {
- log_err("Failed to malloc hashstr.");
- return -ENOMEM;
- }
-
- ipcp_hash_str(hashstr, hash);
-
- if (shim_data_dir_has(udp_data.shim_data, hash)) {
- free(hashstr);
- return 0;
- }
-
-#ifdef HAVE_DDNS
- dns_addr = udp_data.dns_addr;
-
- if (is_addr_specified(&dns_addr)) {
- ip_addr = ddns_resolve(hashstr, dns_addr);
- if (!is_addr_specified(&ip_addr)) {
- log_err("Could not resolve %s.", hashstr);
- free(hashstr);
- return -1;
- }
- } else {
-#endif
- memset(&hints, 0, sizeof(hints));
-
- hints.ai_family = __AF;
- if (getaddrinfo(hashstr, NULL, &hints, &ai) != 0) {
- log_err("Could not resolve %s: %s.", hashstr,
- gai_strerror(errno));
- free(hashstr);
- return -1;
- }
-
- if (ai->ai_family != __AF) {
- log_err("Wrong addres family for %s.", hashstr);
- freeaddrinfo(ai);
- free(hashstr);
- return -1;
- }
-
- #ifdef BUILD_IPCP_UDP4
- addr.ip4 = ((struct sockaddr_in *) (ai->ai_addr))->sin_addr;
- #else
- addr.ip6 = ((struct sockaddr_in6 *) (ai->ai_addr))->sin6_addr;
- #endif
- freeaddrinfo(ai);
-#ifdef HAVE_DDNS
- }
-#endif
- if (shim_data_dir_add_entry(udp_data.shim_data, hash, addr)) {
- log_err("Failed to add directory entry.");
- free(hashstr);
- return -1;
- }
-
- free(hashstr);
-
- return 0;
-}
-
-static int udp_ipcp_flow_alloc(int fd,
- const uint8_t * dst,
- qosspec_t qs,
- const buffer_t * data)
-{
- struct __SOCKADDR r_saddr; /* Server address */
- struct __ADDR ip_addr;
- struct addr addr;
- char ipstr[__ADDRSTRLEN];
-
- (void) qs;
-
- assert(dst);
-
- if (!shim_data_dir_has(udp_data.shim_data, dst)) {
- log_err("Could not resolve destination.");
- return -1;
- }
-
- addr = shim_data_dir_get_addr(udp_data.shim_data, dst);
-#ifdef BUILD_IPCP_UDP4
- ip_addr = addr.ip4;
-#else
- ip_addr = addr.ip6;
-#endif
- if (__inet_ntop(&ip_addr, ipstr) == NULL) {
- log_err("Could not convert IP address.");
- return -1;
- }
-
- log_dbg("Destination " HASH_FMT32 " resolved at IP %s.",
- HASH_VAL32(dst), ipstr);
-
- memset((char *) &r_saddr, 0, sizeof(r_saddr));
-#ifdef BUILD_IPCP_UDP4
- r_saddr.sin_family = AF_INET;
- r_saddr.sin_addr = addr.ip4;
- r_saddr.sin_port = udp_data.s_saddr.sin_port;
-#else
- r_saddr.sin6_family = AF_INET6;
- r_saddr.sin6_addr = addr.ip6;
- r_saddr.sin6_port = udp_data.s_saddr.sin6_port;
-#endif
-
- if (udp_ipcp_port_alloc(&r_saddr, fd, dst, qs, data) < 0) {
- log_err("Could not allocate port.");
- return -1;
- }
-
- pthread_rwlock_wrlock(&udp_data.flows_lock);
-
- udp_data.fd_to_uf[fd].d_eid = -1;
- udp_data.fd_to_uf[fd].r_saddr = r_saddr;
-
- pthread_rwlock_unlock(&udp_data.flows_lock);
-
- fset_add(udp_data.np1_flows, fd);
-
- return 0;
-}
-
-static int udp_ipcp_flow_alloc_resp(int fd,
- int resp,
- const buffer_t * data)
-{
- struct __SOCKADDR saddr;
- int d_eid;
-
- if (ipcp_wait_flow_resp(fd) < 0) {
- log_err("Failed to wait for flow response.");
- return -1;
- }
-
- pthread_rwlock_rdlock(&udp_data.flows_lock);
-
- saddr = udp_data.fd_to_uf[fd].r_saddr;
- d_eid = udp_data.fd_to_uf[fd].d_eid;
-
- pthread_rwlock_unlock(&udp_data.flows_lock);
-
- if (udp_ipcp_port_alloc_resp(&saddr, d_eid, fd, resp, data) < 0) {
- fset_del(udp_data.np1_flows, fd);
- log_err("Failed to respond to flow request.");
- return -1;
- }
-
- fset_add(udp_data.np1_flows, fd);
-
- return 0;
-}
-
-static int udp_ipcp_flow_dealloc(int fd)
-{
- ipcp_flow_fini(fd);
-
- fset_del(udp_data.np1_flows, fd);
-
- pthread_rwlock_wrlock(&udp_data.flows_lock);
-
- udp_data.fd_to_uf[fd].d_eid = -1;
- memset(&udp_data.fd_to_uf[fd].r_saddr, 0, SADDR_SIZE);
-
- pthread_rwlock_unlock(&udp_data.flows_lock);
-
- ipcp_flow_dealloc(fd);
-
- return 0;
-}
-
-static struct ipcp_ops udp_ops = {
- .ipcp_bootstrap = udp_ipcp_bootstrap,
- .ipcp_enroll = NULL,
- .ipcp_connect = NULL,
- .ipcp_disconnect = NULL,
- .ipcp_reg = udp_ipcp_reg,
- .ipcp_unreg = udp_ipcp_unreg,
- .ipcp_query = udp_ipcp_query,
- .ipcp_flow_alloc = udp_ipcp_flow_alloc,
- .ipcp_flow_join = NULL,
- .ipcp_flow_alloc_resp = udp_ipcp_flow_alloc_resp,
- .ipcp_flow_dealloc = udp_ipcp_flow_dealloc,
- .ipcp_flow_update = udp_ipcp_flow_update
-};
-
-int main(int argc,
- char * argv[])
-{
- int i;
-
-
- if (udp_data_init() < 0) {
- log_err("Failed to init udp data.");
- goto fail_data_init;
- }
-
- if (ipcp_init(argc, argv, &udp_ops, THIS_TYPE) < 0) {
- log_err("Failed to initialize IPCP.");
- goto fail_init;
- }
-
- if (ipcp_start() < 0) {
- log_err("Failed to start IPCP.");
- goto fail_start;
- }
-
- ipcp_sigwait();
-
- if (ipcp_get_state() == IPCP_SHUTDOWN) {
- for (i = 0; i < IPCP_UDP_WR_THR; ++i)
- pthread_cancel(udp_data.packet_writer[i]);
- for (i = 0; i < IPCP_UDP_RD_THR; ++i)
- pthread_cancel(udp_data.packet_reader[i]);
- pthread_cancel(udp_data.mgmt_handler);
-
- for (i = 0; i < IPCP_UDP_WR_THR; ++i)
- pthread_join(udp_data.packet_writer[i], NULL);
- for (i = 0; i < IPCP_UDP_RD_THR; ++i)
- pthread_join(udp_data.packet_reader[i], NULL);
- pthread_join(udp_data.mgmt_handler, NULL);
- close(udp_data.s_fd);
- }
-
- ipcp_stop();
-
- ipcp_fini();
-
- udp_data_fini();
-
- exit(EXIT_SUCCESS);
-
- fail_start:
- ipcp_fini();
- fail_init:
- udp_data_fini();
- fail_data_init:
- exit(EXIT_FAILURE);
-}
diff --git a/src/ipcpd/udp/udp4.c b/src/ipcpd/udp/udp4.c
deleted file mode 100644
index ff57bc09..00000000
--- a/src/ipcpd/udp/udp4.c
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Ouroboros - Copyright (C) 2016 - 2026
- *
- * IPC process over UDP/IPv4
- *
- * Dimitri Staessens <dimitri@ouroboros.rocks>
- * Sander Vrijders <sander@ouroboros.rocks>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., http://www.fsf.org/about/contact/.
- */
-
-#if defined(__linux__) || defined(__CYGWIN__)
-#define _DEFAULT_SOURCE
-#else
-#define _POSIX_C_SOURCE 200112L
-#endif
-
-#include <ouroboros/ipcp-dev.h>
-
-#define BUILD_IPCP_UDP4
-#define THIS_TYPE IPCP_UDP4
-#define TYPE_STR "IPCP over UDP/IPv4"
-#define OUROBOROS_PREFIX "ipcpd/udp4"
-#define IPCP_UDP_MAX_PACKET_SIZE 8980
-#define __AF AF_INET
-#define __ADDRSTRLEN INET_ADDRSTRLEN
-#define __SOCKADDR sockaddr_in
-#define __ADDR in_addr
-#define __ADDR_ANY_INIT { .s_addr = INADDR_ANY }
-
-#include "udp.c"
diff --git a/src/ipcpd/udp/udp6.c b/src/ipcpd/udp/udp6.c
deleted file mode 100644
index 2ceb95f0..00000000
--- a/src/ipcpd/udp/udp6.c
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Ouroboros - Copyright (C) 2016 - 2026
- *
- * IPC process over UDP/IPv6
- *
- * Dimitri Staessens <dimitri@ouroboros.rocks>
- * Sander Vrijders <sander@ouroboros.rocks>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., http://www.fsf.org/about/contact/.
- */
-
-#if defined(__linux__) || defined(__CYGWIN__)
-#define _DEFAULT_SOURCE
-#else
-#define _POSIX_C_SOURCE 200112L
-#endif
-
-#include <ouroboros/ipcp-dev.h>
-
-#define BUILD_IPCP_UDP6
-#define THIS_TYPE IPCP_UDP6
-#define TYPE_STR "IPCP over UDP/IPv6"
-#define OUROBOROS_PREFIX "ipcpd/udp6"
-#define IPCP_UDP_MAX_PACKET_SIZE 8952
-#define __AF AF_INET6
-#define __ADDRSTRLEN INET6_ADDRSTRLEN
-#define __SOCKADDR sockaddr_in6
-#define __ADDR in6_addr
-#define __ADDR_ANY_INIT IN6ADDR_ANY_INIT
-
-#include "udp.c"
diff --git a/src/ipcpd/unicast/fa.c b/src/ipcpd/unicast/fa.c
index 596b101b..744eb316 100644
--- a/src/ipcpd/unicast/fa.c
+++ b/src/ipcpd/unicast/fa.c
@@ -130,8 +130,8 @@ struct fa_flow {
size_t u_snd; /* Flow updates sent */
size_t u_rcv; /* Flow updates received */
#endif
- uint64_t s_eid; /* Local endpoint id */
- uint64_t r_eid; /* Remote endpoint id */
+ uint64_t s_eid; /* Local PoA id */
+ uint64_t r_eid; /* Remote PoA id */
uint64_t r_addr; /* Remote address */
void * ctx; /* Congestion avoidance context */
uint64_t fair; /* SFQ virtual finish tag (bytes) */
@@ -208,8 +208,8 @@ static int fa_rib_read(const char * path,
sprintf(buf,
"Flow established at: %20s\n"
"Remote address: %20s\n"
- "Local endpoint ID: %20s\n"
- "Remote endpoint ID: %20s\n"
+ "Local PoA ID: %20s\n"
+ "Remote PoA ID: %20s\n"
"Sent (packets): %20zu\n"
"Sent (bytes): %20zu\n"
"Send failed (packets): %20zu\n"
diff --git a/src/ipcpd/unicast/main.c b/src/ipcpd/unicast/main.c
index 86cb1f06..3ee53401 100644
--- a/src/ipcpd/unicast/main.c
+++ b/src/ipcpd/unicast/main.c
@@ -35,6 +35,7 @@
#include <ouroboros/ipcp-dev.h>
#include <ouroboros/logs.h>
#include <ouroboros/notifier.h>
+#include <ouroboros/qos.h>
#include <ouroboros/random.h>
#include <ouroboros/rib.h>
#include <ouroboros/time.h>
@@ -175,12 +176,14 @@ static void stop_components(void)
ipcp_set_state(IPCP_BOOT);
}
-static int unicast_ipcp_enroll(const char * dst,
- struct layer_info * info)
+static int unicast_ipcp_enroll(const char * dst,
+ const struct poa_addr * addr,
+ struct layer_info * info)
{
struct ipcp_config * conf;
struct conn conn;
uint8_t id[ENROLL_ID_LEN];
+ qosspec_t qs = qos_msg;
if (random_buffer(id, ENROLL_ID_LEN) < 0) {
log_err("Failed to generate enrollment ID.");
@@ -189,7 +192,7 @@ static int unicast_ipcp_enroll(const char * dst,
log_info_id(id, "Requesting enrollment.");
- if (connmgr_alloc(COMPID_ENROLL, dst, NULL, &conn) < 0) {
+ if (connmgr_alloc(COMPID_ENROLL, dst, &qs, addr, &conn) < 0) {
log_err_id(id, "Failed to get connection.");
goto fail_id;
}