diff options
-rw-r--r-- | src/ipcpd/ipcp.c | 4 | ||||
-rw-r--r-- | src/ipcpd/ipcp.h | 3 | ||||
-rw-r--r-- | src/ipcpd/shim-udp/main.c | 341 | ||||
-rw-r--r-- | src/irmd/main.c | 69 | ||||
-rw-r--r-- | src/lib/ipcpd_messages.proto | 1 | ||||
-rw-r--r-- | src/lib/irmd_messages.proto | 3 | ||||
-rw-r--r-- | src/tools/echo/echo_server.c | 5 |
7 files changed, 395 insertions, 31 deletions
diff --git a/src/ipcpd/ipcp.c b/src/ipcpd/ipcp.c index 0b652ff6..e0dac20b 100644 --- a/src/ipcpd/ipcp.c +++ b/src/ipcpd/ipcp.c @@ -174,8 +174,8 @@ int ipcp_main_loop(struct ipcp * _ipcp) LOG_ERR("Flow_alloc unsupported."); break; } - ret_msg.has_result = true; - ret_msg.result = _ipcp->ops->ipcp_flow_alloc( + ret_msg.has_fd = true; + ret_msg.fd = _ipcp->ops->ipcp_flow_alloc( msg->port_id, msg->dst_ap_name, msg->ap_name, diff --git a/src/ipcpd/ipcp.h b/src/ipcpd/ipcp.h index 9decac8b..f640d78b 100644 --- a/src/ipcpd/ipcp.h +++ b/src/ipcpd/ipcp.h @@ -26,6 +26,9 @@ #include "ipcp-ops.h" #include "ipcp-data.h" +/* needed to run over shim DIFs */ +#define ANONYMOUS_AP "__ANONYMOUS__" + enum ipcp_state { IPCP_INIT = 0, IPCP_ENROLLING, diff --git a/src/ipcpd/shim-udp/main.c b/src/ipcpd/shim-udp/main.c index df731490..14b08ba8 100644 --- a/src/ipcpd/shim-udp/main.c +++ b/src/ipcpd/shim-udp/main.c @@ -29,6 +29,7 @@ #include <ouroboros/utils.h> #include <ouroboros/ipcp.h> #include <ouroboros/dif_config.h> +#include <ouroboros/sockets.h> #define OUROBOROS_PREFIX "ipcpd/shim-udp" @@ -36,6 +37,7 @@ #include <string.h> #include <sys/socket.h> +#include <sys/select.h> #include <arpa/inet.h> #include <netdb.h> #include <netinet/in.h> @@ -44,9 +46,15 @@ #include <pthread.h> #define THIS_TYPE IPCP_SHIM_UDP +#define LISTEN_PORT htons(0x0D1F) +#define SHIM_UDP_BUF_SIZE 256 +#define SHIM_UDP_MAX_SDU_SIZE 8980 #define shim_data(type) ((struct ipcp_udp_data *) type->data) +#define local_ip (((struct ipcp_udp_data *) \ + _ipcp->data)->s_saddr.sin_addr.s_addr) + /* global for trapping signal */ int irmd_pid; @@ -64,16 +72,19 @@ struct ipcp_udp_data { uint32_t ip_addr; uint32_t dns_addr; + /* listen server */ + struct sockaddr_in s_saddr; + int s_fd; + + fd_set flow_fd_s; + flow_t * fd_to_flow_ptr[FD_SETSIZE]; + pthread_mutex_t lock; }; struct udp_flow { /* FLOW MUST BE FIRST !!!! */ flow_t flow; - - uint16_t localport; - - struct sockaddr_in * remote; int fd; }; @@ -100,6 +111,7 @@ struct ipcp_udp_data * ipcp_udp_data_create(char * ap_name, struct ipcp_data * data; instance_name_t * instance_name; enum ipcp_type ipcp_type; + int n; instance_name = instance_name_create(); if (instance_name == NULL) { @@ -110,12 +122,12 @@ struct ipcp_udp_data * ipcp_udp_data_create(char * ap_name, instance_name = instance_name_init_with( instance_name, ap_name, (uint16_t)atoi(ap_id)); - if (instance_name == NULL) { + if (instance_name == NULL) { LOG_ERR("Failed to create instance name struct."); return NULL; } - udp_data= malloc (sizeof *udp_data); + udp_data = malloc(sizeof *udp_data); if (udp_data == NULL) { LOG_DBGF("Failed to allocate."); return NULL; @@ -128,13 +140,170 @@ struct ipcp_udp_data * ipcp_udp_data_create(char * ap_name, return NULL; } + FD_ZERO(&udp_data->flow_fd_s); + for (n = 0; n < FD_SETSIZE; ++n) + udp_data->fd_to_flow_ptr[n] = NULL; + return udp_data; } +static void * ipcp_udp_listener() +{ + char buf[SHIM_UDP_BUF_SIZE]; + int n = 0; + + struct sockaddr_in f_saddr; + struct sockaddr_in c_saddr; + struct hostent * hostp; + struct udp_flow * flow; + int sfd = shim_data(_ipcp)->s_fd; + + irm_msg_t msg = IRM_MSG__INIT; + irm_msg_t * ret_msg ; + + while (true) { + n = sizeof c_saddr; + n = recvfrom(sfd, buf, SHIM_UDP_BUF_SIZE, 0, + (struct sockaddr *) &c_saddr, (unsigned *) &n); + if (n < 0) + continue; + + /* flow alloc request from other host */ + hostp = gethostbyaddr((const char *)&c_saddr.sin_addr.s_addr, + sizeof(c_saddr.sin_addr.s_addr), AF_INET); + if (hostp == NULL) + continue; + + /* create a new socket for the server */ + flow = malloc(sizeof *flow); + if (flow == NULL) + continue; + + flow->fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (flow->fd == -1) { + free(flow); + continue; + } + + memset((char *)&f_saddr, 0, sizeof f_saddr); + f_saddr.sin_family = AF_INET; + f_saddr.sin_addr.s_addr = local_ip; + + /* + * FIXME: we could have a port dedicated per registered AP + * Not that critical for UDP, but will be for LLC + */ + + f_saddr.sin_port = 0; + + /* + * store the remote address in the file descriptor + * this avoids having to store the sockaddr_in in + * the flow structure + */ + + if (connect(flow->fd, + (struct sockaddr *)&c_saddr, sizeof c_saddr) < 0) { + close(flow->fd); + free(flow); + continue; + } + + /* reply to IRM */ + + msg.code = IRM_MSG_CODE__IPCP_FLOW_REQ_ARR; + msg.ap_name = ANONYMOUS_AP; + msg.ae_name = ""; /* no AE */ + msg.has_reg_ap_id = true; + msg.reg_ap_id = ipcp_data_get_reg_ap_id(_ipcp->data, buf); + + ret_msg = send_recv_irm_msg(&msg); + if (ret_msg == NULL) { + LOG_ERR("Could not send message to IRM."); + close(flow->fd); + free(flow); + continue; + } + + if (!ret_msg->has_port_id) { + LOG_ERR("Didn't get port_id."); + free(ret_msg); + close(flow->fd); + free(flow); + continue; + } + + flow->flow.port_id = ret_msg->port_id; + flow->flow.oflags = FLOW_O_DEFAULT; + flow->flow.state = FLOW_PENDING; + + if(ipcp_data_add_flow(_ipcp->data, (flow_t *) flow)) { + LOG_DBGF("Could not add flow."); + free(ret_msg); + close(flow->fd); + free(flow); + continue; + } + + FD_SET(flow->fd, &shim_data(_ipcp)->flow_fd_s); + shim_data(_ipcp)->fd_to_flow_ptr[flow->fd] = &flow->flow; + + } +} + +static void * ipcp_udp_sdu_reader() +{ + int n; + int fd; + char buf[SHIM_UDP_MAX_SDU_SIZE]; + + struct sockaddr_in r_saddr; + + while (true) { + flow_t * flow; + + if (select(FD_SETSIZE, + &shim_data(_ipcp)->flow_fd_s, + NULL, NULL, NULL) + < 0) + continue; + + for (fd = 0; fd < FD_SETSIZE; ++fd) { + if (!FD_ISSET(fd, &shim_data(_ipcp)->flow_fd_s)) + continue; + + n = sizeof r_saddr; + n = recvfrom(fd, + buf, + SHIM_UDP_MAX_SDU_SIZE, + 0, + (struct sockaddr *) &r_saddr, + (unsigned *) &n); + + flow = shim_data(_ipcp)->fd_to_flow_ptr[fd]; + if (flow->state == FLOW_PENDING) { + if (connect(fd, + (struct sockaddr *)&r_saddr, + sizeof r_saddr) + < 0) + continue; + flow->state = FLOW_ALLOCATED; + } + + /* send the sdu to the correct port_id */ + LOG_MISSING; + } + } + + return (void *) 0; +} + int ipcp_udp_bootstrap(struct dif_config * conf) { char ipstr[INET_ADDRSTRLEN]; char dnsstr[INET_ADDRSTRLEN]; + pthread_t handler; + pthread_t sdu_reader; if (conf->type != THIS_TYPE) { LOG_ERR("Config doesn't match IPCP type."); @@ -162,6 +331,28 @@ int ipcp_udp_bootstrap(struct dif_config * conf) shim_data(_ipcp)->ip_addr = conf->ip_addr; shim_data(_ipcp)->dns_addr = conf->dns_addr; + /* UDP listen server */ + + if ((shim_data(_ipcp)->s_fd = + socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) { + LOG_DBGF("Can't create socket."); + return -1; + } + + shim_data(_ipcp)->s_saddr.sin_family = AF_INET; + shim_data(_ipcp)->s_saddr.sin_addr.s_addr = conf->ip_addr; + shim_data(_ipcp)->s_saddr.sin_port = LISTEN_PORT; + + if (bind(shim_data(_ipcp)->s_fd, + (struct sockaddr *)&shim_data(_ipcp)->s_saddr, + sizeof shim_data(_ipcp)->s_saddr ) < 0) { + LOG_ERR("Couldn't bind to %s.", ipstr); + return -1; + } + + pthread_create(&handler, NULL, ipcp_udp_listener, NULL); + pthread_create(&sdu_reader, NULL, ipcp_udp_sdu_reader, NULL); + _ipcp->state = IPCP_ENROLLED; LOG_DBG("Bootstrapped shim IPCP over UDP %s-%d.", @@ -175,8 +366,6 @@ int ipcp_udp_bootstrap(struct dif_config * conf) int ipcp_udp_ap_reg(char * ap_name, uint32_t reg_ap_id) { - LOG_DBG("Registering local ap %s, %u.", ap_name, reg_ap_id); - if (_ipcp->state != IPCP_ENROLLED) { LOG_DBGF("Won't register with non-enrolled IPCP."); return -1; @@ -187,6 +376,9 @@ int ipcp_udp_ap_reg(char * ap_name, uint32_t reg_ap_id) return -1; } + LOG_DBG("Registered local ap %s, %u.", ap_name, reg_ap_id); + + /* FIXME: register application with DNS server */ LOG_MISSING; return 0; @@ -194,17 +386,11 @@ int ipcp_udp_ap_reg(char * ap_name, uint32_t reg_ap_id) int ipcp_udp_ap_unreg(uint32_t reg_ap_id) { - char * name = strdup(ipcp_data_get_reg_ap_name(_ipcp->data, - reg_ap_id)); - LOG_DBG("Unregistering %s.", name); - ipcp_data_del_reg_entry(_ipcp->data, reg_ap_id); - /* we are using dns */ + /* FIXME: unregister application from DNS server */ LOG_MISSING; - free (name); - return 0; } @@ -214,11 +400,132 @@ int ipcp_udp_flow_alloc(uint32_t port_id, char * src_ae_name, struct qos_spec * qos) { + struct udp_flow * flow = NULL; + struct sockaddr_in l_saddr; + struct sockaddr_in r_saddr; + + irm_msg_t msg = IRM_MSG__INIT; + irm_msg_t * ret_msg = NULL; + + if (dst_ap_name == NULL || src_ap_name == NULL || src_ae_name == NULL) + return -1; + + LOG_DBG("Received flow allocation request from %s to %s.", + src_ap_name, dst_ap_name); + + if (strlen(dst_ap_name) > 255 + || strlen(src_ap_name) > 255 + || strlen(src_ae_name) > 255) { + LOG_ERR("Name too long for this shim."); + return -1; + } + + if (qos != NULL) + LOG_DBGF("QoS requested. UDP/IP can't do that."); + + flow = malloc(sizeof *flow); + if (flow == NULL) + return -1; + + flow->fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (flow->fd == -1) { + free(flow); + return -1; + } + + /* this socket is for the flow */ + memset((char *)&l_saddr, 0, sizeof l_saddr); + l_saddr.sin_family = AF_INET; + l_saddr.sin_addr.s_addr = local_ip; + l_saddr.sin_port = 0; + + if (bind(flow->fd, (struct sockaddr *) &l_saddr, sizeof l_saddr) < 0) { + char ipstr[INET_ADDRSTRLEN]; + inet_ntop(AF_INET, + &l_saddr.sin_addr.s_addr, + ipstr, + INET_ADDRSTRLEN); + close(flow->fd); + free(flow); + return -1; + } + + /* FIXME: use calls to specify DDNS server */ + +#define IP_ADDR 0x7f000001; /* localhost */ + + LOG_MISSING; + + memset((char *)&r_saddr, 0, sizeof r_saddr); + r_saddr.sin_family = AF_INET; + /* FIXME: pull in correct IP address */ + r_saddr.sin_addr.s_addr = IP_ADDR; /* FIXME */ + r_saddr.sin_port = LISTEN_PORT; + + /* at least try to get the packet on the wire */ + while (sendto(flow->fd, dst_ap_name, strlen(dst_ap_name), 0, + (struct sockaddr *) &r_saddr, sizeof r_saddr) < 0) + + flow->flow.port_id = port_id; + flow->flow.oflags = FLOW_O_DEFAULT; + flow->flow.state = FLOW_PENDING; + + /* add flow to the list */ + + pthread_mutex_lock(&_ipcp->data->flow_lock); + + if(ipcp_data_add_flow(_ipcp->data, (flow_t *)flow)) { + LOG_DBGF("Could not add flow."); + pthread_mutex_unlock(&_ipcp->data->flow_lock); + close(flow->fd); + free(flow); + return -1; + } + + pthread_mutex_unlock(&_ipcp->data->flow_lock); + + /* tell IRMd that flow allocation "worked" */ + + msg.code = IRM_MSG_CODE__IPCP_FLOW_ALLOC_REPLY; + msg.has_port_id = true; + msg.port_id = flow->flow.port_id; + msg.has_response = true; + msg.response = 0; + + ret_msg = send_recv_irm_msg(&msg); + if (ret_msg == NULL) { + close(flow->fd); + ipcp_data_del_flow(_ipcp->data, flow->flow.port_id); + return -1; + } + + FD_SET(flow->fd, &shim_data(_ipcp)->flow_fd_s); + shim_data(_ipcp)->fd_to_flow_ptr[flow->fd] = &flow->flow; + return 0; } + int ipcp_udp_flow_alloc_resp(uint32_t port_id, - int result) + int response) { + struct udp_flow * flow = + (struct udp_flow *) ipcp_data_find_flow(_ipcp->data, port_id); + if (flow == NULL) { + return -1; + } + + if (response) { + ipcp_data_del_flow(_ipcp->data, port_id); + return 0; + } + + /* awaken pending flow */ + + if (flow->flow.state != FLOW_PENDING) + return -1; + + flow->flow.state = FLOW_ALLOCATED; + return 0; } @@ -255,7 +562,7 @@ struct ipcp * ipcp_udp_create(char * ap_name, char * i_id) return NULL; } - ops = malloc (sizeof *ops); + ops = malloc(sizeof *ops); if (ops == NULL) { free(data); free(i); diff --git a/src/irmd/main.c b/src/irmd/main.c index 13076cd1..374bfb6c 100644 --- a/src/irmd/main.c +++ b/src/irmd/main.c @@ -87,6 +87,24 @@ static struct ipcp_entry * find_ipcp_by_name(instance_name_t * api) return tmp; } +static pid_t find_pid_by_dif_name(char * dif_name) +{ + struct list_head * pos = NULL; + + list_for_each(pos, &instance->ipcps) { + struct ipcp_entry * tmp = + list_entry(pos, struct ipcp_entry, next); + + if (tmp->dif_name == NULL) + return tmp->pid; + + if (strcmp(dif_name, tmp->dif_name) == 0) + return tmp->pid; + } + + return 0; +} + static int create_ipcp(instance_name_t * api, enum ipcp_type ipcp_type) { @@ -266,7 +284,41 @@ static int ap_reg(char * ap_name, char ** difs, size_t difs_size) { - return -1; + pid_t pid = 0; + int i; + int ret = 0; + + if (instance->ipcps.next == NULL) + LOG_ERR("No IPCPs in this system."); + + /* + * FIXME: this should be resolved by NSM + * Now it just takes the first DIF + */ + + if (strcmp(difs[0], "*") == 0) { + difs[0] = list_entry(instance->ipcps.next, + struct ipcp_entry, + next)->dif_name; + difs_size = 1; + } + + for (i = 0; i < difs_size; ++i) { + pid = find_pid_by_dif_name(difs[i]); + if (pid == 0) { + LOG_ERR("%s: No such DIF.", difs[i]); + continue; + } + + /* FIXME: get proper reg_ap_id */ + if (ipcp_ap_reg(pid, rand(),ap_name)) { + LOG_ERR("Could not register %s in DIF %s.", + ap_name, difs[i]); + ret = -1; + } + } + + return ret; } static int ap_unreg(char * ap_name, @@ -366,7 +418,6 @@ int main() sigaction(SIGTERM, &sig_act, NULL); sigaction(SIGHUP, &sig_act, NULL); - if (access("/dev/shm/" SHM_DU_MAP_FILENAME, F_OK) != -1) unlink("/dev/shm/" SHM_DU_MAP_FILENAME); @@ -480,8 +531,8 @@ int main() msg->oflags); break; case IRM_MSG_CODE__IRM_FLOW_ALLOC_RES: - ret_msg.has_result = true; - ret_msg.result = flow_alloc_res(msg->fd); + ret_msg.has_response = true; + ret_msg.response = flow_alloc_res(msg->fd); break; case IRM_MSG_CODE__IRM_FLOW_DEALLOC: ret_msg.has_result = true; @@ -493,15 +544,15 @@ int main() msg->oflags); break; case IRM_MSG_CODE__IPCP_FLOW_REQ_ARR: - ret_msg.has_fd = true; - ret_msg.fd = flow_req_arr(msg->port_id, - msg->ap_name, - msg->ae_name); + ret_msg.has_port_id = true; + ret_msg.port_id = flow_req_arr(msg->port_id, + msg->ap_name, + msg->ae_name); break; case IRM_MSG_CODE__IPCP_FLOW_ALLOC_REPLY: ret_msg.has_result = true; ret_msg.result = flow_alloc_reply(msg->port_id, - msg->result); + msg->response); break; case IRM_MSG_CODE__IPCP_FLOW_DEALLOC: ret_msg.has_result = true; diff --git a/src/lib/ipcpd_messages.proto b/src/lib/ipcpd_messages.proto index 796638c7..850c64e4 100644 --- a/src/lib/ipcpd_messages.proto +++ b/src/lib/ipcpd_messages.proto @@ -26,4 +26,5 @@ message ipcp_msg { optional string ae_name = 10; optional dif_config_msg conf = 11; optional int32 result = 12; + optional int32 fd = 13; }; diff --git a/src/lib/irmd_messages.proto b/src/lib/irmd_messages.proto index 92ea439e..d484a007 100644 --- a/src/lib/irmd_messages.proto +++ b/src/lib/irmd_messages.proto @@ -31,11 +31,12 @@ message irm_msg { optional uint32 ipcp_type = 5; repeated string dif_name = 6; optional int32 fd = 7; - optional int32 result = 8; + optional int32 response = 8; optional int32 oflags = 9; optional string dst_ap_name = 10; optional uint32 port_id = 11; optional uint32 reg_ap_id = 12; optional int32 pid = 13; optional dif_config_msg conf = 14; + optional int32 result = 15; }; diff --git a/src/tools/echo/echo_server.c b/src/tools/echo/echo_server.c index b1547d8c..e457e22b 100644 --- a/src/tools/echo/echo_server.c +++ b/src/tools/echo/echo_server.c @@ -64,15 +64,16 @@ int server_main() return -1; } + printf("Echo server started...\n"); + while (true) { client_fd = flow_accept(server_fd, client_name, NULL); if (client_fd < 0) { - printf("Failed to accept flow\n"); continue; } - printf("New flow from %s", client_name); + printf("New flow from %s\n", client_name); if (flow_alloc_resp(client_fd, 0)) { printf("Failed to give an allocate response\n"); |