From c31cf5d383638f3c2cde790f0ade12b726ab09aa Mon Sep 17 00:00:00 2001 From: Denis Kenzior Date: Tue, 1 May 2018 11:01:51 -0500 Subject: [PATCH] eapol: Fully separate eapol transport details With the introduction of Control Port Over NL80211 feature, the transport details need to be moved out of eapol and into netdev.c. Whether a given WiFi hardware supports transfer of Control Port packets over NL80211 is Wiphy and kernel version related, so the transport decisions need to be made elsewhere. --- src/ap.c | 8 +-- src/eapol.c | 168 ++++++++------------------------------------------- src/eapol.h | 20 +++--- src/netdev.c | 5 -- 4 files changed, 37 insertions(+), 164 deletions(-) diff --git a/src/ap.c b/src/ap.c index 6a674a54..3c9f7401 100644 --- a/src/ap.c +++ b/src/ap.c @@ -375,8 +375,8 @@ static void ap_send_ptk_1_of_4(struct ap_state *ap, struct sta_state *sta) ek->header.packet_len = L_CPU_TO_BE16(sizeof(struct eapol_key) + L_BE16_TO_CPU(ek->key_data_len) - 4); - eapol_tx_frame(ifindex, ETH_P_PAE, sta->addr, - (struct eapol_frame *) ek); + __eapol_tx_packet(ifindex, sta->addr, ETH_P_PAE, + (struct eapol_frame *) ek, false); } static void ap_ptk_1_of_4_retry(struct l_timeout *timeout, void *user_data) @@ -451,8 +451,8 @@ static void ap_send_ptk_3_of_4(struct ap_state *ap, struct sta_state *sta) if (!eapol_calculate_mic(ptk->kck, ek, ek->key_mic_data)) return; - eapol_tx_frame(ifindex, ETH_P_PAE, sta->addr, - (struct eapol_frame *) ek); + __eapol_tx_packet(ifindex, sta->addr, ETH_P_PAE, + (struct eapol_frame *) ek, false); } static void ap_ptk_3_of_4_retry(struct l_timeout *timeout, void *user_data) diff --git a/src/eapol.c b/src/eapol.c index 2c3de1b7..fefb3fdc 100644 --- a/src/eapol.c +++ b/src/eapol.c @@ -25,14 +25,7 @@ #endif #include -#include -#include -#include -#include -#include #include -#include -#include #include #include "crypto.h" @@ -52,129 +45,11 @@ static uint32_t eapol_4way_handshake_time = 2; eapol_deauthenticate_func_t deauthenticate = NULL; eapol_rekey_offload_func_t rekey_offload = NULL; -static struct l_io *pae_io; eapol_tx_packet_func_t tx_packet = NULL; void *tx_user_data; uint32_t next_frame_watch_id; -/* - * BPF filter to match skb->dev->type == 1 (ARPHRD_ETHER) and - * match skb->protocol == 0x888e (PAE) or 0x88c7 (preauthentication). - */ -static struct sock_filter pae_filter[] = { - { 0x28, 0, 0, 0xfffff01c }, /* ldh #hatype */ - { 0x15, 0, 4, 0x00000001 }, /* jne #1, drop */ - { 0x28, 0, 0, 0xfffff000 }, /* ldh #proto */ - { 0x15, 1, 0, 0x0000888e }, /* je #0x888e, keep */ - { 0x15, 0, 1, 0x000088c7 }, /* jne #0x88c7, drop */ - { 0x06, 0, 0, 0xffffffff }, /* keep: ret #-1 */ - { 0x06, 0, 0, 0000000000 }, /* drop: ret #0 */ -}; - -static const struct sock_fprog pae_fprog = { .len = 7, .filter = pae_filter }; - -static struct l_io *pae_open(void) -{ - struct l_io *io; - int fd; - - fd = socket(PF_PACKET, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, - htons(ETH_P_ALL)); - if (fd < 0) - return NULL; - - if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, - &pae_fprog, sizeof(pae_fprog)) < 0) { - close(fd); - return NULL; - } - - io = l_io_new(fd); - l_io_set_close_on_destroy(io, true); - - return io; -} - -static bool pae_read(struct l_io *io, void *user_data) -{ - int fd = l_io_get_fd(io); - struct sockaddr_ll sll; - socklen_t sll_len; - ssize_t bytes; - uint8_t frame[IEEE80211_MAX_DATA_LEN]; - - memset(&sll, 0, sizeof(sll)); - sll_len = sizeof(sll); - - bytes = recvfrom(fd, frame, sizeof(frame), 0, - (struct sockaddr *) &sll, &sll_len); - if (bytes <= 0) { - l_error("EAPoL read socket: %s", strerror(errno)); - return false; - } - - if (sll.sll_halen != ETH_ALEN) - return true; - - __eapol_rx_packet(sll.sll_ifindex, sll.sll_addr, - ntohs(sll.sll_protocol), frame, bytes); - - return true; -} - -static void pae_destroy() -{ - pae_io = NULL; -} - -static void pae_write(uint32_t ifindex, const uint8_t *aa, const uint8_t *spa, - uint16_t proto, const struct eapol_frame *ef) -{ - size_t frame_size; - struct sockaddr_ll sll; - ssize_t r; - int fd; - - if (!pae_io) { - if (tx_packet) /* Used for unit tests */ - tx_packet(ifindex, aa, spa, ef, tx_user_data); - - return; - } - - fd = l_io_get_fd(pae_io); - - memset(&sll, 0, sizeof(sll)); - sll.sll_family = AF_PACKET; - sll.sll_ifindex = ifindex; - sll.sll_protocol = htons(proto); - sll.sll_halen = ETH_ALEN; - memcpy(sll.sll_addr, aa, ETH_ALEN); - - frame_size = sizeof(struct eapol_header) + - L_BE16_TO_CPU(ef->header.packet_len); - - r = sendto(fd, ef, frame_size, 0, - (struct sockaddr *) &sll, sizeof(sll)); - if (r < 0) - l_error("EAPoL write socket: %s", strerror(errno)); -} - -void eapol_pae_open() -{ - pae_io = pae_open(); - if (!pae_io) - return; - - l_io_set_read_handler(pae_io, pae_read, NULL, pae_destroy); -} - -void eapol_pae_close() -{ - l_io_destroy(pae_io); -} - #define VERIFY_IS_ZERO(field) \ do { \ if (!util_mem_is_zero((field), sizeof((field)))) \ @@ -856,6 +731,13 @@ void eapol_sm_set_event_func(struct eapol_sm *sm, eapol_sm_event_func_t func) sm->event_func = func; } +static void eapol_sm_write(struct eapol_sm *sm, const struct eapol_frame *ef, + bool noencrypt) +{ + __eapol_tx_packet(sm->handshake->ifindex, sm->handshake->aa, ETH_P_PAE, + ef, noencrypt); +} + static inline void handshake_failed(struct eapol_sm *sm, uint16_t reason_code) { if (deauthenticate) @@ -876,12 +758,6 @@ static void eapol_timeout(struct l_timeout *timeout, void *user_data) handshake_failed(sm, MMPDU_REASON_CODE_4WAY_HANDSHAKE_TIMEOUT); } -static void eapol_write(struct eapol_sm *sm, const struct eapol_frame *ef) -{ - pae_write(sm->handshake->ifindex, - sm->handshake->aa, sm->handshake->spa, ETH_P_PAE, ef); -} - static void eapol_install_gtk(struct eapol_sm *sm, uint8_t gtk_key_index, const uint8_t *gtk, size_t gtk_len, const uint8_t *rsc) @@ -933,7 +809,7 @@ static void send_eapol_start(struct l_timeout *timeout, void *user_data) frame->header.packet_type = 1; l_put_be16(0, &frame->header.packet_len); - eapol_write(sm, frame); + eapol_sm_write(sm, frame, false); } static void eapol_handle_ptk_1_of_4(struct eapol_sm *sm, @@ -1061,7 +937,7 @@ static void eapol_handle_ptk_1_of_4(struct eapol_sm *sm, } memcpy(step2->key_mic_data, mic, sizeof(mic)); - eapol_write(sm, (struct eapol_frame *) step2); + eapol_sm_write(sm, (struct eapol_frame *) step2, false); l_free(step2); l_timeout_remove(sm->eapol_start_timeout); @@ -1329,7 +1205,7 @@ retransmit: } memcpy(step4->key_mic_data, mic, sizeof(mic)); - eapol_write(sm, (struct eapol_frame *) step4); + eapol_sm_write(sm, (struct eapol_frame *) step4, false); l_free(step4); if (sm->handshake->ptk_complete) @@ -1442,7 +1318,7 @@ static void eapol_handle_gtk_1_of_2(struct eapol_sm *sm, } memcpy(step2->key_mic_data, mic, sizeof(mic)); - eapol_write(sm, (struct eapol_frame *) step2); + eapol_sm_write(sm, (struct eapol_frame *) step2, false); l_free(step2); eapol_install_gtk(sm, gtk_key_index, gtk, gtk_len, ek->key_rsc); @@ -1599,7 +1475,7 @@ static void eapol_eap_msg_cb(const uint8_t *eap_data, size_t len, memcpy(frame->data, eap_data, len); - eapol_write(sm, frame); + eapol_sm_write(sm, frame, false); } /* This respresentes the eapTimout, eapFail and eapSuccess messages */ @@ -1904,12 +1780,6 @@ bool eapol_frame_watch_remove(uint32_t id) return watchlist_remove(&frame_watches, id); } -void eapol_tx_frame(uint32_t ifindex, uint16_t proto, const uint8_t *dst, - const struct eapol_frame *frame) -{ - pae_write(ifindex, dst, NULL, proto, frame); -} - struct preauth_sm { uint32_t ifindex; uint8_t aa[6]; @@ -1952,7 +1822,7 @@ static void preauth_frame(struct preauth_sm *sm, uint8_t packet_type, if (data_len) memcpy(frame->data, data, data_len); - pae_write(sm->ifindex, sm->aa, sm->spa, 0x88c7, frame); + __eapol_tx_packet(sm->ifindex, sm->aa, 0x88c7, frame, false); } static void preauth_rx_packet(uint16_t proto, const uint8_t *from, @@ -2123,7 +1993,8 @@ static bool eapol_frame_watch_match_ifindex(const void *a, const void *b) } void __eapol_rx_packet(uint32_t ifindex, const uint8_t *src, uint16_t proto, - const uint8_t *frame, size_t len) + const uint8_t *frame, size_t len, + bool noencrypt) { const struct eapol_header *eh; @@ -2151,6 +2022,15 @@ void __eapol_rx_packet(uint32_t ifindex, const uint8_t *src, uint16_t proto, (const struct eapol_frame *) eh); } +void __eapol_tx_packet(uint32_t ifindex, const uint8_t *dst, uint16_t proto, + const struct eapol_frame *frame, bool noencrypt) +{ + if (!tx_packet) + return; + + tx_packet(ifindex, dst, proto, frame, noencrypt, tx_user_data); +} + void __eapol_set_config(struct l_settings *config) { if (!l_settings_get_uint(config, "EAPoL", diff --git a/src/eapol.h b/src/eapol.h index ebc73722..eae2f5c5 100644 --- a/src/eapol.h +++ b/src/eapol.h @@ -107,10 +107,11 @@ struct eapol_key { uint8_t key_data[0]; } __attribute__ ((packed)); -typedef int (*eapol_tx_packet_func_t)(uint32_t ifindex, const uint8_t *aa, - const uint8_t *spa, - const struct eapol_frame *ef, - void *user_data); +typedef int (*eapol_tx_packet_func_t)(uint32_t ifindex, + const uint8_t *dest, uint16_t proto, + const struct eapol_frame *ef, + bool noencrypt, + void *user_data); typedef void (*eapol_rekey_offload_func_t)(uint32_t ifindex, const uint8_t *kek, const uint8_t *kck, @@ -175,8 +176,10 @@ struct eapol_key *eapol_create_gtk_2_of_2( const uint8_t *eapol_find_rsne(const uint8_t *data, size_t data_len, const uint8_t **optional); -void __eapol_rx_packet(uint32_t ifindex, const uint8_t *aa, uint16_t proto, - const uint8_t *frame, size_t len); +void __eapol_rx_packet(uint32_t ifindex, const uint8_t *src, uint16_t proto, + const uint8_t *frame, size_t len, bool noencrypt); +void __eapol_tx_packet(uint32_t ifindex, const uint8_t *dst, uint16_t proto, + const struct eapol_frame *frame, bool noencrypt); void __eapol_set_tx_packet_func(eapol_tx_packet_func_t func); void __eapol_set_tx_user_data(void *user_data); @@ -204,8 +207,6 @@ uint32_t eapol_frame_watch_add(uint32_t ifindex, eapol_frame_watch_func_t handler, void *user_data); bool eapol_frame_watch_remove(uint32_t id); -void eapol_tx_frame(uint32_t ifindex, uint16_t proto, const uint8_t *dst, - const struct eapol_frame *frame); struct preauth_sm *eapol_preauth_start(const uint8_t *aa, const struct handshake_state *hs, @@ -213,8 +214,5 @@ struct preauth_sm *eapol_preauth_start(const uint8_t *aa, eapol_preauth_destroy_func_t destroy); void eapol_preauth_cancel(uint32_t ifindex); -void eapol_pae_open(); -void eapol_pae_close(); - bool eapol_init(); bool eapol_exit(); diff --git a/src/netdev.c b/src/netdev.c index 1c28fc4d..305de85d 100644 --- a/src/netdev.c +++ b/src/netdev.c @@ -3590,9 +3590,6 @@ static void netdev_create_from_genl(struct l_genl_msg *msg) l_queue_push_tail(netdev_list, netdev); - if (l_queue_length(netdev_list) == 1) - eapol_pae_open(); - l_debug("Created interface %s[%d]", netdev->name, netdev->index); /* Query interface flags */ @@ -3809,6 +3806,4 @@ void netdev_shutdown(void) l_queue_destroy(netdev_list, netdev_free); netdev_list = NULL; - - eapol_pae_close(); }