diff options
| author | Dimitri Staessens <dimitri@ouroboros.rocks> | 2026-08-16 18:55:15 +0000 |
|---|---|---|
| committer | Sander Vrijders <sander@ouroboros.rocks> | 2026-08-31 08:31:45 +0200 |
| commit | 5c239c128c04883dbed6d66f574edf8b48d11e11 (patch) | |
| tree | 6dfcc043c81bd10e1366172b9db5cf5ce93bb8d8 /src/irmd/main.c | |
| parent | a830ed966eb3b7d6dbcc43e42a7b6b7c5d796c6a (diff) | |
| download | ouroboros-5c239c128c04883dbed6d66f574edf8b48d11e11.tar.gz ouroboros-5c239c128c04883dbed6d66f574edf8b48d11e11.zip | |
lib: Replace shim IPCPs with points of attachment
Removes the UDP and Ethernet shim IPCPs. The unicast and broadcast
IPCPs can now directly attach to a "legacy" socket. We adopt Saltzer's
Point-of-Attachment terminology, also advocated in Day's "Patterns in
Network Architecture". The "poa" component manages these
PoA's with one management thread, one link monitoring thread and one
thread per attached point.
For Ethernet PoA's the irm connect and enroll can resolve the
destination IPCP or Layer name with a broadcast name query over the
attached PoAs (first reply wins). UDP PoA's require a destination IP
address or FQDN.
attach to a local endpoint (required both server and client side):
irm ipcp poa attach name a udp 10.0.0.1
irm ipcp poa attach name a udp 10.0.0.1:3435
irm ipcp poa attach name a udp [::1]:3435
irm ipcp poa attach name a eth dev eth0
irm ipcp poa attach name a eth dev eth0 ethertype 0xA000
release a PoA (refused while it carries a flow):
irm ipcp poa detach name a udp 10.0.0.1:3435
irm ipcp poa detach name a eth eth0
list an IPCP's PoAs:
irm ipcp poa list name a
connect to a peer, by name or at an address:
irm ipcp connect name b dst a
irm ipcp connect name b dst a eth
irm ipcp connect name b dst a eth dev eth0
irm ipcp connect name b dst a udp 10.0.0.1:3435
irm ipcp connect name b dst a udp peer.example.com:3435
disconnect by peer name, no address:
irm ipcp disconnect name b dst a
irm ipcp disconnect name b dst a component mgmt
enroll has the same shape as connect:
irm ipcp enroll name b layer lr autobind
irm ipcp enroll name b layer lr autobind eth dev eth0
irm ipcp enroll name b layer lr autobind udp 10.0.0.1:3435
the IRMd config file attaches PoAs and names peers the same way:
udp = [ "10.0.0.1", "10.0.0.1:3436" ]
eth = [ "eth0", {dev="eth1", ethertype=0xA007} ]
enrol={dst="LAN", eth={dev="eth0"}}
conn=[{dst="lan3", eth={}}, {dst="lan4", udp="10.0.0.1:3435"}]
Signed-off-by: Dimitri Staessens <dimitri@ouroboros.rocks>
Signed-off-by: Sander Vrijders <sander@ouroboros.rocks>
Diffstat (limited to 'src/irmd/main.c')
| -rw-r--r-- | src/irmd/main.c | 610 |
1 files changed, 577 insertions, 33 deletions
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; |
