rndis_wlan: Make connections to TKIP PSK networks work
authorScott Ashcroft <scott.ashcroft@talk21.com>
Mon, 26 May 2008 21:06:15 +0000 (00:06 +0300)
committerJohn W. Linville <linville@tuxdriver.com>
Wed, 28 May 2008 20:43:46 +0000 (16:43 -0400)
This patch allows the rndis_wlan driver to connect to TKIP PSK
networks.  It uses the ASSOCIATION_INFORMATION RNDIS call to pull back
the IEs and sends them back to userspace using wireless events. Tested
on a few wireless networks I have access to. Based on the similar
code in ndiswrapper.

Signed-off-by: Scott Ashcroft <scott.ashcroft@talk21.com>
[edit: cleanups]
Signed-off-by: Jussi Kivilinna <jussi.kivilinna@mbnet.fi>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
drivers/net/wireless/rndis_wlan.c

index d0b1fb15c7091f8b3334c94f240fe6fa445e6c17..ac56f8d9a5e56026eb1097c3c638a93b5d5b2279 100644 (file)
@@ -116,6 +116,7 @@ MODULE_PARM_DESC(workaround_interval,
 #define OID_802_11_ENCRYPTION_STATUS           ccpu2(0x0d01011b)
 #define OID_802_11_ADD_KEY                     ccpu2(0x0d01011d)
 #define OID_802_11_REMOVE_KEY                  ccpu2(0x0d01011e)
+#define OID_802_11_ASSOCIATION_INFORMATION     ccpu2(0x0d01011f)
 #define OID_802_11_PMKID                       ccpu2(0x0d010123)
 #define OID_802_11_NETWORK_TYPES_SUPPORTED     ccpu2(0x0d010203)
 #define OID_802_11_NETWORK_TYPE_IN_USE         ccpu2(0x0d010204)
@@ -271,6 +272,26 @@ struct ndis_config_param {
        __le32 value_length;
 } __attribute__((packed));
 
+struct ndis_80211_assoc_info {
+       __le32 length;
+       __le16 req_ies;
+       struct req_ie {
+               __le16 capa;
+               __le16 listen_interval;
+               u8 cur_ap_address[6];
+       } req_ie;
+       __le32 req_ie_length;
+       __le32 offset_req_ies;
+       __le16 resp_ies;
+       struct resp_ie {
+               __le16 capa;
+               __le16 status_code;
+               __le16 assoc_id;
+       } resp_ie;
+       __le32 resp_ie_length;
+       __le32 offset_resp_ies;
+} __attribute__((packed));
+
 /* these have to match what is in wpa_supplicant */
 enum wpa_alg { WPA_ALG_NONE, WPA_ALG_WEP, WPA_ALG_TKIP, WPA_ALG_CCMP };
 enum wpa_cipher { CIPHER_NONE, CIPHER_WEP40, CIPHER_TKIP, CIPHER_CCMP,
@@ -674,6 +695,12 @@ static int get_bssid(struct usbnet *usbdev, u8 bssid[ETH_ALEN])
        return ret;
 }
 
+static int get_association_info(struct usbnet *usbdev,
+                       struct ndis_80211_assoc_info *info, int len)
+{
+       return rndis_query_oid(usbdev, OID_802_11_ASSOCIATION_INFORMATION,
+                               info, &len);
+}
 
 static int is_associated(struct usbnet *usbdev)
 {
@@ -2182,11 +2209,40 @@ static void rndis_wext_worker(struct work_struct *work)
        struct usbnet *usbdev = priv->usbdev;
        union iwreq_data evt;
        unsigned char bssid[ETH_ALEN];
-       int ret;
+       struct ndis_80211_assoc_info *info;
+       int assoc_size = sizeof(*info) + IW_CUSTOM_MAX + 32;
+       int ret, offset;
 
        if (test_and_clear_bit(WORK_CONNECTION_EVENT, &priv->work_pending)) {
-               ret = get_bssid(usbdev, bssid);
+               info = kzalloc(assoc_size, GFP_KERNEL);
+               if (!info)
+                       goto get_bssid;
 
+               /* Get association info IEs from device and send them back to
+                * userspace. */
+               ret = get_association_info(usbdev, info, assoc_size);
+               if (!ret) {
+                       evt.data.length = le32_to_cpu(info->req_ie_length);
+                       if (evt.data.length > 0) {
+                               offset = le32_to_cpu(info->offset_req_ies);
+                               wireless_send_event(usbdev->net,
+                                       IWEVASSOCREQIE, &evt,
+                                       (char *)info + offset);
+                       }
+
+                       evt.data.length = le32_to_cpu(info->resp_ie_length);
+                       if (evt.data.length > 0) {
+                               offset = le32_to_cpu(info->offset_resp_ies);
+                               wireless_send_event(usbdev->net,
+                                       IWEVASSOCRESPIE, &evt,
+                                       (char *)info + offset);
+                       }
+               }
+
+               kfree(info);
+
+get_bssid:
+               ret = get_bssid(usbdev, bssid);
                if (!ret) {
                        evt.data.flags = 0;
                        evt.data.length = 0;