netdev: Add netdev->addr_list_lock protection.
[safe/jmp/linux-2.6] / net / mac80211 / mlme.c
index 1e4054b..1232ba2 100644 (file)
@@ -78,7 +78,7 @@ static void ieee80211_send_probe_req(struct net_device *dev, u8 *dst,
 static struct ieee80211_sta_bss *
 ieee80211_rx_bss_get(struct net_device *dev, u8 *bssid, int freq,
                     u8 *ssid, u8 ssid_len);
-static void ieee80211_rx_bss_put(struct net_device *dev,
+static void ieee80211_rx_bss_put(struct ieee80211_local *local,
                                 struct ieee80211_sta_bss *bss);
 static int ieee80211_sta_find_ibss(struct net_device *dev,
                                   struct ieee80211_if_sta *ifsta);
@@ -345,8 +345,8 @@ static void ieee80211_sta_wmm_params(struct net_device *dev,
                params.aifs = pos[0] & 0x0f;
                params.cw_max = ecw2cw((pos[1] & 0xf0) >> 4);
                params.cw_min = ecw2cw(pos[1] & 0x0f);
-               params.txop = pos[2] | (pos[3] << 8);
-#ifdef CONFIG_MAC80211_DEBUG
+               params.txop = get_unaligned_le16(pos + 2);
+#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
                printk(KERN_DEBUG "%s: WMM queue=%d aci=%d acm=%d aifs=%d "
                       "cWmin=%d cWmax=%d txop=%d\n",
                       dev->name, queue, aci, acm, params.aifs, params.cw_min,
@@ -366,11 +366,14 @@ static u32 ieee80211_handle_protect_preamb(struct ieee80211_sub_if_data *sdata,
                                           bool use_short_preamble)
 {
        struct ieee80211_bss_conf *bss_conf = &sdata->bss_conf;
+#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
        struct ieee80211_if_sta *ifsta = &sdata->u.sta;
        DECLARE_MAC_BUF(mac);
+#endif
        u32 changed = 0;
 
        if (use_protection != bss_conf->use_cts_prot) {
+#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
                if (net_ratelimit()) {
                        printk(KERN_DEBUG "%s: CTS protection %s (BSSID="
                               "%s)\n",
@@ -378,11 +381,13 @@ static u32 ieee80211_handle_protect_preamb(struct ieee80211_sub_if_data *sdata,
                               use_protection ? "enabled" : "disabled",
                               print_mac(mac, ifsta->bssid));
                }
+#endif
                bss_conf->use_cts_prot = use_protection;
                changed |= BSS_CHANGED_ERP_CTS_PROT;
        }
 
        if (use_short_preamble != bss_conf->use_short_preamble) {
+#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
                if (net_ratelimit()) {
                        printk(KERN_DEBUG "%s: switched to %s barker preamble"
                               " (BSSID=%s)\n",
@@ -390,6 +395,7 @@ static u32 ieee80211_handle_protect_preamb(struct ieee80211_sub_if_data *sdata,
                               use_short_preamble ? "short" : "long",
                               print_mac(mac, ifsta->bssid));
                }
+#endif
                bss_conf->use_short_preamble = use_short_preamble;
                changed |= BSS_CHANGED_ERP_PREAMBLE;
        }
@@ -548,7 +554,7 @@ static void ieee80211_set_associated(struct net_device *dev,
 
                        changed |= ieee80211_handle_bss_capability(sdata, bss);
 
-                       ieee80211_rx_bss_put(dev, bss);
+                       ieee80211_rx_bss_put(local, bss);
                }
 
                if (conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) {
@@ -558,16 +564,15 @@ static void ieee80211_set_associated(struct net_device *dev,
                        sdata->bss_conf.ht_bss_conf = &conf->ht_bss_conf;
                }
 
-               netif_carrier_on(dev);
                ifsta->flags |= IEEE80211_STA_PREV_BSSID_SET;
                memcpy(ifsta->prev_bssid, sdata->u.sta.bssid, ETH_ALEN);
                memcpy(wrqu.ap_addr.sa_data, sdata->u.sta.bssid, ETH_ALEN);
                ieee80211_sta_send_associnfo(dev, ifsta);
        } else {
+               netif_carrier_off(dev);
                ieee80211_sta_tear_down_BA_sessions(dev, ifsta->bssid);
                ifsta->flags &= ~IEEE80211_STA_ASSOCIATED;
-               netif_carrier_off(dev);
-               ieee80211_reset_erp_info(dev);
+               changed |= ieee80211_reset_erp_info(dev);
 
                sdata->bss_conf.assoc_ht = 0;
                sdata->bss_conf.ht_conf = NULL;
@@ -580,6 +585,10 @@ static void ieee80211_set_associated(struct net_device *dev,
 
        sdata->bss_conf.assoc = assoc;
        ieee80211_bss_info_change_notify(sdata, changed);
+
+       if (assoc)
+               netif_carrier_on(dev);
+
        wrqu.ap_addr.sa_family = ARPHRD_ETHER;
        wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
 }
@@ -751,7 +760,7 @@ static void ieee80211_send_assoc(struct net_device *dev,
                    (local->hw.flags & IEEE80211_HW_SPECTRUM_MGMT))
                        capab |= WLAN_CAPABILITY_SPECTRUM_MGMT;
 
-               ieee80211_rx_bss_put(dev, bss);
+               ieee80211_rx_bss_put(local, bss);
        } else {
                rates = ~0;
                rates_len = sband->n_bitrates;
@@ -983,7 +992,7 @@ static int ieee80211_privacy_mismatch(struct net_device *dev,
        wep_privacy = !!ieee80211_sta_wep_configured(dev);
        privacy_invoked = !!(ifsta->flags & IEEE80211_STA_PRIVACY_INVOKED);
 
-       ieee80211_rx_bss_put(dev, bss);
+       ieee80211_rx_bss_put(local, bss);
 
        if ((bss_privacy == wep_privacy) || (bss_privacy == privacy_invoked))
                return 0;
@@ -1175,14 +1184,10 @@ static void ieee80211_auth_challenge(struct net_device *dev,
        u8 *pos;
        struct ieee802_11_elems elems;
 
-       printk(KERN_DEBUG "%s: replying to auth challenge\n", dev->name);
        pos = mgmt->u.auth.variable;
        ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems);
-       if (!elems.challenge) {
-               printk(KERN_DEBUG "%s: no challenge IE in shared key auth "
-                      "frame\n", dev->name);
+       if (!elems.challenge)
                return;
-       }
        ieee80211_send_auth(dev, ifsta, 3, elems.challenge - 2,
                            elems.challenge_len + 2, 1);
 }
@@ -1364,9 +1369,11 @@ static void ieee80211_sta_process_addba_request(struct net_device *dev,
        sta->ampdu_mlme.tid_rx[tid] =
                        kmalloc(sizeof(struct tid_ampdu_rx), GFP_ATOMIC);
        if (!sta->ampdu_mlme.tid_rx[tid]) {
+#ifdef CONFIG_MAC80211_HT_DEBUG
                if (net_ratelimit())
                        printk(KERN_ERR "allocate rx mlme to tid %d failed\n",
                                        tid);
+#endif
                goto end;
        }
        /* rx timer */
@@ -1382,9 +1389,11 @@ static void ieee80211_sta_process_addba_request(struct net_device *dev,
        tid_agg_rx->reorder_buf =
                kmalloc(buf_size * sizeof(struct sk_buff *), GFP_ATOMIC);
        if (!tid_agg_rx->reorder_buf) {
+#ifdef CONFIG_MAC80211_HT_DEBUG
                if (net_ratelimit())
                        printk(KERN_ERR "can not allocate reordering buffer "
                               "to tid %d\n", tid);
+#endif
                kfree(sta->ampdu_mlme.tid_rx[tid]);
                goto end;
        }
@@ -1451,8 +1460,6 @@ static void ieee80211_sta_process_addba_resp(struct net_device *dev,
 
        if (!(*state & HT_ADDBA_REQUESTED_MSK)) {
                spin_unlock_bh(&sta->lock);
-               printk(KERN_DEBUG "state not HT_ADDBA_REQUESTED_MSK:"
-                       "%d\n", *state);
                goto addba_resp_exit;
        }
 
@@ -1471,22 +1478,14 @@ static void ieee80211_sta_process_addba_resp(struct net_device *dev,
 #endif /* CONFIG_MAC80211_HT_DEBUG */
        if (le16_to_cpu(mgmt->u.action.u.addba_resp.status)
                        == WLAN_STATUS_SUCCESS) {
-               if (*state & HT_ADDBA_RECEIVED_MSK)
-                       printk(KERN_DEBUG "double addBA response\n");
-
                *state |= HT_ADDBA_RECEIVED_MSK;
                sta->ampdu_mlme.addba_req_num[tid] = 0;
 
-               if (*state == HT_AGG_STATE_OPERATIONAL) {
-                       printk(KERN_DEBUG "Aggregation on for tid %d \n", tid);
+               if (*state == HT_AGG_STATE_OPERATIONAL)
                        ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]);
-               }
 
                spin_unlock_bh(&sta->lock);
-               printk(KERN_DEBUG "recipient accepted agg: tid %d \n", tid);
        } else {
-               printk(KERN_DEBUG "recipient rejected agg: tid %d \n", tid);
-
                sta->ampdu_mlme.addba_req_num[tid]++;
                /* this will allow the state check in stop_BA_session */
                *state = HT_AGG_STATE_OPERATIONAL;
@@ -1542,6 +1541,35 @@ void ieee80211_send_delba(struct net_device *dev, const u8 *da, u16 tid,
        ieee80211_sta_tx(dev, skb, 0);
 }
 
+void ieee80211_send_bar(struct net_device *dev, u8 *ra, u16 tid, u16 ssn)
+{
+       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+       struct sk_buff *skb;
+       struct ieee80211_bar *bar;
+       u16 bar_control = 0;
+
+       skb = dev_alloc_skb(sizeof(*bar) + local->hw.extra_tx_headroom);
+       if (!skb) {
+               printk(KERN_ERR "%s: failed to allocate buffer for "
+                       "bar frame\n", dev->name);
+               return;
+       }
+       skb_reserve(skb, local->hw.extra_tx_headroom);
+       bar = (struct ieee80211_bar *)skb_put(skb, sizeof(*bar));
+       memset(bar, 0, sizeof(*bar));
+       bar->frame_control = IEEE80211_FC(IEEE80211_FTYPE_CTL,
+                                       IEEE80211_STYPE_BACK_REQ);
+       memcpy(bar->ra, ra, ETH_ALEN);
+       memcpy(bar->ta, dev->dev_addr, ETH_ALEN);
+       bar_control |= (u16)IEEE80211_BAR_CTRL_ACK_POLICY_NORMAL;
+       bar_control |= (u16)IEEE80211_BAR_CTRL_CBMTID_COMPRESSED_BA;
+       bar_control |= (u16)(tid << 12);
+       bar->control = cpu_to_le16(bar_control);
+       bar->start_seq_num = cpu_to_le16(ssn);
+
+       ieee80211_sta_tx(dev, skb, 0);
+}
+
 void ieee80211_sta_stop_rx_ba_session(struct net_device *dev, u8 *ra, u16 tid,
                                        u16 initiator, u16 reason)
 {
@@ -1585,7 +1613,7 @@ void ieee80211_sta_stop_rx_ba_session(struct net_device *dev, u8 *ra, u16 tid,
                                        ra, tid, NULL);
        if (ret)
                printk(KERN_DEBUG "HW problem - can not stop rx "
-                               "aggergation for tid %d\n", tid);
+                               "aggregation for tid %d\n", tid);
 
        /* shutdown timer has not expired */
        if (initiator != WLAN_BACK_TIMER)
@@ -1691,12 +1719,16 @@ void sta_addba_resp_timer_expired(unsigned long data)
        if (!(*state & HT_ADDBA_REQUESTED_MSK)) {
                spin_unlock_bh(&sta->lock);
                *state = HT_AGG_STATE_IDLE;
+#ifdef CONFIG_MAC80211_HT_DEBUG
                printk(KERN_DEBUG "timer expired on tid %d but we are not "
                                "expecting addBA response there", tid);
+#endif
                goto timer_expired_exit;
        }
 
+#ifdef CONFIG_MAC80211_HT_DEBUG
        printk(KERN_DEBUG "addBA response timer expired on tid %d\n", tid);
+#endif
 
        /* go through the state check in stop_BA_session */
        *state = HT_AGG_STATE_OPERATIONAL;
@@ -1724,7 +1756,9 @@ static void sta_rx_agg_session_timer_expired(unsigned long data)
        struct sta_info *sta = container_of(timer_to_id, struct sta_info,
                                         timer_to_tid[0]);
 
+#ifdef CONFIG_MAC80211_HT_DEBUG
        printk(KERN_DEBUG "rx session timer expired on tid %d\n", (u16)*ptid);
+#endif
        ieee80211_sta_stop_rx_ba_session(sta->sdata->dev, sta->addr,
                                         (u16)*ptid, WLAN_BACK_TIMER,
                                         WLAN_REASON_QSTA_TIMEOUT);
@@ -1819,47 +1853,24 @@ static void ieee80211_rx_mgmt_auth(struct net_device *dev,
        DECLARE_MAC_BUF(mac);
 
        if (ifsta->state != IEEE80211_AUTHENTICATE &&
-           sdata->vif.type != IEEE80211_IF_TYPE_IBSS) {
-               printk(KERN_DEBUG "%s: authentication frame received from "
-                      "%s, but not in authenticate state - ignored\n",
-                      dev->name, print_mac(mac, mgmt->sa));
+           sdata->vif.type != IEEE80211_IF_TYPE_IBSS)
                return;
-       }
 
-       if (len < 24 + 6) {
-               printk(KERN_DEBUG "%s: too short (%zd) authentication frame "
-                      "received from %s - ignored\n",
-                      dev->name, len, print_mac(mac, mgmt->sa));
+       if (len < 24 + 6)
                return;
-       }
 
        if (sdata->vif.type != IEEE80211_IF_TYPE_IBSS &&
-           memcmp(ifsta->bssid, mgmt->sa, ETH_ALEN) != 0) {
-               printk(KERN_DEBUG "%s: authentication frame received from "
-                      "unknown AP (SA=%s BSSID=%s) - "
-                      "ignored\n", dev->name, print_mac(mac, mgmt->sa),
-                      print_mac(mac, mgmt->bssid));
+           memcmp(ifsta->bssid, mgmt->sa, ETH_ALEN) != 0)
                return;
-       }
 
        if (sdata->vif.type != IEEE80211_IF_TYPE_IBSS &&
-           memcmp(ifsta->bssid, mgmt->bssid, ETH_ALEN) != 0) {
-               printk(KERN_DEBUG "%s: authentication frame received from "
-                      "unknown BSSID (SA=%s BSSID=%s) - "
-                      "ignored\n", dev->name, print_mac(mac, mgmt->sa),
-                      print_mac(mac, mgmt->bssid));
+           memcmp(ifsta->bssid, mgmt->bssid, ETH_ALEN) != 0)
                return;
-       }
 
        auth_alg = le16_to_cpu(mgmt->u.auth.auth_alg);
        auth_transaction = le16_to_cpu(mgmt->u.auth.auth_transaction);
        status_code = le16_to_cpu(mgmt->u.auth.status_code);
 
-       printk(KERN_DEBUG "%s: RX authentication from %s (alg=%d "
-              "transaction=%d status=%d)\n",
-              dev->name, print_mac(mac, mgmt->sa), auth_alg,
-              auth_transaction, status_code);
-
        if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS) {
                /*
                 * IEEE 802.11 standard does not require authentication in IBSS
@@ -1867,26 +1878,16 @@ static void ieee80211_rx_mgmt_auth(struct net_device *dev,
                 * However, try to reply to authentication attempts if someone
                 * has actually implemented this.
                 */
-               if (auth_alg != WLAN_AUTH_OPEN || auth_transaction != 1) {
-                       printk(KERN_DEBUG "%s: unexpected IBSS authentication "
-                              "frame (alg=%d transaction=%d)\n",
-                              dev->name, auth_alg, auth_transaction);
+               if (auth_alg != WLAN_AUTH_OPEN || auth_transaction != 1)
                        return;
-               }
                ieee80211_send_auth(dev, ifsta, 2, NULL, 0, 0);
        }
 
        if (auth_alg != ifsta->auth_alg ||
-           auth_transaction != ifsta->auth_transaction) {
-               printk(KERN_DEBUG "%s: unexpected authentication frame "
-                      "(alg=%d transaction=%d)\n",
-                      dev->name, auth_alg, auth_transaction);
+           auth_transaction != ifsta->auth_transaction)
                return;
-       }
 
        if (status_code != WLAN_STATUS_SUCCESS) {
-               printk(KERN_DEBUG "%s: AP denied authentication (auth_alg=%d "
-                      "code=%d)\n", dev->name, ifsta->auth_alg, status_code);
                if (status_code == WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG) {
                        u8 algs[3];
                        const int num_algs = ARRAY_SIZE(algs);
@@ -1915,9 +1916,6 @@ static void ieee80211_rx_mgmt_auth(struct net_device *dev,
                                    !ieee80211_sta_wep_configured(dev))
                                        continue;
                                ifsta->auth_alg = algs[pos];
-                               printk(KERN_DEBUG "%s: set auth_alg=%d for "
-                                      "next try\n",
-                                      dev->name, ifsta->auth_alg);
                                break;
                        }
                }
@@ -1947,27 +1945,14 @@ static void ieee80211_rx_mgmt_deauth(struct net_device *dev,
        u16 reason_code;
        DECLARE_MAC_BUF(mac);
 
-       if (len < 24 + 2) {
-               printk(KERN_DEBUG "%s: too short (%zd) deauthentication frame "
-                      "received from %s - ignored\n",
-                      dev->name, len, print_mac(mac, mgmt->sa));
+       if (len < 24 + 2)
                return;
-       }
 
-       if (memcmp(ifsta->bssid, mgmt->sa, ETH_ALEN) != 0) {
-               printk(KERN_DEBUG "%s: deauthentication frame received from "
-                      "unknown AP (SA=%s BSSID=%s) - "
-                      "ignored\n", dev->name, print_mac(mac, mgmt->sa),
-                      print_mac(mac, mgmt->bssid));
+       if (memcmp(ifsta->bssid, mgmt->sa, ETH_ALEN))
                return;
-       }
 
        reason_code = le16_to_cpu(mgmt->u.deauth.reason_code);
 
-       printk(KERN_DEBUG "%s: RX deauthentication from %s"
-              " (reason=%d)\n",
-              dev->name, print_mac(mac, mgmt->sa), reason_code);
-
        if (ifsta->flags & IEEE80211_STA_AUTHENTICATED)
                printk(KERN_DEBUG "%s: deauthenticated\n", dev->name);
 
@@ -1992,27 +1977,14 @@ static void ieee80211_rx_mgmt_disassoc(struct net_device *dev,
        u16 reason_code;
        DECLARE_MAC_BUF(mac);
 
-       if (len < 24 + 2) {
-               printk(KERN_DEBUG "%s: too short (%zd) disassociation frame "
-                      "received from %s - ignored\n",
-                      dev->name, len, print_mac(mac, mgmt->sa));
+       if (len < 24 + 2)
                return;
-       }
 
-       if (memcmp(ifsta->bssid, mgmt->sa, ETH_ALEN) != 0) {
-               printk(KERN_DEBUG "%s: disassociation frame received from "
-                      "unknown AP (SA=%s BSSID=%s) - "
-                      "ignored\n", dev->name, print_mac(mac, mgmt->sa),
-                      print_mac(mac, mgmt->bssid));
+       if (memcmp(ifsta->bssid, mgmt->sa, ETH_ALEN))
                return;
-       }
 
        reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code);
 
-       printk(KERN_DEBUG "%s: RX disassociation from %s"
-              " (reason=%d)\n",
-              dev->name, print_mac(mac, mgmt->sa), reason_code);
-
        if (ifsta->flags & IEEE80211_STA_ASSOCIATED)
                printk(KERN_DEBUG "%s: disassociated\n", dev->name);
 
@@ -2048,27 +2020,14 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
        /* AssocResp and ReassocResp have identical structure, so process both
         * of them in this function. */
 
-       if (ifsta->state != IEEE80211_ASSOCIATE) {
-               printk(KERN_DEBUG "%s: association frame received from "
-                      "%s, but not in associate state - ignored\n",
-                      dev->name, print_mac(mac, mgmt->sa));
+       if (ifsta->state != IEEE80211_ASSOCIATE)
                return;
-       }
 
-       if (len < 24 + 6) {
-               printk(KERN_DEBUG "%s: too short (%zd) association frame "
-                      "received from %s - ignored\n",
-                      dev->name, len, print_mac(mac, mgmt->sa));
+       if (len < 24 + 6)
                return;
-       }
 
-       if (memcmp(ifsta->bssid, mgmt->sa, ETH_ALEN) != 0) {
-               printk(KERN_DEBUG "%s: association frame received from "
-                      "unknown AP (SA=%s BSSID=%s) - "
-                      "ignored\n", dev->name, print_mac(mac, mgmt->sa),
-                      print_mac(mac, mgmt->bssid));
+       if (memcmp(ifsta->bssid, mgmt->sa, ETH_ALEN) != 0)
                return;
-       }
 
        capab_info = le16_to_cpu(mgmt->u.assoc_resp.capab_info);
        status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code);
@@ -2135,7 +2094,7 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
                        sta->last_signal = bss->signal;
                        sta->last_qual = bss->qual;
                        sta->last_noise = bss->noise;
-                       ieee80211_rx_bss_put(dev, bss);
+                       ieee80211_rx_bss_put(local, bss);
                }
 
                err = sta_info_insert(sta);
@@ -2253,10 +2212,9 @@ static void __ieee80211_rx_bss_hash_add(struct net_device *dev,
 
 
 /* Caller must hold local->sta_bss_lock */
-static void __ieee80211_rx_bss_hash_del(struct net_device *dev,
+static void __ieee80211_rx_bss_hash_del(struct ieee80211_local *local,
                                        struct ieee80211_sta_bss *bss)
 {
-       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
        struct ieee80211_sta_bss *b, *prev = NULL;
        b = local->sta_bss_hash[STA_HASH(bss->bssid)];
        while (b) {
@@ -2408,39 +2366,35 @@ static void ieee80211_rx_bss_free(struct ieee80211_sta_bss *bss)
 }
 
 
-static void ieee80211_rx_bss_put(struct net_device *dev,
+static void ieee80211_rx_bss_put(struct ieee80211_local *local,
                                 struct ieee80211_sta_bss *bss)
 {
-       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-
        local_bh_disable();
        if (!atomic_dec_and_lock(&bss->users, &local->sta_bss_lock)) {
                local_bh_enable();
                return;
        }
 
-       __ieee80211_rx_bss_hash_del(dev, bss);
+       __ieee80211_rx_bss_hash_del(local, bss);
        list_del(&bss->list);
        spin_unlock_bh(&local->sta_bss_lock);
        ieee80211_rx_bss_free(bss);
 }
 
 
-void ieee80211_rx_bss_list_init(struct net_device *dev)
+void ieee80211_rx_bss_list_init(struct ieee80211_local *local)
 {
-       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
        spin_lock_init(&local->sta_bss_lock);
        INIT_LIST_HEAD(&local->sta_bss_list);
 }
 
 
-void ieee80211_rx_bss_list_deinit(struct net_device *dev)
+void ieee80211_rx_bss_list_deinit(struct ieee80211_local *local)
 {
-       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
        struct ieee80211_sta_bss *bss, *tmp;
 
        list_for_each_entry_safe(bss, tmp, &local->sta_bss_list, list)
-               ieee80211_rx_bss_put(dev, bss);
+               ieee80211_rx_bss_put(local, bss);
 }
 
 
@@ -2452,8 +2406,6 @@ static int ieee80211_sta_join_ibss(struct net_device *dev,
        int res, rates, i, j;
        struct sk_buff *skb;
        struct ieee80211_mgmt *mgmt;
-       struct ieee80211_tx_info *control;
-       struct rate_selection ratesel;
        u8 *pos;
        struct ieee80211_sub_if_data *sdata;
        struct ieee80211_supported_band *sband;
@@ -2471,7 +2423,7 @@ static int ieee80211_sta_join_ibss(struct net_device *dev,
                local->ops->reset_tsf(local_to_hw(local));
        }
        memcpy(ifsta->bssid, bss->bssid, ETH_ALEN);
-       res = ieee80211_if_config(dev);
+       res = ieee80211_if_config(sdata, IEEE80211_IFCC_BSSID);
        if (res)
                return res;
 
@@ -2485,24 +2437,22 @@ static int ieee80211_sta_join_ibss(struct net_device *dev,
        if (res)
                return res;
 
-       /* Set beacon template */
+       /* Build IBSS probe response */
        skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400);
-       do {
-               if (!skb)
-                       break;
-
+       if (skb) {
                skb_reserve(skb, local->hw.extra_tx_headroom);
 
                mgmt = (struct ieee80211_mgmt *)
                        skb_put(skb, 24 + sizeof(mgmt->u.beacon));
                memset(mgmt, 0, 24 + sizeof(mgmt->u.beacon));
                mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT,
-                                                  IEEE80211_STYPE_BEACON);
+                                                  IEEE80211_STYPE_PROBE_RESP);
                memset(mgmt->da, 0xff, ETH_ALEN);
                memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN);
                memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN);
                mgmt->u.beacon.beacon_int =
                        cpu_to_le16(local->hw.conf.beacon_int);
+               mgmt->u.beacon.timestamp = cpu_to_le64(bss->timestamp);
                mgmt->u.beacon.capab_info = cpu_to_le16(bss->capability);
 
                pos = skb_put(skb, 2 + ifsta->ssid_len);
@@ -2540,60 +2490,22 @@ static int ieee80211_sta_join_ibss(struct net_device *dev,
                        memcpy(pos, &bss->supp_rates[8], rates);
                }
 
-               control = IEEE80211_SKB_CB(skb);
-
-               rate_control_get_rate(dev, sband, skb, &ratesel);
-               if (ratesel.rate_idx < 0) {
-                       printk(KERN_DEBUG "%s: Failed to determine TX rate "
-                              "for IBSS beacon\n", dev->name);
-                       break;
-               }
-               control->control.vif = &sdata->vif;
-               control->tx_rate_idx = ratesel.rate_idx;
-               if (sdata->bss_conf.use_short_preamble &&
-                   sband->bitrates[ratesel.rate_idx].flags & IEEE80211_RATE_SHORT_PREAMBLE)
-                       control->flags |= IEEE80211_TX_CTL_SHORT_PREAMBLE;
-               control->antenna_sel_tx = local->hw.conf.antenna_sel_tx;
-               control->flags |= IEEE80211_TX_CTL_NO_ACK;
-               control->control.retry_limit = 1;
-
-               ifsta->probe_resp = skb_copy(skb, GFP_ATOMIC);
-               if (ifsta->probe_resp) {
-                       mgmt = (struct ieee80211_mgmt *)
-                               ifsta->probe_resp->data;
-                       mgmt->frame_control =
-                               IEEE80211_FC(IEEE80211_FTYPE_MGMT,
-                                            IEEE80211_STYPE_PROBE_RESP);
-               } else {
-                       printk(KERN_DEBUG "%s: Could not allocate ProbeResp "
-                              "template for IBSS\n", dev->name);
-               }
-
-               if (local->ops->beacon_update &&
-                   local->ops->beacon_update(local_to_hw(local), skb) == 0) {
-                       printk(KERN_DEBUG "%s: Configured IBSS beacon "
-                              "template\n", dev->name);
-                       skb = NULL;
-               }
-
-               rates = 0;
-               sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
-               for (i = 0; i < bss->supp_rates_len; i++) {
-                       int bitrate = (bss->supp_rates[i] & 0x7f) * 5;
-                       for (j = 0; j < sband->n_bitrates; j++)
-                               if (sband->bitrates[j].bitrate == bitrate)
-                                       rates |= BIT(j);
-               }
-               ifsta->supp_rates_bits[local->hw.conf.channel->band] = rates;
+               ifsta->probe_resp = skb;
 
-               ieee80211_sta_def_wmm_params(dev, bss, 1);
-       } while (0);
+               ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON);
+       }
 
-       if (skb) {
-               printk(KERN_DEBUG "%s: Failed to configure IBSS beacon "
-                      "template\n", dev->name);
-               dev_kfree_skb(skb);
+       rates = 0;
+       sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
+       for (i = 0; i < bss->supp_rates_len; i++) {
+               int bitrate = (bss->supp_rates[i] & 0x7f) * 5;
+               for (j = 0; j < sband->n_bitrates; j++)
+                       if (sband->bitrates[j].bitrate == bitrate)
+                               rates |= BIT(j);
        }
+       ifsta->supp_rates_bits[local->hw.conf.channel->band] = rates;
+
+       ieee80211_sta_def_wmm_params(dev, bss, 1);
 
        ifsta->state = IEEE80211_IBSS_JOINED;
        mod_timer(&ifsta->timer, jiffies + IEEE80211_IBSS_MERGE_INTERVAL);
@@ -2662,12 +2574,6 @@ static void ieee80211_rx_bss_info(struct net_device *dev,
        if (!beacon && memcmp(mgmt->da, dev->dev_addr, ETH_ALEN))
                return; /* ignore ProbeResp to foreign address */
 
-#if 0
-       printk(KERN_DEBUG "%s: RX %s from %s to %s\n",
-              dev->name, beacon ? "Beacon" : "Probe Response",
-              print_mac(mac, mgmt->sa), print_mac(mac2, mgmt->da));
-#endif
-
        beacon_timestamp = le64_to_cpu(mgmt->u.beacon.timestamp);
 
        if (ieee80211_vif_is_mesh(&sdata->vif) && elems->mesh_id &&
@@ -2697,15 +2603,6 @@ static void ieee80211_rx_bss_info(struct net_device *dev,
                        sta->supp_rates[rx_status->band] =
                                sdata->u.sta.supp_rates_bits[rx_status->band];
                }
-               if (sta->supp_rates[rx_status->band] != prev_rates) {
-                       printk(KERN_DEBUG "%s: updated supp_rates set for "
-                              "%s based on beacon info (0x%llx & 0x%llx -> "
-                              "0x%llx)\n",
-                              dev->name, print_mac(mac, sta->addr),
-                              (unsigned long long) prev_rates,
-                              (unsigned long long) supp_rates,
-                              (unsigned long long) sta->supp_rates[rx_status->band]);
-               }
        }
 
        rcu_read_unlock();
@@ -2829,7 +2726,7 @@ static void ieee80211_rx_bss_info(struct net_device *dev,
         */
        if (sdata->vif.type != IEEE80211_IF_TYPE_IBSS &&
            bss->probe_resp && beacon) {
-               ieee80211_rx_bss_put(dev, bss);
+               ieee80211_rx_bss_put(local, bss);
                return;
        }
 
@@ -2961,11 +2858,10 @@ static void ieee80211_rx_bss_info(struct net_device *dev,
 #endif /* CONFIG_MAC80211_IBSS_DEBUG */
                if (beacon_timestamp > rx_timestamp) {
 #ifndef CONFIG_MAC80211_IBSS_DEBUG
-                       if (net_ratelimit())
+                       printk(KERN_DEBUG "%s: beacon TSF higher than "
+                              "local TSF - IBSS merge with BSSID %s\n",
+                              dev->name, print_mac(mac, mgmt->bssid));
 #endif
-                               printk(KERN_DEBUG "%s: beacon TSF higher than "
-                                      "local TSF - IBSS merge with BSSID %s\n",
-                                      dev->name, print_mac(mac, mgmt->bssid));
                        ieee80211_sta_join_ibss(dev, &sdata->u.sta, bss);
                        ieee80211_ibss_add_sta(dev, NULL,
                                               mgmt->bssid, mgmt->sa,
@@ -2973,7 +2869,7 @@ static void ieee80211_rx_bss_info(struct net_device *dev,
                }
        }
 
-       ieee80211_rx_bss_put(dev, bss);
+       ieee80211_rx_bss_put(local, bss);
 }
 
 
@@ -3105,11 +3001,11 @@ static void ieee80211_rx_mgmt_probe_req(struct net_device *dev,
        pos = mgmt->u.probe_req.variable;
        if (pos[0] != WLAN_EID_SSID ||
            pos + 2 + pos[1] > end) {
-               if (net_ratelimit()) {
-                       printk(KERN_DEBUG "%s: Invalid SSID IE in ProbeReq "
-                              "from %s\n",
-                              dev->name, print_mac(mac, mgmt->sa));
-               }
+#ifdef CONFIG_MAC80211_IBSS_DEBUG
+               printk(KERN_DEBUG "%s: Invalid SSID IE in ProbeReq "
+                      "from %s\n",
+                      dev->name, print_mac(mac, mgmt->sa));
+#endif
                return;
        }
        if (pos[1] != 0 &&
@@ -3178,11 +3074,6 @@ static void ieee80211_rx_mgmt_action(struct net_device *dev,
                                break;
                        ieee80211_sta_process_delba(dev, mgmt, len);
                        break;
-               default:
-                       if (net_ratelimit())
-                          printk(KERN_DEBUG "%s: Rx unknown A-MPDU action\n",
-                                       dev->name);
-                       break;
                }
                break;
        case PLINK_CATEGORY:
@@ -3193,11 +3084,6 @@ static void ieee80211_rx_mgmt_action(struct net_device *dev,
                if (ieee80211_vif_is_mesh(&sdata->vif))
                        mesh_rx_path_sel_frame(dev, mgmt, len);
                break;
-       default:
-               if (net_ratelimit())
-                       printk(KERN_DEBUG "%s: Rx unknown action frame - "
-                       "category=%d\n", dev->name, mgmt->u.action.category);
-               break;
        }
 }
 
@@ -3233,11 +3119,6 @@ void ieee80211_sta_rx_mgmt(struct net_device *dev, struct sk_buff *skb,
                skb_queue_tail(&ifsta->skb_queue, skb);
                queue_work(local->hw.workqueue, &ifsta->work);
                return;
-       default:
-               printk(KERN_DEBUG "%s: received unknown management frame - "
-                      "stype=%d\n", dev->name,
-                      (fc & IEEE80211_FCTL_STYPE) >> 4);
-               break;
        }
 
  fail:
@@ -3366,8 +3247,10 @@ static void ieee80211_sta_expire(struct net_device *dev, unsigned long exp_time)
        spin_lock_irqsave(&local->sta_lock, flags);
        list_for_each_entry_safe(sta, tmp, &local->sta_list, list)
                if (time_after(jiffies, sta->last_rx + exp_time)) {
+#ifdef CONFIG_MAC80211_IBSS_DEBUG
                        printk(KERN_DEBUG "%s: expiring inactive STA %s\n",
                               dev->name, print_mac(mac, sta->addr));
+#endif
                        __sta_info_unlink(&sta);
                        if (sta)
                                list_add(&sta->list, &tmp_list);
@@ -3406,7 +3289,7 @@ static void ieee80211_mesh_housekeeping(struct net_device *dev,
 
        free_plinks = mesh_plink_availables(sdata);
        if (free_plinks != sdata->u.sta.accepting_plinks)
-               ieee80211_if_config_beacon(dev);
+               ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON);
 
        mod_timer(&ifsta->timer, jiffies +
                        IEEE80211_MESH_HOUSEKEEPING_INTERVAL);
@@ -3450,13 +3333,10 @@ void ieee80211_sta_work(struct work_struct *work)
        if (local->sta_sw_scanning || local->sta_hw_scanning)
                return;
 
-       if (sdata->vif.type != IEEE80211_IF_TYPE_STA &&
-           sdata->vif.type != IEEE80211_IF_TYPE_IBSS &&
-           sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT) {
-               printk(KERN_DEBUG "%s: ieee80211_sta_work: non-STA interface "
-                      "(type=%d)\n", dev->name, sdata->vif.type);
+       if (WARN_ON(sdata->vif.type != IEEE80211_IF_TYPE_STA &&
+                   sdata->vif.type != IEEE80211_IF_TYPE_IBSS &&
+                   sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT))
                return;
-       }
        ifsta = &sdata->u.sta;
 
        while ((skb = skb_dequeue(&ifsta->skb_queue)))
@@ -3510,8 +3390,7 @@ void ieee80211_sta_work(struct work_struct *work)
                break;
 #endif
        default:
-               printk(KERN_DEBUG "ieee80211_sta_work: Unknown state %d\n",
-                      ifsta->state);
+               WARN_ON(1);
                break;
        }
 
@@ -3546,8 +3425,6 @@ static void ieee80211_sta_reset_auth(struct net_device *dev,
                ifsta->auth_alg = WLAN_AUTH_LEAP;
        else
                ifsta->auth_alg = WLAN_AUTH_OPEN;
-       printk(KERN_DEBUG "%s: Initial auth_alg=%d\n", dev->name,
-              ifsta->auth_alg);
        ifsta->auth_transaction = -1;
        ifsta->flags &= ~IEEE80211_STA_ASSOCIATED;
        ifsta->auth_tries = ifsta->assoc_tries = 0;
@@ -3652,7 +3529,7 @@ static int ieee80211_sta_config_auth(struct net_device *dev,
                                               selected->ssid_len);
                ieee80211_sta_set_bssid(dev, selected->bssid);
                ieee80211_sta_def_wmm_params(dev, selected, 0);
-               ieee80211_rx_bss_put(dev, selected);
+               ieee80211_rx_bss_put(local, selected);
                ifsta->state = IEEE80211_AUTHENTICATE;
                ieee80211_sta_reset_auth(dev, ifsta);
                return 0;
@@ -3729,7 +3606,7 @@ static int ieee80211_sta_create_ibss(struct net_device *dev,
        }
 
        ret = ieee80211_sta_join_ibss(dev, ifsta, bss);
-       ieee80211_rx_bss_put(dev, bss);
+       ieee80211_rx_bss_put(local, bss);
        return ret;
 }
 
@@ -3771,8 +3648,10 @@ static int ieee80211_sta_find_ibss(struct net_device *dev,
        spin_unlock_bh(&local->sta_bss_lock);
 
 #ifdef CONFIG_MAC80211_IBSS_DEBUG
-       printk(KERN_DEBUG "   sta_find_ibss: selected %s current "
-              "%s\n", print_mac(mac, bssid), print_mac(mac2, ifsta->bssid));
+       if (found)
+               printk(KERN_DEBUG "   sta_find_ibss: selected %s current "
+                      "%s\n", print_mac(mac, bssid),
+                      print_mac(mac2, ifsta->bssid));
 #endif /* CONFIG_MAC80211_IBSS_DEBUG */
        if (found && memcmp(ifsta->bssid, bssid, ETH_ALEN) != 0 &&
            (bss = ieee80211_rx_bss_get(dev, bssid,
@@ -3783,7 +3662,7 @@ static int ieee80211_sta_find_ibss(struct net_device *dev,
                       " based on configured SSID\n",
                       dev->name, print_mac(mac, bssid));
                ret = ieee80211_sta_join_ibss(dev, ifsta, bss);
-               ieee80211_rx_bss_put(dev, bss);
+               ieee80211_rx_bss_put(local, bss);
                return ret;
        }
 #ifdef CONFIG_MAC80211_IBSS_DEBUG
@@ -3834,28 +3713,45 @@ int ieee80211_sta_set_ssid(struct net_device *dev, char *ssid, size_t len)
 {
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        struct ieee80211_if_sta *ifsta;
+       int res;
 
        if (len > IEEE80211_MAX_SSID_LEN)
                return -EINVAL;
 
        ifsta = &sdata->u.sta;
 
-       if (ifsta->ssid_len != len || memcmp(ifsta->ssid, ssid, len) != 0)
+       if (ifsta->ssid_len != len || memcmp(ifsta->ssid, ssid, len) != 0) {
+               memset(ifsta->ssid, 0, sizeof(ifsta->ssid));
+               memcpy(ifsta->ssid, ssid, len);
+               ifsta->ssid_len = len;
                ifsta->flags &= ~IEEE80211_STA_PREV_BSSID_SET;
-       memcpy(ifsta->ssid, ssid, len);
-       memset(ifsta->ssid + len, 0, IEEE80211_MAX_SSID_LEN - len);
-       ifsta->ssid_len = len;
+
+               res = 0;
+               /*
+                * Hack! MLME code needs to be cleaned up to have different
+                * entry points for configuration and internal selection change
+                */
+               if (netif_running(sdata->dev))
+                       res = ieee80211_if_config(sdata, IEEE80211_IFCC_SSID);
+               if (res) {
+                       printk(KERN_DEBUG "%s: Failed to config new SSID to "
+                              "the low-level driver\n", dev->name);
+                       return res;
+               }
+       }
 
        if (len)
                ifsta->flags |= IEEE80211_STA_SSID_SET;
        else
                ifsta->flags &= ~IEEE80211_STA_SSID_SET;
+
        if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS &&
            !(ifsta->flags & IEEE80211_STA_BSSID_SET)) {
                ifsta->ibss_join_req = jiffies;
                ifsta->state = IEEE80211_IBSS_SEARCH;
                return ieee80211_sta_find_ibss(dev, ifsta);
        }
+
        return 0;
 }
 
@@ -3881,7 +3777,12 @@ int ieee80211_sta_set_bssid(struct net_device *dev, u8 *bssid)
 
        if (memcmp(ifsta->bssid, bssid, ETH_ALEN) != 0) {
                memcpy(ifsta->bssid, bssid, ETH_ALEN);
-               res = ieee80211_if_config(dev);
+               res = 0;
+               /*
+                * Hack! See also ieee80211_sta_set_ssid.
+                */
+               if (netif_running(sdata->dev))
+                       res = ieee80211_if_config(sdata, IEEE80211_IFCC_BSSID);
                if (res) {
                        printk(KERN_DEBUG "%s: Failed to config new BSSID to "
                               "the low-level driver\n", dev->name);
@@ -3968,6 +3869,7 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw)
 
 
        netif_tx_lock_bh(local->mdev);
+       netif_addr_lock(local->mdev);
        local->filter_flags &= ~FIF_BCN_PRBRESP_PROMISC;
        local->ops->configure_filter(local_to_hw(local),
                                     FIF_BCN_PRBRESP_PROMISC,
@@ -3975,15 +3877,11 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw)
                                     local->mdev->mc_count,
                                     local->mdev->mc_list);
 
+       netif_addr_unlock(local->mdev);
        netif_tx_unlock_bh(local->mdev);
 
        rcu_read_lock();
        list_for_each_entry_rcu(sdata, &local->interfaces, list) {
-
-               /* No need to wake the master device. */
-               if (sdata->dev == local->mdev)
-                       continue;
-
                /* Tell AP we're back */
                if (sdata->vif.type == IEEE80211_IF_TYPE_STA &&
                    sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED)
@@ -4149,12 +4047,6 @@ static int ieee80211_sta_start_scan(struct net_device *dev,
 
        rcu_read_lock();
        list_for_each_entry_rcu(sdata, &local->interfaces, list) {
-
-               /* Don't stop the master interface, otherwise we can't transmit
-                * probes! */
-               if (sdata->dev == local->mdev)
-                       continue;
-
                netif_stop_queue(sdata->dev);
                if (sdata->vif.type == IEEE80211_IF_TYPE_STA &&
                    (sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED))
@@ -4173,12 +4065,14 @@ static int ieee80211_sta_start_scan(struct net_device *dev,
        local->scan_dev = dev;
 
        netif_tx_lock_bh(local->mdev);
+       netif_addr_lock(local->mdev);
        local->filter_flags |= FIF_BCN_PRBRESP_PROMISC;
        local->ops->configure_filter(local_to_hw(local),
                                     FIF_BCN_PRBRESP_PROMISC,
                                     &local->filter_flags,
                                     local->mdev->mc_count,
                                     local->mdev->mc_list);
+       netif_addr_unlock(local->mdev);
        netif_tx_unlock_bh(local->mdev);
 
        /* TODO: start scan as soon as all nullfunc frames are ACKed */
@@ -4470,11 +4364,13 @@ struct sta_info *ieee80211_ibss_add_sta(struct net_device *dev,
                return NULL;
        }
 
-       if (!ieee80211_bssid_match(bssid, sdata->u.sta.bssid))
+       if (compare_ether_addr(bssid, sdata->u.sta.bssid))
                return NULL;
 
+#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
        printk(KERN_DEBUG "%s: Adding new IBSS station %s (dev=%s)\n",
               wiphy_name(local->hw.wiphy), print_mac(mac, addr), dev->name);
+#endif
 
        sta = sta_info_alloc(sdata, addr, GFP_ATOMIC);
        if (!sta)
@@ -4501,7 +4397,7 @@ int ieee80211_sta_deauthenticate(struct net_device *dev, u16 reason)
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        struct ieee80211_if_sta *ifsta = &sdata->u.sta;
 
-       printk(KERN_DEBUG "%s: deauthenticate(reason=%d)\n",
+       printk(KERN_DEBUG "%s: deauthenticating by local choice (reason=%d)\n",
               dev->name, reason);
 
        if (sdata->vif.type != IEEE80211_IF_TYPE_STA &&
@@ -4519,7 +4415,7 @@ int ieee80211_sta_disassociate(struct net_device *dev, u16 reason)
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        struct ieee80211_if_sta *ifsta = &sdata->u.sta;
 
-       printk(KERN_DEBUG "%s: disassociate(reason=%d)\n",
+       printk(KERN_DEBUG "%s: disassociating by local choice (reason=%d)\n",
               dev->name, reason);
 
        if (sdata->vif.type != IEEE80211_IF_TYPE_STA)
@@ -4543,12 +4439,10 @@ void ieee80211_notify_mac(struct ieee80211_hw *hw,
        case IEEE80211_NOTIFY_RE_ASSOC:
                rcu_read_lock();
                list_for_each_entry_rcu(sdata, &local->interfaces, list) {
+                       if (sdata->vif.type != IEEE80211_IF_TYPE_STA)
+                               continue;
 
-                       if (sdata->vif.type == IEEE80211_IF_TYPE_STA) {
-                               ieee80211_sta_req_auth(sdata->dev,
-                                                      &sdata->u.sta);
-                       }
-
+                       ieee80211_sta_req_auth(sdata->dev, &sdata->u.sta);
                }
                rcu_read_unlock();
                break;