From f05c3c30d199cb915e766dde9b2463387b43fbe0 Mon Sep 17 00:00:00 2001 From: Andrew Zaborowski Date: Thu, 7 Sep 2017 23:04:45 +0200 Subject: [PATCH] eapol: Add eapol_frame_watch_add / remove Allow other files to receive EAPoL frames on specified interfaces. --- Makefile.am | 4 ++++ src/eapol.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++--- src/eapol.h | 8 +++++++ 3 files changed, 71 insertions(+), 3 deletions(-) diff --git a/Makefile.am b/Makefile.am index 668e53f3..f46a2528 100644 --- a/Makefile.am +++ b/Makefile.am @@ -113,6 +113,7 @@ monitor_iwmon_SOURCES = monitor/main.c linux/nl80211.h \ src/mpdu.h src/mpdu.c \ src/util.h src/util.c \ src/crypto.h src/crypto.c \ + src/watchlist.h src/watchlist.c \ src/eapol.h src/eapol.c \ src/handshake.h src/handshake.c \ src/eap.h src/eap.c \ @@ -150,6 +151,7 @@ endif unit_test_eap_sim_SOURCES = unit/test-eap-sim.c \ src/crypto.h src/crypto.c src/simutil.h src/simutil.c \ src/ie.h src/ie.c \ + src/watchlist.h src/watchlist.c \ src/eapol.h src/eapol.c \ src/handshake.h src/handshake.c \ src/eap.h src/eap.c \ @@ -205,6 +207,7 @@ unit_test_mpdu_LDADD = ell/libell-internal.la unit_test_eapol_SOURCES = unit/test-eapol.c \ src/crypto.h src/crypto.c \ src/ie.h src/ie.c \ + src/watchlist.h src/watchlist.c \ src/eapol.h src/eapol.c \ src/handshake.h src/handshake.c \ src/eap.h src/eap.c \ @@ -223,6 +226,7 @@ unit_test_ssid_security_LDADD = ell/libell-internal.la unit_test_wsc_SOURCES = unit/test-wsc.c src/wscutil.h src/wscutil.c \ src/crypto.h src/crypto.c \ src/ie.h src/ie.c \ + src/watchlist.h src/watchlist.c \ src/eapol.h src/eapol.c \ src/handshake.h src/handshake.c \ src/eap.h src/eap.c \ diff --git a/src/eapol.c b/src/eapol.c index 0f58d5cf..0d9072e0 100644 --- a/src/eapol.c +++ b/src/eapol.c @@ -42,9 +42,11 @@ #include "mpdu.h" #include "eap.h" #include "handshake.h" +#include "watchlist.h" struct l_queue *state_machines; struct l_queue *preauths; +struct watchlist frame_watches; eapol_deauthenticate_func_t deauthenticate = NULL; eapol_rekey_offload_func_t rekey_offload = NULL; @@ -53,6 +55,8 @@ 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). @@ -1747,6 +1751,41 @@ eap_error: (int) sm->handshake->ifindex); } +struct eapol_frame_watch { + uint32_t ifindex; + struct watchlist_item super; +}; + +static void eapol_frame_watch_free(struct watchlist_item *item) +{ + struct eapol_frame_watch *efw = + container_of(item, struct eapol_frame_watch, super); + + l_free(efw); +} + +static const struct watchlist_ops eapol_frame_watch_ops = { + .item_free = eapol_frame_watch_free, +}; + +uint32_t eapol_frame_watch_add(uint32_t ifindex, + eapol_frame_watch_func_t handler, + void *user_data) +{ + struct eapol_frame_watch *efw; + + efw = l_new(struct eapol_frame_watch, 1); + efw->ifindex = ifindex; + + return watchlist_link(&frame_watches, &efw->super, + handler, user_data, NULL); +} + +bool eapol_frame_watch_remove(uint32_t id) +{ + return watchlist_remove(&frame_watches, id); +} + struct preauth_sm { uint32_t ifindex; uint8_t aa[6]; @@ -1962,7 +2001,15 @@ void eapol_preauth_cancel(uint32_t ifindex) L_UINT_TO_PTR(ifindex)); } -void __eapol_rx_packet(uint32_t ifindex, const uint8_t *aa, uint16_t proto, +static bool eapol_frame_watch_match_ifindex(const void *a, const void *b) +{ + struct eapol_frame_watch *efw = + container_of(a, struct eapol_frame_watch, super); + + return efw->ifindex == L_PTR_TO_UINT(b); +} + +void __eapol_rx_packet(uint32_t ifindex, const uint8_t *src, uint16_t proto, const uint8_t *frame, size_t len) { const struct eapol_header *eh; @@ -1984,15 +2031,21 @@ void __eapol_rx_packet(uint32_t ifindex, const uint8_t *aa, uint16_t proto, if (len < (size_t) 4 + L_BE16_TO_CPU(eh->packet_len)) return; + WATCHLIST_NOTIFY_MATCHES(&frame_watches, + eapol_frame_watch_match_ifindex, + L_UINT_TO_PTR(ifindex), + eapol_frame_watch_func_t, proto, src, + (const struct eapol_frame *) eh); + if (proto == ETH_P_PAE) { - struct eapol_sm *sm = eapol_find_sm(ifindex, aa); + struct eapol_sm *sm = eapol_find_sm(ifindex, src); if (!sm) return; eapol_rx_packet(sm, frame, len); } else if (proto == 0x88c7) { - struct preauth_sm *sm = preauth_find_sm(ifindex, aa); + struct preauth_sm *sm = preauth_find_sm(ifindex, src); if (!sm) return; @@ -2005,6 +2058,7 @@ bool eapol_init() { state_machines = l_queue_new(); preauths = l_queue_new(); + watchlist_init(&frame_watches, &eapol_frame_watch_ops); return true; } @@ -2021,5 +2075,7 @@ bool eapol_exit() l_queue_destroy(preauths, preauth_sm_destroy); + watchlist_destroy(&frame_watches); + return true; } diff --git a/src/eapol.h b/src/eapol.h index 41567b56..57ad9876 100644 --- a/src/eapol.h +++ b/src/eapol.h @@ -124,6 +124,9 @@ typedef void (*eapol_deauthenticate_func_t)(uint32_t ifindex, const uint8_t *aa, void *user_data); typedef void (*eapol_preauth_cb_t)(const uint8_t *pmk, void *user_data); typedef void (*eapol_preauth_destroy_func_t)(void *user_data); +typedef void (*eapol_frame_watch_func_t)(uint16_t proto, const uint8_t *from, + const struct eapol_frame *frame, + void *user_data); bool eapol_calculate_mic(const uint8_t *kck, const struct eapol_key *frame, uint8_t *mic); @@ -190,6 +193,11 @@ void eapol_sm_set_event_func(struct eapol_sm *sm, eapol_sm_event_func_t func); void eapol_register(struct eapol_sm *sm); void eapol_start(struct eapol_sm *sm); +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); + struct preauth_sm *eapol_preauth_start(const uint8_t *aa, const struct handshake_state *hs, eapol_preauth_cb_t cb, void *user_data,