mirror of
https://github.com/Mathewnd/Astral.git
synced 2026-11-02 07:28:21 +00:00
wlan: expose scan, scan wait and bss cache get to userspace
This commit is contained in:
@@ -2,8 +2,14 @@
|
|||||||
#define _WLAN_H
|
#define _WLAN_H
|
||||||
|
|
||||||
#include <u80211_drv/kernel_interface.h>
|
#include <u80211_drv/kernel_interface.h>
|
||||||
|
#include <kernel/net.h>
|
||||||
|
|
||||||
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);
|
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);
|
void wlan_process_packet(u80211_drv_network_device_handle_t handle, void *packet, size_t packet_size);
|
||||||
|
|
||||||
|
int wlan_active_scan(netdev_t *netdev);
|
||||||
|
int wlan_wait_for_scan(netdev_t *netdev);
|
||||||
|
|
||||||
|
int wlan_get_bss_cache(netdev_t *netdev, void *buffer, size_t size, size_t *records_written);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
#include <logging.h>
|
#include <logging.h>
|
||||||
#include <kernel/usercopy.h>
|
#include <kernel/usercopy.h>
|
||||||
#include <kernel/sock.h>
|
#include <kernel/sock.h>
|
||||||
|
#include <kernel/wlan.h>
|
||||||
|
|
||||||
static int current_minor;
|
static int current_minor;
|
||||||
static netdev_t *minors[64];
|
static netdev_t *minors[64];
|
||||||
@@ -22,13 +23,66 @@ typedef struct {
|
|||||||
int mtu;
|
int mtu;
|
||||||
} net_info_t;
|
} net_info_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
void *buffer;
|
||||||
|
size_t buffer_size;
|
||||||
|
size_t records_returned; // filled in by kernel
|
||||||
|
} wlan_bss_request_t;
|
||||||
|
|
||||||
|
#define NETDEV_IOCTL_GET_INFO 0x1337631
|
||||||
|
#define NETDEV_IOCTL_WLAN_SCAN 0x8021101
|
||||||
|
#define NETDEV_IOCTL_WLAN_SCAN_WAIT 0x8021102
|
||||||
|
#define NETDEV_IOCTL_WLAN_GET_BSS_CACHE 0x8021103
|
||||||
|
#define NETDEV_IOCTL_WLAN_ASSOCIATE 0x8021104
|
||||||
|
#define NETDEV_IOCTL_WLAN_ASSOCIATION_WAIT 0x8021105
|
||||||
|
#define NETDEV_IOCTL_WLAN_DISASSOCIATE 0x8021106
|
||||||
|
#define NETDEV_IOCTL_WLAN_SET_KEY 0x8021107
|
||||||
|
#define NETDEV_IOCTL_WLAN_DEL_KEY 0x8021108
|
||||||
|
|
||||||
|
int handle_wlan_ioctl(netdev_t *netdev, unsigned long request, void *arg, int *result, cred_t *cred) {
|
||||||
|
// TODO: make every operation besides get bss cache be privileged
|
||||||
|
switch (request) {
|
||||||
|
case NETDEV_IOCTL_WLAN_SCAN:
|
||||||
|
return wlan_active_scan(netdev);
|
||||||
|
case NETDEV_IOCTL_WLAN_SCAN_WAIT:
|
||||||
|
return wlan_wait_for_scan(netdev);
|
||||||
|
case NETDEV_IOCTL_WLAN_GET_BSS_CACHE: {
|
||||||
|
wlan_bss_request_t bss_request;
|
||||||
|
int error = USERCOPY_POSSIBLY_FROM_USER(&bss_request, arg, sizeof(bss_request));
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
|
||||||
|
if (IS_USER_ADDRESS(arg) && !IS_USER_ADDRESS(bss_request.buffer))
|
||||||
|
return EFAULT;
|
||||||
|
|
||||||
|
wlan_get_bss_cache(netdev, bss_request.buffer, bss_request.buffer_size, &bss_request.records_returned);
|
||||||
|
return USERCOPY_POSSIBLY_TO_USER(arg, &bss_request, sizeof(bss_request));
|
||||||
|
}
|
||||||
|
case NETDEV_IOCTL_WLAN_ASSOCIATE:
|
||||||
|
|
||||||
|
break;
|
||||||
|
case NETDEV_IOCTL_WLAN_DISASSOCIATE:
|
||||||
|
|
||||||
|
break;
|
||||||
|
case NETDEV_IOCTL_WLAN_SET_KEY:
|
||||||
|
|
||||||
|
break;
|
||||||
|
case NETDEV_IOCTL_WLAN_DEL_KEY:
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return ENOTTY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int netdev_ioctl(int minor, unsigned long request, void *arg, int *result, cred_t *cred) {
|
static int netdev_ioctl(int minor, unsigned long request, void *arg, int *result, cred_t *cred) {
|
||||||
netdev_t *netdev = minors[minor];
|
netdev_t *netdev = minors[minor];
|
||||||
if (netdev == NULL)
|
if (netdev == NULL)
|
||||||
return ENODEV;
|
return ENODEV;
|
||||||
|
|
||||||
switch (request) {
|
switch (request) {
|
||||||
case 0x1337631: {
|
case NETDEV_IOCTL_GET_INFO: {
|
||||||
net_info_t *info = arg;
|
net_info_t *info = arg;
|
||||||
sockaddr_t addr = {0};
|
sockaddr_t addr = {0};
|
||||||
abisockaddr_t abisockaddr;
|
abisockaddr_t abisockaddr;
|
||||||
@@ -77,7 +131,7 @@ static int netdev_ioctl(int minor, unsigned long request, void *arg, int *result
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
return ENOTTY;
|
return handle_wlan_ioctl(netdev, request, arg, result, cred);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
#include <kernel/net.h>
|
#include <kernel/net.h>
|
||||||
#include <kernel/eth.h>
|
#include <kernel/eth.h>
|
||||||
#include <kernel/interrupt.h>
|
#include <kernel/interrupt.h>
|
||||||
|
#include <kernel/usercopy.h>
|
||||||
#include <logging.h>
|
#include <logging.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
@@ -18,6 +19,8 @@ typedef struct {
|
|||||||
int id;
|
int id;
|
||||||
} wlan_device_t;
|
} wlan_device_t;
|
||||||
|
|
||||||
|
// TODO: make u80211 bss cache get more generic than having to pass the bss cache directly
|
||||||
|
// TODO: handle hotplug
|
||||||
// TODO: in u80211_drv *_tx_buffer ops, pass device handle
|
// TODO: in u80211_drv *_tx_buffer ops, pass device handle
|
||||||
// TODO: change how netdesc_t is handled in kernel overall (?)
|
// TODO: change how netdesc_t is handled in kernel overall (?)
|
||||||
// TODO: map u80211 errors to errnos
|
// TODO: map u80211 errors to errnos
|
||||||
@@ -244,3 +247,92 @@ void wlan_process_packet(u80211_drv_network_device_handle_t handle, void *packet
|
|||||||
u80211_process_packet(wlan->u80211_device, packet, packet_size);
|
u80211_process_packet(wlan->u80211_device, packet, packet_size);
|
||||||
interrupt_loweripl(ipl);
|
interrupt_loweripl(ipl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int wlan_active_scan(netdev_t *netdev) {
|
||||||
|
wlan_device_t *wlan = (wlan_device_t *)netdev;
|
||||||
|
|
||||||
|
return u80211_scan(wlan->u80211_device) == U80211_STATUS_SUCCESS ? 0 : EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int wlan_wait_for_scan(netdev_t *netdev) {
|
||||||
|
wlan_device_t *wlan = (wlan_device_t *)netdev;
|
||||||
|
|
||||||
|
return u80211_wait_for_scan_completion(wlan->u80211_device) == U80211_STATUS_SUCCESS ? 0 : EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint16_t length;
|
||||||
|
uint16_t rsn_ie_length;
|
||||||
|
uint16_t variable_offset;
|
||||||
|
uint16_t interval;
|
||||||
|
uint16_t capabilities;
|
||||||
|
uint8_t bssid[6];
|
||||||
|
uint8_t rate_bitmap[16];
|
||||||
|
uint8_t channel;
|
||||||
|
uint8_t ssid_length;
|
||||||
|
// SSID
|
||||||
|
// RSN IE
|
||||||
|
} wlan_bss_info_t;
|
||||||
|
|
||||||
|
// this may seem excessive (and, for your average residential air, it is).
|
||||||
|
// however, some places (like university campi or dense urban environments)
|
||||||
|
// can easily cross into the hundreds of APs. many different implementations
|
||||||
|
// have moved to use a 1000 limit to bss entries (see cfg80211 or the discussions on
|
||||||
|
// hostapd/wpa_supplicant to raise the limit)
|
||||||
|
#define MAX_APS 1000
|
||||||
|
|
||||||
|
int wlan_get_bss_cache(netdev_t *netdev, void *buffer, size_t size, size_t *records_written) {
|
||||||
|
wlan_device_t *wlan = (wlan_device_t *)netdev;
|
||||||
|
|
||||||
|
u80211_ap_t **ap_buffer = alloc(sizeof(u80211_ap_t *) * MAX_APS);
|
||||||
|
if (ap_buffer == NULL)
|
||||||
|
return ENOMEM;
|
||||||
|
|
||||||
|
size_t ap_count = u80211_bss_cache_get_aps(&wlan->u80211_device->bss_cache, ap_buffer, MAX_APS);
|
||||||
|
|
||||||
|
int error = 0;
|
||||||
|
*records_written = 0;
|
||||||
|
for (size_t i = 0; i < ap_count; ++i) {
|
||||||
|
u80211_ap_t *ap = ap_buffer[i];
|
||||||
|
wlan_bss_info_t bss_info;
|
||||||
|
bss_info.ssid_length = strlen(ap->ssid);
|
||||||
|
bss_info.length = sizeof(wlan_bss_info_t) + bss_info.ssid_length + ap->rsn_size;
|
||||||
|
|
||||||
|
if (size < bss_info.length)
|
||||||
|
break;
|
||||||
|
|
||||||
|
bss_info.variable_offset = sizeof(bss_info);
|
||||||
|
bss_info.rsn_ie_length = ap->rsn_size;
|
||||||
|
bss_info.interval = ap->interval;
|
||||||
|
bss_info.capabilities = ap->capabilities;
|
||||||
|
bss_info.channel = ap->channel;
|
||||||
|
memcpy(bss_info.bssid, &ap->mac_address, 6);
|
||||||
|
memcpy(bss_info.rate_bitmap, ap->rate_bitmap, sizeof(bss_info.rate_bitmap));
|
||||||
|
|
||||||
|
error = USERCOPY_POSSIBLY_TO_USER(buffer, &bss_info, sizeof(bss_info));
|
||||||
|
if (error)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (bss_info.ssid_length) {
|
||||||
|
error = USERCOPY_POSSIBLY_TO_USER((void *)((uintptr_t)buffer + sizeof(bss_info)), ap->ssid, bss_info.ssid_length);
|
||||||
|
if (error)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bss_info.rsn_ie_length) {
|
||||||
|
error = USERCOPY_POSSIBLY_TO_USER((void *)((uintptr_t)buffer + sizeof(bss_info) + bss_info.ssid_length), ap->rsn, bss_info.rsn_ie_length);
|
||||||
|
if (error)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
size -= bss_info.length;
|
||||||
|
buffer = (void *)((uintptr_t)buffer + bss_info.length);
|
||||||
|
*records_written += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < ap_count; ++i)
|
||||||
|
u80211_ap_release(ap_buffer[i]);
|
||||||
|
|
||||||
|
free(ap_buffer);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user