diff options
Diffstat (limited to 'src/ipcpd')
-rw-r--r-- | src/ipcpd/ipcp-data.c | 308 | ||||
-rw-r--r-- | src/ipcpd/ipcp-data.h | 56 | ||||
-rw-r--r-- | src/ipcpd/ipcp-ops.h | 2 | ||||
-rw-r--r-- | src/ipcpd/ipcp.c | 17 | ||||
-rw-r--r-- | src/ipcpd/local/main.c | 25 | ||||
-rw-r--r-- | src/ipcpd/normal/main.c | 30 | ||||
-rw-r--r-- | src/ipcpd/shim-eth-llc/main.c | 147 | ||||
-rw-r--r-- | src/ipcpd/shim-eth-llc/shim_eth_llc_messages.proto | 10 | ||||
-rw-r--r-- | src/ipcpd/shim-udp/main.c | 163 |
9 files changed, 555 insertions, 203 deletions
diff --git a/src/ipcpd/ipcp-data.c b/src/ipcpd/ipcp-data.c index ed7e578d..b3078054 100644 --- a/src/ipcpd/ipcp-data.c +++ b/src/ipcpd/ipcp-data.c @@ -21,14 +21,16 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include <ouroboros/config.h> -#include <ouroboros/list.h> - #define OUROBOROS_PREFIX "ipcp-utils" +#include <ouroboros/config.h> +#include <ouroboros/list.h> +#include <ouroboros/time_utils.h> #include <ouroboros/logs.h> +#include <ouroboros/errno.h> #include "ipcp-data.h" +#include "ipcp.h" #include <string.h> #include <stdlib.h> @@ -41,8 +43,8 @@ struct reg_entry { struct dir_entry { struct list_head list; - char * ap_name; - uint64_t addr; + char * name; + uint64_t addr; }; static struct reg_entry * reg_entry_create(char * name) @@ -70,18 +72,18 @@ static void reg_entry_destroy(struct reg_entry * entry) free(entry); } -static struct dir_entry * dir_entry_create(char * ap_name, +static struct dir_entry * dir_entry_create(char * name, uint64_t addr) { struct dir_entry * entry = malloc(sizeof(*entry)); if (entry == NULL) return NULL; - assert(ap_name); + assert(name); entry->addr = addr; - entry->ap_name = ap_name; - if (entry->ap_name == NULL) + entry->name = name; + if (entry->name == NULL) return NULL; return entry; @@ -91,8 +93,8 @@ static void dir_entry_destroy(struct dir_entry * entry) { assert(entry); - if (entry->ap_name != NULL) - free(entry->ap_name); + if (entry->name != NULL) + free(entry->name); free(entry); } @@ -120,10 +122,12 @@ struct ipcp_data * ipcp_data_init(struct ipcp_data * dst, /* init the lists */ INIT_LIST_HEAD(&dst->registry); INIT_LIST_HEAD(&dst->directory); + INIT_LIST_HEAD(&dst->dir_queries); /* init the locks */ pthread_rwlock_init(&dst->reg_lock, NULL); pthread_rwlock_init(&dst->dir_lock, NULL); + pthread_mutex_init(&dst->dir_queries_lock, NULL); return dst; } @@ -156,6 +160,20 @@ static void clear_directory(struct ipcp_data * data) } } +static void clear_dir_queries(struct ipcp_data * data) +{ + struct list_head * h; + struct list_head * t; + + assert(data); + + list_for_each_safe(h, t, &data->dir_queries) { + struct dir_query * e = list_entry(h, struct dir_query, next); + list_del(&e->next); + ipcp_data_dir_query_destroy(e); + } +} + void ipcp_data_destroy(struct ipcp_data * data) { if (data == NULL) @@ -163,27 +181,27 @@ void ipcp_data_destroy(struct ipcp_data * data) /* clear the lists */ pthread_rwlock_wrlock(&data->reg_lock); - clear_registry(data); - pthread_rwlock_unlock(&data->reg_lock); - pthread_rwlock_wrlock(&data->dir_lock); + pthread_rwlock_wrlock(&data->dir_lock); clear_directory(data); - pthread_rwlock_unlock(&data->dir_lock); + pthread_mutex_lock(&data->dir_queries_lock); + clear_dir_queries(data); + pthread_mutex_unlock(&data->dir_queries_lock); + if (data->dif_name != NULL) free(data->dif_name); pthread_rwlock_destroy(&data->dir_lock); pthread_rwlock_destroy(&data->reg_lock); + pthread_mutex_destroy(&data->dir_queries_lock); free(data); } - - static struct reg_entry * find_reg_entry_by_name(struct ipcp_data * data, const char * name) { @@ -202,13 +220,13 @@ static struct reg_entry * find_reg_entry_by_name(struct ipcp_data * data, } static struct dir_entry * find_dir_entry(struct ipcp_data * data, - const char * ap_name, + const char * name, uint64_t addr) { struct list_head * h; list_for_each(h, &data->directory) { struct dir_entry * e = list_entry(h, struct dir_entry, list); - if (e->addr == addr && !strcmp(e->ap_name, ap_name)) + if (e->addr == addr && !strcmp(e->name, name)) return e; } @@ -216,33 +234,47 @@ static struct dir_entry * find_dir_entry(struct ipcp_data * data, } static struct dir_entry * find_dir_entry_any(struct ipcp_data * data, - const char * ap_name) + const char * name) { struct list_head * h; list_for_each(h, &data->directory) { struct dir_entry * e = list_entry(h, struct dir_entry, list); - if (!strcmp(e->ap_name, ap_name)) + if (!strcmp(e->name, name)) return e; } return NULL; } -bool ipcp_data_is_in_directory(struct ipcp_data * data, - const char * ap_name) +int ipcp_data_reg_add_entry(struct ipcp_data * data, + char * name) { - bool ret = false; + struct reg_entry * entry; - pthread_rwlock_rdlock(&data->dir_lock); + if (data == NULL || name == NULL) + return -1; - ret = (find_dir_entry_any(data, ap_name) != NULL); + pthread_rwlock_wrlock(&data->reg_lock); - pthread_rwlock_unlock(&data->dir_lock); + if (find_reg_entry_by_name(data, name)) { + pthread_rwlock_unlock(&data->reg_lock); + return -1; + } - return ret; + entry = reg_entry_create(name); + if (entry == NULL) { + pthread_rwlock_unlock(&data->reg_lock); + return -1; + } + + list_add(&entry->list, &data->registry); + + pthread_rwlock_unlock(&data->reg_lock); + + return 0; } -int ipcp_data_del_reg_entry(struct ipcp_data * data, +int ipcp_data_reg_del_entry(struct ipcp_data * data, const char * name) { struct reg_entry * e; @@ -266,114 +298,109 @@ int ipcp_data_del_reg_entry(struct ipcp_data * data, return 0; } -int ipcp_data_del_dir_entry(struct ipcp_data * data, - const char * ap_name, - uint64_t addr) +bool ipcp_data_reg_has(struct ipcp_data * data, + const char * name) { - struct dir_entry * e; - if (data == NULL) - return -1; - - pthread_rwlock_wrlock(&data->dir_lock); + bool ret = false; - e = find_dir_entry(data, ap_name, addr); - if (e == NULL) { - pthread_rwlock_unlock(&data->dir_lock); - return 0; /* nothing to do */ - } + if (data == NULL || name == NULL) + return false; - list_del(&e->list); + pthread_rwlock_rdlock(&data->reg_lock); - pthread_rwlock_unlock(&data->dir_lock); + ret = (find_reg_entry_by_name(data, name) != NULL); - dir_entry_destroy(e); + pthread_rwlock_unlock(&data->reg_lock); - return 0; + return ret; } -int ipcp_data_add_reg_entry(struct ipcp_data * data, - char * name) +int ipcp_data_dir_add_entry(struct ipcp_data * data, + char * name, + uint64_t addr) { - struct reg_entry * entry; + struct dir_entry * entry; + char * entry_name; if (data == NULL || name == NULL) return -1; - pthread_rwlock_wrlock(&data->reg_lock); + pthread_rwlock_wrlock(&data->dir_lock); - if (find_reg_entry_by_name(data, name)) { - pthread_rwlock_unlock(&data->reg_lock); + if (find_dir_entry(data, name, addr) != NULL) { + pthread_rwlock_unlock(&data->dir_lock); return -1; } - entry = reg_entry_create(name); + entry_name = strdup(name); + if (entry_name == NULL) { + pthread_rwlock_unlock(&data->dir_lock); + return -1; + } + + entry = dir_entry_create(entry_name, addr); if (entry == NULL) { - pthread_rwlock_unlock(&data->reg_lock); + pthread_rwlock_unlock(&data->dir_lock); return -1; } - list_add(&entry->list, &data->registry); + list_add(&entry->list,&data->directory); - pthread_rwlock_unlock(&data->reg_lock); + pthread_rwlock_unlock(&data->dir_lock); + + LOG_DBG("Added directory entry for %s.", entry_name); return 0; } -int ipcp_data_add_dir_entry(struct ipcp_data * data, - char * ap_name, +int ipcp_data_dir_del_entry(struct ipcp_data * data, + const char * name, uint64_t addr) { - struct dir_entry * entry; - - if (data == NULL || ap_name == NULL) + struct dir_entry * e; + if (data == NULL) return -1; pthread_rwlock_wrlock(&data->dir_lock); - if (find_dir_entry(data, ap_name, addr) != NULL) { - pthread_rwlock_unlock(&data->dir_lock); - return -1; - } - - entry = dir_entry_create(ap_name, addr); - if (entry == NULL) { + e = find_dir_entry(data, name, addr); + if (e == NULL) { pthread_rwlock_unlock(&data->dir_lock); - return -1; + return 0; /* nothing to do */ } - list_add(&entry->list,&data->directory); + list_del(&e->list); pthread_rwlock_unlock(&data->dir_lock); + dir_entry_destroy(e); + return 0; } -bool ipcp_data_is_in_registry(struct ipcp_data * data, - const char * ap_name) +bool ipcp_data_dir_has(struct ipcp_data * data, + const char * name) { bool ret = false; - if (data == NULL || ap_name == NULL) - return false; - - pthread_rwlock_rdlock(&data->reg_lock); + pthread_rwlock_rdlock(&data->dir_lock); - ret = (find_reg_entry_by_name(data, ap_name) != NULL); + ret = (find_dir_entry_any(data, name) != NULL); - pthread_rwlock_unlock(&data->reg_lock); + pthread_rwlock_unlock(&data->dir_lock); return ret; } -uint64_t ipcp_data_get_addr(struct ipcp_data * data, - const char * ap_name) +uint64_t ipcp_data_dir_get_addr(struct ipcp_data * data, + const char * name) { struct dir_entry * entry; uint64_t addr; pthread_rwlock_rdlock(&data->dir_lock); - entry = find_dir_entry_any(data, ap_name); + entry = find_dir_entry_any(data, name); if (entry == NULL) { pthread_rwlock_unlock(&data->dir_lock); @@ -386,3 +413,122 @@ uint64_t ipcp_data_get_addr(struct ipcp_data * data, return addr; } + +struct dir_query * ipcp_data_dir_query_create(char * name) +{ + struct dir_query * query; + pthread_condattr_t cattr; + + query = malloc(sizeof(*query)); + if (query == NULL) + return NULL; + + query->name = strdup(name); + if (query->name == NULL) { + free(query); + return NULL; + } + + query->state = QUERY_INIT; + + pthread_condattr_init(&cattr); +#ifndef __APPLE__ + pthread_condattr_setclock(&cattr, PTHREAD_COND_CLOCK); +#endif + pthread_cond_init(&query->cond, &cattr); + pthread_mutex_init(&query->lock, NULL); + + INIT_LIST_HEAD(&query->next); + + return query; +} + +void ipcp_data_dir_query_respond(struct dir_query * query) +{ + assert(query); + + pthread_mutex_lock(&query->lock); + + if (query->state != QUERY_PENDING) { + pthread_mutex_unlock(&query->lock); + return; + } + + query->state = QUERY_RESPONSE; + pthread_cond_broadcast(&query->cond); + + while (query->state == QUERY_RESPONSE) + pthread_cond_wait(&query->cond, &query->lock); + + pthread_mutex_unlock(&query->lock); +} + +void ipcp_data_dir_query_destroy(struct dir_query * query) +{ + assert(query); + + pthread_mutex_lock(&query->lock); + + if (query->state == QUERY_DESTROY) { + pthread_mutex_unlock(&query->lock); + return; + } + + if (query->state == QUERY_INIT) + query->state = QUERY_DONE; + + if (query->state == QUERY_PENDING) { + query->state = QUERY_DESTROY; + pthread_cond_broadcast(&query->cond); + } + + while (query->state != QUERY_DONE) + pthread_cond_wait(&query->cond, &query->lock); + + pthread_mutex_unlock(&query->lock); + + pthread_cond_destroy(&query->cond); + pthread_mutex_destroy(&query->lock); + + free(query->name); + free(query); +} + +int ipcp_data_dir_query_wait(struct dir_query * query, + const struct timespec * timeout) +{ + struct timespec abstime; + int ret = 0; + + assert(query); + assert(timeout); + + clock_gettime(PTHREAD_COND_CLOCK, &abstime); + ts_add(&abstime, timeout, &abstime); + + pthread_mutex_lock(&query->lock); + + if (query->state != QUERY_INIT) { + pthread_mutex_unlock(&query->lock); + return -EINVAL; + } + + query->state = QUERY_PENDING; + + while (query->state == QUERY_PENDING) { + if ((ret = -pthread_cond_timedwait(&query->cond, + &query->lock, + &abstime)) == -ETIMEDOUT) + break; + } + + if (query->state == QUERY_DESTROY) + ret = -1; + + query->state = QUERY_DONE; + pthread_cond_broadcast(&query->cond); + + pthread_mutex_unlock(&query->lock); + + return ret; +} diff --git a/src/ipcpd/ipcp-data.h b/src/ipcpd/ipcp-data.h index 4472a1d7..5263b156 100644 --- a/src/ipcpd/ipcp-data.h +++ b/src/ipcpd/ipcp-data.h @@ -26,10 +26,28 @@ #include <ouroboros/shared.h> #include <ouroboros/list.h> + +#include "ipcp-ops.h" + #include <sys/types.h> #include <pthread.h> -#include "ipcp-ops.h" +enum dir_query_state { + QUERY_INIT = 0, + QUERY_PENDING, + QUERY_RESPONSE, + QUERY_DONE, + QUERY_DESTROY +}; + +struct dir_query { + struct list_head next; + char * name; + enum dir_query_state state; + + pthread_mutex_t lock; + pthread_cond_t cond; +}; struct ipcp_data { enum ipcp_type type; @@ -40,6 +58,9 @@ struct ipcp_data { struct list_head directory; pthread_rwlock_t dir_lock; + + struct list_head dir_queries; + pthread_mutex_t dir_queries_lock; }; struct ipcp_data * ipcp_data_create(void); @@ -49,26 +70,35 @@ struct ipcp_data * ipcp_data_init(struct ipcp_data * dst, void ipcp_data_destroy(struct ipcp_data * data); -int ipcp_data_add_reg_entry(struct ipcp_data * data, +int ipcp_data_reg_add_entry(struct ipcp_data * data, char * name); -int ipcp_data_del_reg_entry(struct ipcp_data * data, +int ipcp_data_reg_del_entry(struct ipcp_data * data, const char * name); -int ipcp_data_add_dir_entry(struct ipcp_data * data, - char * ap_name, +bool ipcp_data_reg_has(struct ipcp_data * data, + const char * name); + +int ipcp_data_dir_add_entry(struct ipcp_data * data, + char * name, uint64_t addr); -int ipcp_data_del_dir_entry(struct ipcp_data * data, - const char * ap_name, +int ipcp_data_dir_del_entry(struct ipcp_data * data, + const char * name, uint64_t addr); -bool ipcp_data_is_in_registry(struct ipcp_data * data, - const char * name); +bool ipcp_data_dir_has(struct ipcp_data * data, + const char * name); + +uint64_t ipcp_data_dir_get_addr(struct ipcp_data * data, + const char * name); + +struct dir_query * ipcp_data_dir_query_create(char * name); + +void ipcp_data_dir_query_respond(struct dir_query * query); -bool ipcp_data_is_in_directory(struct ipcp_data * data, - const char * ap_name); +void ipcp_data_dir_query_destroy(struct dir_query * query); -uint64_t ipcp_data_get_addr(struct ipcp_data * data, - const char * ap_name); +int ipcp_data_dir_query_wait(struct dir_query * query, + const struct timespec * timeout); #endif /* IPCPD_IPCP_DATA_H */ diff --git a/src/ipcpd/ipcp-ops.h b/src/ipcpd/ipcp-ops.h index 815cda09..0b79a328 100644 --- a/src/ipcpd/ipcp-ops.h +++ b/src/ipcpd/ipcp-ops.h @@ -36,6 +36,8 @@ struct ipcp_ops { int (* ipcp_name_unreg)(char * name); + int (* ipcp_name_query)(char * name); + int (* ipcp_flow_alloc)(int fd, char * dst_ap_name, char * src_ae_name, diff --git a/src/ipcpd/ipcp.c b/src/ipcpd/ipcp.c index c2d343f8..90fb94ef 100644 --- a/src/ipcpd/ipcp.c +++ b/src/ipcpd/ipcp.c @@ -20,7 +20,11 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#define OUROBOROS_PREFIX "ipcpd/ipcp" + #include <ouroboros/config.h> +#include <ouroboros/logs.h> #include <ouroboros/time_utils.h> #include <ouroboros/utils.h> #include <ouroboros/sockets.h> @@ -28,13 +32,11 @@ #include <ouroboros/dev.h> #include <ouroboros/np1_flow.h> -#define OUROBOROS_PREFIX "ipcpd/ipcp" -#include <ouroboros/logs.h> +#include "ipcp.h" #include <string.h> #include <sys/socket.h> #include <stdlib.h> -#include "ipcp.h" int ipcp_init(enum ipcp_type type, struct ipcp_ops * ops) { @@ -307,6 +309,15 @@ void * ipcp_main_loop(void * o) ret_msg.result = ipcpi.ops->ipcp_name_unreg(msg->name); break; + case IPCP_MSG_CODE__IPCP_NAME_QUERY: + if (ipcpi.ops->ipcp_name_query == NULL) { + LOG_ERR("Ap_query unsupported."); + break; + } + ret_msg.has_result = true; + ret_msg.result = + ipcpi.ops->ipcp_name_query(msg->name); + break; case IPCP_MSG_CODE__IPCP_FLOW_ALLOC: if (ipcpi.ops->ipcp_flow_alloc == NULL) { LOG_ERR("Flow_alloc unsupported."); diff --git a/src/ipcpd/local/main.c b/src/ipcpd/local/main.c index 347c7f2f..a8d5c273 100644 --- a/src/ipcpd/local/main.c +++ b/src/ipcpd/local/main.c @@ -20,17 +20,18 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#define OUROBOROS_PREFIX "ipcpd/local" + #include <ouroboros/config.h> -#include "ipcp.h" +#include <ouroboros/logs.h> #include <ouroboros/errno.h> #include <ouroboros/dev.h> #include <ouroboros/fcntl.h> #include <ouroboros/fqueue.h> #include <ouroboros/ipcp-dev.h> #include <ouroboros/local-dev.h> -#define OUROBOROS_PREFIX "ipcpd/local" -#include <ouroboros/logs.h> +#include "ipcp.h" #include <string.h> #include <signal.h> @@ -179,7 +180,7 @@ static int ipcp_local_name_reg(char * name) { pthread_rwlock_rdlock(&ipcpi.state_lock); - if (ipcp_data_add_reg_entry(ipcpi.data, name)) { + if (ipcp_data_reg_add_entry(ipcpi.data, name)) { pthread_rwlock_unlock(&ipcpi.state_lock); LOG_DBG("Failed to add %s to local registry.", name); return -1; @@ -196,7 +197,7 @@ static int ipcp_local_name_unreg(char * name) { pthread_rwlock_rdlock(&ipcpi.state_lock); - ipcp_data_del_reg_entry(ipcpi.data, name); + ipcp_data_reg_del_entry(ipcpi.data, name); pthread_rwlock_unlock(&ipcpi.state_lock); @@ -205,6 +206,19 @@ static int ipcp_local_name_unreg(char * name) return 0; } +static int ipcp_local_name_query(char * name) +{ + int ret; + + pthread_rwlock_rdlock(&ipcpi.state_lock); + + ret = (ipcp_data_reg_has(ipcpi.data, name) ? 0 : -1); + + pthread_rwlock_unlock(&ipcpi.state_lock); + + return ret; +} + static int ipcp_local_flow_alloc(int fd, char * dst_name, char * src_ae_name, @@ -305,6 +319,7 @@ static struct ipcp_ops local_ops = { .ipcp_enroll = NULL, /* shim */ .ipcp_name_reg = ipcp_local_name_reg, .ipcp_name_unreg = ipcp_local_name_unreg, + .ipcp_name_query = ipcp_local_name_query, .ipcp_flow_alloc = ipcp_local_flow_alloc, .ipcp_flow_alloc_resp = ipcp_local_flow_alloc_resp, .ipcp_flow_dealloc = ipcp_local_flow_dealloc diff --git a/src/ipcpd/normal/main.c b/src/ipcpd/normal/main.c index 32aabdf2..2402972f 100644 --- a/src/ipcpd/normal/main.c +++ b/src/ipcpd/normal/main.c @@ -28,6 +28,11 @@ #include <ouroboros/ipcp-dev.h> #include <ouroboros/time_utils.h> +#include "fmgr.h" +#include "ribmgr.h" +#include "ipcp.h" +#include "frct.h" + #include <stdbool.h> #include <signal.h> #include <stdlib.h> @@ -35,11 +40,6 @@ #include <string.h> #include <errno.h> -#include "fmgr.h" -#include "ribmgr.h" -#include "ipcp.h" -#include "frct.h" - #define THIS_TYPE IPCP_NORMAL /* global for trapping signal */ @@ -72,7 +72,7 @@ static int normal_ipcp_name_reg(char * name) { pthread_rwlock_rdlock(&ipcpi.state_lock); - if (ipcp_data_add_reg_entry(ipcpi.data, name)) { + if (ipcp_data_reg_add_entry(ipcpi.data, name)) { pthread_rwlock_unlock(&ipcpi.state_lock); LOG_ERR("Failed to add %s to local registry.", name); return -1; @@ -89,13 +89,28 @@ static int normal_ipcp_name_unreg(char * name) { pthread_rwlock_rdlock(&ipcpi.state_lock); - ipcp_data_del_reg_entry(ipcpi.data, name); + ipcp_data_reg_del_entry(ipcpi.data, name); pthread_rwlock_unlock(&ipcpi.state_lock); return 0; } +static int normal_ipcp_name_query(char * name) +{ + LOG_MISSING; + + (void) name; + + /* + * NOTE: For the moment we just return -1, + * for testing purposes we may return zero here + * for certain names. + */ + + return -1; +} + static int normal_ipcp_enroll(char * dif_name) { struct timespec timeout = {(ENROLL_TIMEOUT / 1000), @@ -165,6 +180,7 @@ static struct ipcp_ops normal_ops = { .ipcp_enroll = normal_ipcp_enroll, .ipcp_name_reg = normal_ipcp_name_reg, .ipcp_name_unreg = normal_ipcp_name_unreg, + .ipcp_name_query = normal_ipcp_name_query, .ipcp_flow_alloc = fmgr_np1_alloc, .ipcp_flow_alloc_resp = fmgr_np1_alloc_resp, .ipcp_flow_dealloc = fmgr_np1_dealloc diff --git a/src/ipcpd/shim-eth-llc/main.c b/src/ipcpd/shim-eth-llc/main.c index 6046d939..f6cded2b 100644 --- a/src/ipcpd/shim-eth-llc/main.c +++ b/src/ipcpd/shim-eth-llc/main.c @@ -20,10 +20,11 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include <ouroboros/config.h> - #define _DEFAULT_SOURCE +#define OUROBOROS_PREFIX "ipcpd/shim-eth-llc" + +#include <ouroboros/config.h> #include <ouroboros/errno.h> #include <ouroboros/list.h> #include <ouroboros/utils.h> @@ -32,12 +33,10 @@ #include <ouroboros/ipcp-dev.h> #include <ouroboros/fcntl.h> #include <ouroboros/fqueue.h> - -#define OUROBOROS_PREFIX "ipcpd/shim-eth-llc" - #include <ouroboros/logs.h> #include "ipcp.h" +#include "shim_eth_llc_messages.pb-c.h" #include <net/if.h> #include <signal.h> @@ -65,8 +64,6 @@ #include <poll.h> #include <sys/mman.h> -#include "shim_eth_llc_messages.pb-c.h" - typedef ShimEthLlcMsg shim_eth_llc_msg_t; #define THIS_TYPE IPCP_SHIM_ETH_LLC @@ -80,6 +77,7 @@ typedef ShimEthLlcMsg shim_eth_llc_msg_t; + SHIM_ETH_LLC_MAX_SDU_SIZE) #define EVENT_WAIT_TIMEOUT 100 /* us */ +#define NAME_QUERY_TIMEOUT 100000000 /* ns */ /* global for trapping signal */ int irmd_api; @@ -115,6 +113,7 @@ struct { int tx_offset; #endif flow_set_t * np1_flows; + fqueue_t * fq; int * ef_to_fd; struct ef * fd_to_ef; pthread_rwlock_t flows_lock; @@ -152,6 +151,15 @@ static int eth_llc_data_init(void) return -ENOMEM; } + eth_llc_data.fq = fqueue_create(); + if (eth_llc_data.fq == NULL) { + flow_set_destroy(eth_llc_data.np1_flows); + bmp_destroy(eth_llc_data.saps); + free(eth_llc_data.ef_to_fd); + free(eth_llc_data.fd_to_ef); + return -ENOMEM; + } + for (i = 0; i < MAX_SAPS; ++i) eth_llc_data.ef_to_fd[i] = -1; @@ -170,6 +178,7 @@ void eth_llc_data_fini(void) { bmp_destroy(eth_llc_data.saps); flow_set_destroy(eth_llc_data.np1_flows); + fqueue_destroy(eth_llc_data.fq); free(eth_llc_data.fd_to_ef); free(eth_llc_data.ef_to_fd); pthread_rwlock_destroy(ð_llc_data.flows_lock); @@ -313,6 +322,7 @@ static int eth_llc_ipcp_sap_alloc(uint8_t * dst_addr, shim_eth_llc_msg_t msg = SHIM_ETH_LLC_MSG__INIT; msg.code = SHIM_ETH_LLC_MSG_CODE__FLOW_REQ; + msg.has_ssap = true; msg.ssap = ssap; msg.dst_name = dst_name; msg.src_ae_name = src_ae_name; @@ -328,6 +338,7 @@ static int eth_llc_ipcp_sap_alloc_resp(uint8_t * dst_addr, shim_eth_llc_msg_t msg = SHIM_ETH_LLC_MSG__INIT; msg.code = SHIM_ETH_LLC_MSG_CODE__FLOW_REPLY; + msg.has_ssap = true; msg.ssap = ssap; msg.has_dsap = true; msg.dsap = dsap; @@ -341,8 +352,9 @@ static int eth_llc_ipcp_sap_dealloc(uint8_t * dst_addr, uint8_t ssap) { shim_eth_llc_msg_t msg = SHIM_ETH_LLC_MSG__INIT; - msg.code = SHIM_ETH_LLC_MSG_CODE__FLOW_DEALLOC; - msg.ssap = ssap; + msg.code = SHIM_ETH_LLC_MSG_CODE__FLOW_DEALLOC; + msg.has_ssap = true; + msg.ssap = ssap; return eth_llc_ipcp_send_mgmt_frame(&msg, dst_addr); } @@ -438,6 +450,42 @@ static int eth_llc_ipcp_flow_dealloc_req(uint8_t ssap) return 0; } +static int eth_llc_ipcp_name_query_req(char * name, uint8_t * r_addr) +{ + shim_eth_llc_msg_t msg = SHIM_ETH_LLC_MSG__INIT; + + if (ipcp_data_reg_has(ipcpi.data, name)) { + msg.code = SHIM_ETH_LLC_MSG_CODE__NAME_QUERY_REPLY; + msg.dst_name = name; + + eth_llc_ipcp_send_mgmt_frame(&msg, r_addr); + } + + return 0; +} + +static int eth_llc_ipcp_name_query_reply(char * name, uint8_t * r_addr) +{ + uint64_t address = 0; + struct list_head * pos; + + memcpy(&address, r_addr, MAC_SIZE); + + ipcp_data_dir_add_entry(ipcpi.data, name, address); + + pthread_mutex_lock(&ipcpi.data->dir_queries_lock); + list_for_each(pos, &ipcpi.data->dir_queries) { + struct dir_query * e = + list_entry(pos, struct dir_query, next); + if (strcmp(e->name, name) == 0) { + ipcp_data_dir_query_respond(e); + } + } + pthread_mutex_unlock(&ipcpi.data->dir_queries_lock); + + return 0; +} + static int eth_llc_ipcp_mgmt_frame(uint8_t * buf, size_t len, uint8_t * r_addr) { shim_eth_llc_msg_t * msg = shim_eth_llc_msg__unpack(NULL, len, buf); @@ -448,7 +496,7 @@ static int eth_llc_ipcp_mgmt_frame(uint8_t * buf, size_t len, uint8_t * r_addr) switch (msg->code) { case SHIM_ETH_LLC_MSG_CODE__FLOW_REQ: - if (ipcp_data_is_in_registry(ipcpi.data, msg->dst_name)) { + if (ipcp_data_reg_has(ipcpi.data, msg->dst_name)) { eth_llc_ipcp_sap_req(msg->ssap, r_addr, msg->dst_name, @@ -464,6 +512,12 @@ static int eth_llc_ipcp_mgmt_frame(uint8_t * buf, size_t len, uint8_t * r_addr) case SHIM_ETH_LLC_MSG_CODE__FLOW_DEALLOC: eth_llc_ipcp_flow_dealloc_req(msg->ssap); break; + case SHIM_ETH_LLC_MSG_CODE__NAME_QUERY_REQ: + eth_llc_ipcp_name_query_req(msg->dst_name, r_addr); + break; + case SHIM_ETH_LLC_MSG_CODE__NAME_QUERY_REPLY: + eth_llc_ipcp_name_query_reply(msg->dst_name, r_addr); + break; default: LOG_ERR("Unknown message received %d.", msg->code); shim_eth_llc_msg__free_unpacked(msg, NULL); @@ -605,20 +659,16 @@ static void * eth_llc_ipcp_sdu_writer(void * o) uint8_t dsap; uint8_t r_addr[MAC_SIZE]; struct timespec timeout = {0, EVENT_WAIT_TIMEOUT * 1000}; - fqueue_t * fq = fqueue_create(); - if (fq == NULL) - return (void *) 1; (void) o; while (true) { - int ret = flow_event_wait(eth_llc_data.np1_flows, fq, &timeout); - if (ret == -ETIMEDOUT) + if (flow_event_wait(eth_llc_data.np1_flows, + eth_llc_data.fq, + &timeout) == -ETIMEDOUT) continue; - assert(!ret); - - while ((fd = fqueue_next(fq)) >= 0) { + while ((fd = fqueue_next(eth_llc_data.fq)) >= 0) { if (ipcp_flow_read(fd, &sdb)) { LOG_ERR("Bad read from fd %d.", fd); continue; @@ -686,13 +736,11 @@ static int eth_llc_ipcp_bootstrap(struct dif_config * conf) struct tpacket_req req; #endif - if (conf == NULL) - return -1; /* -EINVAL */ + assert(conf); + assert(conf->type == THIS_TYPE); - if (conf->type != THIS_TYPE) { - LOG_ERR("Config doesn't match IPCP type."); - return -1; - } + /* this IPCP doesn't need to maintain its dif_name */ + free(conf->dif_name); if (conf->if_name == NULL) { LOG_ERR("Interface name is NULL."); @@ -854,7 +902,7 @@ static int eth_llc_ipcp_name_reg(char * name) { pthread_rwlock_rdlock(&ipcpi.state_lock); - if (ipcp_data_add_reg_entry(ipcpi.data, name)) { + if (ipcp_data_reg_add_entry(ipcpi.data, name)) { pthread_rwlock_unlock(&ipcpi.state_lock); LOG_ERR("Failed to add %s to local registry.", name); return -1; @@ -871,13 +919,49 @@ static int eth_llc_ipcp_name_unreg(char * name) { pthread_rwlock_rdlock(&ipcpi.state_lock); - ipcp_data_del_reg_entry(ipcpi.data, name); + ipcp_data_reg_del_entry(ipcpi.data, name); pthread_rwlock_unlock(&ipcpi.state_lock); return 0; } +static int eth_llc_ipcp_name_query(char * name) +{ + uint8_t r_addr[MAC_SIZE]; + struct timespec timeout = {0, NAME_QUERY_TIMEOUT}; + shim_eth_llc_msg_t msg = SHIM_ETH_LLC_MSG__INIT; + struct dir_query * query; + int ret; + + if (ipcp_data_dir_has(ipcpi.data, name)) + return 0; + + msg.code = SHIM_ETH_LLC_MSG_CODE__NAME_QUERY_REQ; + msg.dst_name = name; + + memset(r_addr, 0xff, MAC_SIZE); + + query = ipcp_data_dir_query_create(name); + if (query == NULL) + return -1; + + pthread_mutex_lock(&ipcpi.data->dir_queries_lock); + list_add(&query->next, &ipcpi.data->dir_queries); + pthread_mutex_unlock(&ipcpi.data->dir_queries_lock); + + eth_llc_ipcp_send_mgmt_frame(&msg, r_addr); + + ret = ipcp_data_dir_query_wait(query, &timeout); + + pthread_mutex_lock(&ipcpi.data->dir_queries_lock); + list_del(&query->next); + ipcp_data_dir_query_destroy(query); + pthread_mutex_unlock(&ipcpi.data->dir_queries_lock); + + return ret; +} + static int eth_llc_ipcp_flow_alloc(int fd, char * dst_name, char * src_ae_name, @@ -885,6 +969,7 @@ static int eth_llc_ipcp_flow_alloc(int fd, { uint8_t ssap = 0; uint8_t r_addr[MAC_SIZE]; + uint64_t addr = 0; LOG_DBG("Allocating flow to %s.", dst_name); @@ -902,6 +987,13 @@ static int eth_llc_ipcp_flow_alloc(int fd, return -1; /* -ENOTENROLLED */ } + if (!ipcp_data_dir_has(ipcpi.data, dst_name)) { + pthread_rwlock_unlock(&ipcpi.state_lock); + LOG_ERR("Destination unreachable."); + return -1; + } + addr = ipcp_data_dir_get_addr(ipcpi.data, dst_name); + pthread_rwlock_wrlock(ð_llc_data.flows_lock); ssap = bmp_allocate(eth_llc_data.saps); @@ -917,7 +1009,7 @@ static int eth_llc_ipcp_flow_alloc(int fd, pthread_rwlock_unlock(ð_llc_data.flows_lock); pthread_rwlock_unlock(&ipcpi.state_lock); - memset(r_addr, 0xff, MAC_SIZE); + memcpy(r_addr, &addr, MAC_SIZE); if (eth_llc_ipcp_sap_alloc(r_addr, ssap, @@ -1025,6 +1117,7 @@ static struct ipcp_ops eth_llc_ops = { .ipcp_enroll = NULL, .ipcp_name_reg = eth_llc_ipcp_name_reg, .ipcp_name_unreg = eth_llc_ipcp_name_unreg, + .ipcp_name_query = eth_llc_ipcp_name_query, .ipcp_flow_alloc = eth_llc_ipcp_flow_alloc, .ipcp_flow_alloc_resp = eth_llc_ipcp_flow_alloc_resp, .ipcp_flow_dealloc = eth_llc_ipcp_flow_dealloc diff --git a/src/ipcpd/shim-eth-llc/shim_eth_llc_messages.proto b/src/ipcpd/shim-eth-llc/shim_eth_llc_messages.proto index 0e8a1ce2..4d027d98 100644 --- a/src/ipcpd/shim-eth-llc/shim_eth_llc_messages.proto +++ b/src/ipcpd/shim-eth-llc/shim_eth_llc_messages.proto @@ -1,14 +1,16 @@ enum shim_eth_llc_msg_code { - FLOW_REQ = 1; - FLOW_REPLY = 2; - FLOW_DEALLOC = 3; + FLOW_REQ = 1; + FLOW_REPLY = 2; + FLOW_DEALLOC = 3; + NAME_QUERY_REQ = 4; + NAME_QUERY_REPLY = 5; }; message shim_eth_llc_msg { required shim_eth_llc_msg_code code = 1; optional string dst_name = 2; optional string src_ae_name = 3; - required uint32 ssap = 4; + optional uint32 ssap = 4; optional uint32 dsap = 5; optional sint32 response = 6; }; diff --git a/src/ipcpd/shim-udp/main.c b/src/ipcpd/shim-udp/main.c index 62e1b2d0..e06787ce 100644 --- a/src/ipcpd/shim-udp/main.c +++ b/src/ipcpd/shim-udp/main.c @@ -20,9 +20,9 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#define OUROBOROS_PREFIX "ipcpd/shim-udp" + #include <ouroboros/config.h> -#include "ipcp.h" -#include "shim_udp_config.h" #include <ouroboros/list.h> #include <ouroboros/utils.h> #include <ouroboros/dev.h> @@ -30,11 +30,12 @@ #include <ouroboros/fqueue.h> #include <ouroboros/fcntl.h> #include <ouroboros/errno.h> - -#define OUROBOROS_PREFIX "ipcpd/shim-udp" - #include <ouroboros/logs.h> +#include "shim_udp_messages.pb-c.h" +#include "ipcp.h" +#include "shim_udp_config.h" + #include <string.h> #include <sys/socket.h> #include <sys/select.h> @@ -47,8 +48,6 @@ #include <sys/wait.h> #include <fcntl.h> -#include "shim_udp_messages.pb-c.h" - typedef ShimUdpMsg shim_udp_msg_t; #define THIS_TYPE IPCP_SHIM_UDP @@ -79,6 +78,7 @@ struct { int s_fd; flow_set_t * np1_flows; + fqueue_t * fq; fd_set flow_fd_s; /* bidir mappings of (n - 1) file descriptor to (n) flow descriptor */ int uf_to_fd[FD_SETSIZE]; @@ -112,6 +112,12 @@ static int udp_data_init(void) if (udp_data.np1_flows == NULL) return -ENOMEM; + udp_data.fq = fqueue_create(); + if (udp_data.fq == NULL) { + flow_set_destroy(udp_data.np1_flows); + return -ENOMEM; + } + pthread_rwlock_init(&udp_data.flows_lock, NULL); pthread_cond_init(&udp_data.fd_set_cond, NULL); pthread_mutex_init(&udp_data.fd_set_lock, NULL); @@ -122,6 +128,7 @@ static int udp_data_init(void) static void udp_data_fini(void) { flow_set_destroy(udp_data.np1_flows); + fqueue_destroy(udp_data.fq); pthread_rwlock_destroy(&udp_data.flows_lock); pthread_mutex_destroy(&udp_data.fd_set_lock); @@ -523,23 +530,16 @@ static void * ipcp_udp_sdu_loop(void * o) int fd; struct timespec timeout = {0, FD_UPDATE_TIMEOUT * 1000}; struct shm_du_buff * sdb; - fqueue_t * fq = fqueue_create(); - if (fq == NULL) - return (void *) 1; (void) o; while (true) { - int ret = flow_event_wait(udp_data.np1_flows, fq, &timeout); - if (ret == -ETIMEDOUT) + if (flow_event_wait(udp_data.np1_flows, + udp_data.fq, + &timeout) == -ETIMEDOUT) continue; - if (ret < 0) { - LOG_ERR("Event wait returned error code %d.", -ret); - continue; - } - - while ((fd = fqueue_next(fq)) >= 0) { + while ((fd = fqueue_next(udp_data.fq)) >= 0) { if (ipcp_flow_read(fd, &sdb)) { LOG_ERR("Bad read from fd %d.", fd); continue; @@ -594,13 +594,11 @@ static int ipcp_udp_bootstrap(struct dif_config * conf) int enable = 1; int fd = -1; - if (conf == NULL) - return -1; /* -EINVAL */ + assert(conf); + assert(conf->type == THIS_TYPE); - if (conf->type != THIS_TYPE) { - LOG_ERR("Config doesn't match IPCP type."); - return -1; - } + /* this IPCP doesn't need to maintain its dif_name */ + free(conf->dif_name); if (inet_ntop(AF_INET, &conf->ip_addr, @@ -833,7 +831,7 @@ static int ipcp_udp_name_reg(char * name) pthread_rwlock_rdlock(&ipcpi.state_lock); - if (ipcp_data_add_reg_entry(ipcpi.data, name)) { + if (ipcp_data_reg_add_entry(ipcpi.data, name)) { pthread_rwlock_unlock(&ipcpi.state_lock); LOG_ERR("Failed to add %s to local registry.", name); return -1; @@ -864,7 +862,7 @@ static int ipcp_udp_name_reg(char * name) if (ddns_send(cmd)) { pthread_rwlock_rdlock(&ipcpi.state_lock); - ipcp_data_del_reg_entry(ipcpi.data, name); + ipcp_data_reg_del_entry(ipcpi.data, name); pthread_rwlock_unlock(&ipcpi.state_lock); return -1; } @@ -885,7 +883,6 @@ static int ipcp_udp_name_unreg(char * name) char cmd[100]; uint32_t dns_addr; #endif - if (strlen(name) > 24) { LOG_ERR("DNS names cannot be longer than 24 chars."); return -1; @@ -914,7 +911,74 @@ static int ipcp_udp_name_unreg(char * name) pthread_rwlock_rdlock(&ipcpi.state_lock); - ipcp_data_del_reg_entry(ipcpi.data, name); + ipcp_data_reg_del_entry(ipcpi.data, name); + + pthread_rwlock_unlock(&ipcpi.state_lock); + + return 0; +} + +static int ipcp_udp_name_query(char * name) +{ + uint32_t ip_addr = 0; + struct hostent * h; +#ifdef CONFIG_OUROBOROS_ENABLE_DNS + uint32_t dns_addr = 0; +#endif + + assert(name); + + if (strlen(name) > 24) { + LOG_ERR("DNS names cannot be longer than 24 chars."); + return -1; + } + + pthread_rwlock_rdlock(&ipcpi.state_lock); + + if (ipcp_get_state() != IPCP_ENROLLED) { + pthread_rwlock_unlock(&ipcpi.state_lock); + LOG_DBG("Won't query a name on a non-enrolled IPCP."); + return -1; /* -ENOTENROLLED */ + } + +#ifdef CONFIG_OUROBOROS_ENABLE_DNS + dns_addr = udp_data.dns_addr; + + if (dns_addr != 0) { + pthread_rwlock_unlock(&ipcpi.state_lock); + + ip_addr = ddns_resolve(name, dns_addr); + if (ip_addr == 0) { + LOG_DBG("Could not resolve %s.", name); + return -1; + } + + pthread_rwlock_rdlock(&ipcpi.state_lock); + + if (ipcp_get_state() != IPCP_ENROLLED) { + pthread_rwlock_unlock(&ipcpi.state_lock); + LOG_DBG("Won't add name to the directory."); + return -1; /* -ENOTENROLLED */ + } + } else { +#endif + h = gethostbyname(name); + if (h == NULL) { + pthread_rwlock_unlock(&ipcpi.state_lock); + LOG_DBG("Could not resolve %s.", name); + return -1; + } + + ip_addr = *((uint32_t *) (h->h_addr_list[0])); +#ifdef CONFIG_OUROBOROS_ENABLE_DNS + } +#endif + + if (ipcp_data_dir_add_entry(ipcpi.data, name, ip_addr)) { + pthread_rwlock_unlock(&ipcpi.state_lock); + LOG_ERR("Failed to add directory entry."); + return -1; + } pthread_rwlock_unlock(&ipcpi.state_lock); @@ -930,15 +994,13 @@ static int ipcp_udp_flow_alloc(int fd, struct sockaddr_in f_saddr; /* flow */ socklen_t f_saddr_len = sizeof(f_saddr); int skfd; - struct hostent * h; uint32_t ip_addr = 0; -#ifdef CONFIG_OUROBOROS_ENABLE_DNS - uint32_t dns_addr = 0; -#endif + LOG_DBG("Allocating flow to %s.", dst_name); if (dst_name == NULL || src_ae_name == NULL) return -1; + if (strlen(dst_name) > 255 || strlen(src_ae_name) > 255) { LOG_ERR("Name too long for this shim."); @@ -976,39 +1038,13 @@ static int ipcp_udp_flow_alloc(int fd, return -1; /* -ENOTENROLLED */ } -#ifdef CONFIG_OUROBOROS_ENABLE_DNS - dns_addr = udp_data.dns_addr; - - if (dns_addr != 0) { + if (!ipcp_data_dir_has(ipcpi.data, dst_name)) { pthread_rwlock_unlock(&ipcpi.state_lock); - - ip_addr = ddns_resolve(dst_name, dns_addr); - if (ip_addr == 0) { - LOG_DBG("Could not resolve %s.", dst_name); - close(fd); - return -1; - } - - pthread_rwlock_rdlock(&ipcpi.state_lock); - if (ipcp_get_state() != IPCP_ENROLLED) { - pthread_rwlock_unlock(&ipcpi.state_lock); - LOG_DBG("Won't allocate flow with non-enrolled IPCP."); - close(skfd); - return -1; /* -ENOTENROLLED */ - } - } else { -#endif - h = gethostbyname(dst_name); - if (h == NULL) { - LOG_DBG("Could not resolve %s.", dst_name); - close(skfd); - return -1; - } - - ip_addr = *((uint32_t *) (h->h_addr_list[0])); -#ifdef CONFIG_OUROBOROS_ENABLE_DNS + LOG_DBG("Could not resolve destination."); + close(skfd); + return -1; } -#endif + ip_addr = (uint32_t) ipcp_data_dir_get_addr(ipcpi.data, dst_name); /* connect to server (store the remote IP address in the fd) */ memset((char *) &r_saddr, 0, sizeof(r_saddr)); @@ -1171,6 +1207,7 @@ static struct ipcp_ops udp_ops = { .ipcp_enroll = NULL, /* shim */ .ipcp_name_reg = ipcp_udp_name_reg, .ipcp_name_unreg = ipcp_udp_name_unreg, + .ipcp_name_query = ipcp_udp_name_query, .ipcp_flow_alloc = ipcp_udp_flow_alloc, .ipcp_flow_alloc_resp = ipcp_udp_flow_alloc_resp, .ipcp_flow_dealloc = ipcp_udp_flow_dealloc |