diff options
Diffstat (limited to 'src/ipcpd/udp')
| -rw-r--r-- | src/ipcpd/udp/udp.c | 155 |
1 files changed, 145 insertions, 10 deletions
diff --git a/src/ipcpd/udp/udp.c b/src/ipcpd/udp/udp.c index 452bbc1a..db57e2f4 100644 --- a/src/ipcpd/udp/udp.c +++ b/src/ipcpd/udp/udp.c @@ -28,6 +28,8 @@ #include <ouroboros/list.h> #include <ouroboros/utils.h> #include <ouroboros/dev.h> +#include <ouroboros/ipcp-dev.h> +#include <ouroboros/np1_flow.h> #include <ouroboros/fqueue.h> #include <ouroboros/errno.h> #include <ouroboros/logs.h> @@ -47,9 +49,14 @@ #include <stdlib.h> #include <sys/wait.h> #include <fcntl.h> +#include <unistd.h> +#if defined(__linux__) +#include <netinet/ip.h> +#endif #define FLOW_REQ 1 #define FLOW_REPLY 2 +#define FLOW_IRM_UPDATE 3 #define OUR_HEADER_LEN sizeof(uint32_t) /* adds eid */ @@ -87,7 +94,7 @@ struct mgmt_msg { uint8_t code; /* QoS parameters from spec */ uint8_t availability; - uint8_t in_order; + uint8_t service; } __attribute__((packed)); struct mgmt_frame { @@ -130,6 +137,53 @@ static const char * __inet_ntop(const struct __ADDR * addr, return inet_ntop(__AF, addr, buf, __ADDRSTRLEN); } +#if defined(BUILD_IPCP_UDP4) +#define UDP_MTU_FALLBACK IPCP_UDP4_MTU +#define UDP_IP_OVERHEAD 28U /* IPv4 + UDP */ +#else +#define UDP_MTU_FALLBACK IPCP_UDP6_MTU +#define UDP_IP_OVERHEAD 48U /* IPv6 + UDP */ +#endif + +static uint32_t udp_query_mtu(const struct __SOCKADDR * saddr) +{ +#if defined(__linux__) && (defined(IP_MTU) || defined(IPV6_MTU)) + int sock; + int mtu = 0; + socklen_t len = sizeof(mtu); + + sock = socket(__AF, SOCK_DGRAM, IPPROTO_UDP); + if (sock < 0) + return UDP_MTU_FALLBACK; + + if (connect(sock, (const struct sockaddr *) saddr, + sizeof(*saddr)) < 0) + goto fallback; + +#if defined(BUILD_IPCP_UDP4) && defined(IP_MTU) + if (getsockopt(sock, IPPROTO_IP, IP_MTU, &mtu, &len) < 0) + goto fallback; +#elif defined(BUILD_IPCP_UDP6) && defined(IPV6_MTU) + if (getsockopt(sock, IPPROTO_IPV6, IPV6_MTU, &mtu, &len) < 0) + goto fallback; +#else + goto fallback; +#endif + close(sock); + + if (mtu <= (int) UDP_IP_OVERHEAD) + return UDP_MTU_FALLBACK; + + return (uint32_t) mtu - UDP_IP_OVERHEAD; + + fallback: + close(sock); +#else + (void) saddr; +#endif + return UDP_MTU_FALLBACK; +} + static int udp_data_init(void) { int i; @@ -220,7 +274,7 @@ static int udp_ipcp_port_alloc(const struct __SOCKADDR * r_saddr, msg->availability = qs.availability; msg->loss = hton32(qs.loss); msg->ber = hton32(qs.ber); - msg->in_order = qs.in_order; + msg->service = qs.service; msg->max_gap = hton32(qs.max_gap); msg->timeout = hton32(qs.timeout); @@ -277,6 +331,48 @@ static int udp_ipcp_port_alloc_resp(const struct __SOCKADDR * r_saddr, return 0; } +static int udp_ipcp_flow_update(int fd, + const buffer_t * data) +{ + struct mgmt_msg * msg; + struct __SOCKADDR r_saddr; + uint32_t d_eid; + + msg = malloc(sizeof(*msg) + data->len); + if (msg == NULL) + return -1; + + memset(msg, 0, sizeof(*msg) + data->len); + + pthread_rwlock_rdlock(&udp_data.flows_lock); + + r_saddr = udp_data.fd_to_uf[fd].r_saddr; + d_eid = (uint32_t) udp_data.fd_to_uf[fd].d_eid; + + pthread_rwlock_unlock(&udp_data.flows_lock); + + msg->eid = hton32(MGMT_EID); + msg->code = FLOW_IRM_UPDATE; + msg->s_eid = hton32(d_eid); + msg->d_eid = hton32((uint32_t) fd); + + if (data->len > 0) + memcpy(msg + 1, data->data, data->len); + + if (sendto(udp_data.s_fd, msg, sizeof(*msg) + data->len, + SENDTO_FLAGS, + (const struct sockaddr *) &r_saddr, + sizeof(r_saddr)) < 0) { + log_err("Failed to send flow update: %s.", strerror(errno)); + free(msg); + return -1; + } + + free(msg); + + return 0; +} + static int udp_ipcp_port_req(struct __SOCKADDR * c_saddr, int d_eid, const uint8_t * dst, @@ -285,7 +381,8 @@ static int udp_ipcp_port_req(struct __SOCKADDR * c_saddr, { int fd; - fd = ipcp_wait_flow_req_arr(dst, qs, IPCP_UDP_MPL, data); + fd = ipcp_wait_flow_req_arr(dst, qs, IPCP_UDP_MPL, + udp_query_mtu(c_saddr), data); if (fd < 0) { log_err("Could not get new flow from IRMd."); return -1; @@ -332,7 +429,8 @@ static int udp_ipcp_port_alloc_reply(const struct __SOCKADDR * saddr, pthread_rwlock_unlock(&udp_data.flows_lock); - if (ipcp_flow_alloc_reply(s_eid, response, mpl, data) < 0) { + if (ipcp_flow_alloc_reply(s_eid, response, mpl, + udp_query_mtu(saddr), data) < 0) { log_err("Failed to reply to flow allocation."); return -1; } @@ -343,6 +441,37 @@ static int udp_ipcp_port_alloc_reply(const struct __SOCKADDR * saddr, return 0; } +static int udp_ipcp_flow_update_arr(const uint8_t * buf, + size_t len) +{ + struct mgmt_msg * msg; + buffer_t data; + int fd; + int flow_id; + + msg = (struct mgmt_msg *) buf; + + fd = (int) ntoh32(msg->s_eid); + if (fd < 0 || fd >= SYS_MAX_FLOWS) { + log_err("Flow update for invalid eid %d.", fd); + return -1; + } + + data.len = len - sizeof(*msg); + data.data = (uint8_t *) buf + sizeof(*msg); + + flow_id = np1_flow_id(fd); + if (flow_id < 0) + return -1; + + if (ipcp_flow_update_arr(flow_id, &data) < 0) { + log_err("Failed to relay flow update on fd %d.", fd); + return -1; + } + + return 0; +} + static int udp_ipcp_mgmt_frame(struct __SOCKADDR c_saddr, const uint8_t * buf, size_t len) @@ -352,13 +481,18 @@ static int udp_ipcp_mgmt_frame(struct __SOCKADDR c_saddr, qosspec_t qs; buffer_t data; + /* Defence against malformed/corrupted wire input. */ + if (len < sizeof(*msg)) + return -1; + msg = (struct mgmt_msg *) buf; switch (msg->code) { case FLOW_REQ: msg_len = sizeof(*msg) + ipcp_dir_hash_len(); - assert(len >= msg_len); + if (len < msg_len) + return -1; data.len = len - msg_len; data.data = (uint8_t *) buf + msg_len; @@ -369,7 +503,7 @@ static int udp_ipcp_mgmt_frame(struct __SOCKADDR c_saddr, qs.availability = msg->availability; qs.loss = ntoh32(msg->loss); qs.ber = ntoh32(msg->ber); - qs.in_order = msg->in_order; + qs.service = msg->service; qs.max_gap = ntoh32(msg->max_gap); qs.timeout = ntoh32(msg->timeout); @@ -377,8 +511,6 @@ static int udp_ipcp_mgmt_frame(struct __SOCKADDR c_saddr, (uint8_t *) (msg + 1), qs, &data); case FLOW_REPLY: - assert(len >= sizeof(*msg)); - data.len = len - sizeof(*msg); data.data = (uint8_t *) buf + sizeof(*msg); @@ -387,6 +519,8 @@ static int udp_ipcp_mgmt_frame(struct __SOCKADDR c_saddr, ntoh32(msg->d_eid), ntoh32(msg->response), &data); + case FLOW_IRM_UPDATE: + return udp_ipcp_flow_update_arr(buf, len); default: log_err("Unknown message received %d.", msg->code); return -1; @@ -549,7 +683,7 @@ static void * udp_ipcp_packet_writer(void * o) continue; } - buf = ssm_pk_buff_head_alloc(spb, OUR_HEADER_LEN); + buf = ssm_pk_buff_push(spb, OUR_HEADER_LEN); if (buf == NULL) { log_dbg("Failed to allocate header."); ipcp_spb_release(spb); @@ -1140,7 +1274,8 @@ static struct ipcp_ops udp_ops = { .ipcp_flow_alloc = udp_ipcp_flow_alloc, .ipcp_flow_join = NULL, .ipcp_flow_alloc_resp = udp_ipcp_flow_alloc_resp, - .ipcp_flow_dealloc = udp_ipcp_flow_dealloc + .ipcp_flow_dealloc = udp_ipcp_flow_dealloc, + .ipcp_flow_update = udp_ipcp_flow_update }; int main(int argc, |
