diff options
-rw-r--r-- | src/ipcpd/shim-eth-llc/main.c | 63 |
1 files changed, 42 insertions, 21 deletions
diff --git a/src/ipcpd/shim-eth-llc/main.c b/src/ipcpd/shim-eth-llc/main.c index 142ca680..34a25ee2 100644 --- a/src/ipcpd/shim-eth-llc/main.c +++ b/src/ipcpd/shim-eth-llc/main.c @@ -96,6 +96,13 @@ struct ef { uint8_t r_addr[MAC_SIZE]; }; +struct mgmt_frame { + struct list_head next; + uint8_t r_addr[MAC_SIZE]; + uint8_t buf[ETH_FRAME_SIZE]; + size_t len; +}; + struct { #ifdef __FreeBSD__ struct sockaddr_dl device; @@ -118,10 +125,8 @@ struct { pthread_t mgmt_handler; pthread_mutex_t mgmt_lock; pthread_cond_t mgmt_cond; - uint8_t mgmt_r_addr[MAC_SIZE]; - uint8_t mgmt_buf[ETH_FRAME_SIZE]; - size_t mgmt_len; - bool mgmt_arrived; + struct list_head mgmt_frames; + } eth_llc_data; static int eth_llc_data_init(void) @@ -183,6 +188,8 @@ static int eth_llc_data_init(void) if (pthread_cond_init(ð_llc_data.mgmt_cond, &cattr)) goto mgmt_lock_destroy; + list_head_init(ð_llc_data.mgmt_frames); + return 0; mgmt_lock_destroy: @@ -488,10 +495,11 @@ static int eth_llc_ipcp_mgmt_frame(uint8_t * buf, static void * eth_llc_ipcp_mgmt_handler(void * o) { - int ret; - struct timespec timeout = {(MGMT_TIMEOUT / 1000), - (MGMT_TIMEOUT % 1000) * MILLION}; - struct timespec abstime; + int ret; + struct timespec timeout = {(MGMT_TIMEOUT / 1000), + (MGMT_TIMEOUT % 1000) * MILLION}; + struct timespec abstime; + struct mgmt_frame * frame; (void) o; @@ -506,7 +514,8 @@ static void * eth_llc_ipcp_mgmt_handler(void * o) pthread_mutex_lock(ð_llc_data.mgmt_lock); - while (!eth_llc_data.mgmt_arrived && ret != -ETIMEDOUT) + while (list_is_empty(ð_llc_data.mgmt_frames) && + ret != -ETIMEDOUT) ret = -pthread_cond_timedwait(ð_llc_data.mgmt_cond, ð_llc_data.mgmt_lock, &abstime); @@ -516,10 +525,18 @@ static void * eth_llc_ipcp_mgmt_handler(void * o) continue; } - eth_llc_ipcp_mgmt_frame(eth_llc_data.mgmt_buf, - eth_llc_data.mgmt_len, - eth_llc_data.mgmt_r_addr); - eth_llc_data.mgmt_arrived = false; + frame = list_first_entry((ð_llc_data.mgmt_frames), + struct mgmt_frame, next); + if (frame == NULL) { + pthread_mutex_unlock(ð_llc_data.mgmt_lock); + continue; + } + + eth_llc_ipcp_mgmt_frame(frame->buf, frame->len, frame->r_addr); + + list_del(&frame->next); + free(frame); + pthread_mutex_unlock(ð_llc_data.mgmt_lock); } } @@ -534,6 +551,7 @@ static void * eth_llc_ipcp_sdu_reader(void * o) uint8_t buf[ETH_FRAME_SIZE]; int frame_len = 0; struct eth_llc_frame * llc_frame; + struct mgmt_frame * frame; (void) o; @@ -573,14 +591,17 @@ static void * eth_llc_ipcp_sdu_reader(void * o) if (ssap == MGMT_SAP && dsap == MGMT_SAP) { pthread_mutex_lock(ð_llc_data.mgmt_lock); - memcpy(eth_llc_data.mgmt_buf, - &llc_frame->payload, - length); - memcpy(eth_llc_data.mgmt_r_addr, - llc_frame->src_hwaddr, - MAC_SIZE); - eth_llc_data.mgmt_len = length; - eth_llc_data.mgmt_arrived = true; + + frame = malloc(sizeof(*frame)); + if (frame == NULL) { + pthread_mutex_unlock(ð_llc_data.mgmt_lock); + continue; + } + + memcpy(frame->buf, &llc_frame->payload, length); + memcpy(frame->r_addr, llc_frame->src_hwaddr, MAC_SIZE); + frame->len = length; + list_add(&frame->next, ð_llc_data.mgmt_frames); pthread_cond_signal(ð_llc_data.mgmt_cond); pthread_mutex_unlock(ð_llc_data.mgmt_lock); } else { |