openbsd_wlan: Add a Haiku-specific "FreeBSD-style" ioctl for joining networks.

In the long run it may make more sense to have Haiku-style ioctls for
this purpose, but since we are currently coexisting with FreeBSD-style
ioctls, just add this as another FreeBSD-style ioctl for now (we already
have two custom ones anyway.)

This ioctl pretty much just consists of the same parameters we pass
to wpa_supplicant using the Haiku-specific constants already, with one
notable difference: the PSK must be in proper WPA format, i.e. already
hashed. Hence we will submit this ioctl, for now, from our own code in
our wpa_supplicant port.

WPS is not implemented in this commit, but it could be if someone actually
needs to connect to WPS networks for some reason...

Tested and verified as working along with the wpa_supplicant changes.
This commit is contained in:
Augustin Cavalier
2022-06-09 01:28:56 -04:00
parent 7cb5a6d24f
commit 2f7936a683
2 changed files with 125 additions and 0 deletions
@@ -768,6 +768,23 @@ struct ieee80211req {
*/
#define IEEE80211_IOC_HAIKU_COMPAT_WLAN_UP 0x6000
#define IEEE80211_IOC_HAIKU_COMPAT_WLAN_DOWN 0x6001
/*
Haiku extension: initiate join of network, potentially encrypted.
*/
#define IEEE80211_IOC_HAIKU_JOIN 0x6002
struct ieee80211_haiku_join_req {
uint8 i_nwid[IEEE80211_NWID_LEN];
uint8 i_nwid_len;
uint32 i_authentication_mode;
uint32 i_ciphers;
uint32 i_group_ciphers;
uint32 i_key_mode;
uint32 i_key_len;
uint8 i_key[];
};
#endif /* __HAIKU__ */
/*
@@ -37,6 +37,7 @@ extern "C" {
#include <shared.h>
#include <ether_driver.h>
#include <NetworkDevice.h>
#include <net_notifications.h>
@@ -146,6 +147,22 @@ fbsd_capinfo_from_obsd(uint16_t obsd_capinfo)
}
static uint32
obsd_ciphers_from_haiku(uint32 ciphers)
{
uint32 obsd_ciphers = 0;
if ((ciphers & B_NETWORK_CIPHER_WEP_40) != 0)
obsd_ciphers |= IEEE80211_WPA_CIPHER_WEP40;
if ((ciphers & B_NETWORK_CIPHER_WEP_104) != 0)
obsd_ciphers |= IEEE80211_WPA_CIPHER_WEP104;
if ((ciphers & B_NETWORK_CIPHER_TKIP) != 0)
obsd_ciphers |= IEEE80211_WPA_CIPHER_TKIP;
if ((ciphers & B_NETWORK_CIPHER_CCMP) != 0)
obsd_ciphers |= IEEE80211_WPA_CIPHER_CCMP;
return obsd_ciphers;
}
status_t
wlan_control(void* cookie, uint32 op, void* arg, size_t length)
{
@@ -304,6 +321,97 @@ wlan_control(void* cookie, uint32 op, void* arg, size_t length)
break;
}
case IEEE80211_IOC_HAIKU_JOIN: {
if (op != SIOCS80211)
return B_BAD_VALUE;
struct ieee80211_haiku_join_req* haiku_join =
(struct ieee80211_haiku_join_req*)calloc(1, ireq.i_len);
MemoryDeleter haikuJoinDeleter(haiku_join);
if (!haikuJoinDeleter.IsSet())
return B_NO_MEMORY;
if (user_memcpy(haiku_join, ireq.i_data, ireq.i_len) != B_OK)
return B_BAD_ADDRESS;
struct ifreq ifr;
struct ieee80211_nwid nwid;
struct ieee80211_wpaparams wpaparams;
struct ieee80211_wpapsk wpapsk;
memset(&wpaparams, 0, sizeof(wpaparams));
memset(&wpapsk, 0, sizeof(wpapsk));
// Convert join information.
ifr.ifr_data = (uint8_t*)&nwid;
nwid.i_len = haiku_join->i_nwid_len;
memcpy(nwid.i_nwid, haiku_join->i_nwid, nwid.i_len);
switch (haiku_join->i_authentication_mode) {
case B_NETWORK_AUTHENTICATION_NONE:
break;
case B_NETWORK_AUTHENTICATION_WPA:
case B_NETWORK_AUTHENTICATION_WPA2:
wpaparams.i_enabled = 1;
wpaparams.i_protos |=
(haiku_join->i_authentication_mode == B_NETWORK_AUTHENTICATION_WPA2) ?
IEEE80211_WPA_PROTO_WPA2 : IEEE80211_WPA_PROTO_WPA1;
// NOTE: i_wpaparams.i_groupcipher is not a flags field!
wpaparams.i_ciphers = obsd_ciphers_from_haiku(haiku_join->i_ciphers);
wpaparams.i_groupcipher =
fls(obsd_ciphers_from_haiku(haiku_join->i_group_ciphers));
if ((haiku_join->i_key_mode & B_KEY_MODE_IEEE802_1X) != 0)
wpaparams.i_akms |= IEEE80211_WPA_AKM_8021X;
if ((haiku_join->i_key_mode & B_KEY_MODE_PSK) != 0)
wpaparams.i_akms |= IEEE80211_WPA_AKM_PSK;
if ((haiku_join->i_key_mode & B_KEY_MODE_IEEE802_1X_SHA256) != 0)
wpaparams.i_akms |= IEEE80211_WPA_AKM_SHA256_8021X;
if ((haiku_join->i_key_mode & B_KEY_MODE_PSK_SHA256) != 0)
wpaparams.i_akms |= IEEE80211_WPA_AKM_SHA256_PSK;
if (haiku_join->i_key_len != 0) {
wpapsk.i_enabled = 1;
memcpy(wpapsk.i_psk, haiku_join->i_key, haiku_join->i_key_len);
memset(&wpapsk.i_psk[haiku_join->i_key_len], 0,
sizeof(wpapsk.i_psk) - haiku_join->i_key_len);
}
break;
default:
TRACE("openbsd wlan_control: unsupported authentication mode %" B_PRIu32 "\n",
haiku_join->i_authentication_mode);
return EOPNOTSUPP;
}
IFF_LOCKGIANT(ifp);
status_t status = ifp->if_ioctl(ifp, SIOCS80211NWID, (caddr_t)&ifr);
if (status != B_OK) {
IFF_UNLOCKGIANT(ifp);
return status;
}
if (wpapsk.i_enabled) {
status = ifp->if_ioctl(ifp, SIOCS80211WPAPSK, (caddr_t)&wpapsk);
if (status != B_OK) {
IFF_UNLOCKGIANT(ifp);
return status;
}
}
if (wpaparams.i_enabled) {
status = ifp->if_ioctl(ifp, SIOCS80211WPAPARMS, (caddr_t)&wpaparams);
if (status != B_OK) {
IFF_UNLOCKGIANT(ifp);
return status;
}
}
IFF_UNLOCKGIANT(ifp);
if (status != B_OK)
return status;
break;
}
default:
TRACE("openbsd wlan_control: %" B_PRIu32 ", %d (not supported)\n", op, ireq.i_type);
return EOPNOTSUPP;