Merge branch 'upstream' of git://git.linux-mips.org/pub/scm/ralf/upstream-linus
[linux-2.6-block.git] / net / wireless / sme.c
index 5445581717874e1409d994f24c9ca7263e62ab38..584fdc347221d36d0be28ebfe87906d7e978508a 100644 (file)
@@ -81,7 +81,7 @@ static int cfg80211_conn_scan(struct wireless_dev *wdev)
                return -ENOMEM;
 
        if (wdev->conn->params.channel) {
-               enum ieee80211_band band = wdev->conn->params.channel->band;
+               enum nl80211_band band = wdev->conn->params.channel->band;
                struct ieee80211_supported_band *sband =
                        wdev->wiphy->bands[band];
 
@@ -93,11 +93,11 @@ static int cfg80211_conn_scan(struct wireless_dev *wdev)
                request->rates[band] = (1 << sband->n_bitrates) - 1;
        } else {
                int i = 0, j;
-               enum ieee80211_band band;
+               enum nl80211_band band;
                struct ieee80211_supported_band *bands;
                struct ieee80211_channel *channel;
 
-               for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
+               for (band = 0; band < NUM_NL80211_BANDS; band++) {
                        bands = wdev->wiphy->bands[band];
                        if (!bands)
                                continue;
@@ -119,6 +119,8 @@ static int cfg80211_conn_scan(struct wireless_dev *wdev)
                wdev->conn->params.ssid_len);
        request->ssids[0].ssid_len = wdev->conn->params.ssid_len;
 
+       eth_broadcast_addr(request->bssid);
+
        request->wdev = wdev;
        request->wiphy = &rdev->wiphy;
        request->scan_start = jiffies;
@@ -221,7 +223,7 @@ void cfg80211_conn_work(struct work_struct *work)
 
        rtnl_lock();
 
-       list_for_each_entry(wdev, &rdev->wdev_list, list) {
+       list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) {
                if (!wdev->netdev)
                        continue;
 
@@ -490,8 +492,18 @@ static int cfg80211_sme_connect(struct wireless_dev *wdev,
        if (!rdev->ops->auth || !rdev->ops->assoc)
                return -EOPNOTSUPP;
 
-       if (wdev->current_bss)
-               return -EALREADY;
+       if (wdev->current_bss) {
+               if (!prev_bssid)
+                       return -EALREADY;
+               if (prev_bssid &&
+                   !ether_addr_equal(prev_bssid, wdev->current_bss->pub.bssid))
+                       return -ENOTCONN;
+               cfg80211_unhold_bss(wdev->current_bss);
+               cfg80211_put_bss(wdev->wiphy, &wdev->current_bss->pub);
+               wdev->current_bss = NULL;
+
+               cfg80211_sme_free(wdev);
+       }
 
        if (WARN_ON(wdev->conn))
                return -EINPROGRESS;
@@ -605,7 +617,7 @@ static bool cfg80211_is_all_idle(void)
         * count as new regulatory hints.
         */
        list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
-               list_for_each_entry(wdev, &rdev->wdev_list, list) {
+               list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) {
                        wdev_lock(wdev);
                        if (wdev->conn || wdev->current_bss)
                                is_all_idle = false;
@@ -741,19 +753,32 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
        kfree(country_ie);
 }
 
-void cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
-                            const u8 *req_ie, size_t req_ie_len,
-                            const u8 *resp_ie, size_t resp_ie_len,
-                            u16 status, gfp_t gfp)
+/* Consumes bss object one way or another */
+void cfg80211_connect_bss(struct net_device *dev, const u8 *bssid,
+                         struct cfg80211_bss *bss, const u8 *req_ie,
+                         size_t req_ie_len, const u8 *resp_ie,
+                         size_t resp_ie_len, u16 status, gfp_t gfp)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
        struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
        struct cfg80211_event *ev;
        unsigned long flags;
 
+       if (bss) {
+               /* Make sure the bss entry provided by the driver is valid. */
+               struct cfg80211_internal_bss *ibss = bss_from_pub(bss);
+
+               if (WARN_ON(list_empty(&ibss->list))) {
+                       cfg80211_put_bss(wdev->wiphy, bss);
+                       return;
+               }
+       }
+
        ev = kzalloc(sizeof(*ev) + req_ie_len + resp_ie_len, gfp);
-       if (!ev)
+       if (!ev) {
+               cfg80211_put_bss(wdev->wiphy, bss);
                return;
+       }
 
        ev->type = EVENT_CONNECT_RESULT;
        if (bssid)
@@ -768,6 +793,9 @@ void cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
                ev->cr.resp_ie_len = resp_ie_len;
                memcpy((void *)ev->cr.resp_ie, resp_ie, resp_ie_len);
        }
+       if (bss)
+               cfg80211_hold_bss(bss_from_pub(bss));
+       ev->cr.bss = bss;
        ev->cr.status = status;
 
        spin_lock_irqsave(&wdev->event_lock, flags);
@@ -775,7 +803,7 @@ void cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
        spin_unlock_irqrestore(&wdev->event_lock, flags);
        queue_work(cfg80211_wq, &rdev->event_work);
 }
-EXPORT_SYMBOL(cfg80211_connect_result);
+EXPORT_SYMBOL(cfg80211_connect_bss);
 
 /* Consumes bss object one way or another */
 void __cfg80211_roamed(struct wireless_dev *wdev,