From 2c73b64e3f34f8fe06f4ce9e6855abf5e3adbd7e Mon Sep 17 00:00:00 2001 From: Matheus Date: Thu, 10 Sep 2026 14:11:12 -0300 Subject: [PATCH] wlan: set_key and del_key --- kernel-src/include/kernel/wlan.h | 24 ++++++++++ kernel-src/io/net/netdev.c | 75 ++++++++++++++++++++++++++++++-- kernel-src/io/net/wlan.c | 67 ++++++++++++++++++++++++++++ 3 files changed, 162 insertions(+), 4 deletions(-) diff --git a/kernel-src/include/kernel/wlan.h b/kernel-src/include/kernel/wlan.h index 4621b513..99f59361 100644 --- a/kernel-src/include/kernel/wlan.h +++ b/kernel-src/include/kernel/wlan.h @@ -4,6 +4,27 @@ #include #include +#define WLAN_CIPHER_CCMP 0 +#define WLAN_CIPHER_TKIP 1 +#define WLAN_CIPHER_WEP40 2 +#define WLAN_CIPHER_WEP104 3 + +#define WLAN_KEY_PAIRWISE 1 +#define WLAN_KEY_GROUP 2 +#define WLAN_KEY_RX 4 +#define WLAN_KEY_TX 8 + +typedef struct { + uint8_t cipher; + uint8_t index; + uint8_t peer[6]; + uint8_t *key; + size_t key_len; + uint8_t *rx_seq; + size_t rx_seq_len; + uint32_t flags; +} wlan_key_t; + int wlan_register(void *handle, const u80211_drv_device_metadata_t *metadata, const u80211_drv_device_ops_t *ops, u80211_drv_network_device_handle_t *network_device); void wlan_process_packet(u80211_drv_network_device_handle_t handle, void *packet, size_t packet_size); @@ -16,4 +37,7 @@ int wlan_associate(netdev_t *netdev, uint8_t bssid[6], void *ie, size_t ie_size) int wlan_associate_wait(netdev_t *netdev); int wlan_disassociate(netdev_t *netdev); +int wlan_set_key(netdev_t *netdev, wlan_key_t *key); +int wlan_del_key(netdev_t *netdev, uint8_t index, uint8_t peer[6], uint32_t flags); + #endif diff --git a/kernel-src/io/net/netdev.c b/kernel-src/io/net/netdev.c index bbbb155f..1fcc1fa3 100644 --- a/kernel-src/io/net/netdev.c +++ b/kernel-src/io/net/netdev.c @@ -35,6 +35,14 @@ typedef struct { size_t ie_size; } wlan_association_request_t; +typedef struct { + uint8_t peer[6]; + uint8_t index; + uint32_t flags; +} wlan_del_key_request_t; + +#define MAX_KEY_SIZE 128 +#define MAX_SEQ_SIZE 16 #define MAX_IE_SIZE 1024 #define NETDEV_IOCTL_GET_INFO 0x1337631 @@ -96,12 +104,71 @@ int handle_wlan_ioctl(netdev_t *netdev, unsigned long request, void *arg, int *r return wlan_associate_wait(netdev); case NETDEV_IOCTL_WLAN_DISASSOCIATE: return wlan_disassociate(netdev); - case NETDEV_IOCTL_WLAN_SET_KEY: + case NETDEV_IOCTL_WLAN_SET_KEY: { + wlan_key_t req; + int error = USERCOPY_POSSIBLY_FROM_USER(&req, arg, sizeof(req)); + if (error) + return error; - break; - case NETDEV_IOCTL_WLAN_DEL_KEY: + if (req.rx_seq_len > MAX_SEQ_SIZE) + return EINVAL; - break; + if (req.key_len > MAX_KEY_SIZE) + return EINVAL; + + void *key = NULL; + void *seq = NULL; + + if (req.key_len) { + if (IS_USER_ADDRESS(arg) && !IS_USER_ADDRESS(req.key)) + return EFAULT; + + key = alloc(req.key_len); + if (key == NULL) + return ENOMEM; + + error = USERCOPY_POSSIBLY_FROM_USER(key, req.key, req.key_len); + if (error) + goto wlan_set_key_done; + } + + if (req.rx_seq_len) { + if (IS_USER_ADDRESS(arg) && !IS_USER_ADDRESS(req.rx_seq)) { + error = EFAULT; + goto wlan_set_key_done; + } + + seq = alloc(req.rx_seq_len); + if (seq == NULL) { + error = ENOMEM; + goto wlan_set_key_done; + } + + error = USERCOPY_POSSIBLY_FROM_USER(seq, req.rx_seq, req.rx_seq_len); + if (error) + goto wlan_set_key_done; + } + + req.key = key; + req.rx_seq = seq; + + error = wlan_set_key(netdev, &req); + +wlan_set_key_done: + if (key) + free(key); + if (seq) + free(seq); + return error; + } + case NETDEV_IOCTL_WLAN_DEL_KEY: { + wlan_del_key_request_t req; + int error = USERCOPY_POSSIBLY_FROM_USER(&req, arg, sizeof(req)); + if (error) + return error; + + return wlan_del_key(netdev, req.index, req.peer, req.flags); + } default: return ENOTTY; } diff --git a/kernel-src/io/net/wlan.c b/kernel-src/io/net/wlan.c index 24c9b52c..353f5f0a 100644 --- a/kernel-src/io/net/wlan.c +++ b/kernel-src/io/net/wlan.c @@ -363,3 +363,70 @@ int wlan_disassociate(netdev_t *netdev) { return u80211_disassociate(wlan->u80211_device) == U80211_STATUS_SUCCESS ? 0 : EINVAL; } + +static bool wlan_cipher_to_u80211_cipher(uint8_t cipher, u80211_cipher_t *out) { + switch (cipher) { + case WLAN_CIPHER_CCMP: + *out = U80211_CIPHER_CCMP; + break; + case WLAN_CIPHER_TKIP: + *out = U80211_CIPHER_TKIP; + break; + case WLAN_CIPHER_WEP40: + *out = U80211_CIPHER_WEP40; + break; + case WLAN_CIPHER_WEP104: + *out = U80211_CIPHER_WEP104; + break; + default: + return false; + } + + return true; +} + +static uint32_t wlan_flags_to_u80211_flags(uint32_t flags) { + uint32_t out = 0; + + if (flags & WLAN_KEY_PAIRWISE) + out |= U80211_KEY_PAIRWISE; + + if (flags & WLAN_KEY_GROUP) + out |= U80211_KEY_GROUP; + + if (flags & WLAN_KEY_RX) + out |= U80211_KEY_RX; + + if (flags & WLAN_KEY_TX) + out |= U80211_KEY_TX; + + return out; +} + +int wlan_set_key(netdev_t *netdev, wlan_key_t *key) { + wlan_device_t *wlan = (wlan_device_t *)netdev; + + u80211_key_t u80211_key = { + .index = key->index, + .key = key->key, + .key_len = key->key_len, + .rx_seq = key->rx_seq, + .rx_seq_len = key->rx_seq_len, + .flags = wlan_flags_to_u80211_flags(key->flags) + }; + memcpy(&u80211_key.peer, key->peer, 6); + + if (!wlan_cipher_to_u80211_cipher(key->cipher, &u80211_key.cipher)) + return EINVAL; + + return u80211_set_key(wlan->u80211_device, &u80211_key) == U80211_STATUS_SUCCESS ? 0 : EINVAL; +} + +int wlan_del_key(netdev_t *netdev, uint8_t index, uint8_t peer[6], uint32_t flags) { + wlan_device_t *wlan = (wlan_device_t *)netdev; + + u80211_mac_address_t mac; + memcpy(&mac, peer, 6); + + return u80211_del_key(wlan->u80211_device, index, &mac, flags) == U80211_STATUS_SUCCESS ? 0 : EINVAL; +}