summaryrefslogtreecommitdiff
path: root/src/ipcpd/shim-eth-llc/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/ipcpd/shim-eth-llc/main.c')
-rw-r--r--src/ipcpd/shim-eth-llc/main.c147
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(&eth_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(&eth_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(&eth_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