diff options
Diffstat (limited to 'src/ipcpd/shim-eth-llc/main.c')
-rw-r--r-- | src/ipcpd/shim-eth-llc/main.c | 147 |
1 files changed, 120 insertions, 27 deletions
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 |