]> Pileus Git - ~andy/linux/blobdiff - drivers/net/wireless/rndis_wlan.c
rndis_wlan: enable infrastructure before setting random essid
[~andy/linux] / drivers / net / wireless / rndis_wlan.c
index 2309ad2214a06e8ed6178ca9af2e5ba829b3a9ec..c5a674d8d1fbc37b85b671bcda0e0f8b62f15048 100644 (file)
@@ -514,11 +514,6 @@ static struct cfg80211_ops rndis_config_ops = {
 static void *rndis_wiphy_privid = &rndis_wiphy_privid;
 
 
-static const unsigned char zero_bssid[ETH_ALEN] = {0,};
-static const unsigned char ffff_bssid[ETH_ALEN] = { 0xff, 0xff, 0xff,
-                                                       0xff, 0xff, 0xff };
-
-
 static struct rndis_wlan_private *get_rndis_wlan_priv(struct usbnet *dev)
 {
        return (struct rndis_wlan_private *)dev->driver_priv;
@@ -926,6 +921,7 @@ static int freq_to_dsconfig(struct iw_freq *freq, unsigned int *dsconfig)
 /*
  * common functions
  */
+static int set_infra_mode(struct usbnet *usbdev, int mode);
 static void restore_keys(struct usbnet *usbdev);
 static int rndis_check_bssid_list(struct usbnet *usbdev);
 
@@ -995,7 +991,7 @@ static int is_associated(struct usbnet *usbdev)
 
        ret = get_bssid(usbdev, bssid);
 
-       return(ret == 0 && memcmp(bssid, zero_bssid, ETH_ALEN) != 0);
+       return (ret == 0 && !is_zero_ether_addr(bssid));
 }
 
 
@@ -1019,6 +1015,11 @@ static int disassociate(struct usbnet *usbdev, int reset_ssid)
        /* disassociate causes radio to be turned off; if reset_ssid
         * is given, set random ssid to enable radio */
        if (reset_ssid) {
+               /* Set device to infrastructure mode so we don't get ad-hoc
+                * 'media connect' indications with the random ssid.
+                */
+               set_infra_mode(usbdev, NDIS_80211_INFRA_INFRA);
+
                ssid.length = cpu_to_le32(sizeof(ssid.essid));
                get_random_bytes(&ssid.essid[2], sizeof(ssid.essid)-2);
                ssid.essid[0] = 0x1;
@@ -1293,8 +1294,8 @@ static int add_wpa_key(struct usbnet *usbdev, const u8 *key, int key_len,
                devdbg(usbdev, "add_wpa_key: recv seq flag without buffer");
                return -EINVAL;
        }
-       is_addr_ok = addr && memcmp(addr, zero_bssid, ETH_ALEN) != 0 &&
-                       memcmp(addr, ffff_bssid, ETH_ALEN) != 0;
+       is_addr_ok = addr && !is_zero_ether_addr(addr) &&
+                                       !is_broadcast_ether_addr(addr);
        if ((flags & NDIS_80211_ADDKEY_PAIRWISE_KEY) && !is_addr_ok) {
                devdbg(usbdev, "add_wpa_key: pairwise but bssid invalid (%pM)",
                        addr);
@@ -1379,8 +1380,8 @@ static int restore_key(struct usbnet *usbdev, int key_idx)
                /*if (priv->encr_tx_key_index == key_idx)
                        flags |= NDIS_80211_ADDKEY_TRANSMIT_KEY;*/
 
-               if (memcmp(key.bssid, zero_bssid, ETH_ALEN) != 0 &&
-                               memcmp(key.bssid, ffff_bssid, ETH_ALEN) != 0)
+               if (!is_zero_ether_addr(key.bssid) &&
+                               !is_broadcast_ether_addr(key.bssid))
                        flags |= NDIS_80211_ADDKEY_PAIRWISE_KEY;
 
                return add_wpa_key(usbdev, key.material, key.len, key_idx,
@@ -1430,7 +1431,7 @@ static int remove_key(struct usbnet *usbdev, int index, u8 bssid[ETH_ALEN])
                remove_key.index = cpu_to_le32(index);
                if (bssid) {
                        /* pairwise key */
-                       if (memcmp(bssid, ffff_bssid, ETH_ALEN) != 0)
+                       if (!is_broadcast_ether_addr(bssid))
                                remove_key.index |=
                                        NDIS_80211_ADDKEY_PAIRWISE_KEY;
                        memcpy(remove_key.bssid, bssid,
@@ -1531,7 +1532,8 @@ static int rndis_change_virtual_intf(struct wiphy *wiphy,
                                        enum nl80211_iftype type, u32 *flags,
                                        struct vif_params *params)
 {
-       struct usbnet *usbdev = netdev_priv(dev);
+       struct rndis_wlan_private *priv = wiphy_priv(wiphy);
+       struct usbnet *usbdev = priv->usbdev;
        int mode;
 
        switch (type) {
@@ -1545,6 +1547,8 @@ static int rndis_change_virtual_intf(struct wiphy *wiphy,
                return -EINVAL;
        }
 
+       priv->wdev.iftype = type;
+
        return set_infra_mode(usbdev, mode);
 }
 
@@ -1607,7 +1611,7 @@ static int rndis_get_tx_power(struct wiphy *wiphy, int *dbm)
 }
 
 
-#define SCAN_DELAY_JIFFIES (HZ)
+#define SCAN_DELAY_JIFFIES (6 * HZ)
 static int rndis_scan(struct wiphy *wiphy, struct net_device *dev,
                        struct cfg80211_scan_request *request)
 {
@@ -2319,68 +2323,77 @@ static const struct iw_handler_def rndis_iw_handlers = {
 };
 
 
-static void rndis_wlan_worker(struct work_struct *work)
+static void rndis_wlan_do_link_up_work(struct usbnet *usbdev)
 {
-       struct rndis_wlan_private *priv =
-               container_of(work, struct rndis_wlan_private, work);
-       struct usbnet *usbdev = priv->usbdev;
-       union iwreq_data evt;
-       unsigned char bssid[ETH_ALEN];
        struct ndis_80211_assoc_info *info;
-       int assoc_size = sizeof(*info) + IW_CUSTOM_MAX + 32;
+       union iwreq_data evt;
+       u8 assoc_buf[sizeof(*info) + IW_CUSTOM_MAX + 32];
+       u8 bssid[ETH_ALEN];
        int ret, offset;
 
-       if (test_and_clear_bit(WORK_LINK_UP, &priv->work_pending)) {
-               netif_carrier_on(usbdev->net);
-
-               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);
-                       }
+       memset(assoc_buf, 0, sizeof(assoc_buf));
+       info = (void *)assoc_buf;
+
+       netif_carrier_on(usbdev->net);
+
+       /* Get association info IEs from device and send them back to
+        * userspace. */
+       ret = get_association_info(usbdev, info, sizeof(assoc_buf));
+       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);
                }
 
-               kfree(info);
-
-get_bssid:
-               ret = get_bssid(usbdev, bssid);
-               if (!ret) {
-                       evt.data.flags = 0;
-                       evt.data.length = 0;
-                       memcpy(evt.ap_addr.sa_data, bssid, ETH_ALEN);
-                       wireless_send_event(usbdev->net, SIOCGIWAP, &evt, NULL);
+               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);
                }
 
                usbnet_resume_rx(usbdev);
        }
 
-       if (test_and_clear_bit(WORK_LINK_DOWN, &priv->work_pending)) {
-               netif_carrier_off(usbdev->net);
-
+       ret = get_bssid(usbdev, bssid);
+       if (!ret) {
                evt.data.flags = 0;
                evt.data.length = 0;
-               memset(evt.ap_addr.sa_data, 0, ETH_ALEN);
+               memcpy(evt.ap_addr.sa_data, bssid, ETH_ALEN);
                wireless_send_event(usbdev->net, SIOCGIWAP, &evt, NULL);
        }
 
+       usbnet_resume_rx(usbdev);
+}
+
+static void rndis_wlan_do_link_down_work(struct usbnet *usbdev)
+{
+       union iwreq_data evt;
+
+       netif_carrier_off(usbdev->net);
+
+       evt.data.flags = 0;
+       evt.data.length = 0;
+       memset(evt.ap_addr.sa_data, 0, ETH_ALEN);
+       wireless_send_event(usbdev->net, SIOCGIWAP, &evt, NULL);
+}
+
+static void rndis_wlan_worker(struct work_struct *work)
+{
+       struct rndis_wlan_private *priv =
+               container_of(work, struct rndis_wlan_private, work);
+       struct usbnet *usbdev = priv->usbdev;
+
+       if (test_and_clear_bit(WORK_LINK_UP, &priv->work_pending))
+               rndis_wlan_do_link_up_work(usbdev);
+
+       if (test_and_clear_bit(WORK_LINK_DOWN, &priv->work_pending))
+               rndis_wlan_do_link_down_work(usbdev);
+
        if (test_and_clear_bit(WORK_SET_MULTICAST_LIST, &priv->work_pending))
                set_multicast_list(usbdev);
 }