* Parse the additional information elements the station sends in order to
retrieve the WLAN cipher/key configuration. Might not work perfectly yet; so far I've only seen WPA2, and WPA networks. * Have wlan_test show this extra info. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@39792 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -22,6 +22,7 @@ struct wireless_network {
|
||||
uint32 flags;
|
||||
uint32 authentication_mode;
|
||||
uint32 cipher;
|
||||
uint32 group_cipher;
|
||||
uint32 key_mode;
|
||||
};
|
||||
|
||||
@@ -41,15 +42,18 @@ enum {
|
||||
B_NETWORK_CIPHER_NONE = 0x01,
|
||||
B_NETWORK_CIPHER_WEP_40 = 0x02,
|
||||
B_NETWORK_CIPHER_WEP_104 = 0x04,
|
||||
B_NETWORK_CIPHER_WEP_TKIP = 0x08,
|
||||
B_NETWORK_CIPHER_WEP_CCMP = 0x10,
|
||||
B_NETWORK_CIPHER_WEP_AES_128_CMAC = 0x20
|
||||
B_NETWORK_CIPHER_TKIP = 0x08,
|
||||
B_NETWORK_CIPHER_CCMP = 0x10,
|
||||
B_NETWORK_CIPHER_AES_128_CMAC = 0x20
|
||||
};
|
||||
|
||||
// key modes
|
||||
enum {
|
||||
B_KEY_MODE_IEEE802_1X = 0x0001,
|
||||
B_KEY_MODE_PSK = 0x0002,
|
||||
B_KEY_MODE_NONE = 0x0004,
|
||||
B_KEY_MODE_FT_IEEE802_1X = 0x0020,
|
||||
B_KEY_MODE_FT_PSK = 0x0040,
|
||||
B_KEY_MODE_IEEE802_1X_SHA256 = 0x0080,
|
||||
B_KEY_MODE_PSK_SHA256 = 0x0100,
|
||||
B_KEY_MODE_WPS = 0x0200
|
||||
|
||||
@@ -22,6 +22,14 @@ extern "C" {
|
||||
}
|
||||
|
||||
|
||||
//#define TRACE_DEVICE
|
||||
#ifdef TRACE_DEVICE
|
||||
# define TRACE(x, ...) printf(x, __VA_ARGS__);
|
||||
#else
|
||||
# define TRACE(x, ...) ;
|
||||
#endif
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
|
||||
@@ -111,27 +119,217 @@ do_request(T& request, const char* name, int option)
|
||||
}
|
||||
|
||||
|
||||
//! Read a 16 bit little endian value
|
||||
static uint16
|
||||
read_le16(uint8*& data, int32& length)
|
||||
{
|
||||
uint16 value = B_LENDIAN_TO_HOST_INT16(*(uint16*)data);
|
||||
data += 2;
|
||||
length -= 2;
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
//! Read a 32 bit little endian value
|
||||
static uint32
|
||||
read_le32(uint8*& data, int32& length)
|
||||
{
|
||||
uint32 value = B_LENDIAN_TO_HOST_INT32(*(uint32*)data);
|
||||
data += 4;
|
||||
length -= 4;
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
static uint32
|
||||
from_rsn_cipher(uint32 cipher)
|
||||
{
|
||||
if ((cipher & 0xffffff) != RSN_OUI)
|
||||
return B_NETWORK_CIPHER_CCMP;
|
||||
|
||||
switch (cipher >> 24) {
|
||||
case RSN_CSE_NULL:
|
||||
return B_NETWORK_CIPHER_NONE;
|
||||
case RSN_CSE_WEP40:
|
||||
return B_NETWORK_CIPHER_WEP_40;
|
||||
case RSN_CSE_WEP104:
|
||||
return B_NETWORK_CIPHER_WEP_104;
|
||||
case RSN_CSE_TKIP:
|
||||
return B_NETWORK_CIPHER_TKIP;
|
||||
default:
|
||||
case RSN_CSE_CCMP:
|
||||
return B_NETWORK_CIPHER_CCMP;
|
||||
case RSN_CSE_WRAP:
|
||||
return B_NETWORK_CIPHER_AES_128_CMAC;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static uint32
|
||||
from_rsn_key_mode(uint32 mode)
|
||||
{
|
||||
if ((mode & 0xffffff) != RSN_OUI)
|
||||
return B_KEY_MODE_IEEE802_1X;
|
||||
|
||||
switch (mode >> 24) {
|
||||
default:
|
||||
case RSN_ASE_8021X_UNSPEC:
|
||||
return B_KEY_MODE_IEEE802_1X;
|
||||
case RSN_ASE_8021X_PSK:
|
||||
return B_KEY_MODE_PSK;
|
||||
// the following are currently not defined in net80211
|
||||
case 3:
|
||||
return B_KEY_MODE_FT_IEEE802_1X;
|
||||
case 4:
|
||||
return B_KEY_MODE_FT_PSK;
|
||||
case 5:
|
||||
return B_KEY_MODE_IEEE802_1X_SHA256;
|
||||
case 6:
|
||||
return B_KEY_MODE_PSK_SHA256;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//! Parse RSN/WPA information elements common data
|
||||
static void
|
||||
parse_ie_rsn_wpa(wireless_network& network, uint8*& data, int32& length)
|
||||
{
|
||||
if (length >= 4) {
|
||||
// parse group cipher
|
||||
network.group_cipher = from_rsn_cipher(read_le32(data, length));
|
||||
} else if (length > 0)
|
||||
return;
|
||||
|
||||
if (length >= 2) {
|
||||
// parse unicast cipher
|
||||
uint16 count = read_le16(data, length);
|
||||
network.cipher = 0;
|
||||
|
||||
for (uint16 i = 0; i < count; i++) {
|
||||
if (length < 4)
|
||||
return;
|
||||
network.cipher |= from_rsn_cipher(read_le32(data, length));
|
||||
}
|
||||
} else if (length > 0)
|
||||
return;
|
||||
|
||||
if (length >= 2) {
|
||||
// parse key management mode
|
||||
uint16 count = read_le16(data, length);
|
||||
network.key_mode = 0;
|
||||
|
||||
for (uint16 i = 0; i < count; i++) {
|
||||
if (length < 4)
|
||||
return;
|
||||
network.key_mode |= from_rsn_key_mode(read_le32(data, length));
|
||||
}
|
||||
} else if (length > 0)
|
||||
return;
|
||||
|
||||
// TODO: capabilities, and PMKID following in case of RSN
|
||||
}
|
||||
|
||||
|
||||
//! Parse RSN (Robust Security Network) information element.
|
||||
static void
|
||||
parse_ie_rsn(wireless_network& network, ie_data* ie)
|
||||
{
|
||||
network.authentication_mode = B_NETWORK_AUTHENTICATION_WPA2;
|
||||
network.cipher = B_NETWORK_CIPHER_CCMP;
|
||||
network.group_cipher = B_NETWORK_CIPHER_CCMP;
|
||||
network.key_mode = B_KEY_MODE_IEEE802_1X;
|
||||
|
||||
int32 length = ie->length;
|
||||
if (length < 2)
|
||||
return;
|
||||
|
||||
uint8* data = ie->data;
|
||||
|
||||
uint16 version = read_le16(data, length);
|
||||
if (version != RSN_VERSION)
|
||||
return;
|
||||
|
||||
parse_ie_rsn_wpa(network, data, length);
|
||||
}
|
||||
|
||||
|
||||
//! Parse WPA information element.
|
||||
static bool
|
||||
parse_ie_wpa(wireless_network& network, ie_data* ie)
|
||||
{
|
||||
int32 length = ie->length;
|
||||
if (length < 6)
|
||||
return false;
|
||||
|
||||
uint8* data = ie->data;
|
||||
|
||||
uint32 oui = read_le32(data, length);
|
||||
TRACE(" oui: %" B_PRIx32 "\n", oui);
|
||||
if (oui != ((WPA_OUI_TYPE << 24) | WPA_OUI))
|
||||
return false;
|
||||
|
||||
uint16 version = read_le16(data, length);
|
||||
if (version != WPA_VERSION)
|
||||
return false;
|
||||
|
||||
network.authentication_mode = B_NETWORK_AUTHENTICATION_WPA;
|
||||
network.cipher = B_NETWORK_CIPHER_TKIP;
|
||||
network.group_cipher = B_NETWORK_CIPHER_TKIP;
|
||||
network.key_mode = B_KEY_MODE_IEEE802_1X;
|
||||
|
||||
parse_ie_rsn_wpa(network, data, length);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//! Parse information elements.
|
||||
static void
|
||||
parse_ie(wireless_network& network, uint8* _ie, int32 ieLength)
|
||||
{
|
||||
struct ie_data* ie = (ie_data*)_ie;
|
||||
bool hadRSN = false;
|
||||
bool hadWPA = false;
|
||||
|
||||
while (ieLength > 1) {
|
||||
TRACE("ie type %u\n", ie->type);
|
||||
switch (ie->type) {
|
||||
case IEEE80211_ELEMID_SSID:
|
||||
strlcpy(network.name, (char*)ie->data,
|
||||
min_c(ie->length + 1, (int)sizeof(network.name)));
|
||||
break;
|
||||
case IEEE80211_ELEMID_RSN:
|
||||
// TODO: we might need to parse those in order to find out
|
||||
// the authentication mode (WPA info in vendor?)
|
||||
parse_ie_rsn(network, ie);
|
||||
hadRSN = true;
|
||||
break;
|
||||
case IEEE80211_ELEMID_VENDOR:
|
||||
if (!hadRSN && parse_ie_wpa(network, ie))
|
||||
hadWPA = true;
|
||||
break;
|
||||
}
|
||||
|
||||
ieLength -= 2 + ie->length;
|
||||
ie = (ie_data*)((uint8*)ie + 2 + ie->length);
|
||||
}
|
||||
|
||||
if (hadRSN || hadWPA) {
|
||||
// Determine authentication mode
|
||||
|
||||
if ((network.key_mode & (B_KEY_MODE_IEEE802_1X_SHA256
|
||||
| B_KEY_MODE_PSK_SHA256)) != 0) {
|
||||
network.authentication_mode = B_NETWORK_AUTHENTICATION_WPA2;
|
||||
} else if ((network.key_mode & (B_KEY_MODE_IEEE802_1X
|
||||
| B_KEY_MODE_PSK | B_KEY_MODE_FT_IEEE802_1X
|
||||
| B_KEY_MODE_FT_PSK)) != 0) {
|
||||
if (!hadRSN)
|
||||
network.authentication_mode = B_NETWORK_AUTHENTICATION_WPA;
|
||||
} else if ((network.key_mode & B_KEY_MODE_NONE) != 0) {
|
||||
if ((network.cipher & (B_NETWORK_CIPHER_WEP_40
|
||||
| B_NETWORK_CIPHER_WEP_104)) != 0)
|
||||
network.authentication_mode = B_NETWORK_AUTHENTICATION_WEP;
|
||||
else
|
||||
network.authentication_mode = B_NETWORK_AUTHENTICATION_NONE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -188,8 +386,11 @@ fill_wireless_network(wireless_network& network,
|
||||
network.noise_level = info.isi_noise;
|
||||
network.flags |= (info.isi_capinfo & IEEE80211_CAPINFO_PRIVACY) != 0
|
||||
? B_NETWORK_IS_ENCRYPTED : 0;
|
||||
|
||||
network.authentication_mode = 0;
|
||||
// TODO: build from IE if possible
|
||||
network.cipher = 0;
|
||||
network.group_cipher = 0;
|
||||
network.key_mode = 0;
|
||||
|
||||
parse_ie(network, info);
|
||||
}
|
||||
@@ -206,8 +407,11 @@ fill_wireless_network(wireless_network& network, const char* networkName,
|
||||
network.noise_level = result.isr_noise;
|
||||
network.flags = (result.isr_capinfo & IEEE80211_CAPINFO_PRIVACY)
|
||||
!= 0 ? B_NETWORK_IS_ENCRYPTED : 0;
|
||||
|
||||
network.authentication_mode = 0;
|
||||
// TODO: build from IE if possible
|
||||
network.cipher = 0;
|
||||
network.group_cipher = 0;
|
||||
network.key_mode = 0;
|
||||
|
||||
parse_ie(network, result);
|
||||
}
|
||||
|
||||
@@ -21,11 +21,30 @@ usage()
|
||||
}
|
||||
|
||||
|
||||
const char*
|
||||
get_authentication_mode(uint32 mode)
|
||||
{
|
||||
switch (mode) {
|
||||
default:
|
||||
case B_NETWORK_AUTHENTICATION_NONE:
|
||||
return "-";
|
||||
case B_NETWORK_AUTHENTICATION_WEP:
|
||||
return "WEP";
|
||||
case B_NETWORK_AUTHENTICATION_WPA:
|
||||
return "WPA";
|
||||
case B_NETWORK_AUTHENTICATION_WPA2:
|
||||
return "WPA2";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
show(const wireless_network& network)
|
||||
{
|
||||
printf("%-32s %s %3g dB%s\n", network.name,
|
||||
network.address.ToString().String(), network.signal_strength / 2.0,
|
||||
printf("%-32s %s %4g dB %s C%02" B_PRIx32 " K%02" B_PRIx32
|
||||
" %s\n", network.name, network.address.ToString().String(),
|
||||
network.signal_strength / 2.0, get_authentication_mode(
|
||||
network.authentication_mode), network.cipher, network.key_mode,
|
||||
(network.flags & B_NETWORK_IS_ENCRYPTED) != 0 ? " (encrypted)" : "");
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user