summaryrefslogtreecommitdiff
path: root/src/tools
diff options
context:
space:
mode:
Diffstat (limited to 'src/tools')
-rw-r--r--src/tools/CMakeLists.txt4
-rw-r--r--src/tools/irm/irm_bind.c4
-rw-r--r--src/tools/irm/irm_bind_ipcp.c13
-rw-r--r--src/tools/irm/irm_bind_process.c22
-rw-r--r--src/tools/irm/irm_bind_program.c19
-rw-r--r--src/tools/irm/irm_ipcp.c2
-rw-r--r--src/tools/irm/irm_ipcp_bootstrap.c148
-rw-r--r--src/tools/irm/irm_ipcp_connect.c90
-rw-r--r--src/tools/irm/irm_ipcp_create.c15
-rw-r--r--src/tools/irm/irm_ipcp_enroll.c58
-rw-r--r--src/tools/irm/irm_ipcp_list.c23
-rw-r--r--src/tools/irm/irm_ipcp_poa.c98
-rw-r--r--src/tools/irm/irm_ipcp_poa_attach.c153
-rw-r--r--src/tools/irm/irm_ipcp_poa_detach.c153
-rw-r--r--src/tools/irm/irm_ipcp_poa_list.c136
-rw-r--r--src/tools/irm/irm_name_create.c5
-rw-r--r--src/tools/irm/irm_name_list.c13
-rw-r--r--src/tools/irm/irm_name_reg.c5
-rw-r--r--src/tools/irm/irm_name_unreg.c5
-rw-r--r--src/tools/irm/irm_ops.h12
-rw-r--r--src/tools/irm/irm_unbind.c4
-rw-r--r--src/tools/irm/irm_unbind_ipcp.c13
-rw-r--r--src/tools/irm/irm_unbind_process.c13
-rw-r--r--src/tools/irm/irm_unbind_program.c18
-rw-r--r--src/tools/irm/irm_utils.c233
-rw-r--r--src/tools/irm/irm_utils.h41
-rw-r--r--src/tools/ocbr/ocbr_client.c23
-rw-r--r--src/tools/oftp/oftp.c5
-rw-r--r--src/tools/oping/oping_client.c4
29 files changed, 1093 insertions, 239 deletions
diff --git a/src/tools/CMakeLists.txt b/src/tools/CMakeLists.txt
index 6b418838..bb601733 100644
--- a/src/tools/CMakeLists.txt
+++ b/src/tools/CMakeLists.txt
@@ -15,6 +15,10 @@ set(IRM_SOURCES
irm/irm_ipcp_destroy.c
irm/irm_ipcp_bootstrap.c
irm/irm_ipcp_enroll.c
+ irm/irm_ipcp_poa.c
+ irm/irm_ipcp_poa_attach.c
+ irm/irm_ipcp_poa_detach.c
+ irm/irm_ipcp_poa_list.c
irm/irm_ipcp_list.c
irm/irm_ipcp_connect.c
irm/irm_ipcp_disconnect.c
diff --git a/src/tools/irm/irm_bind.c b/src/tools/irm/irm_bind.c
index 3107837a..2d3fc554 100644
--- a/src/tools/irm/irm_bind.c
+++ b/src/tools/irm/irm_bind.c
@@ -78,8 +78,8 @@ static int do_cmd(const char * argv0,
const struct cmd * c;
for (c = cmds; c->cmd; ++c) {
- if (!matches(argv0, c->cmd))
- return c->func(argc, argv);
+ if (matches(argv0, c->cmd) == 0)
+ return c->func(argc - 1, argv + 1);
}
fprintf(stderr, "\"%s\" is unknown, try \"irm bind help\".\n", argv0);
diff --git a/src/tools/irm/irm_bind_ipcp.c b/src/tools/irm/irm_bind_ipcp.c
index 4c183534..b6223074 100644
--- a/src/tools/irm/irm_bind_ipcp.c
+++ b/src/tools/irm/irm_bind_ipcp.c
@@ -61,15 +61,20 @@ int do_bind_ipcp(int argc,
ssize_t len;
ssize_t i;
+ if (argc < 1) {
+ usage();
+ return -1;
+ }
+
+ ipcp = *argv;
+ ++argv;
+ --argc;
+
while (argc > 0) {
if (matches(*argv, "name") == 0) {
name = *(argv + 1);
++argv;
--argc;
- } else if (matches(*argv, "ipcp") == 0) {
- ipcp = *(argv + 1);
- ++argv;
- --argc;
} else {
printf("\"%s\" is unknown, try \"irm "
"bind ipcp\".\n", *argv);
diff --git a/src/tools/irm/irm_bind_process.c b/src/tools/irm/irm_bind_process.c
index fee0c46b..c401df14 100644
--- a/src/tools/irm/irm_bind_process.c
+++ b/src/tools/irm/irm_bind_process.c
@@ -61,20 +61,24 @@ int do_bind_process(int argc,
char * name = NULL;
char * t;
+ if (argc < 1) {
+ usage();
+ return -1;
+ }
+
+ pid = strtol(*argv, &t, 10);
+ if (*argv == t || *t != '\0' || kill(pid, 0)) {
+ printf("\"%s\" is not a valid process id.\n", *argv);
+ return -1;
+ }
+ ++argv;
+ --argc;
+
while (argc > 1) {
if (matches(*argv, "name") == 0) {
name = *(argv + 1);
++argv;
--argc;
- } else if (matches(*argv, "process") == 0) {
- pid = strtol(*(argv + 1), &t, 10);
- if (*(argv + 1) == t || *t != '\0' || kill(pid, 0)) {
- printf("\"%s\" is not a valid process id.\n",
- *(argv + 1));
- return -1;
- }
- ++argv;
- --argc;
} else {
printf("\"%s\" is unknown, try \"irm "
"bind process\".\n", *argv);
diff --git a/src/tools/irm/irm_bind_program.c b/src/tools/irm/irm_bind_program.c
index 14d09db7..592c2ec3 100644
--- a/src/tools/irm/irm_bind_program.c
+++ b/src/tools/irm/irm_bind_program.c
@@ -67,18 +67,23 @@ int do_bind_program(int argc,
int ret = 0;
char * temp = NULL;
+ if (argc < 1) {
+ usage();
+ return -1;
+ }
+
+ temp = realpath(*argv, NULL);
+ if (temp != NULL)
+ *argv = temp;
+ prog = *argv;
+ ++argv;
+ --argc;
+
while (argc > 0) {
if (matches(*argv, "name") == 0) {
name = *(argv + 1);
++argv;
--argc;
- } else if (matches(*argv, "program") == 0) {
- ++argv;
- temp = realpath(*argv, NULL);
- if (temp != NULL)
- *argv = temp;
- prog = *argv;
- --argc;
} else if (strcmp(*argv, "auto") == 0) {
flags |= BIND_AUTO;
} else if (strcmp(*argv, "--") == 0) {
diff --git a/src/tools/irm/irm_ipcp.c b/src/tools/irm/irm_ipcp.c
index 34458a20..5c0db9cf 100644
--- a/src/tools/irm/irm_ipcp.c
+++ b/src/tools/irm/irm_ipcp.c
@@ -46,6 +46,7 @@ static void usage(void)
printf("Usage: irm ipcp [OPERATION]\n\n"
"where OPERATION in {create destroy\n"
" bootstrap enroll\n"
+ " poa\n"
" connect disconnect\n"
" list\n"
" help}\n");
@@ -68,6 +69,7 @@ static const struct cmd {
{ "destroy", do_destroy_ipcp },
{ "bootstrap", do_bootstrap_ipcp },
{ "enroll", do_enroll_ipcp },
+ { "poa", poa_cmd },
{ "connect", do_connect_ipcp },
{ "disconnect", do_disconnect_ipcp },
{ "list", do_list_ipcp},
diff --git a/src/tools/irm/irm_ipcp_bootstrap.c b/src/tools/irm/irm_ipcp_bootstrap.c
index cc8bf8fa..bbcf2312 100644
--- a/src/tools/irm/irm_ipcp_bootstrap.c
+++ b/src/tools/irm/irm_ipcp_bootstrap.c
@@ -53,10 +53,6 @@
#define UNICAST "unicast"
#define BROADCAST "broadcast"
-#define IP_UDP4 "udp4"
-#define IP_UDP6 "udp6"
-#define ETH_LLC "eth-llc"
-#define ETH_DIX "eth-dix"
#define LOCAL "local"
#define MD5 "MD5"
@@ -76,18 +72,13 @@
#define DT(x) default_dt_config.x
#define DHT(x) default_dht_config.params.x
#define UNI(x) default_uni_config.x
-#define DIX(x) eth_dix_default_conf.eth.x
-#define LLC(x) eth_llc_default_conf.eth.x
-#define UD4(x) udp4_default_conf.udp4.x
-#define UD6(x) udp6_default_conf.udp6.x
static char * usage_str = \
"Usage: irm ipcp bootstrap\n"
" name <ipcp name>\n"
" layer <layer name>\n"
" [type [TYPE]]\n"
- "where TYPE in {" UNICAST " " BROADCAST " " LOCAL " "
- IP_UDP4 " " IP_UDP6 " " ETH_LLC " " ETH_DIX "},\n\n"
+ "where TYPE in {" UNICAST " " BROADCAST " " LOCAL "},\n\n"
"if TYPE == " UNICAST "\n"
" [addr_auth <ADDRESS_POLICY> (default: %s)]\n"
" [directory <DIRECTORY_POLICY> (default: %s)]\n"
@@ -117,28 +108,6 @@ static char * usage_str = \
" [ls_t_recalc <pff recalc interval (s)> (default: %ld)]\n"
" [ls_t_update <LSA update interval (s)> (default: %ld)]\n"
" [ls_t_timeo <link timeout (s)> (default: %ld)]\n\n"
- "if TYPE == " IP_UDP4 "\n"
- " ip <IP address in dotted notation>\n"
- " [port <UDP port> (default: %d)]\n"
- " [dns <DDNS IPv4 address in dotted notation>"
- " (default: none)]\n\n"
- "if TYPE == " IP_UDP6 "\n"
- " ip <IPv6 address>\n"
- " [port <UDP port> (default: %d)]\n"
- " [dns <DDNS IPv6 address>"
- " (default: none)]\n\n"
-
- "if TYPE == " ETH_LLC "\n"
- " dev <interface name>\n"
- " [hash [ALGORITHM] (default: %s)]\n"
- "where ALGORITHM in {" SHA3_224 " " SHA3_256 " "
- SHA3_384 " " SHA3_512 "}\n\n"
- "if TYPE == " ETH_DIX "\n"
- " dev <interface name>\n"
- " [ethertype <ethertype> (default: 0x%4X)]\n"
- " [hash [ALGORITHM] (default: %s)]\n"
- "where ALGORITHM in {" SHA3_224 " " SHA3_256 " "
- SHA3_384 " " SHA3_512 "}\n\n"
"if TYPE == " LOCAL "\n"
" [hash [ALGORITHM] (default: %s)]\n"
"where ALGORITHM in {" SHA3_224 " " SHA3_256 " "
@@ -160,15 +129,6 @@ static void usage(void)
/* ls */
default_ls_config.t_recalc, default_ls_config.t_update,
default_ls_config.t_timeo,
- /* udp4 */
- UD4(port),
- /* udp6 */
- UD6(port),
- /* eth_llc */
- SHA3_256,
- /* eth_dix */
- DIX(ethertype),
- SHA3_256,
/* local */
SHA3_256,
/* broadcast */
@@ -190,19 +150,9 @@ int do_bootstrap_ipcp(int argc,
enum pol_addr_auth addr_auth_type = UNI(addr_auth_type);
enum pol_cong_avoid cong_avoid = UNI(cong_avoid);
enum pol_dir_hash hash_algo = DIR_HASH_SHA3_256;
- char * ipstr = NULL;
- char * dnsstr = NULL;
- struct in_addr ip4_addr = {.s_addr = INADDR_ANY};
- struct in_addr dns4_addr = UD4(dns_addr);
- int port4 = UD4(port);
- struct in6_addr ip6_addr = IN6ADDR_ANY_INIT;
- struct in6_addr dns6_addr = UD6(dns_addr);
- int port6 = UD6(port);
char * ipcp_type = NULL;
enum ipcp_type type = IPCP_INVALID;
char * layer = NULL;
- char * dev = NULL;
- uint16_t ethertype = DIX(ethertype);
struct ipcp_list_info * ipcps;
ssize_t len = 0;
int i = 0;
@@ -211,6 +161,14 @@ int do_bootstrap_ipcp(int argc,
while (argc > 0) {
cargs = 2;
+ if (matches(*argv, "autobind") == 0)
+ cargs = 1;
+
+ if (argc < cargs) {
+ usage();
+ return -1;
+ }
+
if (matches(*argv, "type") == 0) {
ipcp_type = *(argv + 1);
} else if (matches(*argv, "layer") == 0) {
@@ -228,24 +186,6 @@ int do_bootstrap_ipcp(int argc,
hash_algo = DIR_HASH_SHA3_512;
else
goto unknown_param;
- } else if (matches(*argv, "ip") == 0) {
- ipstr = *(argv + 1);
- } else if (matches(*argv, "dns") == 0) {
- dnsstr = *(argv + 1);
- } else if (matches(*argv, "device") == 0) {
- dev = *(argv + 1);
- } else if (matches(*argv, "ethertype") == 0) {
- /* NOTE: We might do some more checks on strtol. */
- if (matches(*(argv + 1), "0x") == 0)
- ethertype = strtol(*(argv + 1), NULL, 0);
- else
- ethertype = strtol(*(argv + 1), NULL, 16);
- if (ethertype < 0x0600 || ethertype >= 0xFFFF) {
- printf("Invalid Ethertype: \"%s\".\n"
- "Recommended range: 0xA000-0xEFFF.\n",
- *(argv + 1));
- return -1;
- }
} else if (matches(*argv, "addr") == 0) {
addr_size = atoi(*(argv + 1));
} else if (matches(*argv, "eid") == 0) {
@@ -254,9 +194,6 @@ int do_bootstrap_ipcp(int argc,
max_ttl = atoi(*(argv + 1));
} else if (matches(*argv, "rtt") == 0) {
max_rtt = atoi(*(argv + 1));
- } else if (matches(*argv, "port") == 0) {
- port4 = atoi(*(argv + 1));
- port6 = port4;
} else if (matches(*argv, "autobind") == 0) {
autobind = true;
cargs = 1;
@@ -334,55 +271,11 @@ int do_bootstrap_ipcp(int argc,
type = IPCP_UNICAST;
else if (matches(ipcp_type, BROADCAST) == 0)
type = IPCP_BROADCAST;
- else if (matches(ipcp_type, IP_UDP4) == 0)
- type = IPCP_UDP4;
- else if (matches(ipcp_type, IP_UDP6) == 0)
- type = IPCP_UDP6;
- else if (matches(ipcp_type, ETH_DIX) == 0)
- type = IPCP_ETH_DIX;
- else if (matches(ipcp_type, ETH_LLC) == 0)
- type = IPCP_ETH_LLC;
else if (matches(ipcp_type, LOCAL) == 0)
type = IPCP_LOCAL;
else goto fail_usage;
}
- if (type == IPCP_UDP4) {
- if (inet_pton (AF_INET, ipstr, &ip4_addr) != 1) {
- printf("Invalid IPv4 address: \"%s\".\n", ipstr);
- goto fail_usage;
- }
-
- if (ip4_addr.s_addr == INADDR_ANY) {
- printf("Cannot use IPv4 address: \"%s\".\n", ipstr);
- goto fail_usage;
- }
-
- if (dnsstr != NULL &&
- inet_pton(AF_INET, dnsstr, &dns4_addr) != 1) {
- printf("Invalid DNS IPv4 address: \"%s\".\n", dnsstr);
- goto fail_usage;
- }
- }
-
- if (type == IPCP_UDP6) {
- if (inet_pton(AF_INET6, ipstr, &ip6_addr) != 1) {
- printf("Invalid IPv6 address: \"%s\".\n", ipstr);
- goto fail_usage;
- }
-
- if (IN6_IS_ADDR_UNSPECIFIED(&ip6_addr)) {
- printf("Cannot use IPv6 address: \"%s\".\n", ipstr);
- goto fail_usage;
- }
-
- if (dnsstr != NULL &&
- inet_pton(AF_INET6, dnsstr, &dns6_addr) != 1) {
- printf("Invalid DNS IPv6 address: \"%s\".\n", dnsstr);
- goto fail_usage;
- }
- }
-
if (pid == -1) {
if (ipcp_type == NULL) {
printf("No IPCPs matching %s found.\n\n", ipcp);
@@ -432,29 +325,6 @@ int do_bootstrap_ipcp(int argc,
conf.unicast.cong_avoid = cong_avoid;
conf.unicast.dir = dir_config;
break;
- case IPCP_UDP4:
- conf.udp4.ip_addr = ip4_addr;
- conf.udp4.dns_addr = dns4_addr;
- conf.udp4.port = port4;
- break;
- case IPCP_UDP6:
- conf.udp6.ip_addr = ip6_addr;
- conf.udp6.dns_addr = dns6_addr;
- conf.udp6.port = port6;
- break;
- case IPCP_ETH_DIX:
- conf.eth.ethertype = ethertype;
- /* FALLTHRU */
- case IPCP_ETH_LLC:
- if (dev == NULL)
- goto fail_usage;
- if (strlen(dev) > DEV_NAME_SIZE) {
- printf("Device name too long.\n\n");
- goto fail_usage;
- }
-
- strcpy(conf.eth.dev, dev);
- break;
case IPCP_BROADCAST:
/* FALLTHRU */
case IPCP_LOCAL:
diff --git a/src/tools/irm/irm_ipcp_connect.c b/src/tools/irm/irm_ipcp_connect.c
index fb21faec..66646e7d 100644
--- a/src/tools/irm/irm_ipcp_connect.c
+++ b/src/tools/irm/irm_ipcp_connect.c
@@ -44,6 +44,7 @@
#include <stdio.h>
#include <stdlib.h>
+#include <arpa/inet.h>
#include <string.h>
#define DT "dt"
@@ -55,10 +56,14 @@ static void usage(void)
" name <ipcp name>\n"
" dst <name of destination IPCP>\n"
" [component [COMPONENT]]\n"
- "where COMPONENT in {" DT " " MGMT "}\n\n"
+ " [udp [UDP_PEER]]\n"
+ " [eth [dev <device>]"
+ " [ethertype <ethertype>]]\n"
+ "where COMPONENT in {" DT " " MGMT "}\n"
+ "and UDP_PEER is <IP address or host>[:<port>]\n\n"
"if COMPONENT == " DT "\n"
- " [qos [QOS]\n"
- "where QOS in {raw, best, voice, video, data}\n");
+ " [qos [QOS]]\n"
+ "where QOS in {raw, safe, rt, rt-safe, msg}\n");
}
int do_connect_ipcp(int argc,
@@ -69,13 +74,29 @@ int do_connect_ipcp(int argc,
char * comp = "*";
char * component = NULL;
char * qos = NULL;
+ char * udpstr = NULL;
+ char * devstr = NULL;
+ uint16_t ethertype = POA_ETHERTYPE;
+ bool eth = false;
+ struct poa_addr addr;
+ struct poa_addr * pa = NULL;
struct ipcp_list_info * ipcps;
ssize_t len = 0;
pid_t pid = -1;
ssize_t i;
+ int cargs;
qosspec_t qs = qos_raw;
while (argc > 0) {
+ cargs = 2;
+ if (strcmp(*argv, "eth") == 0)
+ cargs = 1;
+
+ if (argc < cargs) {
+ usage();
+ return -1;
+ }
+
if (matches(*argv, "name") == 0) {
ipcp = *(argv + 1);
} else if (matches(*argv, "dst") == 0) {
@@ -84,21 +105,66 @@ int do_connect_ipcp(int argc,
comp = *(argv + 1);
} else if (matches(*argv, "qos") == 0) {
qos = *(argv + 1);
+ } else if (strcmp(*argv, "udp") == 0) {
+ udpstr = *(argv + 1);
+ } else if (strcmp(*argv, "dev") == 0) {
+ devstr = *(argv + 1);
+ } else if (strcmp(*argv, "ethertype") == 0) {
+ if (parse_ethertype(*(argv + 1), &ethertype) < 0) {
+ printf("Invalid ethertype: \"%s\".\n",
+ *(argv + 1));
+ return -1;
+ }
+ } else if (strcmp(*argv, "eth") == 0) {
+ eth = true;
+ cargs = 1;
} else {
printf("\"%s\" is unknown, try \"irm "
"ipcp connect\".\n", *argv);
return -1;
}
- argc -= 2;
- argv += 2;
+ argc -= cargs;
+ argv += cargs;
}
- if (ipcp == NULL || dst == NULL || comp == NULL) {
+ if (ipcp == NULL || comp == NULL) {
usage();
return -1;
}
+ memset(&addr, 0, sizeof(addr));
+
+ if (udpstr != NULL) {
+ if (poa_addr_set_udp(&addr, udpstr) < 0)
+ return -1;
+ pa = &addr;
+ }
+
+ if (eth) {
+ if (udpstr != NULL) {
+ printf("Connect via udp or eth, not both.\n");
+ return -1;
+ }
+
+ if (dst == NULL) {
+ usage();
+ return -1;
+ }
+
+ if (poa_addr_set_eth(&addr, devstr, ethertype) < 0)
+ return -1;
+ pa = &addr;
+ }
+
+ if (dst == NULL && pa == NULL) {
+ usage();
+ return -1;
+ }
+
+ if (dst == NULL)
+ dst = "";
+
if (qos != NULL) {
if (strcmp(qos, "raw") == 0)
qs = qos_raw;
@@ -110,9 +176,11 @@ int do_connect_ipcp(int argc,
qs = qos_rt_safe;
else if (strcmp(qos, "msg") == 0)
qs = qos_msg;
- else if (strcmp(qos, "stream") == 0)
- qs = qos_stream;
- else
+ else if (strcmp(qos, "stream") == 0) {
+ printf("Stream QoS is not allowed on "
+ "IPCP component flows.\n");
+ return -1;
+ } else
printf("Unknown QoS cube, defaulting to raw.\n");
}
@@ -129,13 +197,13 @@ int do_connect_ipcp(int argc,
if (wildcard_match(comp, MGMT) == 0) {
component = MGMT_COMP;
/* FIXME: move to qos_msg when stable */
- if (irm_connect_ipcp(pid, dst, component, qos_raw))
+ if (irm_connect_ipcp(pid, dst, component, qos_raw, pa))
return -1;
}
if (wildcard_match(comp, DT) == 0) {
component = DT_COMP;
- if (irm_connect_ipcp(pid, dst, component, qs))
+ if (irm_connect_ipcp(pid, dst, component, qs, pa))
return -1;
}
diff --git a/src/tools/irm/irm_ipcp_create.c b/src/tools/irm/irm_ipcp_create.c
index c6b2074b..15cfedde 100644
--- a/src/tools/irm/irm_ipcp_create.c
+++ b/src/tools/irm/irm_ipcp_create.c
@@ -46,10 +46,6 @@
#define UNICAST "unicast"
#define BROADCAST "broadcast"
-#define UDP4 "udp4"
-#define UDP6 "udp6"
-#define ETH_LLC "eth-llc"
-#define ETH_DIX "eth-dix"
#define LOCAL "local"
static void usage(void)
@@ -57,8 +53,7 @@ static void usage(void)
printf("Usage: irm ipcp create\n"
" name <ipcp name>\n"
" type [TYPE]\n\n"
- "where TYPE in {" UNICAST " " BROADCAST " " LOCAL " "
- UDP4 " " UDP6 " " ETH_LLC " " ETH_DIX "}\n");
+ "where TYPE in {" UNICAST " " BROADCAST " " LOCAL "}\n");
}
int do_create_ipcp(int argc,
@@ -93,16 +88,8 @@ int do_create_ipcp(int argc,
type = IPCP_UNICAST;
else if (strcmp(ipcp_type, BROADCAST) == 0)
type = IPCP_BROADCAST;
- else if (strcmp(ipcp_type, UDP4) == 0)
- type = IPCP_UDP4;
- else if (strcmp(ipcp_type, UDP6) == 0)
- type = IPCP_UDP6;
else if (strcmp(ipcp_type, LOCAL) == 0)
type = IPCP_LOCAL;
- else if (strcmp(ipcp_type, ETH_LLC) == 0)
- type = IPCP_ETH_LLC;
- else if (strcmp(ipcp_type, ETH_DIX) == 0)
- type = IPCP_ETH_DIX;
else {
printf("IPCP type \"%s\" is unknown.\n", ipcp_type);
usage();
diff --git a/src/tools/irm/irm_ipcp_enroll.c b/src/tools/irm/irm_ipcp_enroll.c
index 350b536e..54fed022 100644
--- a/src/tools/irm/irm_ipcp_enroll.c
+++ b/src/tools/irm/irm_ipcp_enroll.c
@@ -44,6 +44,7 @@
#include "irm_ops.h"
#include "irm_utils.h"
+#include <arpa/inet.h>
#include <string.h>
#define UNICAST "unicast"
@@ -57,7 +58,10 @@ static void usage(void)
" [dst <destination to enroll with>]\n"
" [type [TYPE], default = " UNICAST "]\n"
" [autobind]\n"
- "where TYPE in {" UNICAST " " BROADCAST "}\n");
+ " [udp [UDP_PEER]]\n"
+ " [eth [dev <device>] [ethertype <ethertype>]]\n"
+ "where TYPE in {" UNICAST " " BROADCAST "}\n"
+ "and UDP_PEER is <IP address or host>[:<port>]\n");
}
static int get_layer_name(const char * ipcp,
@@ -86,6 +90,12 @@ int do_enroll_ipcp(int argc,
char * ipcp = NULL;
char * layer = NULL;
char * dst = NULL;
+ char * udpstr = NULL;
+ char * devstr = NULL;
+ uint16_t ethertype = POA_ETHERTYPE;
+ bool eth = false;
+ struct poa_addr addr;
+ struct poa_addr * pa = NULL;
struct ipcp_list_info * ipcps;
pid_t pid = -1;
ssize_t len = 0;
@@ -97,14 +107,37 @@ int do_enroll_ipcp(int argc,
while (argc > 0) {
cargs = 2;
+ if (strcmp(*argv, "eth") == 0)
+ cargs = 1;
+ else if (matches(*argv, "autobind") == 0)
+ cargs = 1;
+
+ if (argc < cargs) {
+ usage();
+ return -1;
+ }
+
if (matches(*argv, "name") == 0) {
ipcp = *(argv + 1);
} else if (matches(*argv, "type") == 0) {
ipcp_type = *(argv + 1);
} else if (matches(*argv, "layer") == 0) {
layer = *(argv + 1);
- } else if (matches(*argv, "dst") == 0) {
+ } else if (strcmp(*argv, "dst") == 0) {
dst = *(argv + 1);
+ } else if (strcmp(*argv, "udp") == 0) {
+ udpstr = *(argv + 1);
+ } else if (strcmp(*argv, "dev") == 0) {
+ devstr = *(argv + 1);
+ } else if (strcmp(*argv, "ethertype") == 0) {
+ if (parse_ethertype(*(argv + 1), &ethertype) < 0) {
+ printf("Invalid ethertype: \"%s\".\n",
+ *(argv + 1));
+ return -1;
+ }
+ } else if (strcmp(*argv, "eth") == 0) {
+ eth = true;
+ cargs = 1;
} else if (matches(*argv, "autobind") == 0) {
autobind = true;
cargs = 1;
@@ -126,6 +159,25 @@ int do_enroll_ipcp(int argc,
if (dst == NULL)
dst = layer;
+ memset(&addr, 0, sizeof(addr));
+
+ if (udpstr != NULL) {
+ if (poa_addr_set_udp(&addr, udpstr) < 0)
+ return -1;
+ pa = &addr;
+ }
+
+ if (eth) {
+ if (udpstr != NULL) {
+ printf("Enroll via udp or eth, not both.\n");
+ return -1;
+ }
+
+ if (poa_addr_set_eth(&addr, devstr, ethertype) < 0)
+ return -1;
+ pa = &addr;
+ }
+
if (strcmp(ipcp_type, UNICAST) == 0)
type = IPCP_UNICAST;
else if (strcmp(ipcp_type, BROADCAST) == 0)
@@ -155,7 +207,7 @@ int do_enroll_ipcp(int argc,
pid = ipcps[i].pid;
- if (irm_enroll_ipcp(pid, dst)) {
+ if (irm_enroll_ipcp(pid, dst, pa) < 0) {
printf("Failed to enroll IPCP.\n");
goto fail;
}
diff --git a/src/tools/irm/irm_ipcp_list.c b/src/tools/irm/irm_ipcp_list.c
index a211a02b..60154efb 100644
--- a/src/tools/irm/irm_ipcp_list.c
+++ b/src/tools/irm/irm_ipcp_list.c
@@ -48,10 +48,6 @@
#define UNICAST "unicast"
#define BROADCAST "broadcast"
-#define UDP4 "udp4"
-#define UDP6 "udp6"
-#define ETH_LLC "eth-llc"
-#define ETH_DIX "eth-dix"
#define LOCAL "local"
static void usage(void)
@@ -60,8 +56,7 @@ static void usage(void)
" [name <ipcp name>]\n"
" [layer <layer_name>]\n\n"
" [type [TYPE]]\n\n"
- "where TYPE = {" UNICAST " " LOCAL " "
- UDP4 " " UDP6 " " ETH_LLC " " ETH_DIX "}\n");
+ "where TYPE = {" UNICAST " " BROADCAST " " LOCAL "}\n");
}
static char * str_type(enum ipcp_type type)
@@ -71,14 +66,6 @@ static char * str_type(enum ipcp_type type)
return UNICAST;
case IPCP_BROADCAST:
return BROADCAST;
- case IPCP_ETH_LLC:
- return ETH_LLC;
- case IPCP_ETH_DIX:
- return ETH_DIX;
- case IPCP_UDP4:
- return UDP4;
- case IPCP_UDP6:
- return UDP6;
case IPCP_LOCAL:
return LOCAL;
default:
@@ -116,16 +103,8 @@ int do_list_ipcp(int argc,
type = IPCP_UNICAST;
else if (strcmp(ipcp_type, BROADCAST) == 0)
type = IPCP_BROADCAST;
- else if (strcmp(ipcp_type, UDP4) == 0)
- type = IPCP_UDP4;
- else if (strcmp(ipcp_type, UDP6) == 0)
- type = IPCP_UDP6;
else if (strcmp(ipcp_type, LOCAL) == 0)
type = IPCP_LOCAL;
- else if (strcmp(ipcp_type, ETH_LLC) == 0)
- type = IPCP_ETH_LLC;
- else if (strcmp(ipcp_type, ETH_DIX) == 0)
- type = IPCP_ETH_DIX;
else {
usage();
return -1;
diff --git a/src/tools/irm/irm_ipcp_poa.c b/src/tools/irm/irm_ipcp_poa.c
new file mode 100644
index 00000000..cd939020
--- /dev/null
+++ b/src/tools/irm/irm_ipcp_poa.c
@@ -0,0 +1,98 @@
+/*
+ * Ouroboros - Copyright (C) 2016 - 2026
+ *
+ * Connect components of unicast or broadcast IPC processes
+ *
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "irm_ops.h"
+#include "irm_utils.h"
+
+#include <stdio.h>
+#include <string.h>
+
+static void usage(void)
+{
+ printf("Usage: irm ipcp poa [OPERATION]\n\n"
+ "where OPERATION in {attach detach list help}\n");
+}
+
+static int do_help(int argc,
+ char ** argv)
+{
+ (void) argc;
+ (void) argv;
+
+ usage();
+
+ return 0;
+}
+
+static const struct cmd {
+ const char * cmd;
+ int (* func)(int argc, char ** argv);
+} cmds[] = {
+ { "attach", do_attach_ipcp },
+ { "detach", do_detach_ipcp },
+ { "list", do_list_poas },
+ { "help", do_help },
+ { NULL, NULL }
+};
+
+static int do_cmd(const char * argv0,
+ int argc,
+ char ** argv)
+{
+ const struct cmd * c;
+
+ for (c = cmds; c->cmd != NULL; ++c)
+ if (matches(argv0, c->cmd) == 0)
+ return c->func(argc - 1, argv + 1);
+
+ fprintf(stderr, "\"%s\" is unknown, try \"irm ipcp poa help\".\n",
+ argv0);
+
+ return -1;
+}
+
+int poa_cmd(int argc,
+ char ** argv)
+{
+ if (argc < 1) {
+ usage();
+ return -1;
+ }
+
+ return do_cmd(argv[0], argc, argv);
+}
diff --git a/src/tools/irm/irm_ipcp_poa_attach.c b/src/tools/irm/irm_ipcp_poa_attach.c
new file mode 100644
index 00000000..74a83344
--- /dev/null
+++ b/src/tools/irm/irm_ipcp_poa_attach.c
@@ -0,0 +1,153 @@
+/*
+ * Ouroboros - Copyright (C) 2016 - 2026
+ *
+ * Connect components of unicast or broadcast IPC processes
+ *
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <ouroboros/irm.h>
+
+#include "irm_ops.h"
+#include "irm_utils.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+static void usage(void)
+{
+ printf("Usage: irm ipcp poa attach\n"
+ " name <ipcp name>\n"
+ " [udp [UDP_POA]]\n"
+ " [eth [ETH_POA]]\n"
+ "where exactly one of udp or eth is given\n"
+ "and UDP_POA is <local IP address>[:<port>]\n"
+ "and ETH_POA is dev <device> [ethertype <ethertype>]\n");
+}
+
+int do_attach_ipcp(int argc,
+ char ** argv)
+{
+ char * ipcp = NULL;
+ char * udpstr = NULL;
+ char * devstr = NULL;
+ uint16_t ethertype = POA_ETHERTYPE;
+ bool eth = false;
+ struct poa_spec poa;
+ char str[POA_STRLEN + 1];
+ struct ipcp_list_info * ipcps;
+ ssize_t len = 0;
+ pid_t pid = -1;
+ ssize_t i;
+ int cargs;
+
+ while (argc > 0) {
+ cargs = 2;
+
+ if (strcmp(*argv, "eth") == 0)
+ cargs = 1;
+
+ if (argc < cargs) {
+ usage();
+ return -1;
+ }
+
+ if (matches(*argv, "name") == 0) {
+ ipcp = *(argv + 1);
+ } else if (strcmp(*argv, "udp") == 0) {
+ udpstr = *(argv + 1);
+ } else if (strcmp(*argv, "dev") == 0) {
+ devstr = *(argv + 1);
+ } else if (strcmp(*argv, "ethertype") == 0) {
+ if (parse_ethertype(*(argv + 1), &ethertype) < 0) {
+ printf("Invalid ethertype: \"%s\".\n",
+ *(argv + 1));
+ return -1;
+ }
+ } else if (strcmp(*argv, "eth") == 0) {
+ eth = true;
+ cargs = 1;
+ } else {
+ printf("\"%s\" is unknown, try \"irm ipcp "
+ "poa attach\".\n", *argv);
+ return -1;
+ }
+
+ argc -= cargs;
+ argv += cargs;
+ }
+
+ if (ipcp == NULL) {
+ usage();
+ return -1;
+ }
+
+ if (eth && udpstr != NULL) {
+ printf("A PoA is udp or eth, not both.\n");
+ return -1;
+ }
+
+ if (eth && devstr == NULL) {
+ printf("An eth PoA needs a device.\n");
+ return -1;
+ }
+
+ if (!eth && udpstr == NULL) {
+ usage();
+ return -1;
+ }
+
+ if (poa_spec_set(&poa, udpstr, devstr, ethertype) < 0)
+ return -1;
+
+ len = irm_list_ipcps(&ipcps);
+ for (i = 0; i < len; i++)
+ if (strcmp(ipcps[i].name, ipcp) == 0)
+ pid = ipcps[i].pid;
+
+ free(ipcps);
+
+ if (pid == -1) {
+ printf("No such IPCP: \"%s\".\n", ipcp);
+ return -1;
+ }
+
+ if (irm_attach_ipcp(pid, &poa) < 0) {
+ poa_spec_str(&poa, str, sizeof(str));
+ printf("Failed to attach PoA %s on IPCP %s.\n", str, ipcp);
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/src/tools/irm/irm_ipcp_poa_detach.c b/src/tools/irm/irm_ipcp_poa_detach.c
new file mode 100644
index 00000000..ce6bef13
--- /dev/null
+++ b/src/tools/irm/irm_ipcp_poa_detach.c
@@ -0,0 +1,153 @@
+/*
+ * Ouroboros - Copyright (C) 2016 - 2026
+ *
+ * Connect components of unicast or broadcast IPC processes
+ *
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <ouroboros/irm.h>
+
+#include "irm_ops.h"
+#include "irm_utils.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+static void usage(void)
+{
+ printf("Usage: irm ipcp poa detach\n"
+ " name <ipcp name>\n"
+ " [udp [UDP_POA]]\n"
+ " [eth [ETH_POA]]\n"
+ "where exactly one of udp or eth is given\n"
+ "and UDP_POA is <local IP address>[:<port>]\n"
+ "and ETH_POA is dev <device> [ethertype <ethertype>]\n");
+}
+
+int do_detach_ipcp(int argc,
+ char ** argv)
+{
+ char * ipcp = NULL;
+ char * udpstr = NULL;
+ char * devstr = NULL;
+ uint16_t ethertype = POA_ETHERTYPE;
+ bool eth = false;
+ struct poa_spec poa;
+ char str[POA_STRLEN + 1];
+ struct ipcp_list_info * ipcps;
+ ssize_t len = 0;
+ pid_t pid = -1;
+ ssize_t i;
+ int cargs;
+
+ while (argc > 0) {
+ cargs = 2;
+
+ if (strcmp(*argv, "eth") == 0)
+ cargs = 1;
+
+ if (argc < cargs) {
+ usage();
+ return -1;
+ }
+
+ if (matches(*argv, "name") == 0) {
+ ipcp = *(argv + 1);
+ } else if (strcmp(*argv, "udp") == 0) {
+ udpstr = *(argv + 1);
+ } else if (strcmp(*argv, "dev") == 0) {
+ devstr = *(argv + 1);
+ } else if (strcmp(*argv, "ethertype") == 0) {
+ if (parse_ethertype(*(argv + 1), &ethertype) < 0) {
+ printf("Invalid ethertype: \"%s\".\n",
+ *(argv + 1));
+ return -1;
+ }
+ } else if (strcmp(*argv, "eth") == 0) {
+ eth = true;
+ cargs = 1;
+ } else {
+ printf("\"%s\" is unknown, try \"irm ipcp "
+ "poa detach\".\n", *argv);
+ return -1;
+ }
+
+ argc -= cargs;
+ argv += cargs;
+ }
+
+ if (ipcp == NULL) {
+ usage();
+ return -1;
+ }
+
+ if (eth && udpstr != NULL) {
+ printf("A PoA is udp or eth, not both.\n");
+ return -1;
+ }
+
+ if (eth && devstr == NULL) {
+ printf("An eth PoA needs a device.\n");
+ return -1;
+ }
+
+ if (!eth && udpstr == NULL) {
+ usage();
+ return -1;
+ }
+
+ if (poa_spec_set(&poa, udpstr, devstr, ethertype) < 0)
+ return -1;
+
+ len = irm_list_ipcps(&ipcps);
+ for (i = 0; i < len; i++)
+ if (strcmp(ipcps[i].name, ipcp) == 0)
+ pid = ipcps[i].pid;
+
+ free(ipcps);
+
+ if (pid == -1) {
+ printf("No such IPCP: \"%s\".\n", ipcp);
+ return -1;
+ }
+
+ if (irm_detach_ipcp(pid, &poa) < 0) {
+ poa_spec_str(&poa, str, sizeof(str));
+ printf("Failed to detach PoA %s on IPCP %s.\n", str, ipcp);
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/src/tools/irm/irm_ipcp_poa_list.c b/src/tools/irm/irm_ipcp_poa_list.c
new file mode 100644
index 00000000..8797c3c1
--- /dev/null
+++ b/src/tools/irm/irm_ipcp_poa_list.c
@@ -0,0 +1,136 @@
+/*
+ * Ouroboros - Copyright (C) 2016 - 2026
+ *
+ * List the points of attachment of an IPC process
+ *
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <ouroboros/irm.h>
+
+#include "irm_ops.h"
+#include "irm_utils.h"
+
+#include <arpa/inet.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+static void usage(void)
+{
+ printf("Usage: irm ipcp poa list\n"
+ " name <ipcp name>\n");
+}
+
+static void print_poa(const struct poa_spec * poa)
+{
+ char buf[INET6_ADDRSTRLEN];
+
+ switch (poa->type) {
+ case POA_UDP4:
+ if (inet_ntop(AF_INET, &poa->udp4.ip_addr, buf,
+ sizeof(buf)) == NULL)
+ return;
+ printf("%-6s %s:%u\n", "udp4", buf, poa->udp4.port);
+ break;
+ case POA_UDP6:
+ if (inet_ntop(AF_INET6, &poa->udp6.ip_addr, buf,
+ sizeof(buf)) == NULL)
+ return;
+ printf("%-6s [%s]:%u\n", "udp6", buf, poa->udp6.port);
+ break;
+ case POA_ETH:
+ printf("%-6s %s 0x%04X %02x:%02x:%02x:%02x:%02x:%02x\n",
+ "eth", poa->eth.dev, poa->eth.ethertype,
+ poa->eth.mac[0], poa->eth.mac[1], poa->eth.mac[2],
+ poa->eth.mac[3], poa->eth.mac[4], poa->eth.mac[5]);
+ break;
+ default:
+ break;
+ }
+}
+
+int do_list_poas(int argc,
+ char ** argv)
+{
+ char * ipcp = NULL;
+ struct poa_spec * poas = NULL;
+ struct ipcp_list_info * ipcps;
+ ssize_t len = 0;
+ pid_t pid = -1;
+ ssize_t n;
+ ssize_t i;
+
+ while (argc > 1) {
+ if (matches(*argv, "name") == 0) {
+ ipcp = *(argv + 1);
+ } else {
+ printf("\"%s\" is unknown, try \"irm ipcp "
+ "poa list\".\n", *argv);
+ return -1;
+ }
+
+ argc -= 2;
+ argv += 2;
+ }
+
+ if (ipcp == NULL) {
+ usage();
+ return -1;
+ }
+
+ len = irm_list_ipcps(&ipcps);
+ for (i = 0; i < len; i++)
+ if (strcmp(ipcps[i].name, ipcp) == 0)
+ pid = ipcps[i].pid;
+
+ free(ipcps);
+
+ if (pid == -1) {
+ printf("No such IPCP: \"%s\".\n", ipcp);
+ return -1;
+ }
+
+ n = irm_list_poas(pid, &poas);
+ if (n < 0) {
+ printf("Failed to list PoAs of %s.\n", ipcp);
+ return -1;
+ }
+
+ for (i = 0; i < n; i++)
+ print_poa(&poas[i]);
+
+ free(poas);
+
+ return 0;
+}
diff --git a/src/tools/irm/irm_name_create.c b/src/tools/irm/irm_name_create.c
index 40a51193..034b4c99 100644
--- a/src/tools/irm/irm_name_create.c
+++ b/src/tools/irm/irm_name_create.c
@@ -117,6 +117,11 @@ int do_create_name(int argc,
--argc;
while (argc > 0) {
+ if (argc < 2) {
+ usage();
+ return -1;
+ }
+
if (matches(*argv, "lb") == 0) {
lb_pol = *(argv + 1);
} else if (matches(*argv, "ssecpath") == 0) {
diff --git a/src/tools/irm/irm_name_list.c b/src/tools/irm/irm_name_list.c
index 37e1f023..a5a33073 100644
--- a/src/tools/irm/irm_name_list.c
+++ b/src/tools/irm/irm_name_list.c
@@ -49,6 +49,12 @@
#define RR "round-robin"
#define SPILL "spillover"
+static void usage(void)
+{
+ printf("Usage: irm name list\n"
+ " [name <name>]\n");
+}
+
static char * str_pol(enum pol_balance p)
{
switch(p) {
@@ -70,7 +76,12 @@ int do_list_name(int argc,
ssize_t i;
while (argc > 0) {
- if (matches(*argv, "list") == 0) {
+ if (argc < 2) {
+ usage();
+ return -1;
+ }
+
+ if (matches(*argv, "name") == 0) {
name = *(argv + 1);
} else {
printf("\"%s\" is unknown, try \"irm "
diff --git a/src/tools/irm/irm_name_reg.c b/src/tools/irm/irm_name_reg.c
index 860f4a70..25e9fbb8 100644
--- a/src/tools/irm/irm_name_reg.c
+++ b/src/tools/irm/irm_name_reg.c
@@ -80,6 +80,11 @@ int do_reg_name(int argc,
--argc;
while (argc > 0) {
+ if (argc < 2) {
+ usage();
+ return -1;
+ }
+
if (matches(*argv, "layer") == 0) {
layers[layers_len++] = *(argv + 1);
if (layers_len > MAX_LAYERS) {
diff --git a/src/tools/irm/irm_name_unreg.c b/src/tools/irm/irm_name_unreg.c
index abf08548..1b2cf29c 100644
--- a/src/tools/irm/irm_name_unreg.c
+++ b/src/tools/irm/irm_name_unreg.c
@@ -76,6 +76,11 @@ int do_unreg_name(int argc,
--argc;
while (argc > 0) {
+ if (argc < 2) {
+ usage();
+ return -1;
+ }
+
if (matches(*argv, "layer") == 0) {
layers[layers_len++] = *(argv + 1);
if (layers_len > MAX_LAYERS) {
diff --git a/src/tools/irm/irm_ops.h b/src/tools/irm/irm_ops.h
index 195c5cbc..7f6c65cd 100644
--- a/src/tools/irm/irm_ops.h
+++ b/src/tools/irm/irm_ops.h
@@ -51,6 +51,18 @@ int do_bootstrap_ipcp(int argc,
int do_enroll_ipcp(int argc,
char ** argv);
+int poa_cmd(int argc,
+ char ** argv);
+
+int do_attach_ipcp(int argc,
+ char ** argv);
+
+int do_detach_ipcp(int argc,
+ char ** argv);
+
+int do_list_poas(int argc,
+ char ** argv);
+
int do_connect_ipcp(int argc,
char ** argv);
diff --git a/src/tools/irm/irm_unbind.c b/src/tools/irm/irm_unbind.c
index 4e5914a9..f98d0931 100644
--- a/src/tools/irm/irm_unbind.c
+++ b/src/tools/irm/irm_unbind.c
@@ -78,8 +78,8 @@ static int do_cmd(const char * argv0,
const struct cmd * c;
for (c = cmds; c->cmd; ++c)
- if (!matches(argv0, c->cmd))
- return c->func(argc, argv);
+ if (matches(argv0, c->cmd) == 0)
+ return c->func(argc - 1, argv + 1);
fprintf(stderr, "\"%s\" is unknown, try \"irm unbind help\".\n", argv0);
diff --git a/src/tools/irm/irm_unbind_ipcp.c b/src/tools/irm/irm_unbind_ipcp.c
index 23e25057..5d78603d 100644
--- a/src/tools/irm/irm_unbind_ipcp.c
+++ b/src/tools/irm/irm_unbind_ipcp.c
@@ -63,15 +63,20 @@ int do_unbind_ipcp(int argc,
ssize_t len;
ssize_t i;
+ if (argc < 1) {
+ usage();
+ return -1;
+ }
+
+ ipcp = *argv;
+ ++argv;
+ --argc;
+
while (argc > 0) {
if (matches(*argv, "name") == 0) {
name = *(argv + 1);
++argv;
--argc;
- } else if (matches(*argv, "ipcp") == 0) {
- ipcp = *(argv + 1);
- ++argv;
- --argc;
} else {
printf("\"%s\" is unknown, try \"irm "
"unbind ipcp\".\n", *argv);
diff --git a/src/tools/irm/irm_unbind_process.c b/src/tools/irm/irm_unbind_process.c
index bc7e545c..dfa91f4b 100644
--- a/src/tools/irm/irm_unbind_process.c
+++ b/src/tools/irm/irm_unbind_process.c
@@ -58,15 +58,20 @@ int do_unbind_process(int argc,
pid_t pid = -1;
char * name = NULL;
+ if (argc < 1) {
+ usage();
+ return -1;
+ }
+
+ pid = strtol(*argv, NULL, 10);
+ ++argv;
+ --argc;
+
while (argc > 1) {
if (matches(*argv, "name") == 0) {
name = *(argv + 1);
++argv;
--argc;
- } else if (matches(*argv, "process") == 0) {
- pid = strtol(*(argv + 1), NULL, 10);
- ++argv;
- --argc;
} else {
printf("\"%s\" is unknown, try \"irm "
"unbind process\".\n", *argv);
diff --git a/src/tools/irm/irm_unbind_program.c b/src/tools/irm/irm_unbind_program.c
index 031b9909..4ee8ce24 100644
--- a/src/tools/irm/irm_unbind_program.c
+++ b/src/tools/irm/irm_unbind_program.c
@@ -57,15 +57,25 @@ int do_unbind_program(int argc,
char * name = NULL;
char * prog = NULL;
+ if (argc < 1) {
+ usage();
+ return -1;
+ }
+
+ prog = *argv;
+ ++argv;
+ --argc;
+
while (argc > 0) {
+ if (argc < 2) {
+ usage();
+ return -1;
+ }
+
if (matches(*argv, "name") == 0) {
name = *(argv + 1);
++argv;
--argc;
- } else if (matches(*argv, "program") == 0) {
- prog = *(argv + 1);
- ++argv;
- --argc;
} else {
printf("\"%s\" is unknown, try \"irm "
"unbind program\".\n", *argv);
diff --git a/src/tools/irm/irm_utils.c b/src/tools/irm/irm_utils.c
index 69873097..c43accec 100644
--- a/src/tools/irm/irm_utils.c
+++ b/src/tools/irm/irm_utils.c
@@ -77,10 +77,21 @@
*/
-#include <string.h>
+#if defined(__linux__) || defined(__CYGWIN__)
+#define _DEFAULT_SOURCE
+#else
+#define _POSIX_C_SOURCE 200809L
+#endif
+
+#include <ouroboros/ipcp.h>
#include "irm_utils.h"
+#include <arpa/inet.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
int matches(const char * cmd,
const char * pattern)
{
@@ -123,3 +134,223 @@ int wildcard_match(const char * pattern,
}
}
}
+
+/* Splits "<addr>[:<port>]"; bare IPv6 needs no brackets. */
+static int parse_udp_str(const char * str,
+ char * host,
+ int * port)
+{
+ struct in6_addr v6;
+ char buf[POA_HOST_STRLEN + 1];
+ char * p;
+ char * end;
+ long n;
+
+ *port = POA_UDP_PORT;
+
+ if (strlen(str) > POA_HOST_STRLEN)
+ goto fail;
+
+ strcpy(buf, str);
+
+ if (buf[0] == '[') {
+ p = strchr(buf, ']');
+ if (p == NULL)
+ goto fail;
+
+ *p++ = '\0';
+
+ strcpy(host, buf + 1);
+
+ if (*p == '\0')
+ return 0;
+
+ if (*p != ':')
+ goto fail;
+
+ ++p;
+ } else if (inet_pton(AF_INET6, buf, &v6) == 1) {
+ strcpy(host, buf);
+ return 0;
+ } else {
+ p = strrchr(buf, ':');
+ if (p == NULL) {
+ strcpy(host, buf);
+ return 0;
+ }
+
+ *p++ = '\0';
+
+ strcpy(host, buf);
+ }
+
+ n = strtol(p, &end, 10);
+ if (*p == '\0' || *end != '\0' || n < 1 || n > 65535)
+ goto fail;
+
+ *port = (int) n;
+
+ return 0;
+ fail:
+ printf("Invalid UDP address: \"%s\".\n", str);
+ return -1;
+}
+
+/* An unresolved name is left for the IRMd, which picks the family. */
+int poa_addr_set_udp(struct poa_addr * addr,
+ const char * str)
+{
+ char host[POA_HOST_STRLEN + 1];
+ int port;
+
+ if (parse_udp_str(str, host, &port) < 0)
+ return -1;
+
+ if (inet_pton(AF_INET, host, &addr->udp4.ip_addr) == 1) {
+ addr->type = POA_UDP4;
+ addr->udp4.port = port;
+ return 0;
+ }
+
+ if (inet_pton(AF_INET6, host, &addr->udp6.ip_addr) == 1) {
+ addr->type = POA_UDP6;
+ addr->udp6.port = port;
+ return 0;
+ }
+
+ addr->type = POA_UDP;
+ addr->udp4.port = port;
+
+ strcpy(addr->hostname, host);
+
+ return 0;
+}
+
+/*
+ * Parses a hex ethertype; rejects garbage and out-of-range values.
+ * Overflow clamps to LONG_MAX and lands in the range check.
+ */
+int parse_ethertype(const char * str,
+ uint16_t * ethertype)
+{
+ char * end;
+ long val;
+
+ val = strtol(str, &end, 16);
+
+ if (end == str || *end != '\0')
+ return -1;
+
+ if (val < 0 || val > 0xFFFF)
+ return -1;
+
+ *ethertype = (uint16_t) val;
+
+ return 0;
+}
+
+int poa_addr_set_eth(struct poa_addr * addr,
+ const char * devstr,
+ uint16_t ethertype)
+{
+ addr->type = POA_ETH;
+
+ addr->eth.src.ethertype = ethertype;
+ addr->eth.dst.ethertype = ethertype;
+
+ if (devstr != NULL) {
+ if (strlen(devstr) > DEV_NAME_SIZE) {
+ printf("Invalid device name: \"%s\".\n", devstr);
+ return -1;
+ }
+
+ strcpy(addr->eth.src.dev, devstr);
+ }
+
+ return 0;
+}
+
+/* Matches src/ipcpd/ipcp.c; keep in sync. */
+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)");
+}
+
+int poa_spec_set(struct poa_spec * poa,
+ const char * udpstr,
+ const char * devstr,
+ uint16_t ethertype)
+{
+ char host[POA_HOST_STRLEN + 1];
+ int port;
+
+ memset(poa, 0, sizeof(*poa));
+
+ if ((udpstr != NULL) + (devstr != NULL) > 1) {
+ printf("A PoA is an address or a device.\n");
+ return -1;
+ }
+
+ if (udpstr != NULL) {
+ if (parse_udp_str(udpstr, host, &port) < 0)
+ return -1;
+
+ if (inet_pton(AF_INET, host, &poa->udp4.ip_addr) == 1) {
+ poa->type = POA_UDP4;
+ poa->udp4.port = port;
+ return 0;
+ }
+
+ if (inet_pton(AF_INET6, host, &poa->udp6.ip_addr) == 1) {
+ poa->type = POA_UDP6;
+ poa->udp6.port = port;
+ return 0;
+ }
+
+ printf("Invalid IP address: \"%s\".\n", udpstr);
+ return -1;
+ }
+
+ if (devstr != NULL) {
+ if (strlen(devstr) > DEV_NAME_SIZE) {
+ printf("Invalid device name: \"%s\".\n", devstr);
+ return -1;
+ }
+
+ poa->type = POA_ETH;
+ poa->eth.ethertype = ethertype;
+
+ strcpy(poa->eth.dev, devstr);
+
+ return 0;
+ }
+
+ return -1;
+}
diff --git a/src/tools/irm/irm_utils.h b/src/tools/irm/irm_utils.h
index c6d4bf18..3760b4e4 100644
--- a/src/tools/irm/irm_utils.h
+++ b/src/tools/irm/irm_utils.h
@@ -79,10 +79,43 @@
#ifndef OUROBOROS_TOOLS_IRM_UTILS_H
#define OUROBOROS_TOOLS_IRM_UTILS_H
-int matches(const char * cmd,
- const char * pattern);
+#include <ouroboros/ipcp.h>
-int wildcard_match(const char * pattern,
- const char * string);
+#include <arpa/inet.h>
+
+#include <stdint.h>
+
+int matches(const char * cmd,
+ const char * pattern);
+
+int wildcard_match(const char * pattern,
+ const char * string);
+
+/* Fill one PoA to attach or detach: an address or a device. */
+int poa_spec_set(struct poa_spec * poa,
+ const char * udpstr,
+ const char * devstr,
+ uint16_t ethertype);
+
+/* Fill a peer PoA address; a host name is resolved by the IRMd. */
+int poa_addr_set_udp(struct poa_addr * addr,
+ const char * str);
+
+/* Fits "eth <dev> 0x<type>", the longest PoA rendering. */
+/* Matches src/ipcpd/ipcp.c; keep in sync. */
+#define POA_STRLEN (DEV_NAME_SIZE + 11)
+
+/* Names a PoA the way the IPCP logs it. */
+void poa_spec_str(const struct poa_spec * poa,
+ char * buf,
+ size_t len);
+
+int poa_addr_set_eth(struct poa_addr * addr,
+ const char * devstr,
+ uint16_t ethertype);
+
+/* Parses a hex ethertype; rejects garbage and out-of-range values. */
+int parse_ethertype(const char * str,
+ uint16_t * ethertype);
#endif /* OUROBOROS_TOOLS_IRM_UTILS_H */
diff --git a/src/tools/ocbr/ocbr_client.c b/src/tools/ocbr/ocbr_client.c
index 36c07d43..60d4a0fc 100644
--- a/src/tools/ocbr/ocbr_client.c
+++ b/src/tools/ocbr/ocbr_client.c
@@ -88,10 +88,12 @@ int client_main(char * server,
struct timespec start;
struct timespec end;
struct timespec intv = {(gap / BILLION), gap % BILLION};
- int ms;
- const char * qenv;
- qosspec_t qs;
- qosspec_t * qsp;
+ int ms;
+ ssize_t rc;
+ int werr = 0;
+ const char * qenv;
+ qosspec_t qs;
+ qosspec_t * qsp;
qsp = NULL;
@@ -147,7 +149,9 @@ int client_main(char * server,
ts_add(&end, &intv, &end);
memcpy(buf, &seqnr, sizeof(seqnr));
- if (flow_write(fd, buf, size) < 0) {
+ rc = flow_write(fd, buf, size);
+ if (rc < 0) {
+ werr = (int) rc;
stop = true;
continue;
}
@@ -165,7 +169,10 @@ int client_main(char * server,
} else { /* flood */
while (!stop) {
clock_gettime(CLOCK_REALTIME, &end);
- if (flow_write(fd, buf, size) < 0) {
+
+ rc = flow_write(fd, buf, size);
+ if (rc < 0) {
+ werr = (int) rc;
stop = true;
continue;
}
@@ -183,6 +190,10 @@ int client_main(char * server,
ms = ts_diff_ms(&end, &start);
+ /* Codes at or above 1000 are ouroboros errno.h values. */
+ if (werr != 0)
+ printf("Send ended on write error %d.\n", werr);
+
printf("sent statistics: "
"%9ld packets, %12ld bytes in %9d ms, %4.4f Mb/s\n",
seqnr, seqnr * size, ms, (seqnr / (ms * 1000.0)) * size * 8.0);
diff --git a/src/tools/oftp/oftp.c b/src/tools/oftp/oftp.c
index 2504393a..b66ef650 100644
--- a/src/tools/oftp/oftp.c
+++ b/src/tools/oftp/oftp.c
@@ -35,7 +35,12 @@
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+#if defined(__APPLE__)
+/* macOS hides O_NOFOLLOW behind the BSD feature set. */
+#define _DARWIN_C_SOURCE
+#else
#define _POSIX_C_SOURCE 200809L
+#endif
#include <ouroboros/crc64.h>
#include <ouroboros/dev.h>
diff --git a/src/tools/oping/oping_client.c b/src/tools/oping/oping_client.c
index 4b01315d..b60c73cb 100644
--- a/src/tools/oping/oping_client.c
+++ b/src/tools/oping/oping_client.c
@@ -193,8 +193,6 @@ void * writer(void * o)
pthread_cleanup_push(free, buf);
while (!stop && client.sent < client.count) {
- nanosleep(&wait, NULL);
-
clock_gettime(CLOCK_MONOTONIC, &now);
msg->type = htonl(ECHO_REQUEST);
@@ -206,6 +204,8 @@ void * writer(void * o)
printf("Failed to send packet.\n");
stop = true;
}
+
+ nanosleep(&wait, NULL);
}
pthread_cleanup_pop(true);