3
0
mirror of https://git.kernel.org/pub/scm/network/wireless/iwd.git synced 2024-12-20 19:12:33 +01:00

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.
This commit is contained in:
Denis Kenzior 2018-05-01 11:01:51 -05:00
parent 008965882d
commit c31cf5d383
4 changed files with 37 additions and 164 deletions

View File

@ -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)

View File

@ -25,14 +25,7 @@
#endif
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/socket.h>
#include <linux/if.h>
#include <linux/if_packet.h>
#include <linux/if_ether.h>
#include <arpa/inet.h>
#include <linux/filter.h>
#include <ell/ell.h>
#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",

View File

@ -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();

View File

@ -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();
}