[haiku-commits] r39792 - in haiku/trunk: headers/os/net src/kits/network/libnetapi src/tests/kits/net

  • From: axeld@xxxxxxxxxxxxxxxx
  • To: haiku-commits@xxxxxxxxxxxxx
  • Date: Thu, 9 Dec 2010 23:33:35 +0100 (CET)

Author: axeld
Date: 2010-12-09 23:33:34 +0100 (Thu, 09 Dec 2010)
New Revision: 39792
Changeset: http://dev.haiku-os.org/changeset/39792

Modified:
   haiku/trunk/headers/os/net/NetworkDevice.h
   haiku/trunk/src/kits/network/libnetapi/NetworkDevice.cpp
   haiku/trunk/src/tests/kits/net/wlan_test.cpp
Log:
* 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.


Modified: haiku/trunk/headers/os/net/NetworkDevice.h
===================================================================
--- haiku/trunk/headers/os/net/NetworkDevice.h  2010-12-09 16:47:49 UTC (rev 
39791)
+++ haiku/trunk/headers/os/net/NetworkDevice.h  2010-12-09 22:33:34 UTC (rev 
39792)
@@ -22,6 +22,7 @@
        uint32                          flags;
        uint32                          authentication_mode;
        uint32                          cipher;
+       uint32                          group_cipher;
        uint32                          key_mode;
 };
 
@@ -41,15 +42,18 @@
        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

Modified: haiku/trunk/src/kits/network/libnetapi/NetworkDevice.cpp
===================================================================
--- haiku/trunk/src/kits/network/libnetapi/NetworkDevice.cpp    2010-12-09 
16:47:49 UTC (rev 39791)
+++ haiku/trunk/src/kits/network/libnetapi/NetworkDevice.cpp    2010-12-09 
22:33:34 UTC (rev 39792)
@@ -22,6 +22,14 @@
 }
 
 
+//#define TRACE_DEVICE
+#ifdef TRACE_DEVICE
+#      define TRACE(x, ...) printf(x, __VA_ARGS__);
+#else
+#      define TRACE(x, ...) ;
+#endif
+
+
 namespace {
 
 
@@ -111,27 +119,217 @@
 }
 
 
+//! 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 @@
        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 @@
        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);
 }

Modified: haiku/trunk/src/tests/kits/net/wlan_test.cpp
===================================================================
--- haiku/trunk/src/tests/kits/net/wlan_test.cpp        2010-12-09 16:47:49 UTC 
(rev 39791)
+++ haiku/trunk/src/tests/kits/net/wlan_test.cpp        2010-12-09 22:33:34 UTC 
(rev 39792)
@@ -21,11 +21,30 @@
 }
 
 
+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)" 
: "");
 }
 


Other related posts:

  • » [haiku-commits] r39792 - in haiku/trunk: headers/os/net src/kits/network/libnetapi src/tests/kits/net - axeld