diff --git a/kernel-src/include/kernel/wlan.h b/kernel-src/include/kernel/wlan.h index d86e9262..4621b513 100644 --- a/kernel-src/include/kernel/wlan.h +++ b/kernel-src/include/kernel/wlan.h @@ -12,4 +12,8 @@ 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); +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); + #endif diff --git a/kernel-src/io/net/netdev.c b/kernel-src/io/net/netdev.c index 0f3d95ad..bbbb155f 100644 --- a/kernel-src/io/net/netdev.c +++ b/kernel-src/io/net/netdev.c @@ -29,6 +29,14 @@ typedef struct { size_t records_returned; // filled in by kernel } wlan_bss_request_t; +typedef struct { + uint8_t bssid[6]; + void *ie; + size_t ie_size; +} wlan_association_request_t; + +#define MAX_IE_SIZE 1024 + #define NETDEV_IOCTL_GET_INFO 0x1337631 #define NETDEV_IOCTL_WLAN_SCAN 0x8021101 #define NETDEV_IOCTL_WLAN_SCAN_WAIT 0x8021102 @@ -58,19 +66,42 @@ int handle_wlan_ioctl(netdev_t *netdev, unsigned long request, void *arg, int *r 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: + case NETDEV_IOCTL_WLAN_ASSOCIATE: { + wlan_association_request_t ar; + int error = USERCOPY_POSSIBLY_FROM_USER(&ar, arg, sizeof(ar)); + if (error) + return error; - break; + if (IS_USER_ADDRESS(arg) && !IS_USER_ADDRESS(ar.ie)) + return EFAULT; + + if (ar.ie_size > MAX_IE_SIZE) + return EINVAL; + + void *ie = alloc(ar.ie_size); + if (ie == NULL) + return ENOMEM; + + error = USERCOPY_POSSIBLY_FROM_USER(ie, ar.ie, ar.ie_size); + if (error) { + free(ie); + return error; + } + + error = wlan_associate(netdev, ar.bssid, ie, ar.ie_size); + free(ie); + return error; + } + case NETDEV_IOCTL_WLAN_ASSOCIATION_WAIT: + return wlan_associate_wait(netdev); case NETDEV_IOCTL_WLAN_DISASSOCIATE: - - break; + return wlan_disassociate(netdev); case NETDEV_IOCTL_WLAN_SET_KEY: break; case NETDEV_IOCTL_WLAN_DEL_KEY: break; - default: return ENOTTY; } diff --git a/kernel-src/io/net/wlan.c b/kernel-src/io/net/wlan.c index 4fa1b71a..24c9b52c 100644 --- a/kernel-src/io/net/wlan.c +++ b/kernel-src/io/net/wlan.c @@ -336,3 +336,30 @@ int wlan_get_bss_cache(netdev_t *netdev, void *buffer, size_t size, size_t *reco free(ap_buffer); return error; } + +int wlan_associate(netdev_t *netdev, uint8_t bssid[6], void *ie, size_t ie_size) { + wlan_device_t *wlan = (wlan_device_t *)netdev; + + u80211_mac_address_t mac; + memcpy(&mac, bssid, 6); + + u80211_ap_t *ap = u80211_bss_cache_find(&wlan->u80211_device->bss_cache, &mac); + if (ap == NULL) + return EINVAL; + + int error = u80211_associate(wlan->u80211_device, ap, ie, ie_size) == U80211_STATUS_SUCCESS ? 0 : EINVAL; + u80211_ap_release(ap); + return error; +} + +int wlan_associate_wait(netdev_t *netdev) { + wlan_device_t *wlan = (wlan_device_t *)netdev; + + return u80211_wait_for_association_completion(wlan->u80211_device) == U80211_STATUS_SUCCESS ? 0 : EINVAL; +} + +int wlan_disassociate(netdev_t *netdev) { + wlan_device_t *wlan = (wlan_device_t *)netdev; + + return u80211_disassociate(wlan->u80211_device) == U80211_STATUS_SUCCESS ? 0 : EINVAL; +}