summaryrefslogtreecommitdiff
path: root/src/irmd
diff options
context:
space:
mode:
Diffstat (limited to 'src/irmd')
-rw-r--r--src/irmd/config.h.in6
-rw-r--r--src/irmd/configfile.c553
-rw-r--r--src/irmd/ipcp.c129
-rw-r--r--src/irmd/ipcp.h71
-rw-r--r--src/irmd/irmd.h53
-rw-r--r--src/irmd/main.c610
-rw-r--r--src/irmd/oap.h29
-rw-r--r--src/irmd/oap/cli.c38
-rw-r--r--src/irmd/oap/tests/common.c19
-rw-r--r--src/irmd/reg/flow.c3
-rw-r--r--src/irmd/reg/flow.h2
-rw-r--r--src/irmd/reg/name.c1
-rw-r--r--src/irmd/reg/reg.c73
-rw-r--r--src/irmd/reg/reg.h251
-rw-r--r--src/irmd/reg/tests/reg_test.c2
15 files changed, 1423 insertions, 417 deletions
diff --git a/src/irmd/config.h.in b/src/irmd/config.h.in
index 53f80ca4..2440e180 100644
--- a/src/irmd/config.h.in
+++ b/src/irmd/config.h.in
@@ -21,10 +21,6 @@
*/
-#define IPCP_UDP4_EXEC "@IPCP_UDP4_TARGET@"
-#define IPCP_UDP6_EXEC "@IPCP_UDP6_TARGET@"
-#define IPCP_ETH_LLC_EXEC "@IPCP_ETH_LLC_TARGET@"
-#define IPCP_ETH_DIX_EXEC "@IPCP_ETH_DIX_TARGET@"
#define IPCP_UNICAST_EXEC "@IPCP_UNICAST_TARGET@"
#define IPCP_BROADCAST_EXEC "@IPCP_BROADCAST_TARGET@"
#define IPCP_LOCAL_EXEC "@IPCP_LOCAL_TARGET@"
@@ -75,6 +71,8 @@
#define OUROBOROS_CLI_CRT_DIR "@OUROBOROS_CLI_CRT_DIR@"
#define OUROBOROS_CHAIN_DIR "@OUROBOROS_UNTRUSTED_DIR@"
+/* Endpoint peers are keyed on their address, not on a service name. */
+
#define IRMD_PKILL_TIMEOUT @IRMD_PKILL_TIMEOUT@
#cmakedefine DISABLE_DIRECT_IPC
diff --git a/src/irmd/configfile.c b/src/irmd/configfile.c
index e2e1e554..de02242f 100644
--- a/src/irmd/configfile.c
+++ b/src/irmd/configfile.c
@@ -43,6 +43,7 @@
#include <assert.h>
#include <errno.h>
#include <inttypes.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <toml.h>
@@ -92,171 +93,173 @@ static int toml_local(toml_table_t * table,
return toml_hash(table, &conf->layer_info);
}
-static int toml_eth_dev(toml_table_t * table,
- struct eth_config * conf)
-{
- toml_datum_t dev;
- dev = toml_string_in(table, "dev");
- if (!dev.ok) {
- log_err("Missing device.");
- return -1;
- }
+/* Defined with the peer helpers below; shared grammar for both paths. */
+static int toml_udp_str(const char * str,
+ char * host,
+ int * port);
- if (strlen(dev.u.s) > DEV_NAME_SIZE) {
- log_err("Device name too long: %s", dev.u.s);
- free(dev.u.s);
+/* Attach the PoAs an IPCP is given; one call per PoA. */
+static int poa_eth_set(struct poa_spec * poa,
+ const char * dev,
+ uint16_t ethertype)
+{
+ if (strlen(dev) > DEV_NAME_SIZE) {
+ log_err("Invalid device name %s.", dev);
return -1;
}
- strcpy(conf->dev, dev.u.s);
- free(dev.u.s);
+ memset(poa, 0, sizeof(*poa));
+
+ poa->type = POA_ETH;
+ poa->eth.ethertype = ethertype;
+
+ strcpy(poa->eth.dev, dev);
return 0;
}
-static int toml_eth_llc(toml_table_t * table,
- struct ipcp_config * conf)
+static int toml_poa_eth(toml_table_t * tbl,
+ struct poa_spec * poa)
{
- *conf = eth_llc_default_conf;
-
- if (toml_hash(table, &conf->layer_info) < 0)
- return -1;
-
- return toml_eth_dev(table, &conf->eth);
-}
+ toml_datum_t dev;
+ toml_datum_t et;
+ uint16_t ethertype = POA_ETHERTYPE;
+ int ret = -1;
+ dev = toml_string_in(tbl, "dev");
+ if (!dev.ok) {
+ log_err("An eth PoA needs a device.");
+ goto fail;
+ }
-static int toml_ethertype(toml_table_t * table,
- struct eth_config * conf)
-{
- toml_datum_t ethertype;
+ et = toml_int_in(tbl, "ethertype");
+ if (et.ok) {
+ if (et.u.i < 0 || et.u.i > 0xFFFF) {
+ log_err("Invalid ethertype.");
+ goto fail;
+ }
- ethertype = toml_int_in(table, "ethertype");
- if (ethertype.ok)
- conf->ethertype = ethertype.u.i;
+ ethertype = et.u.i;
+ }
- if (conf->ethertype < 0x0600 || conf->ethertype == 0xFFFF)
- return -1;
+ ret = poa_eth_set(poa, dev.u.s, ethertype);
+ fail:
+ if (dev.ok)
+ free(dev.u.s);
- return 0;
+ return ret;
}
-static int toml_eth_dix(toml_table_t * table,
- struct ipcp_config * conf)
+/* A PoA is bound locally: only literal addresses are accepted here. */
+static int toml_poa_udp(const char * str,
+ struct poa_spec * poa)
{
- *conf = eth_dix_default_conf;
+ char host[POA_HOST_STRLEN + 1];
+ int port;
- if (toml_hash(table, &conf->layer_info) < 0)
+ if (toml_udp_str(str, host, &port) < 0)
return -1;
- if (toml_eth_dev(table, &conf->eth) < 0)
- return -1;
+ memset(poa, 0, sizeof(*poa));
- if (toml_ethertype(table, &conf->eth) < 0) {
- log_err("Ethertype not in valid range.");
- return -1;
+ if (inet_pton(AF_INET, host, &poa->udp4.ip_addr.s_addr) == 1) {
+ poa->type = POA_UDP4;
+ poa->udp4.port = port;
+ return 0;
}
- return 0;
-}
-
-static int toml_udp4(toml_table_t * table,
- struct ipcp_config * conf)
-{
- struct udp4_config * udp4;
- toml_datum_t ip;
- toml_datum_t port;
- toml_datum_t dns;
-
- *conf = udp4_default_conf;
- udp4 = &conf->udp4;
-
- ip = toml_string_in(table, "ip");
- if (!ip.ok) {
- log_err("No IP address specified!");
- goto fail_ip;
+ if (inet_pton(AF_INET6, host, &poa->udp6.ip_addr) == 1) {
+ poa->type = POA_UDP6;
+ poa->udp6.port = port;
+ return 0;
}
- if (inet_pton (AF_INET, ip.u.s, &udp4->ip_addr.s_addr) != 1) {
- log_err("Failed to parse IPv4 address %s.", ip.u.s);
- goto fail_addr;
- }
+ log_err("Invalid IP address %s.", host);
- port = toml_int_in(table, "port");
- if (port.ok)
- udp4->port = port.u.i;
+ return -1;
+}
- dns = toml_string_in(table, "dns");
- if (dns.ok) {
- if (inet_pton(AF_INET, dns.u.s, &udp4->dns_addr.s_addr) < 0) {
- log_err("Failed to parse DNS address %s.", ip.u.s);
- goto fail_dns;
+/* Attaches every PoA in the "udp" or "eth" array; string or table. */
+static int toml_poa_array(toml_table_t * table,
+ pid_t pid,
+ const char * key)
+{
+ struct poa_spec poa;
+ toml_array_t * arr;
+ int n;
+ int i;
+ bool is_eth;
+
+ arr = toml_array_in(table, key);
+ if (arr == NULL) {
+ /* A table here would otherwise attach nothing, silently. */
+ if (toml_table_in(table, key) != NULL) {
+ log_err("A %s PoA is an array: %s = [...] "
+ "or [[%s]].", key, key, key);
+ return -1;
}
- free(dns.u.s);
+ return 0;
}
- free(ip.u.s);
+ is_eth = strcmp(key, "eth") == 0;
- return 0;
+ n = toml_array_nelem(arr);
- fail_dns:
- free(dns.u.s);
- fail_addr:
- free(ip.u.s);
- fail_ip:
- return -1;
-}
+ for (i = 0; i < n; i++) {
+ toml_datum_t s;
+ int ret;
-static int toml_udp6(toml_table_t * table,
- struct ipcp_config * conf)
-{
- struct in6_addr ip6;
- struct in6_addr dns6;
- toml_datum_t ip;
- toml_datum_t port;
- toml_datum_t dns;
-
- *conf = udp6_default_conf;
- ip6 = conf->udp6.ip_addr;
- dns6 = conf->udp6.dns_addr;
-
- ip = toml_string_in(table, "ip");
- if (!ip.ok) {
- log_err("No IP address specified!");
- goto fail_ip;
- }
+ s = toml_string_at(arr, i);
+ if (s.ok) {
+ if (is_eth)
+ ret = poa_eth_set(&poa, s.u.s,
+ POA_ETHERTYPE);
+ else
+ ret = toml_poa_udp(s.u.s, &poa);
- if (inet_pton (AF_INET6, ip.u.s, &ip6.s6_addr) != 1) {
- log_err("Failed to parse IPv4 address %s.", ip.u.s);
- goto fail_addr;
- }
+ free(s.u.s);
+ } else {
+ toml_table_t * d = toml_table_at(arr, i);
- port = toml_int_in(table, "port");
- if (port.ok)
- conf->udp6.port = port.u.i;
+ if (d == NULL) {
+ log_err("Invalid %s PoA entry.", key);
+ return -1;
+ }
+
+ if (is_eth) {
+ ret = toml_poa_eth(d, &poa);
+ } else {
+ toml_datum_t addr = toml_string_in(d, "addr");
+
+ if (!addr.ok) {
+ log_err("No addr for udp PoA.");
+ return -1;
+ }
- dns = toml_string_in(table, "dns");
- if (dns.ok) {
- if (inet_pton(AF_INET6, dns.u.s, &dns6.s6_addr) < 0) {
- log_err("Failed to parse DNS address %s.", ip.u.s);
- goto fail_dns;
+ ret = toml_poa_udp(addr.u.s, &poa);
+ free(addr.u.s);
+ }
}
- free(dns.u.s);
- }
+ if (ret < 0)
+ return -1;
- free(ip.u.s);
+ if (attach_ipcp(pid, &poa, true) < 0)
+ return -1;
+ }
return 0;
+}
- fail_dns:
- free(dns.u.s);
- fail_addr:
- free(ip.u.s);
- fail_ip:
- return -1;
+static int toml_attach(toml_table_t * table,
+ pid_t pid)
+{
+ if (toml_poa_array(table, pid, "udp") < 0)
+ return -1;
+
+ return toml_poa_array(table, pid, "eth");
}
static int toml_broadcast(toml_table_t * table,
@@ -265,15 +268,13 @@ static int toml_broadcast(toml_table_t * table,
(void) table;
(void) conf;
- /* Nothing to do here. */
-
return 0;
}
#define BETWEEN(a, b, c) ((a) >= (b) && (a) <= (c))
#define DHT(conf, x) (conf)->dht.params.x
static int toml_dir(toml_table_t * table,
- struct dir_config * conf)
+ struct dir_config * conf)
{
toml_datum_t dir;
toml_datum_t alpha;
@@ -594,6 +595,207 @@ static int toml_register(toml_table_t * table,
return ret;
}
+/* Fills in a peer's eth PoA; dst MAC stays zero, the resolve marker. */
+static int toml_peer_eth(toml_table_t * tbl,
+ struct poa_addr * addr)
+{
+ toml_datum_t dev;
+ toml_datum_t et;
+ int ret = -1;
+
+ dev = toml_string_in(tbl, "dev");
+
+ memset(addr, 0, sizeof(*addr));
+
+ addr->type = POA_ETH;
+ addr->eth.src.ethertype = POA_ETHERTYPE;
+ addr->eth.dst.ethertype = POA_ETHERTYPE;
+
+ et = toml_int_in(tbl, "ethertype");
+ if (et.ok) {
+ if (et.u.i < 0 || et.u.i > 0xFFFF) {
+ log_err("Invalid ethertype.");
+ goto fail;
+ }
+
+ addr->eth.src.ethertype = et.u.i;
+ addr->eth.dst.ethertype = et.u.i;
+ }
+
+ if (dev.ok) {
+ if (strlen(dev.u.s) > DEV_NAME_SIZE) {
+ log_err("Invalid device name %s.", dev.u.s);
+ goto fail;
+ }
+
+ strcpy(addr->eth.src.dev, dev.u.s);
+ }
+
+ ret = 0;
+ fail:
+ if (dev.ok)
+ free(dev.u.s);
+
+ return ret;
+}
+
+/* Same grammar as the CLI's udp keyword; see irm_utils.c parse_udp_str. */
+static int toml_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:
+ log_err("Invalid UDP address: %s.", str);
+ return -1;
+}
+
+/* Fills in a peer's udp PoA; an unresolved name is left for the IRMd. */
+static int toml_peer_udp(const char * str,
+ struct poa_addr * addr)
+{
+ char host[POA_HOST_STRLEN + 1];
+ int port;
+
+ if (toml_udp_str(str, host, &port) < 0)
+ return -1;
+
+ memset(addr, 0, sizeof(*addr));
+
+ 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;
+}
+
+/*
+ * An entry is a name, or a table naming a PoA to reach it over.
+ * On entry, *paddr already points at the caller's struct poa_addr to
+ * fill in. Set to NULL wherever there is no PoA to dial: a bare
+ * dst-only table (recursive lookup) or any parse failure.
+ */
+static int toml_peer(toml_table_t * tbl,
+ char * dst,
+ struct poa_addr ** paddr)
+{
+ struct poa_addr * addr = *paddr;
+ toml_table_t * eth;
+ toml_datum_t name;
+ toml_datum_t udp;
+ int ret = -1;
+
+ name = toml_string_in(tbl, "dst");
+ if (!name.ok) {
+ log_err("PoA table entry has no dst.");
+
+ *paddr = NULL;
+ return -1;
+ }
+
+ if (strlen(name.u.s) > LAYER_NAME_SIZE) {
+ log_err("Destination name too long: %s.", name.u.s);
+ free(name.u.s);
+
+ *paddr = NULL;
+ return -1;
+ }
+
+ strcpy(dst, name.u.s);
+ free(name.u.s);
+
+ eth = toml_table_in(tbl, "eth");
+ udp = toml_string_in(tbl, "udp");
+ if (eth != NULL && udp.ok) {
+ log_err("A PoA is eth or udp, not both.");
+
+ *paddr = NULL;
+ goto fail;
+ }
+
+ if (eth == NULL && !udp.ok) {
+ *paddr = NULL;
+ ret = 0;
+ goto fail;
+ }
+
+ if (eth != NULL)
+ ret = toml_peer_eth(eth, addr);
+ else
+ ret = toml_peer_udp(udp.u.s, addr);
+
+ if (ret < 0)
+ *paddr = NULL;
+ fail:
+ if (udp.ok)
+ free(udp.u.s);
+
+ return ret;
+}
+
static int toml_connect(toml_table_t * table,
pid_t pid)
{
@@ -605,21 +807,40 @@ static int toml_connect(toml_table_t * table,
if (conn == NULL)
return 0;
- for (i=0; ret == 0; i++) {
- toml_datum_t dst;
- qosspec_t qs = qos_raw;
+ for (i = 0; ret == 0; i++) {
+ toml_datum_t dst;
+ toml_table_t * tbl;
+ struct poa_addr addr;
+ struct poa_addr * paddr = &addr;
+ char buf[LAYER_NAME_SIZE + 1];
+ const char * d;
+ qosspec_t qs = qos_raw;
dst = toml_string_at(conn, i);
- if (!dst.ok)
- break;
+ if (dst.ok) {
+ d = dst.u.s;
+ paddr = NULL;
+ } else {
+ tbl = toml_table_at(conn, i);
+ if (tbl == NULL)
+ break;
+
+ ret = toml_peer(tbl, buf, &paddr);
+ if (ret < 0)
+ break;
+
+ d = buf;
+ }
+
+ log_dbg("Connecting %d to %s", pid, d);
- log_dbg("Connecting %d to %s", pid, dst.u.s);
+ ret = connect_ipcp_resolve(pid, d, MGMT_COMP, qs, paddr);
- ret = connect_ipcp(pid, dst.u.s, MGMT_COMP, qs);
if (ret == 0)
- ret = connect_ipcp(pid, dst.u.s, DT_COMP, qs);
+ ret = connect_ipcp_resolve(pid, d, DT_COMP, qs, paddr);
- free(dst.u.s);
+ if (dst.ok)
+ free(dst.u.s);
}
return ret;
@@ -629,9 +850,11 @@ static int toml_ipcp(toml_table_t * table,
struct ipcp_info * info,
struct ipcp_config * conf)
{
- toml_datum_t bootstrap;
- toml_datum_t enrol;
- int ret;
+ toml_datum_t bootstrap;
+ toml_datum_t enrol;
+ toml_table_t * enrol_tbl;
+ bool have_enrol;
+ int ret;
log_dbg("Found IPCP %s in configuration file.", info->name);
@@ -643,21 +866,49 @@ static int toml_ipcp(toml_table_t * table,
bootstrap = toml_string_in(table, "bootstrap");
enrol = toml_string_in(table, "enrol");
- if (bootstrap.ok && enrol.ok) {
+ enrol_tbl = enrol.ok ? NULL : toml_table_in(table, "enrol");
+
+ have_enrol = enrol.ok || enrol_tbl != NULL;
+ if (bootstrap.ok && have_enrol) {
log_err("Ignoring bootstrap for IPCP %s.", info->name);
free(bootstrap.u.s);
bootstrap.ok = false;
}
- if (!bootstrap.ok && !enrol.ok) {
+ if (!bootstrap.ok && !have_enrol) {
log_dbg("Nothing more to do for %s.", info->name);
return 0;
}
- if (enrol.ok) {
+ /* Endpoints come first: enrolment reaches the peer over one. */
+ if (toml_attach(table, info->pid) < 0) {
+ log_err("Failed to attach PoAs for %s.", info->name);
+ return -1;
+ }
+
+ if (have_enrol) {
struct layer_info layer;
- ret = enroll_ipcp(info->pid, enrol.u.s);
- free(enrol.u.s);
+ struct poa_addr addr;
+ struct poa_addr * paddr = &addr;
+ char buf[LAYER_NAME_SIZE + 1];
+ const char * dst;
+
+ if (enrol.ok) {
+ dst = enrol.u.s;
+ paddr = NULL;
+ } else {
+ if (toml_peer(enrol_tbl, buf, &paddr) < 0) {
+ log_err("Invalid enrol table for %s.",
+ info->name);
+ return -1;
+ }
+ dst = buf;
+ }
+
+ ret = enroll_ipcp_resolve(info->pid, dst, paddr);
+
+ if (enrol.ok)
+ free(enrol.u.s);
if (ret < 0) {
log_err("Failed to enrol %s.", info->name);
return -1;
@@ -694,18 +945,6 @@ static int toml_ipcp(toml_table_t * table,
case IPCP_LOCAL:
ret = toml_local(table, conf);
break;
- case IPCP_ETH_DIX:
- ret = toml_eth_dix(table, conf);
- break;
- case IPCP_ETH_LLC:
- ret = toml_eth_llc(table, conf);
- break;
- case IPCP_UDP4:
- ret = toml_udp4(table, conf);
- break;
- case IPCP_UDP6:
- ret = toml_udp6(table, conf);
- break;
case IPCP_BROADCAST:
ret = toml_broadcast(table, conf);
break;
@@ -1031,14 +1270,6 @@ static int toml_toplevel(toml_table_t * table,
return toml_name_list(subtable);
else if (strcmp(key, "local") == 0)
return toml_ipcp_list(subtable, IPCP_LOCAL);
- else if (strcmp(key, "eth-dix") == 0)
- return toml_ipcp_list(subtable, IPCP_ETH_DIX);
- else if (strcmp(key, "eth-llc") == 0)
- return toml_ipcp_list(subtable, IPCP_ETH_LLC);
- else if (strcmp(key, "udp4") == 0)
- return toml_ipcp_list(subtable, IPCP_UDP4);
- else if (strcmp(key, "udp6") == 0)
- return toml_ipcp_list(subtable, IPCP_UDP6);
else if (strcmp(key, "broadcast") == 0)
return toml_ipcp_list(subtable, IPCP_BROADCAST);
else if (strcmp(key, "unicast") == 0)
diff --git a/src/irmd/ipcp.c b/src/irmd/ipcp.c
index 7eccfc80..cd662221 100644
--- a/src/irmd/ipcp.c
+++ b/src/irmd/ipcp.c
@@ -34,6 +34,7 @@
#include <ouroboros/utils.h>
#include "ipcp.h"
+#include "reg/reg.h"
#include <fcntl.h>
#include <pthread.h>
@@ -72,6 +73,10 @@ static char * str_ipcp_cmd(int code)
return "alloc_resp";
case IPCP_MSG_CODE__IPCP_FLOW_DEALLOC:
return "dealloc";
+ case IPCP_MSG_CODE__IPCP_FLOW_UPDATE:
+ return "flow_update";
+ case IPCP_MSG_CODE__IPCP_REPLY:
+ return "reply";
default:
assert(false);
return "unknown";
@@ -196,7 +201,9 @@ int ipcp_bootstrap(pid_t pid,
msg.conf = ipcp_config_s_to_msg(conf);
recv_msg = send_recv_ipcp_msg(pid, &msg);
+
ipcp_config_msg__free_unpacked(msg.conf, NULL);
+
if (recv_msg == NULL)
return -EIPCP;
@@ -225,9 +232,88 @@ int ipcp_bootstrap(pid_t pid,
return ret;
}
-int ipcp_enroll(pid_t pid,
- const char * dst,
- struct layer_info * info)
+ssize_t ipcp_list_poas(pid_t pid,
+ struct poa_spec ** eps)
+{
+ ipcp_msg_t msg = IPCP_MSG__INIT;
+ ipcp_msg_t * recv_msg;
+ size_t nr;
+ size_t i;
+
+ if (eps == NULL)
+ return -EINVAL;
+
+ *eps = NULL;
+
+ msg.code = IPCP_MSG_CODE__IPCP_LIST_POAS;
+
+ recv_msg = send_recv_ipcp_msg(pid, &msg);
+ if (recv_msg == NULL)
+ return -EIPCP;
+
+ nr = recv_msg->n_poas;
+ if (nr == 0) {
+ ipcp_msg__free_unpacked(recv_msg, NULL);
+ return 0;
+ }
+
+ *eps = malloc(nr * sizeof(**eps));
+ if (*eps == NULL) {
+ ipcp_msg__free_unpacked(recv_msg, NULL);
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < nr; i++)
+ (*eps)[i] = poa_spec_msg_to_s(recv_msg->poas[i]);
+
+ ipcp_msg__free_unpacked(recv_msg, NULL);
+
+ return (ssize_t) nr;
+}
+
+int ipcp_attach(pid_t pid,
+ const struct poa_spec * poa,
+ bool attach)
+{
+ ipcp_msg_t msg = IPCP_MSG__INIT;
+ ipcp_msg_t * recv_msg;
+ int ret;
+
+ if (poa == NULL)
+ return -EINVAL;
+
+ if (attach)
+ msg.code = IPCP_MSG_CODE__IPCP_ATTACH;
+ else
+ msg.code = IPCP_MSG_CODE__IPCP_DETACH;
+
+ msg.poa = poa_spec_s_to_msg(poa);
+ if (msg.poa == NULL)
+ return -EINVAL;
+
+ recv_msg = send_recv_ipcp_msg(pid, &msg);
+
+ poa_spec_msg__free_unpacked(msg.poa, NULL);
+
+ if (recv_msg == NULL)
+ return -EIPCP;
+
+ if (!recv_msg->has_result) {
+ ipcp_msg__free_unpacked(recv_msg, NULL);
+ return -EIPCP;
+ }
+
+ ret = recv_msg->result;
+
+ ipcp_msg__free_unpacked(recv_msg, NULL);
+
+ return ret;
+}
+
+int ipcp_enroll(pid_t pid,
+ const char * dst,
+ const struct poa_addr * addr,
+ struct layer_info * info)
{
ipcp_msg_t msg = IPCP_MSG__INIT;
ipcp_msg_t * recv_msg;
@@ -239,7 +325,16 @@ int ipcp_enroll(pid_t pid,
msg.code = IPCP_MSG_CODE__IPCP_ENROLL;
msg.dst = (char *) dst;
+ if (addr != NULL) {
+ msg.peer = poa_addr_s_to_msg(addr);
+ if (msg.peer == NULL)
+ return -ENOMEM;
+ }
+
recv_msg = send_recv_ipcp_msg(pid, &msg);
+
+ if (msg.peer != NULL)
+ poa_addr_msg__free_unpacked(msg.peer, NULL);
if (recv_msg == NULL)
return -EIPCP;
@@ -267,10 +362,11 @@ int ipcp_enroll(pid_t pid,
return 0;
}
-int ipcp_connect(pid_t pid,
- const char * dst,
- const char * component,
- qosspec_t qs)
+int ipcp_connect(pid_t pid,
+ const char * dst,
+ const char * component,
+ qosspec_t qs,
+ const struct poa_addr * addr)
{
ipcp_msg_t msg = IPCP_MSG__INIT;
ipcp_msg_t * recv_msg;
@@ -283,8 +379,21 @@ int ipcp_connect(pid_t pid,
msg.pid = pid;
msg.qosspec = qos_spec_s_to_msg(&qs);
+ if (addr != NULL) {
+ msg.peer = poa_addr_s_to_msg(addr);
+ if (msg.peer == NULL) {
+ free(msg.qosspec);
+ return -ENOMEM;
+ }
+ }
+
recv_msg = send_recv_ipcp_msg(pid, &msg);
+
+ if (msg.peer != NULL)
+ poa_addr_msg__free_unpacked(msg.peer, NULL);
+
free(msg.qosspec);
+
if (recv_msg == NULL)
return -EIPCP;
@@ -457,6 +566,8 @@ int ipcp_flow_update(const struct flow_info * flow,
msg.has_pk = true;
msg.pk.data = data.data;
msg.pk.len = data.len;
+ msg.has_is_poa = true;
+ msg.is_poa = reg_flow_is_poa(flow->id);
recv_msg = send_recv_ipcp_msg(flow->n_1_pid, &msg);
if (recv_msg == NULL) {
@@ -538,6 +649,8 @@ int ipcp_flow_alloc_resp(const struct flow_info * flow,
msg.has_pk = response == 0;
msg.pk.data = data.data;
msg.pk.len = data.len;
+ msg.has_is_poa = true;
+ msg.is_poa = reg_flow_is_poa(flow->id);
recv_msg = send_recv_ipcp_msg(flow->n_1_pid, &msg);
if (recv_msg == NULL)
@@ -567,6 +680,8 @@ int ipcp_flow_dealloc(pid_t pid,
msg.flow_id = flow_id;
msg.has_timeo_sec = true;
msg.timeo_sec = timeo;
+ msg.has_is_poa = true;
+ msg.is_poa = reg_flow_is_poa(flow_id);
recv_msg = send_recv_ipcp_msg(pid, &msg);
if (recv_msg == NULL)
diff --git a/src/irmd/ipcp.h b/src/irmd/ipcp.h
index 8d06623c..1f257e7d 100644
--- a/src/irmd/ipcp.h
+++ b/src/irmd/ipcp.h
@@ -27,48 +27,57 @@
#ifndef OUROBOROS_IRMD_IPCP_H
#define OUROBOROS_IRMD_IPCP_H
-int ipcp_enroll(pid_t pid,
- const char * dst,
- struct layer_info * info);
+int ipcp_enroll(pid_t pid,
+ const char * dst,
+ const struct poa_addr * addr,
+ struct layer_info * info);
-int ipcp_bootstrap(pid_t pid,
- struct ipcp_config * conf,
- struct layer_info * info);
+int ipcp_attach(pid_t pid,
+ const struct poa_spec * poa,
+ bool attach);
-int ipcp_connect(pid_t pid,
- const char * dst,
- const char * component,
- qosspec_t qs);
+ssize_t ipcp_list_poas(pid_t pid,
+ struct poa_spec ** eps);
-int ipcp_disconnect(pid_t pid,
- const char * dst,
- const char * component);
+int ipcp_bootstrap(pid_t pid,
+ struct ipcp_config * conf,
+ struct layer_info * info);
-int ipcp_reg(pid_t pid,
- const buffer_t hash);
+int ipcp_connect(pid_t pid,
+ const char * dst,
+ const char * component,
+ qosspec_t qs,
+ const struct poa_addr * addr);
-int ipcp_unreg(pid_t pid,
+int ipcp_disconnect(pid_t pid,
+ const char * dst,
+ const char * component);
+
+int ipcp_reg(pid_t pid,
const buffer_t hash);
-int ipcp_query(pid_t pid,
- const buffer_t dst);
+int ipcp_unreg(pid_t pid,
+ const buffer_t hash);
+
+int ipcp_query(pid_t pid,
+ const buffer_t dst);
-int ipcp_flow_alloc(const struct flow_info * flow,
- const buffer_t hash,
- const buffer_t data);
+int ipcp_flow_alloc(const struct flow_info * flow,
+ const buffer_t hash,
+ const buffer_t data);
-int ipcp_flow_join(const struct flow_info * flow,
- const buffer_t dst);
+int ipcp_flow_join(const struct flow_info * flow,
+ const buffer_t dst);
-int ipcp_flow_alloc_resp(const struct flow_info * flow,
- int response,
- const buffer_t data);
+int ipcp_flow_alloc_resp(const struct flow_info * flow,
+ int response,
+ const buffer_t data);
-int ipcp_flow_dealloc(pid_t pid,
- int flow_id,
- time_t timeo);
+int ipcp_flow_dealloc(pid_t pid,
+ int flow_id,
+ time_t timeo);
-int ipcp_flow_update(const struct flow_info * flow,
- const buffer_t data);
+int ipcp_flow_update(const struct flow_info * flow,
+ const buffer_t data);
#endif /* OUROBOROS_IRMD_IPCP_H */
diff --git a/src/irmd/irmd.h b/src/irmd/irmd.h
index f88378ad..9d42e248 100644
--- a/src/irmd/irmd.h
+++ b/src/irmd/irmd.h
@@ -26,29 +26,48 @@
#include <ouroboros/ipcp.h>
#include <ouroboros/irm.h>
-int create_ipcp(struct ipcp_info * info);
+int create_ipcp(struct ipcp_info * info);
-int bootstrap_ipcp(pid_t pid,
- struct ipcp_config * conf);
+int bootstrap_ipcp(pid_t pid,
+ struct ipcp_config * conf);
-int enroll_ipcp(pid_t pid,
- const char * dst);
+int enroll_ipcp(pid_t pid,
+ const char * dst,
+ const struct poa_addr * addr);
-int connect_ipcp(pid_t pid,
- const char * dst,
- const char * component,
- qosspec_t qs);
+int enroll_ipcp_resolve(pid_t pid,
+ const char * dst,
+ struct poa_addr * addr);
-int name_create(struct name_info * info);
+int attach_ipcp(pid_t pid,
+ const struct poa_spec * poa,
+ bool attach);
-int name_reg(const char * name,
- pid_t pid);
+ssize_t list_poas(pid_t pid,
+ struct poa_spec ** eps);
-int bind_process(pid_t pid,
- const char * name);
+int connect_ipcp(pid_t pid,
+ const char * dst,
+ const char * component,
+ qosspec_t qs,
+ const struct poa_addr * addr);
-int bind_program(char ** exec,
- const char * name,
- uint8_t flags);
+int connect_ipcp_resolve(pid_t pid,
+ const char * dst,
+ const char * component,
+ qosspec_t qs,
+ struct poa_addr * addr);
+
+int name_create(struct name_info * info);
+
+int name_reg(const char * name,
+ pid_t pid);
+
+int bind_process(pid_t pid,
+ const char * name);
+
+int bind_program(char ** exec,
+ const char * name,
+ uint8_t flags);
#endif /* OUROBOROS_IRMD_H*/
diff --git a/src/irmd/main.c b/src/irmd/main.c
index 19be4ab9..e587a552 100644
--- a/src/irmd/main.c
+++ b/src/irmd/main.c
@@ -61,6 +61,7 @@
#include <dirent.h>
#include <grp.h>
+#include <netdb.h>
#include <pwd.h>
#include <signal.h>
#include <spawn.h>
@@ -225,18 +226,6 @@ static pid_t spawn_ipcp(struct ipcp_info * info)
case IPCP_BROADCAST:
exec_name = IPCP_BROADCAST_EXEC;
break;
- case IPCP_UDP4:
- exec_name = IPCP_UDP4_EXEC;
- break;
- case IPCP_UDP6:
- exec_name = IPCP_UDP6_EXEC;
- break;
- case IPCP_ETH_LLC:
- exec_name = IPCP_ETH_LLC_EXEC;
- break;
- case IPCP_ETH_DIX:
- exec_name = IPCP_ETH_DIX_EXEC;
- break;
case IPCP_LOCAL:
exec_name = IPCP_LOCAL_EXEC;
break;
@@ -367,9 +356,6 @@ int bootstrap_ipcp(pid_t pid,
goto fail;
}
- if (conf->type == IPCP_UDP4 || conf->type == IPCP_UDP6)
- conf->layer_info.dir_hash_algo = (enum pol_dir_hash) HASH_MD5;
-
if (ipcp_bootstrap(pid, conf, &layer)) {
log_err("Could not bootstrap IPCP.");
goto fail;
@@ -389,8 +375,55 @@ int bootstrap_ipcp(pid_t pid,
return -1;
}
-int enroll_ipcp(pid_t pid,
- const char * dst)
+ssize_t list_poas(pid_t pid,
+ struct poa_spec ** eps)
+{
+ struct ipcp_info info;
+
+ info.pid = pid;
+ if (reg_get_ipcp(&info, NULL) < 0) {
+ log_err("Could not find IPCP %d.", pid);
+ return -1;
+ }
+
+ if (info.type != IPCP_UNICAST && info.type != IPCP_BROADCAST)
+ return 0; /* nothing it could be attached to */
+
+ return ipcp_list_poas(pid, eps);
+}
+
+/* Only the types that can carry a PoA may take one. */
+int attach_ipcp(pid_t pid,
+ const struct poa_spec * poa,
+ bool attach)
+{
+ struct ipcp_info info;
+
+ info.pid = pid;
+ if (reg_get_ipcp(&info, NULL) < 0) {
+ log_err("Could not find IPCP %d.", pid);
+ return -1;
+ }
+
+ if (info.type != IPCP_UNICAST && info.type != IPCP_BROADCAST) {
+ log_err("IPCP %d does not support PoAs.", pid);
+ return -1;
+ }
+
+ if (ipcp_attach(pid, poa, attach) < 0) {
+ log_err("Could not %s IPCP %d.",
+ attach ? "attach" : "detach", pid);
+ return -1;
+ }
+
+ log_info("%s IPCP %d.", attach ? "Attached" : "Detached", pid);
+
+ return 0;
+}
+
+int enroll_ipcp(pid_t pid,
+ const char * dst,
+ const struct poa_addr * addr)
{
struct layer_info layer;
struct ipcp_info info;
@@ -402,7 +435,7 @@ int enroll_ipcp(pid_t pid,
goto fail;
}
- if (ipcp_enroll(pid, dst, &layer) < 0) {
+ if (ipcp_enroll(pid, dst, addr, &layer) < 0) {
log_err("Could not enroll IPCP %d.", pid);
goto fail;
}
@@ -421,10 +454,11 @@ int enroll_ipcp(pid_t pid,
return -1;
}
-int connect_ipcp(pid_t pid,
- const char * dst,
- const char * component,
- qosspec_t qs)
+int connect_ipcp(pid_t pid,
+ const char * dst,
+ const char * component,
+ qosspec_t qs,
+ const struct poa_addr * addr)
{
struct ipcp_info info;
@@ -442,7 +476,7 @@ int connect_ipcp(pid_t pid,
log_dbg("Connecting %s to %s.", component, dst);
- if (ipcp_connect(pid, dst, component, qs)) {
+ if (ipcp_connect(pid, dst, component, qs, addr) < 0) {
log_err("Could not connect IPCP %d to %s.", pid, dst);
return -EPERM;
}
@@ -453,6 +487,172 @@ int connect_ipcp(pid_t pid,
return 0;
}
+/* Resolve the dial name, if any, and fill in one record. */
+static int poa_addr_resolve(struct poa_addr * addr,
+ struct addrinfo ** res)
+{
+ struct addrinfo hints;
+
+ *res = NULL;
+
+ if (addr == NULL)
+ return 0;
+
+ if (addr->hostname[0] == '\0')
+ return addr->type == POA_UDP ? -EINVAL : 0;
+
+ if (addr->type != POA_UDP)
+ return -EINVAL;
+
+ memset(&hints, 0, sizeof(hints));
+
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_DGRAM;
+ if (getaddrinfo(addr->hostname, NULL, &hints, res) != 0) {
+ log_err("Failed to resolve %s.", addr->hostname);
+ return -EADDRNOTAVAIL;
+ }
+
+ return 0;
+}
+
+static void poa_addr_from_ai(struct poa_addr * addr,
+ const struct addrinfo * ai,
+ uint16_t port)
+{
+ struct sockaddr_in * in;
+ struct sockaddr_in6 * in6;
+
+ if (ai->ai_family == AF_INET) {
+ in = (struct sockaddr_in *) ai->ai_addr;
+ addr->type = POA_UDP4;
+ addr->udp4.ip_addr = in->sin_addr;
+ addr->udp4.port = port;
+ } else {
+ in6 = (struct sockaddr_in6 *) ai->ai_addr;
+ addr->type = POA_UDP6;
+ addr->udp6.ip_addr = in6->sin6_addr;
+ addr->udp6.port = port;
+ }
+}
+
+/* Skip families without an attached PoA; keep all if none reported. */
+static void poa_families(pid_t pid,
+ bool * v4,
+ bool * v6)
+{
+ struct poa_spec * eps;
+ ssize_t n;
+ ssize_t i;
+
+ eps = NULL;
+
+ *v4 = false;
+ *v6 = false;
+
+ n = list_poas(pid, &eps);
+ for (i = 0; i < n; i++) {
+ if (eps[i].type == POA_UDP4)
+ *v4 = true;
+
+ if (eps[i].type == POA_UDP6)
+ *v6 = true;
+ }
+
+ free(eps);
+
+ if (!*v4 && !*v6) {
+ *v4 = true;
+ *v6 = true;
+ }
+}
+
+/* Try each resolved record in order until an enrolment succeeds. */
+int enroll_ipcp_resolve(pid_t pid,
+ const char * dst,
+ struct poa_addr * addr)
+{
+ struct addrinfo * res;
+ struct addrinfo * ai;
+ uint16_t port;
+ bool v4;
+ bool v6;
+ int ret;
+
+ ret = poa_addr_resolve(addr, &res);
+ if (ret < 0)
+ return ret;
+
+ if (res == NULL)
+ return enroll_ipcp(pid, dst, addr);
+
+ port = addr->udp4.port; /* POA_UDP parks it there */
+
+ poa_families(pid, &v4, &v6);
+
+ ret = -EADDRNOTAVAIL;
+
+ for (ai = res; ai != NULL; ai = ai->ai_next) {
+ if ((ai->ai_family == AF_INET && !v4)
+ || (ai->ai_family == AF_INET6 && !v6))
+ continue;
+
+ poa_addr_from_ai(addr, ai, port);
+
+ ret = enroll_ipcp(pid, dst, addr);
+ if (ret == 0)
+ break;
+ }
+
+ freeaddrinfo(res);
+
+ return ret;
+}
+
+/* Try each resolved record in order until a connect succeeds. */
+int connect_ipcp_resolve(pid_t pid,
+ const char * dst,
+ const char * component,
+ qosspec_t qs,
+ struct poa_addr * addr)
+{
+ struct addrinfo * res;
+ struct addrinfo * ai;
+ uint16_t port;
+ bool v4;
+ bool v6;
+ int ret;
+
+ ret = poa_addr_resolve(addr, &res);
+ if (ret < 0)
+ return ret;
+
+ if (res == NULL)
+ return connect_ipcp(pid, dst, component, qs, addr);
+
+ port = addr->udp4.port; /* POA_UDP parks it there */
+
+ poa_families(pid, &v4, &v6);
+
+ ret = -EADDRNOTAVAIL;
+
+ for (ai = res; ai != NULL; ai = ai->ai_next) {
+ if ((ai->ai_family == AF_INET && !v4)
+ || (ai->ai_family == AF_INET6 && !v6))
+ continue;
+
+ poa_addr_from_ai(addr, ai, port);
+
+ ret = connect_ipcp(pid, dst, component, qs, addr);
+ if (ret == 0)
+ break;
+ }
+
+ freeaddrinfo(res);
+
+ return ret;
+}
+
static int disconnect_ipcp(pid_t pid,
const char * dst,
const char * component)
@@ -882,6 +1082,22 @@ static void __cleanup_flow(void * flow)
reg_destroy_flow(((struct flow_info *) flow)->id);
}
+/*
+ * A PoA flow is secured as the IPCP that owns it: trust is in the
+ * peer itself. Without a security config for that name the flow
+ * stays in the clear.
+ */
+static void poa_name_info(const char * name,
+ struct name_info * info)
+{
+ if (reg_get_name_info(name, info) == 0)
+ return;
+
+ memset(info, 0, sizeof(*info));
+
+ strcpy(info->name, name);
+}
+
static int flow_accept(struct flow_info * flow,
buffer_t * data,
struct timespec * abstime,
@@ -942,7 +1158,9 @@ static int flow_accept(struct flow_info * flow,
goto fail_oap;
}
- if (reg_get_name_info(name, &info) < 0) {
+ if (reg_flow_is_poa(flow->id)) {
+ poa_name_info(name, &info);
+ } else if (reg_get_name_info(name, &info) < 0) {
log_err("Failed to get name info for %s.", name);
err = -ENAME;
goto fail_oap;
@@ -1262,7 +1480,7 @@ static int flow_alloc_direct(const char * dst,
return -EAGAIN;
}
- if (oap_cli_prepare(&ctx, info, &req_hdr, *data, false) < 0) {
+ if (oap_cli_prepare(&ctx, info, NULL, &req_hdr, *data, false) < 0) {
log_err("Failed to prepare OAP for %s.", dst);
return -EBADF;
}
@@ -1295,7 +1513,7 @@ static int flow_alloc_direct(const char * dst,
return -ETIMEDOUT;
}
- err = oap_cli_complete(ctx, info, resp_hdr, data, sk, NULL, NULL);
+ err = oap_cli_complete(ctx, resp_hdr, data, sk, NULL, NULL);
if (err < 0) {
log_err("OAP completion failed for %s.", dst);
freebuf(resp_hdr);
@@ -1378,7 +1596,7 @@ static int flow_alloc(const char * dst,
goto fail_prepare;
}
- if (oap_cli_prepare(&ctx, &info, &req_hdr, *data, false) < 0) {
+ if (oap_cli_prepare(&ctx, &info, NULL, &req_hdr, *data, false) < 0) {
log_err("Failed to prepare OAP request for %s.", dst);
err = -EBADF;
goto fail_prepare;
@@ -1410,7 +1628,7 @@ static int flow_alloc(const char * dst,
goto fail_peer;
}
- err = oap_cli_complete(ctx, &info, resp_hdr, data, sk, NULL, &peer_crt);
+ err = oap_cli_complete(ctx, resp_hdr, data, sk, NULL, &peer_crt);
if (err < 0) {
log_err("OAP completion failed for %s.", dst);
goto fail_complete;
@@ -1444,6 +1662,199 @@ static int flow_alloc(const char * dst,
return err;
}
+/* Creates the flow and prepares the key exchange the IPCP will carry. */
+/* The N-1 is only known once the flow exists. */
+static int poa_alloc(struct flow_info * flow,
+ const char * dst,
+ buffer_t * data)
+{
+ struct ipcp_info ipcp;
+ struct layer_info layer;
+ struct name_info info;
+ buffer_t req_hdr = BUF_INIT;
+ void * ctx;
+ int err;
+
+ ipcp.pid = flow->n_pid;
+ if (reg_get_ipcp(&ipcp, &layer) < 0) {
+ log_err("No IPCP with pid %d.", flow->n_pid);
+
+ err = -EIPCP;
+ goto fail_flow;
+ }
+
+ flow->n_1_pid = 0;
+ if (reg_create_flow(flow) < 0) {
+ log_err("Failed to create PoA flow.");
+
+ err = -EBADF;
+ goto fail_flow;
+ }
+
+ reg_set_name_for_flow_id(ipcp.name, flow->id);
+
+ if (reg_flow_set_poa(flow->id) < 0) {
+ err = -EBADF;
+ goto fail_prepare;
+ }
+
+ flow->uid = reg_get_proc_uid(flow->n_pid);
+ flow->n_1_pid = flow->n_pid; /* the IPCP is its own N-1 */
+ if (reg_prepare_flow_alloc(flow) < 0) {
+ log_err("Failed to prepare PoA flow allocation.");
+
+ err = -EBADF;
+ goto fail_prepare;
+ }
+
+ poa_name_info(ipcp.name, &info);
+
+ if (oap_cli_prepare(&ctx, &info, dst, &req_hdr, *data, false) < 0) {
+ log_err("Failed to prepare OAP request for %s.", ipcp.name);
+
+ err = -EBADF;
+ goto fail_prepare;
+ }
+
+ if (reg_flow_set_oap_ctx(flow->id, ctx) < 0) {
+ err = -EBADF;
+ goto fail_ctx;
+ }
+
+ log_info("Allocating PoA flow %d for %d as %s.",
+ flow->id, flow->n_pid, ipcp.name);
+
+ *data = req_hdr;
+
+ return 0;
+
+ fail_ctx:
+ freebuf(req_hdr);
+ oap_ctx_free(ctx);
+ fail_prepare:
+ reg_destroy_flow(flow->id);
+ fail_flow:
+ return err;
+}
+
+/* Completes the key exchange once the IPCP has the peer's response. */
+/*
+ * We present the PoA's own credentials and expect the peer to present
+ * dst's: the address only says how to reach it. oap_cli_complete
+ * frees the ctx on every path.
+ */
+static int poa_complete(struct flow_info * flow,
+ int response,
+ buffer_t * data,
+ struct crypt_sk * sk)
+{
+ struct name_info info;
+ buffer_t peer_crt = BUF_INIT;
+ buffer_t out = BUF_INIT;
+ buffer_t empty = BUF_INIT;
+ char name[NAME_SIZE + 1];
+ void * ctx;
+ int err;
+
+ ctx = reg_flow_take_oap_ctx(flow->id);
+ if (ctx == NULL) {
+ log_err("No pending PoA flow %d.", flow->id);
+ return -EBADF;
+ }
+
+ if (response < 0) {
+ log_dbg("PoA flow %d refused: %d.", flow->id, response);
+
+ err = response;
+ goto fail;
+ }
+
+ if (reg_get_name_for_flow_id(name, flow->id) < 0) {
+ err = -EBADF;
+ goto fail;
+ }
+
+ poa_name_info(name, &info);
+
+ err = oap_cli_complete(ctx, *data, &out, sk, NULL, &peer_crt);
+ if (err < 0) {
+ log_err("OAP completion failed for %s.", name);
+
+ ctx = NULL;
+ goto fail;
+ }
+
+ if (sk->nid != NID_undef)
+ reg_flow_set_rekey(flow->id, true, peer_crt);
+
+ flow->state = FLOW_ALLOCATED;
+ if (reg_respond_alloc(flow, &empty, 0) < 0) {
+ log_err("Failed to update PoA flow %d.", flow->id);
+
+ err = -EBADF;
+ goto fail_crt;
+ }
+
+ log_info("PoA flow %d allocated to %s.", flow->id, name);
+
+ freebuf(peer_crt);
+ freebuf(out);
+
+ return 0;
+
+ fail_crt:
+ freebuf(peer_crt);
+ freebuf(out);
+ fail:
+ oap_ctx_free(ctx);
+ reg_destroy_flow(flow->id);
+ return err;
+}
+
+/* A peer requested a flow on a PoA of this IPCP. */
+static int poa_req_arr(struct flow_info * flow,
+ buffer_t * data)
+{
+ struct ipcp_info ipcp;
+ struct layer_info layer;
+ int ret;
+
+ ipcp.pid = flow->n_1_pid;
+ if (reg_get_ipcp(&ipcp, &layer) < 0) {
+ log_err("No IPCP with pid %d.", flow->n_1_pid);
+
+ ret = -EIPCP;
+ goto fail;
+ }
+
+ log_info("PoA flow request arrived for %s.", ipcp.name);
+
+ ret = wait_for_accept(ipcp.name);
+ if (ret < 0) {
+ log_err("No active process for %s.", ipcp.name);
+ goto fail;
+ }
+
+ flow->id = ret;
+ flow->state = FLOW_ALLOCATED;
+ if (reg_flow_set_poa(flow->id) < 0) {
+ ret = -EBADF;
+ goto fail;
+ }
+
+ reg_set_name_for_flow_id(ipcp.name, flow->id);
+
+ ret = reg_respond_accept(flow, data);
+ if (ret < 0) {
+ log_err("Failed to respond to PoA flow %d.", flow->id);
+ goto fail;
+ }
+
+ return 0;
+ fail:
+ return ret;
+}
+
static int flow_alloc_reply(struct flow_info * flow,
int response,
buffer_t * data)
@@ -1596,6 +2007,11 @@ static int rekey_name_info(int flow_id,
if (reg_get_name_for_flow_id(name, flow_id) < 0)
return -1;
+ if (reg_flow_is_poa(flow_id)) {
+ poa_name_info(name, info);
+ return 0;
+ }
+
return reg_get_name_info(name, info);
}
@@ -1667,7 +2083,7 @@ static void rekey_do_initiate(struct list_head * tbl,
goto fail;
}
- if (oap_cli_prepare(&ctx, &name, &req, data, true) < 0) {
+ if (oap_cli_prepare(&ctx, &name, NULL, &req, data, true) < 0) {
log_err("Failed to prepare re-key for flow %d.", flow_id);
goto fail;
}
@@ -1758,7 +2174,7 @@ static void rekey_do_complete(struct list_head * tbl,
reg_flow_get_peer_crt(flow_id, &crt);
/* oap_cli_complete frees the ctx on every path. */
- if (oap_cli_complete(e->ctx, &info, buf, &data, &sk, &crt, NULL) < 0) {
+ if (oap_cli_complete(e->ctx, buf, &data, &sk, &crt, NULL) < 0) {
log_warn("Failed to complete re-key for flow %d.", flow_id);
e->ctx = NULL;
goto finish_clear;
@@ -1933,7 +2349,7 @@ static void rekey_do_direct(int flow_id)
return;
}
- if (oap_cli_prepare(&ctx, &info, &req, data, true) < 0) {
+ if (oap_cli_prepare(&ctx, &info, NULL, &req, data, true) < 0) {
log_err("Failed to prepare re-key for flow %d.", flow_id);
reg_flow_clear_in_flight(flow_id);
return;
@@ -2307,6 +2723,10 @@ static irm_msg_t * do_command_msg(irm_msg_t * msg,
pid_t cpid;
irm_msg_t * ret_msg;
buffer_t data;
+ struct poa_addr poa_addr;
+ struct poa_addr * pa;
+ struct poa_spec poa_spec;
+ struct poa_spec * eps = NULL;
memset(&flow, 0, sizeof(flow));
@@ -2350,11 +2770,74 @@ static irm_msg_t * do_command_msg(irm_msg_t * msg,
res = bootstrap_ipcp(msg->pid, &conf);
break;
case IRM_MSG_CODE__IRM_ENROLL_IPCP:
- res = enroll_ipcp(msg->pid, msg->dst);
+ if (msg->peer != NULL) {
+ poa_addr = poa_addr_msg_to_s(msg->peer);
+ if (poa_addr.type == POA_INVALID) {
+ res = -EINVAL;
+ break;
+ }
+ }
+
+ if (msg->conf != NULL)
+ conf = ipcp_config_msg_to_s(msg->conf);
+ res = enroll_ipcp_resolve(msg->pid, msg->dst,
+ msg->peer != NULL ? &poa_addr : NULL);
+ break;
+ case IRM_MSG_CODE__IRM_ATTACH_IPCP:
+ poa_spec = poa_spec_msg_to_s(msg->poa);
+ if (poa_spec.type == POA_INVALID) {
+ res = -EINVAL;
+ break;
+ }
+
+ res = attach_ipcp(msg->pid, &poa_spec, true);
+ break;
+ case IRM_MSG_CODE__IRM_DETACH_IPCP:
+ poa_spec = poa_spec_msg_to_s(msg->poa);
+ if (poa_spec.type == POA_INVALID) {
+ res = -EINVAL;
+ break;
+ }
+
+ res = attach_ipcp(msg->pid, &poa_spec, false);
+ break;
+ case IRM_MSG_CODE__IRM_LIST_POAS:
+ res = list_poas(msg->pid, &eps);
+ if (res > 0) {
+ ssize_t i;
+ ret_msg->poas = malloc(res * sizeof(*ret_msg->poas));
+ if (ret_msg->poas == NULL) {
+ free(eps);
+
+ res = -ENOMEM;
+ break;
+ }
+ for (i = 0; i < res; i++) {
+ ret_msg->poas[i] = poa_spec_s_to_msg(&eps[i]);
+ if (ret_msg->poas[i] == NULL)
+ break;
+ ret_msg->n_poas++;
+ }
+ res = i == res ? 0 : -ENOMEM;
+ }
+ free(eps);
break;
case IRM_MSG_CODE__IRM_CONNECT_IPCP:
flow.qs = qos_spec_msg_to_s(msg->qosspec);
- res = connect_ipcp(msg->pid, msg->dst, msg->comp, flow.qs);
+
+ pa = NULL;
+
+ if (msg->peer != NULL) {
+ poa_addr = poa_addr_msg_to_s(msg->peer);
+ if (poa_addr.type == POA_INVALID) {
+ res = -EINVAL;
+ break;
+ }
+ pa = &poa_addr;
+ }
+
+ res = connect_ipcp_resolve(msg->pid, msg->dst, msg->comp,
+ flow.qs, pa);
break;
case IRM_MSG_CODE__IRM_DISCONNECT_IPCP:
res = disconnect_ipcp(msg->pid, msg->dst, msg->comp);
@@ -2499,6 +2982,67 @@ static irm_msg_t * do_command_msg(irm_msg_t * msg,
if (res == 0)
ret_msg->flow_info = flow_info_s_to_msg(&flow);
break;
+ case IRM_MSG_CODE__IRM_POA_FLOW_ALLOC:
+ flow = flow_info_msg_to_s(msg->flow_info);
+
+ clrbuf(data);
+
+ res = poa_alloc(&flow, msg->dst, &data);
+ if (res == 0) {
+ ret_msg->flow_info = flow_info_s_to_msg(&flow);
+ ret_msg->has_pk = true;
+ ret_msg->pk.len = data.len;
+ ret_msg->pk.data = data.data;
+
+ clrbuf(data);
+ }
+ break;
+ case IRM_MSG_CODE__IRM_POA_FLOW_ALLOC_R:
+ data.len = msg->pk.len;
+ data.data = msg->pk.data;
+ msg->pk.data = NULL; /* pass data */
+ msg->pk.len = 0;
+ flow = flow_info_msg_to_s(msg->flow_info);
+ sk.key = kbuf;
+ res = poa_complete(&flow, msg->response, &data, &sk);
+
+ freebuf(data);
+
+ if (res != 0)
+ break;
+
+ ret_msg->flow_info = flow_info_s_to_msg(&flow);
+ ret_msg->has_cipher_nid = true;
+ ret_msg->cipher_nid = sk.nid;
+
+ if (sk.nid == NID_undef)
+ break;
+
+ hbuf = malloc(SYMMKEYSZ);
+ if (hbuf == NULL) {
+ log_err("Failed to malloc key buf");
+
+ res = -ENOMEM;
+ break;
+ }
+
+ memcpy(hbuf, kbuf, SYMMKEYSZ);
+
+ ret_msg->sym_key.data = hbuf;
+ ret_msg->sym_key.len = SYMMKEYSZ;
+ ret_msg->has_sym_key = true;
+ break;
+ case IRM_MSG_CODE__IPCP_POA_FLOW_REQ_ARR:
+ data.len = msg->pk.len;
+ data.data = msg->pk.data;
+ msg->pk.data = NULL; /* pass data */
+ msg->pk.len = 0;
+ flow = flow_info_msg_to_s(msg->flow_info);
+
+ res = poa_req_arr(&flow, &data);
+ if (res == 0)
+ ret_msg->flow_info = flow_info_s_to_msg(&flow);
+ break;
case IRM_MSG_CODE__IPCP_FLOW_ALLOC_REPLY:
data.len = msg->pk.len;
data.data = msg->pk.data;
diff --git a/src/irmd/oap.h b/src/irmd/oap.h
index 86f11e21..e9d7511b 100644
--- a/src/irmd/oap.h
+++ b/src/irmd/oap.h
@@ -40,21 +40,21 @@ int oap_auth_add_ca_crt(void * crt);
int oap_auth_add_chain_crt(void * crt);
/*
-* Prepare OAP request header for server, returns context
-* Passes client data for srv, returns srv data for client
-* rekey forces ephemeral server-encap KEX (no client-encap; preserves FS/PCS)
-*/
+ * Prepares the request header and returns the context. info holds the
+ * credentials we present, peer the name the server certificate must
+ * carry (NULL expects info->name); rekey forces an ephemeral KEX.
+ */
int oap_cli_prepare(void ** ctx,
const struct name_info * info,
+ const char * peer,
buffer_t * req_buf,
buffer_t data,
bool rekey);
/*
- * Server processes header, creates response header, returns secret key.
- * data is in/out: input=srv data to send, output=cli data received.
- * rekey drops the cert and verifies against cached_crt; peer_crt (or NULL)
- * receives a copy of the peer cert to cache at the initial handshake.
+ * Answers the request header and returns the secret key. data is
+ * in/out; rekey verifies against cached_crt, and peer_crt takes a copy
+ * of the peer cert to cache at the initial handshake.
*/
int oap_srv_process(const struct name_info * info,
buffer_t req_buf,
@@ -70,13 +70,12 @@ int oap_srv_process(const struct name_info * info,
* cached_crt verifies a cert-less re-key; peer_crt (or NULL) receives a
* copy of the peer cert to cache at the initial handshake.
*/
-int oap_cli_complete(void * ctx,
- const struct name_info * info,
- buffer_t rsp_buf,
- buffer_t * data,
- struct crypt_sk * sk,
- const buffer_t * cached_crt,
- buffer_t * peer_crt);
+int oap_cli_complete(void * ctx,
+ buffer_t rsp_buf,
+ buffer_t * data,
+ struct crypt_sk * sk,
+ const buffer_t * cached_crt,
+ buffer_t * peer_crt);
/* Free OAP state (on failure before complete) */
void oap_ctx_free(void * ctx);
diff --git a/src/irmd/oap/cli.c b/src/irmd/oap/cli.c
index ebfcd71f..2203596f 100644
--- a/src/irmd/oap/cli.c
+++ b/src/irmd/oap/cli.c
@@ -50,6 +50,7 @@
struct oap_cli_ctx {
uint8_t __id[OAP_ID_SIZE];
buffer_t id;
+ char peer[NAME_SIZE + 1]; /* expected server name */
uint8_t kex_buf[CRYPT_KEY_BUFSZ];
uint8_t req_hash[MAX_HASH_SIZE];
size_t req_hash_len;
@@ -241,6 +242,7 @@ static int do_client_kex_prepare(const char * server_name,
int oap_cli_prepare(void ** ctx,
const struct name_info * info,
+ const char * peer,
buffer_t * req_buf,
buffer_t data,
bool rekey)
@@ -259,6 +261,11 @@ int oap_cli_prepare(void ** ctx,
clrbuf(*req_buf);
*ctx = NULL;
+ if (peer != NULL && strlen(peer) > NAME_SIZE) {
+ log_err("Peer name too long.");
+ return -EINVAL;
+ }
+
/* Allocate ctx to carry between prepare and complete */
s = malloc(sizeof(*s));
if (s == NULL) {
@@ -269,13 +276,15 @@ int oap_cli_prepare(void ** ctx,
memset(s, 0, sizeof(*s));
OAP_CLI_CTX_INIT(s);
+ strcpy(s->peer, peer != NULL ? peer : info->name);
+
/* Generate session ID */
if (random_buffer(s->__id, OAP_ID_SIZE) < 0) {
log_err("Failed to generate OAP session ID.");
goto fail_id;
}
- log_dbg_id(s->id.data, "Preparing OAP request for %s.", info->name);
+ log_dbg_id(s->id.data, "Preparing OAP request for %s.", s->peer);
/* Load client credentials */
if (load_cli_credentials(info, &pkp, &crt) < 0) {
@@ -315,7 +324,7 @@ int oap_cli_prepare(void ** ctx,
oap_hdr_init(&s->local_hdr, s->id, s->kex_buf, data, s->scfg.c.nid);
- if (do_client_kex_prepare(info->name, s) < 0) {
+ if (do_client_kex_prepare(s->peer, s) < 0) {
log_err_id(s->id.data, "Failed to prepare client KEX.");
goto fail_kex;
}
@@ -482,7 +491,8 @@ static int do_client_kex_complete(struct oap_cli_ctx * s,
}
SET_KEX_CIPHER(scfg, peer_hdr->cipher_str);
- if (crypt_validate_nid(scfg->c.nid) < 0) {
+
+ if (crypt_cipher_rank(scfg->c.nid) < 0) {
log_err_id(id, "Server cipher '%s' not supported.",
peer_hdr->cipher_str);
return -ENOTSUP;
@@ -518,13 +528,12 @@ static int do_client_kex_complete(struct oap_cli_ctx * s,
return do_client_kex_complete_dhe(s, peer_hdr, sk);
}
-int oap_cli_complete(void * ctx,
- const struct name_info * info,
- buffer_t rsp_buf,
- buffer_t * data,
- struct crypt_sk * sk,
- const buffer_t * cached_crt,
- buffer_t * peer_crt)
+int oap_cli_complete(void * ctx,
+ buffer_t rsp_buf,
+ buffer_t * data,
+ struct crypt_sk * sk,
+ const buffer_t * cached_crt,
+ buffer_t * peer_crt)
{
struct oap_cli_ctx * s = ctx;
struct oap_hdr peer_hdr;
@@ -538,7 +547,6 @@ int oap_cli_complete(void * ctx,
int rc;
assert(ctx != NULL);
- assert(info != NULL);
assert(data != NULL);
assert(sk != NULL);
@@ -550,7 +558,7 @@ int oap_cli_complete(void * ctx,
id = s->id.data;
- log_dbg_id(id, "Completing OAP for %s.", info->name);
+ log_dbg_id(id, "Completing OAP for %s.", s->peer);
/* Decode response header using client's md_nid for hash length */
if (oap_hdr_decode(&peer_hdr, rsp_buf, s->req_md_nid, false) < 0) {
@@ -616,9 +624,9 @@ int oap_cli_complete(void * ctx,
}
/* Verify peer certificate name matches expected destination */
- if (peer_hdr.crt.len > 0 && strcmp(peer, info->name) != 0) {
+ if (peer_hdr.crt.len > 0 && strcmp(peer, s->peer) != 0) {
log_err_id(id, "Peer crt for '%s' does not match '%s'.",
- peer, info->name);
+ peer, s->peer);
goto fail_oap;
}
@@ -667,7 +675,7 @@ int oap_cli_complete(void * ctx,
goto fail_oap;
}
- log_info_id(id, "OAP completed for %s.", info->name);
+ log_info_id(id, "OAP completed for %s.", s->peer);
freebuf(peer_hdr.sealed_pt);
diff --git a/src/irmd/oap/tests/common.c b/src/irmd/oap/tests/common.c
index 16d52c63..b65f3997 100644
--- a/src/irmd/oap/tests/common.c
+++ b/src/irmd/oap/tests/common.c
@@ -159,7 +159,7 @@ void oap_test_teardown(struct oap_test_ctx * ctx)
if (ctx->cli.state != NULL) {
res.key = ctx->cli.key;
- oap_cli_complete(ctx->cli.state, &ctx->cli.info, dummy,
+ oap_cli_complete(ctx->cli.state, dummy,
&ctx->data, &res, NULL, NULL);
ctx->cli.state = NULL;
}
@@ -179,8 +179,8 @@ void oap_test_teardown(struct oap_test_ctx * ctx)
int oap_cli_prepare_ctx(struct oap_test_ctx * ctx)
{
- return oap_cli_prepare(&ctx->cli.state, &ctx->cli.info, &ctx->req_hdr,
- ctx->data, ctx->rekey);
+ return oap_cli_prepare(&ctx->cli.state, &ctx->cli.info, NULL,
+ &ctx->req_hdr, ctx->data, ctx->rekey);
}
int oap_srv_process_ctx(struct oap_test_ctx * ctx)
@@ -203,8 +203,7 @@ int oap_cli_complete_ctx(struct oap_test_ctx * ctx)
struct crypt_sk res = { .nid = NID_undef, .key = ctx->cli.key };
int ret;
- ret = oap_cli_complete(ctx->cli.state, &ctx->cli.info, ctx->resp_hdr,
- &ctx->data, &res,
+ ret = oap_cli_complete(ctx->cli.state, ctx->resp_hdr, &ctx->data, &res,
ctx->rekey ? &ctx->cli_crt : NULL,
ctx->rekey ? NULL : &ctx->cli_crt);
ctx->cli.state = NULL;
@@ -527,7 +526,7 @@ int roundtrip_kex_only(void)
goto fail;
}
- if (oap_cli_prepare(&cli_state, &cli_info, &req_hdr,
+ if (oap_cli_prepare(&cli_state, &cli_info, NULL, &req_hdr,
data, false) < 0) {
printf("Client prepare failed.\n");
goto fail_cleanup;
@@ -545,7 +544,7 @@ int roundtrip_kex_only(void)
res.key = cli_key;
- if (oap_cli_complete(cli_state, &cli_info, resp_hdr, &data, &res,
+ if (oap_cli_complete(cli_state, resp_hdr, &data, &res,
NULL, NULL) < 0) {
printf("Client complete failed.\n");
cli_state = NULL;
@@ -575,8 +574,8 @@ int roundtrip_kex_only(void)
fail_cleanup:
if (cli_state != NULL) {
res.key = cli_key;
- oap_cli_complete(cli_state, &cli_info, resp_hdr, &data,
- &res, NULL, NULL);
+
+ oap_cli_complete(cli_state, resp_hdr, &data, &res, NULL, NULL);
}
freebuf(resp_hdr);
freebuf(req_hdr);
@@ -655,7 +654,7 @@ int corrupted_response(const char * root_ca,
res.key = ctx.cli.key;
- if (oap_cli_complete(ctx.cli.state, &ctx.cli.info, ctx.resp_hdr,
+ if (oap_cli_complete(ctx.cli.state, ctx.resp_hdr,
&ctx.data, &res, NULL, NULL) == 0) {
printf("Client should reject corrupted response.\n");
ctx.cli.state = NULL;
diff --git a/src/irmd/reg/flow.c b/src/irmd/reg/flow.c
index 8be2dfc7..63c9199b 100644
--- a/src/irmd/reg/flow.c
+++ b/src/irmd/reg/flow.c
@@ -126,6 +126,9 @@ static int create_rbuffs(struct reg_flow * flow,
assert(flow->n_1_rb == NULL);
flow->info.n_1_pid = info->n_1_pid;
+ if (flow->poa)
+ return 0;
+
flow->n_1_rb = ssm_rbuff_create(info->n_1_pid, info->id);
if (flow->n_1_rb == NULL)
goto fail_n_1_rb;
diff --git a/src/irmd/reg/flow.h b/src/irmd/reg/flow.h
index 166bed61..c7021a0f 100644
--- a/src/irmd/reg/flow.h
+++ b/src/irmd/reg/flow.h
@@ -48,6 +48,8 @@ struct reg_flow {
char name[NAME_SIZE + 1];
bool direct;
+ bool poa; /* transport is a point of attachment */
+ void * oap_ctx; /* key exchange, prepare -> complete */
/* Tier-2 re-key state (encrypted flows only) */
struct {
diff --git a/src/irmd/reg/name.c b/src/irmd/reg/name.c
index a3621fc3..08426033 100644
--- a/src/irmd/reg/name.c
+++ b/src/irmd/reg/name.c
@@ -1,4 +1,3 @@
-
/*
* Ouroboros - Copyright (C) 2016 - 2026
*
diff --git a/src/irmd/reg/reg.c b/src/irmd/reg/reg.c
index ebf3959d..a302fa15 100644
--- a/src/irmd/reg/reg.c
+++ b/src/irmd/reg/reg.c
@@ -2119,6 +2119,77 @@ bool reg_flow_is_direct(int flow_id)
return ret;
}
+bool reg_flow_is_poa(int flow_id)
+{
+ struct reg_flow * flow;
+ bool ret;
+
+ pthread_mutex_lock(&reg.mtx);
+
+ flow = __reg_get_flow(flow_id);
+
+ ret = flow != NULL && flow->poa;
+
+ pthread_mutex_unlock(&reg.mtx);
+
+ return ret;
+}
+
+int reg_flow_set_poa(int flow_id)
+{
+ struct reg_flow * flow;
+ int ret = -1;
+
+ pthread_mutex_lock(&reg.mtx);
+
+ flow = __reg_get_flow(flow_id);
+ if (flow != NULL) {
+ flow->poa = true;
+ ret = 0;
+ }
+
+ pthread_mutex_unlock(&reg.mtx);
+
+ return ret;
+}
+
+int reg_flow_set_oap_ctx(int flow_id,
+ void * ctx)
+{
+ struct reg_flow * flow;
+ int ret = -1;
+
+ pthread_mutex_lock(&reg.mtx);
+
+ flow = __reg_get_flow(flow_id);
+ if (flow != NULL) {
+ flow->oap_ctx = ctx;
+ ret = 0;
+ }
+
+ pthread_mutex_unlock(&reg.mtx);
+
+ return ret;
+}
+
+void * reg_flow_take_oap_ctx(int flow_id)
+{
+ struct reg_flow * flow;
+ void * ctx = NULL;
+
+ pthread_mutex_lock(&reg.mtx);
+
+ flow = __reg_get_flow(flow_id);
+ if (flow != NULL) {
+ ctx = flow->oap_ctx;
+ flow->oap_ctx = NULL;
+ }
+
+ pthread_mutex_unlock(&reg.mtx);
+
+ return ctx;
+}
+
void reg_flow_set_rekey(int flow_id,
bool initiator,
buffer_t peer_crt)
@@ -2607,7 +2678,7 @@ void reg_notify_flow(int flow_id,
pthread_mutex_unlock(&reg.mtx);
}
-/* Wake both endpoints of a direct flow (acceptor and allocator). */
+/* Wake both PoAs of a direct flow (acceptor and allocator). */
void reg_notify_flow_peers(int flow_id,
int event)
{
diff --git a/src/irmd/reg/reg.h b/src/irmd/reg/reg.h
index 8a313d46..6882532c 100644
--- a/src/irmd/reg/reg.h
+++ b/src/irmd/reg/reg.h
@@ -33,138 +33,147 @@
#include "pool.h"
-int reg_init(void);
+int reg_init(void);
-void reg_clear(void);
+void reg_clear(void);
-void reg_fini(void);
+void reg_fini(void);
-int reg_create_flow(struct flow_info * info);
+int reg_create_flow(struct flow_info * info);
-int reg_destroy_flow(int flow_id);
+int reg_destroy_flow(int flow_id);
-bool reg_has_flow(int flow_id);
+bool reg_has_flow(int flow_id);
-int reg_create_proc(const struct proc_info * info);
+int reg_create_proc(const struct proc_info * info);
/* Use this for all processes, including ipcps */
-int reg_destroy_proc(pid_t pid);
+int reg_destroy_proc(pid_t pid);
-bool reg_has_proc(pid_t pid);
+bool reg_has_proc(pid_t pid);
-bool reg_is_proc_privileged(pid_t pid);
+bool reg_is_proc_privileged(pid_t pid);
-int reg_prepare_pool(uid_t uid,
- gid_t gid);
+int reg_prepare_pool(uid_t uid,
+ gid_t gid);
-uid_t reg_get_proc_uid(pid_t pid);
+uid_t reg_get_proc_uid(pid_t pid);
-void reg_kill_all_proc(int signal);
+void reg_kill_all_proc(int signal);
-pid_t reg_get_dead_proc(void);
+pid_t reg_get_dead_proc(void);
-int reg_create_spawned(pid_t pid);
+int reg_create_spawned(pid_t pid);
-bool reg_has_spawned(pid_t pid);
+bool reg_has_spawned(pid_t pid);
-void reg_kill_all_spawned(int signal);
+void reg_kill_all_spawned(int signal);
-int reg_first_spawned(void);
+int reg_first_spawned(void);
-int reg_bind_proc(const char * name,
- pid_t proc);
+int reg_bind_proc(const char * name,
+ pid_t proc);
-int reg_unbind_proc(const char * name,
- pid_t proc);
+int reg_unbind_proc(const char * name,
+ pid_t proc);
-int reg_create_ipcp(const struct ipcp_info * info);
+int reg_create_ipcp(const struct ipcp_info * info);
-bool reg_has_ipcp(pid_t pid);
+bool reg_has_ipcp(pid_t pid);
-int reg_set_layer_for_ipcp(struct ipcp_info * info,
- const struct layer_info * layer);
+int reg_set_layer_for_ipcp(struct ipcp_info * info,
+ const struct layer_info * layer);
-int reg_get_ipcp(struct ipcp_info * info,
- struct layer_info * layer);
+int reg_get_ipcp(struct ipcp_info * info,
+ struct layer_info * layer);
-int reg_get_ipcp_by_layer(struct ipcp_info * info,
- struct layer_info * layer);
+int reg_get_ipcp_by_layer(struct ipcp_info * info,
+ struct layer_info * layer);
/* TODO don't rely on protobuf here */
-int reg_list_ipcps(ipcp_list_msg_t *** msg);
+int reg_list_ipcps(ipcp_list_msg_t *** msg);
-int reg_create_name(const struct name_info * info);
+int reg_create_name(const struct name_info * info);
-int reg_destroy_name(const char * name);
+int reg_destroy_name(const char * name);
-bool reg_has_name(const char * name);
+bool reg_has_name(const char * name);
-int reg_get_name_info(const char * name,
- struct name_info * info);
+int reg_get_name_info(const char * name,
+ struct name_info * info);
-int reg_get_name_for_hash(char * buf,
- enum hash_algo algo,
- const uint8_t * hash);
+int reg_get_name_for_hash(char * buf,
+ enum hash_algo algo,
+ const uint8_t * hash);
-int reg_get_name_for_flow_id(char * buf,
- int flow_id);
+int reg_get_name_for_flow_id(char * buf,
+ int flow_id);
-void reg_set_name_for_flow_id(const char * name,
- int flow_id);
+void reg_set_name_for_flow_id(const char * name,
+ int flow_id);
/* TODO don't rely on protobuf here */
-int reg_list_names(name_info_msg_t *** names);
+int reg_list_names(name_info_msg_t *** names);
-int reg_create_prog(const struct prog_info * info);
+int reg_create_prog(const struct prog_info * info);
-int reg_destroy_prog(const char * name);
+int reg_destroy_prog(const char * name);
-bool reg_has_prog(const char * name);
+bool reg_has_prog(const char * name);
-int reg_get_exec(const char * name,
- char *** exec);
+int reg_get_exec(const char * name,
+ char *** exec);
-int reg_bind_prog(const char * name,
- char ** exec,
- uint8_t flags);
+int reg_bind_prog(const char * name,
+ char ** exec,
+ uint8_t flags);
-int reg_unbind_prog(const char * name,
- const char * prog);
+int reg_unbind_prog(const char * name,
+ const char * prog);
-int reg_prepare_flow_alloc(struct flow_info * info);
+int reg_prepare_flow_alloc(struct flow_info * info);
-int reg_wait_flow_allocated(struct flow_info * info,
+int reg_wait_flow_allocated(struct flow_info * info,
+ buffer_t * pbuf,
+ const struct timespec * abstime);
+
+int reg_respond_alloc(struct flow_info * info,
+ buffer_t * pbuf,
+ int response);
+
+int reg_prepare_flow_accept(struct flow_info * info);
+
+int reg_wait_flow_accepted(struct flow_info * info,
buffer_t * pbuf,
const struct timespec * abstime);
-int reg_respond_alloc(struct flow_info * info,
- buffer_t * pbuf,
- int response);
+int reg_wait_flow_accepting(const char * name,
+ const struct timespec * abstime);
-int reg_prepare_flow_accept(struct flow_info * info);
+int reg_respond_accept(struct flow_info * info,
+ buffer_t * pbuf);
-int reg_wait_flow_accepted(struct flow_info * info,
- buffer_t * pbuf,
- const struct timespec * abstime);
+int reg_prepare_flow_direct(struct flow_info * info,
+ buffer_t * pbuf,
+ uid_t alloc_uid);
-int reg_wait_flow_accepting(const char * name,
- const struct timespec * abstime);
+int reg_respond_flow_direct(int flow_id,
+ buffer_t * pbuf);
+
+int reg_wait_flow_direct(int flow_id,
+ buffer_t * pbuf,
+ const struct timespec * abstime);
-int reg_respond_accept(struct flow_info * info,
- buffer_t * pbuf);
+bool reg_flow_is_direct(int flow_id);
-int reg_prepare_flow_direct(struct flow_info * info,
- buffer_t * pbuf,
- uid_t alloc_uid);
+bool reg_flow_is_poa(int flow_id);
-int reg_respond_flow_direct(int flow_id,
- buffer_t * pbuf);
+int reg_flow_set_poa(int flow_id);
-int reg_wait_flow_direct(int flow_id,
- buffer_t * pbuf,
- const struct timespec * abstime);
+int reg_flow_set_oap_ctx(int flow_id,
+ void * ctx);
-bool reg_flow_is_direct(int flow_id);
+void * reg_flow_take_oap_ctx(int flow_id);
/* Per-flow snapshot for the re-key timer */
struct rekey_info {
@@ -176,70 +185,70 @@ struct rekey_info {
bool direct;
};
-void reg_flow_set_rekey(int flow_id,
- bool initiator,
- buffer_t peer_crt);
+void reg_flow_set_rekey(int flow_id,
+ bool initiator,
+ buffer_t peer_crt);
-int reg_flow_get_peer_crt(int flow_id,
- buffer_t * crt);
+int reg_flow_get_peer_crt(int flow_id,
+ buffer_t * crt);
-int reg_flow_get_epoch(int flow_id);
+int reg_flow_get_epoch(int flow_id);
-bool reg_flow_rekey_pending(int flow_id);
+bool reg_flow_rekey_pending(int flow_id);
-pid_t reg_flow_get_n_1_pid(int flow_id);
+pid_t reg_flow_get_n_1_pid(int flow_id);
-int reg_flow_snapshot_rekey_due(struct rekey_info * snap,
- int max);
+int reg_flow_snapshot_rekey_due(struct rekey_info * snap,
+ int max);
-void reg_flow_clear_in_flight(int flow_id);
+void reg_flow_clear_in_flight(int flow_id);
-bool reg_flow_rekey_begin(int flow_id);
+bool reg_flow_rekey_begin(int flow_id);
-bool reg_flow_rekey_should_yield(int flow_id);
+bool reg_flow_rekey_should_yield(int flow_id);
-int reg_flow_store_pending(int flow_id,
- const uint8_t * seed,
- uint8_t epoch,
- bool initiator);
+int reg_flow_store_pending(int flow_id,
+ const uint8_t * seed,
+ uint8_t epoch,
+ bool initiator);
-int reg_flow_store_pending_direct(int flow_id,
- const uint8_t * seed,
- uint8_t epoch);
+int reg_flow_store_pending_direct(int flow_id,
+ const uint8_t * seed,
+ uint8_t epoch);
-int reg_flow_take_pending(int flow_id,
- uid_t uid,
- pid_t cpid,
- uint8_t * seed,
- uint8_t * epoch,
- bool * initiator);
+int reg_flow_take_pending(int flow_id,
+ uid_t uid,
+ pid_t cpid,
+ uint8_t * seed,
+ uint8_t * epoch,
+ bool * initiator);
-bool reg_flow_rekey_arr_admit(int flow_id,
- pid_t n_1_pid,
- bool is_req);
+bool reg_flow_rekey_arr_admit(int flow_id,
+ pid_t n_1_pid,
+ bool is_req);
-void reg_flow_rekey_arr_done(int flow_id,
- bool is_req);
+void reg_flow_rekey_arr_done(int flow_id,
+ bool is_req);
-bool reg_flow_owned_by(int flow_id,
- uid_t uid);
+bool reg_flow_owned_by(int flow_id,
+ uid_t uid);
-void reg_notify_flow(int flow_id,
- int event);
+void reg_notify_flow(int flow_id,
+ int event);
-void reg_notify_flow_peers(int flow_id,
- int event);
+void reg_notify_flow_peers(int flow_id,
+ int event);
-void reg_dealloc_flow(struct flow_info * info);
+void reg_dealloc_flow(struct flow_info * info);
-void reg_dealloc_flow_resp(struct flow_info * info);
+void reg_dealloc_flow_resp(struct flow_info * info);
-int reg_wait_proc(pid_t pid,
- const struct timespec * abstime);
+int reg_wait_proc(pid_t pid,
+ const struct timespec * abstime);
-int reg_wait_ipcp_boot(struct ipcp_info * ipcp,
- const struct timespec * abstime);
+int reg_wait_ipcp_boot(struct ipcp_info * ipcp,
+ const struct timespec * abstime);
-int reg_respond_ipcp(const struct ipcp_info * info);
+int reg_respond_ipcp(const struct ipcp_info * info);
#endif /* OUROBOROS_IRMD_REG_H */
diff --git a/src/irmd/reg/tests/reg_test.c b/src/irmd/reg/tests/reg_test.c
index a8c1b1fa..ab57241c 100644
--- a/src/irmd/reg/tests/reg_test.c
+++ b/src/irmd/reg/tests/reg_test.c
@@ -746,7 +746,7 @@ static int test_reg_direct_flow_success(void)
reg_dealloc_flow(&info);
if (info.state != FLOW_DEALLOC_PENDING) {
- printf("Same endpoint dealloc changed state.\n");
+ printf("Same PoA dealloc changed state.\n");
goto fail;
}