netdev: Add netdev->addr_list_lock protection.
[safe/jmp/linux-2.6] / net / mac80211 / mlme.c
index d30c113..1232ba2 100644 (file)
@@ -44,7 +44,7 @@
 #define IEEE80211_RETRY_AUTH_INTERVAL (1 * HZ)
 #define IEEE80211_SCAN_INTERVAL (2 * HZ)
 #define IEEE80211_SCAN_INTERVAL_SLOW (15 * HZ)
-#define IEEE80211_IBSS_JOIN_TIMEOUT (20 * HZ)
+#define IEEE80211_IBSS_JOIN_TIMEOUT (7 * HZ)
 
 #define IEEE80211_PROBE_DELAY (HZ / 33)
 #define IEEE80211_CHANNEL_TIME (HZ / 33)
@@ -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);
@@ -204,6 +204,25 @@ void ieee802_11_parse_elems(u8 *start, size_t len,
                        elems->perr = pos;
                        elems->perr_len = elen;
                        break;
+               case WLAN_EID_CHANNEL_SWITCH:
+                       elems->ch_switch_elem = pos;
+                       elems->ch_switch_elem_len = elen;
+                       break;
+               case WLAN_EID_QUIET:
+                       if (!elems->quiet_elem) {
+                               elems->quiet_elem = pos;
+                               elems->quiet_elem_len = elen;
+                       }
+                       elems->num_of_quiet_elem++;
+                       break;
+               case WLAN_EID_COUNTRY:
+                       elems->country_elem = pos;
+                       elems->country_elem_len = elen;
+                       break;
+               case WLAN_EID_PWR_CONSTRAINT:
+                       elems->pwr_constr_elem = pos;
+                       elems->pwr_constr_elem_len = elen;
+                       break;
                default:
                        break;
                }
@@ -326,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,
@@ -347,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",
@@ -359,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",
@@ -371,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;
        }
@@ -529,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) {
@@ -539,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;
@@ -561,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);
 }
@@ -721,7 +749,21 @@ static void ieee80211_send_assoc(struct net_device *dev,
                        capab |= WLAN_CAPABILITY_PRIVACY;
                if (bss->wmm_ie)
                        wmm = 1;
-               ieee80211_rx_bss_put(dev, bss);
+
+               /* get all rates supported by the device and the AP as
+                * some APs don't like getting a superset of their rates
+                * in the association request (e.g. D-Link DAP 1353 in
+                * b-only mode) */
+               rates_len = ieee80211_compatible_rates(bss, sband, &rates);
+
+               if ((bss->capability & WLAN_CAPABILITY_SPECTRUM_MGMT) &&
+                   (local->hw.flags & IEEE80211_HW_SPECTRUM_MGMT))
+                       capab |= WLAN_CAPABILITY_SPECTRUM_MGMT;
+
+               ieee80211_rx_bss_put(local, bss);
+       } else {
+               rates = ~0;
+               rates_len = sband->n_bitrates;
        }
 
        mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);
@@ -752,10 +794,7 @@ static void ieee80211_send_assoc(struct net_device *dev,
        *pos++ = ifsta->ssid_len;
        memcpy(pos, ifsta->ssid, ifsta->ssid_len);
 
-       /* all supported rates should be added here but some APs
-        * (e.g. D-Link DAP 1353 in b-only mode) don't like that
-        * Therefore only add rates the AP supports */
-       rates_len = ieee80211_compatible_rates(bss, sband, &rates);
+       /* add all rates which were marked to be used above */
        supp_rates_len = rates_len;
        if (supp_rates_len > 8)
                supp_rates_len = 8;
@@ -788,6 +827,26 @@ static void ieee80211_send_assoc(struct net_device *dev,
                }
        }
 
+       if (capab & WLAN_CAPABILITY_SPECTRUM_MGMT) {
+               /* 1. power capabilities */
+               pos = skb_put(skb, 4);
+               *pos++ = WLAN_EID_PWR_CAPABILITY;
+               *pos++ = 2;
+               *pos++ = 0; /* min tx power */
+               *pos++ = local->hw.conf.channel->max_power; /* max tx power */
+
+               /* 2. supported channels */
+               /* TODO: get this in reg domain format */
+               pos = skb_put(skb, 2 * sband->n_channels + 2);
+               *pos++ = WLAN_EID_SUPPORTED_CHANNELS;
+               *pos++ = 2 * sband->n_channels;
+               for (i = 0; i < sband->n_channels; i++) {
+                       *pos++ = ieee80211_frequency_to_channel(
+                                       sband->channels[i].center_freq);
+                       *pos++ = 1; /* one channel in the subband*/
+               }
+       }
+
        if (ifsta->extra_ie) {
                pos = skb_put(skb, ifsta->extra_ie_len);
                memcpy(pos, ifsta->extra_ie, ifsta->extra_ie_len);
@@ -933,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;
@@ -1125,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);
 }
@@ -1314,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 */
@@ -1330,16 +1387,18 @@ static void ieee80211_sta_process_addba_request(struct net_device *dev,
 
        /* prepare reordering buffer */
        tid_agg_rx->reorder_buf =
-               kmalloc(buf_size * sizeof(struct sk_buf *), GFP_ATOMIC);
+               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;
        }
        memset(tid_agg_rx->reorder_buf, 0,
-               buf_size * sizeof(struct sk_buf *));
+               buf_size * sizeof(struct sk_buff *));
 
        if (local->ops->ampdu_action)
                ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_RX_START,
@@ -1401,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;
        }
 
@@ -1421,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;
@@ -1492,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)
 {
@@ -1535,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)
@@ -1618,7 +1696,7 @@ void sta_addba_resp_timer_expired(unsigned long data)
         * only one argument, and both sta_info and TID are needed, so init
         * flow in sta_info_create gives the TID as data, while the timer_to_id
         * array gives the sta through container_of */
-       u16 tid = *(int *)data;
+       u16 tid = *(u8 *)data;
        struct sta_info *temp_sta = container_of((void *)data,
                struct sta_info, timer_to_tid[tid]);
 
@@ -1641,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;
@@ -1666,7 +1748,7 @@ timer_expired_exit:
 static void sta_rx_agg_session_timer_expired(unsigned long data)
 {
        /* not an elegant detour, but there is no choice as the timer passes
-        * only one argument, and verious sta_info are needed here, so init
+        * only one argument, and various sta_info are needed here, so init
         * flow in sta_info_create gives the TID as data, while the timer_to_id
         * array gives the sta through container_of */
        u8 *ptid = (u8 *)data;
@@ -1674,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);
@@ -1694,6 +1778,71 @@ void ieee80211_sta_tear_down_BA_sessions(struct net_device *dev, u8 *addr)
        }
 }
 
+static void ieee80211_send_refuse_measurement_request(struct net_device *dev,
+                                       struct ieee80211_msrment_ie *request_ie,
+                                       const u8 *da, const u8 *bssid,
+                                       u8 dialog_token)
+{
+       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+       struct sk_buff *skb;
+       struct ieee80211_mgmt *msr_report;
+
+       skb = dev_alloc_skb(sizeof(*msr_report) + local->hw.extra_tx_headroom +
+                               sizeof(struct ieee80211_msrment_ie));
+
+       if (!skb) {
+               printk(KERN_ERR "%s: failed to allocate buffer for "
+                               "measurement report frame\n", dev->name);
+               return;
+       }
+
+       skb_reserve(skb, local->hw.extra_tx_headroom);
+       msr_report = (struct ieee80211_mgmt *)skb_put(skb, 24);
+       memset(msr_report, 0, 24);
+       memcpy(msr_report->da, da, ETH_ALEN);
+       memcpy(msr_report->sa, dev->dev_addr, ETH_ALEN);
+       memcpy(msr_report->bssid, bssid, ETH_ALEN);
+       msr_report->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT,
+                                               IEEE80211_STYPE_ACTION);
+
+       skb_put(skb, 1 + sizeof(msr_report->u.action.u.measurement));
+       msr_report->u.action.category = WLAN_CATEGORY_SPECTRUM_MGMT;
+       msr_report->u.action.u.measurement.action_code =
+                               WLAN_ACTION_SPCT_MSR_RPRT;
+       msr_report->u.action.u.measurement.dialog_token = dialog_token;
+
+       msr_report->u.action.u.measurement.element_id = WLAN_EID_MEASURE_REPORT;
+       msr_report->u.action.u.measurement.length =
+                       sizeof(struct ieee80211_msrment_ie);
+
+       memset(&msr_report->u.action.u.measurement.msr_elem, 0,
+               sizeof(struct ieee80211_msrment_ie));
+       msr_report->u.action.u.measurement.msr_elem.token = request_ie->token;
+       msr_report->u.action.u.measurement.msr_elem.mode |=
+                       IEEE80211_SPCT_MSR_RPRT_MODE_REFUSED;
+       msr_report->u.action.u.measurement.msr_elem.type = request_ie->type;
+
+       ieee80211_sta_tx(dev, skb, 0);
+}
+
+static void ieee80211_sta_process_measurement_req(struct net_device *dev,
+                                               struct ieee80211_mgmt *mgmt,
+                                               size_t len)
+{
+       /*
+        * Ignoring measurement request is spec violation.
+        * Mandatory measurements must be reported optional
+        * measurements might be refused or reported incapable
+        * For now just refuse
+        * TODO: Answer basic measurement as unmeasured
+        */
+       ieee80211_send_refuse_measurement_request(dev,
+                       &mgmt->u.action.u.measurement.msr_elem,
+                       mgmt->sa, mgmt->bssid,
+                       mgmt->u.action.u.measurement.dialog_token);
+}
+
+
 static void ieee80211_rx_mgmt_auth(struct net_device *dev,
                                   struct ieee80211_if_sta *ifsta,
                                   struct ieee80211_mgmt *mgmt,
@@ -1704,73 +1853,41 @@ 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
+               /*
+                * IEEE 802.11 standard does not require authentication in IBSS
                 * networks and most implementations do not seem to use it.
                 * However, try to reply to authentication attempts if someone
                 * has actually implemented this.
-                * TODO: Could implement shared key authentication. */
-               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);
@@ -1799,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;
                        }
                }
@@ -1831,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);
 
@@ -1876,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);
 
@@ -1932,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);
@@ -2019,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);
@@ -2137,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) {
@@ -2292,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);
 }
 
 
@@ -2336,11 +2406,10 @@ 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;
+       union iwreq_data wrqu;
 
        sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
 
@@ -2354,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;
 
@@ -2363,32 +2432,27 @@ static int ieee80211_sta_join_ibss(struct net_device *dev,
        sdata->drop_unencrypted = bss->capability &
                WLAN_CAPABILITY_PRIVACY ? 1 : 0;
 
-       res = ieee80211_set_freq(local, bss->freq);
+       res = ieee80211_set_freq(dev, bss->freq);
 
-       if (local->oper_channel->flags & IEEE80211_CHAN_NO_IBSS) {
-               printk(KERN_DEBUG "%s: IBSS not allowed on frequency "
-                      "%d MHz\n", dev->name, local->oper_channel->center_freq);
-               return -1;
-       }
+       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);
@@ -2426,65 +2490,29 @@ 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;
-               }
+               ifsta->probe_resp = 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);
-       } 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);
 
-       ieee80211_rx_bss_put(dev, bss);
+       memset(&wrqu, 0, sizeof(wrqu));
+       memcpy(wrqu.ap_addr.sa_data, bss->bssid, ETH_ALEN);
+       wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
 
        return res;
 }
@@ -2530,11 +2558,10 @@ static void ieee80211_rx_bss_info(struct net_device *dev,
                                  struct ieee80211_mgmt *mgmt,
                                  size_t len,
                                  struct ieee80211_rx_status *rx_status,
+                                 struct ieee802_11_elems *elems,
                                  int beacon)
 {
        struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-       struct ieee802_11_elems elems;
-       size_t baselen;
        int freq, clen;
        struct ieee80211_sta_bss *bss;
        struct sta_info *sta;
@@ -2547,35 +2574,24 @@ 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
-
-       baselen = (u8 *) mgmt->u.beacon.variable - (u8 *) mgmt;
-       if (baselen > len)
-               return;
-
        beacon_timestamp = le64_to_cpu(mgmt->u.beacon.timestamp);
-       ieee802_11_parse_elems(mgmt->u.beacon.variable, len - baselen, &elems);
 
-       if (ieee80211_vif_is_mesh(&sdata->vif) && elems.mesh_id &&
-           elems.mesh_config && mesh_matches_local(&elems, dev)) {
-               u64 rates = ieee80211_sta_get_rates(local, &elems,
+       if (ieee80211_vif_is_mesh(&sdata->vif) && elems->mesh_id &&
+           elems->mesh_config && mesh_matches_local(elems, dev)) {
+               u64 rates = ieee80211_sta_get_rates(local, elems,
                                                rx_status->band);
 
                mesh_neighbour_update(mgmt->sa, rates, dev,
-                                     mesh_peer_accepts_plinks(&elems, dev));
+                                     mesh_peer_accepts_plinks(elems, dev));
        }
 
        rcu_read_lock();
 
-       if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS && elems.supp_rates &&
+       if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS && elems->supp_rates &&
            memcmp(mgmt->bssid, sdata->u.sta.bssid, ETH_ALEN) == 0 &&
            (sta = sta_info_get(local, mgmt->sa))) {
                u64 prev_rates;
-               u64 supp_rates = ieee80211_sta_get_rates(local, &elems,
+               u64 supp_rates = ieee80211_sta_get_rates(local, elems,
                                                        rx_status->band);
 
                prev_rates = sta->supp_rates[rx_status->band];
@@ -2587,21 +2603,12 @@ 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();
 
-       if (elems.ds_params && elems.ds_params_len == 1)
-               freq = ieee80211_channel_to_frequency(elems.ds_params[0]);
+       if (elems->ds_params && elems->ds_params_len == 1)
+               freq = ieee80211_channel_to_frequency(elems->ds_params[0]);
        else
                freq = rx_status->freq;
 
@@ -2611,23 +2618,23 @@ static void ieee80211_rx_bss_info(struct net_device *dev,
                return;
 
 #ifdef CONFIG_MAC80211_MESH
-       if (elems.mesh_config)
-               bss = ieee80211_rx_mesh_bss_get(dev, elems.mesh_id,
-                               elems.mesh_id_len, elems.mesh_config, freq);
+       if (elems->mesh_config)
+               bss = ieee80211_rx_mesh_bss_get(dev, elems->mesh_id,
+                               elems->mesh_id_len, elems->mesh_config, freq);
        else
 #endif
                bss = ieee80211_rx_bss_get(dev, mgmt->bssid, freq,
-                                          elems.ssid, elems.ssid_len);
+                                          elems->ssid, elems->ssid_len);
        if (!bss) {
 #ifdef CONFIG_MAC80211_MESH
-               if (elems.mesh_config)
-                       bss = ieee80211_rx_mesh_bss_add(dev, elems.mesh_id,
-                               elems.mesh_id_len, elems.mesh_config,
-                               elems.mesh_config_len, freq);
+               if (elems->mesh_config)
+                       bss = ieee80211_rx_mesh_bss_add(dev, elems->mesh_id,
+                               elems->mesh_id_len, elems->mesh_config,
+                               elems->mesh_config_len, freq);
                else
 #endif
                        bss = ieee80211_rx_bss_add(dev, mgmt->bssid, freq,
-                                                  elems.ssid, elems.ssid_len);
+                                                 elems->ssid, elems->ssid_len);
                if (!bss)
                        return;
        } else {
@@ -2640,43 +2647,43 @@ static void ieee80211_rx_bss_info(struct net_device *dev,
        }
 
        /* save the ERP value so that it is available at association time */
-       if (elems.erp_info && elems.erp_info_len >= 1) {
-               bss->erp_value = elems.erp_info[0];
+       if (elems->erp_info && elems->erp_info_len >= 1) {
+               bss->erp_value = elems->erp_info[0];
                bss->has_erp_value = 1;
        }
 
-       if (elems.ht_cap_elem &&
-            (!bss->ht_ie || bss->ht_ie_len != elems.ht_cap_elem_len ||
-            memcmp(bss->ht_ie, elems.ht_cap_elem, elems.ht_cap_elem_len))) {
+       if (elems->ht_cap_elem &&
+            (!bss->ht_ie || bss->ht_ie_len != elems->ht_cap_elem_len ||
+            memcmp(bss->ht_ie, elems->ht_cap_elem, elems->ht_cap_elem_len))) {
                kfree(bss->ht_ie);
-               bss->ht_ie = kmalloc(elems.ht_cap_elem_len + 2, GFP_ATOMIC);
+               bss->ht_ie = kmalloc(elems->ht_cap_elem_len + 2, GFP_ATOMIC);
                if (bss->ht_ie) {
-                       memcpy(bss->ht_ie, elems.ht_cap_elem - 2,
-                               elems.ht_cap_elem_len + 2);
-                       bss->ht_ie_len = elems.ht_cap_elem_len + 2;
+                       memcpy(bss->ht_ie, elems->ht_cap_elem - 2,
+                               elems->ht_cap_elem_len + 2);
+                       bss->ht_ie_len = elems->ht_cap_elem_len + 2;
                } else
                        bss->ht_ie_len = 0;
-       } else if (!elems.ht_cap_elem && bss->ht_ie) {
+       } else if (!elems->ht_cap_elem && bss->ht_ie) {
                kfree(bss->ht_ie);
                bss->ht_ie = NULL;
                bss->ht_ie_len = 0;
        }
 
-       if (elems.ht_info_elem &&
+       if (elems->ht_info_elem &&
             (!bss->ht_add_ie ||
-            bss->ht_add_ie_len != elems.ht_info_elem_len ||
-            memcmp(bss->ht_add_ie, elems.ht_info_elem,
-                       elems.ht_info_elem_len))) {
+            bss->ht_add_ie_len != elems->ht_info_elem_len ||
+            memcmp(bss->ht_add_ie, elems->ht_info_elem,
+                       elems->ht_info_elem_len))) {
                kfree(bss->ht_add_ie);
                bss->ht_add_ie =
-                       kmalloc(elems.ht_info_elem_len + 2, GFP_ATOMIC);
+                       kmalloc(elems->ht_info_elem_len + 2, GFP_ATOMIC);
                if (bss->ht_add_ie) {
-                       memcpy(bss->ht_add_ie, elems.ht_info_elem - 2,
-                               elems.ht_info_elem_len + 2);
-                       bss->ht_add_ie_len = elems.ht_info_elem_len + 2;
+                       memcpy(bss->ht_add_ie, elems->ht_info_elem - 2,
+                               elems->ht_info_elem_len + 2);
+                       bss->ht_add_ie_len = elems->ht_info_elem_len + 2;
                } else
                        bss->ht_add_ie_len = 0;
-       } else if (!elems.ht_info_elem && bss->ht_add_ie) {
+       } else if (!elems->ht_info_elem && bss->ht_add_ie) {
                kfree(bss->ht_add_ie);
                bss->ht_add_ie = NULL;
                bss->ht_add_ie_len = 0;
@@ -2686,20 +2693,20 @@ static void ieee80211_rx_bss_info(struct net_device *dev,
        bss->capability = le16_to_cpu(mgmt->u.beacon.capab_info);
 
        bss->supp_rates_len = 0;
-       if (elems.supp_rates) {
+       if (elems->supp_rates) {
                clen = IEEE80211_MAX_SUPP_RATES - bss->supp_rates_len;
-               if (clen > elems.supp_rates_len)
-                       clen = elems.supp_rates_len;
-               memcpy(&bss->supp_rates[bss->supp_rates_len], elems.supp_rates,
+               if (clen > elems->supp_rates_len)
+                       clen = elems->supp_rates_len;
+               memcpy(&bss->supp_rates[bss->supp_rates_len], elems->supp_rates,
                       clen);
                bss->supp_rates_len += clen;
        }
-       if (elems.ext_supp_rates) {
+       if (elems->ext_supp_rates) {
                clen = IEEE80211_MAX_SUPP_RATES - bss->supp_rates_len;
-               if (clen > elems.ext_supp_rates_len)
-                       clen = elems.ext_supp_rates_len;
+               if (clen > elems->ext_supp_rates_len)
+                       clen = elems->ext_supp_rates_len;
                memcpy(&bss->supp_rates[bss->supp_rates_len],
-                      elems.ext_supp_rates, clen);
+                      elems->ext_supp_rates, clen);
                bss->supp_rates_len += clen;
        }
 
@@ -2719,37 +2726,37 @@ 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;
        }
 
-       if (elems.wpa &&
-           (!bss->wpa_ie || bss->wpa_ie_len != elems.wpa_len ||
-            memcmp(bss->wpa_ie, elems.wpa, elems.wpa_len))) {
+       if (elems->wpa &&
+           (!bss->wpa_ie || bss->wpa_ie_len != elems->wpa_len ||
+            memcmp(bss->wpa_ie, elems->wpa, elems->wpa_len))) {
                kfree(bss->wpa_ie);
-               bss->wpa_ie = kmalloc(elems.wpa_len + 2, GFP_ATOMIC);
+               bss->wpa_ie = kmalloc(elems->wpa_len + 2, GFP_ATOMIC);
                if (bss->wpa_ie) {
-                       memcpy(bss->wpa_ie, elems.wpa - 2, elems.wpa_len + 2);
-                       bss->wpa_ie_len = elems.wpa_len + 2;
+                       memcpy(bss->wpa_ie, elems->wpa - 2, elems->wpa_len + 2);
+                       bss->wpa_ie_len = elems->wpa_len + 2;
                } else
                        bss->wpa_ie_len = 0;
-       } else if (!elems.wpa && bss->wpa_ie) {
+       } else if (!elems->wpa && bss->wpa_ie) {
                kfree(bss->wpa_ie);
                bss->wpa_ie = NULL;
                bss->wpa_ie_len = 0;
        }
 
-       if (elems.rsn &&
-           (!bss->rsn_ie || bss->rsn_ie_len != elems.rsn_len ||
-            memcmp(bss->rsn_ie, elems.rsn, elems.rsn_len))) {
+       if (elems->rsn &&
+           (!bss->rsn_ie || bss->rsn_ie_len != elems->rsn_len ||
+            memcmp(bss->rsn_ie, elems->rsn, elems->rsn_len))) {
                kfree(bss->rsn_ie);
-               bss->rsn_ie = kmalloc(elems.rsn_len + 2, GFP_ATOMIC);
+               bss->rsn_ie = kmalloc(elems->rsn_len + 2, GFP_ATOMIC);
                if (bss->rsn_ie) {
-                       memcpy(bss->rsn_ie, elems.rsn - 2, elems.rsn_len + 2);
-                       bss->rsn_ie_len = elems.rsn_len + 2;
+                       memcpy(bss->rsn_ie, elems->rsn - 2, elems->rsn_len + 2);
+                       bss->rsn_ie_len = elems->rsn_len + 2;
                } else
                        bss->rsn_ie_len = 0;
-       } else if (!elems.rsn && bss->rsn_ie) {
+       } else if (!elems->rsn && bss->rsn_ie) {
                kfree(bss->rsn_ie);
                bss->rsn_ie = NULL;
                bss->rsn_ie_len = 0;
@@ -2769,20 +2776,21 @@ static void ieee80211_rx_bss_info(struct net_device *dev,
         * inclusion of the WMM Parameters in beacons, however, is optional.
         */
 
-       if (elems.wmm_param &&
-           (!bss->wmm_ie || bss->wmm_ie_len != elems.wmm_param_len ||
-            memcmp(bss->wmm_ie, elems.wmm_param, elems.wmm_param_len))) {
+       if (elems->wmm_param &&
+           (!bss->wmm_ie || bss->wmm_ie_len != elems->wmm_param_len ||
+            memcmp(bss->wmm_ie, elems->wmm_param, elems->wmm_param_len))) {
                kfree(bss->wmm_ie);
-               bss->wmm_ie = kmalloc(elems.wmm_param_len + 2, GFP_ATOMIC);
+               bss->wmm_ie = kmalloc(elems->wmm_param_len + 2, GFP_ATOMIC);
                if (bss->wmm_ie) {
-                       memcpy(bss->wmm_ie, elems.wmm_param - 2,
-                              elems.wmm_param_len + 2);
-                       bss->wmm_ie_len = elems.wmm_param_len + 2;
+                       memcpy(bss->wmm_ie, elems->wmm_param - 2,
+                              elems->wmm_param_len + 2);
+                       bss->wmm_ie_len = elems->wmm_param_len + 2;
                } else
                        bss->wmm_ie_len = 0;
-       } else if (elems.wmm_info &&
-                   (!bss->wmm_ie || bss->wmm_ie_len != elems.wmm_info_len ||
-                    memcmp(bss->wmm_ie, elems.wmm_info, elems.wmm_info_len))) {
+       } else if (elems->wmm_info &&
+                   (!bss->wmm_ie || bss->wmm_ie_len != elems->wmm_info_len ||
+                    memcmp(bss->wmm_ie, elems->wmm_info,
+                                               elems->wmm_info_len))) {
                 /* As for certain AP's Fifth bit is not set in WMM IE in
                  * beacon frames.So while parsing the beacon frame the
                  * wmm_info structure is used instead of wmm_param.
@@ -2792,14 +2800,14 @@ static void ieee80211_rx_bss_info(struct net_device *dev,
                  * n-band association.
                  */
                kfree(bss->wmm_ie);
-               bss->wmm_ie = kmalloc(elems.wmm_info_len + 2, GFP_ATOMIC);
+               bss->wmm_ie = kmalloc(elems->wmm_info_len + 2, GFP_ATOMIC);
                if (bss->wmm_ie) {
-                       memcpy(bss->wmm_ie, elems.wmm_info - 2,
-                              elems.wmm_info_len + 2);
-                       bss->wmm_ie_len = elems.wmm_info_len + 2;
+                       memcpy(bss->wmm_ie, elems->wmm_info - 2,
+                              elems->wmm_info_len + 2);
+                       bss->wmm_ie_len = elems->wmm_info_len + 2;
                } else
                        bss->wmm_ie_len = 0;
-       } else if (!elems.wmm_param && !elems.wmm_info && bss->wmm_ie) {
+       } else if (!elems->wmm_param && !elems->wmm_info && bss->wmm_ie) {
                kfree(bss->wmm_ie);
                bss->wmm_ie = NULL;
                bss->wmm_ie_len = 0;
@@ -2810,8 +2818,9 @@ static void ieee80211_rx_bss_info(struct net_device *dev,
            !local->sta_sw_scanning && !local->sta_hw_scanning &&
            bss->capability & WLAN_CAPABILITY_IBSS &&
            bss->freq == local->oper_channel->center_freq &&
-           elems.ssid_len == sdata->u.sta.ssid_len &&
-           memcmp(elems.ssid, sdata->u.sta.ssid, sdata->u.sta.ssid_len) == 0) {
+           elems->ssid_len == sdata->u.sta.ssid_len &&
+           memcmp(elems->ssid, sdata->u.sta.ssid,
+                               sdata->u.sta.ssid_len) == 0) {
                if (rx_status->flag & RX_FLAG_TSFT) {
                        /* in order for correct IBSS merging we need mactime
                         *
@@ -2849,18 +2858,18 @@ 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);
+                                              mgmt->bssid, mgmt->sa,
+                                              BIT(rx_status->rate_idx));
                }
        }
 
-       ieee80211_rx_bss_put(dev, bss);
+       ieee80211_rx_bss_put(local, bss);
 }
 
 
@@ -2869,7 +2878,17 @@ static void ieee80211_rx_mgmt_probe_resp(struct net_device *dev,
                                         size_t len,
                                         struct ieee80211_rx_status *rx_status)
 {
-       ieee80211_rx_bss_info(dev, mgmt, len, rx_status, 0);
+       size_t baselen;
+       struct ieee802_11_elems elems;
+
+       baselen = (u8 *) mgmt->u.probe_resp.variable - (u8 *) mgmt;
+       if (baselen > len)
+               return;
+
+       ieee802_11_parse_elems(mgmt->u.probe_resp.variable, len - baselen,
+                               &elems);
+
+       ieee80211_rx_bss_info(dev, mgmt, len, rx_status, &elems, 0);
 }
 
 
@@ -2886,7 +2905,14 @@ static void ieee80211_rx_mgmt_beacon(struct net_device *dev,
        struct ieee80211_conf *conf = &local->hw.conf;
        u32 changed = 0;
 
-       ieee80211_rx_bss_info(dev, mgmt, len, rx_status, 1);
+       /* Process beacon from the current BSS */
+       baselen = (u8 *) mgmt->u.beacon.variable - (u8 *) mgmt;
+       if (baselen > len)
+               return;
+
+       ieee802_11_parse_elems(mgmt->u.beacon.variable, len - baselen, &elems);
+
+       ieee80211_rx_bss_info(dev, mgmt, len, rx_status, &elems, 1);
 
        sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        if (sdata->vif.type != IEEE80211_IF_TYPE_STA)
@@ -2897,13 +2923,6 @@ static void ieee80211_rx_mgmt_beacon(struct net_device *dev,
            memcmp(ifsta->bssid, mgmt->bssid, ETH_ALEN) != 0)
                return;
 
-       /* Process beacon from the current BSS */
-       baselen = (u8 *) mgmt->u.beacon.variable - (u8 *) mgmt;
-       if (baselen > len)
-               return;
-
-       ieee802_11_parse_elems(mgmt->u.beacon.variable, len - baselen, &elems);
-
        ieee80211_sta_wmm_params(dev, ifsta, elems.wmm_param,
                                 elems.wmm_param_len);
 
@@ -2982,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 &&
@@ -3017,11 +3036,24 @@ static void ieee80211_rx_mgmt_action(struct net_device *dev,
                                     struct ieee80211_rx_status *rx_status)
 {
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
 
        if (len < IEEE80211_MIN_ACTION_SIZE)
                return;
 
        switch (mgmt->u.action.category) {
+       case WLAN_CATEGORY_SPECTRUM_MGMT:
+               if (local->hw.conf.channel->band != IEEE80211_BAND_5GHZ)
+                       break;
+               switch (mgmt->u.action.u.chan_switch.action_code) {
+               case WLAN_ACTION_SPCT_MSR_REQ:
+                       if (len < (IEEE80211_MIN_ACTION_SIZE +
+                                  sizeof(mgmt->u.action.u.measurement)))
+                               break;
+                       ieee80211_sta_process_measurement_req(dev, mgmt, len);
+                       break;
+               }
+               break;
        case WLAN_CATEGORY_BACK:
                switch (mgmt->u.action.u.addba_req.action_code) {
                case WLAN_ACTION_ADDBA_REQ:
@@ -3042,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:
@@ -3057,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;
        }
 }
 
@@ -3097,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:
@@ -3165,33 +3182,32 @@ ieee80211_sta_rx_scan(struct net_device *dev, struct sk_buff *skb,
                      struct ieee80211_rx_status *rx_status)
 {
        struct ieee80211_mgmt *mgmt;
-       u16 fc;
+       __le16 fc;
 
        if (skb->len < 2)
                return RX_DROP_UNUSABLE;
 
        mgmt = (struct ieee80211_mgmt *) skb->data;
-       fc = le16_to_cpu(mgmt->frame_control);
+       fc = mgmt->frame_control;
 
-       if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL)
+       if (ieee80211_is_ctl(fc))
                return RX_CONTINUE;
 
        if (skb->len < 24)
                return RX_DROP_MONITOR;
 
-       if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) {
-               if ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PROBE_RESP) {
-                       ieee80211_rx_mgmt_probe_resp(dev, mgmt,
-                                                    skb->len, rx_status);
-                       dev_kfree_skb(skb);
-                       return RX_QUEUED;
-               } else if ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_BEACON) {
-                       ieee80211_rx_mgmt_beacon(dev, mgmt, skb->len,
-                                                rx_status);
-                       dev_kfree_skb(skb);
-                       return RX_QUEUED;
-               }
+       if (ieee80211_is_probe_resp(fc)) {
+               ieee80211_rx_mgmt_probe_resp(dev, mgmt, skb->len, rx_status);
+               dev_kfree_skb(skb);
+               return RX_QUEUED;
        }
+
+       if (ieee80211_is_beacon(fc)) {
+               ieee80211_rx_mgmt_beacon(dev, mgmt, skb->len, rx_status);
+               dev_kfree_skb(skb);
+               return RX_QUEUED;
+       }
+
        return RX_CONTINUE;
 }
 
@@ -3231,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);
@@ -3271,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);
@@ -3315,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)))
@@ -3375,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;
        }
 
@@ -3411,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;
@@ -3476,21 +3488,17 @@ static int ieee80211_sta_config_auth(struct net_device *dev,
        struct ieee80211_sta_bss *bss, *selected = NULL;
        int top_rssi = 0, freq;
 
-       if (!(ifsta->flags & (IEEE80211_STA_AUTO_SSID_SEL |
-           IEEE80211_STA_AUTO_BSSID_SEL | IEEE80211_STA_AUTO_CHANNEL_SEL))) {
-               ifsta->state = IEEE80211_AUTHENTICATE;
-               ieee80211_sta_reset_auth(dev, ifsta);
-               return 0;
-       }
-
        spin_lock_bh(&local->sta_bss_lock);
        freq = local->oper_channel->center_freq;
        list_for_each_entry(bss, &local->sta_bss_list, list) {
                if (!(bss->capability & WLAN_CAPABILITY_ESS))
                        continue;
 
-               if (!!(bss->capability & WLAN_CAPABILITY_PRIVACY) ^
-                   !!sdata->default_key)
+               if ((ifsta->flags & (IEEE80211_STA_AUTO_SSID_SEL |
+                       IEEE80211_STA_AUTO_BSSID_SEL |
+                       IEEE80211_STA_AUTO_CHANNEL_SEL)) &&
+                   (!!(bss->capability & WLAN_CAPABILITY_PRIVACY) ^
+                    !!sdata->default_key))
                        continue;
 
                if (!(ifsta->flags & IEEE80211_STA_AUTO_CHANNEL_SEL) &&
@@ -3515,13 +3523,13 @@ static int ieee80211_sta_config_auth(struct net_device *dev,
        spin_unlock_bh(&local->sta_bss_lock);
 
        if (selected) {
-               ieee80211_set_freq(local, selected->freq);
+               ieee80211_set_freq(dev, selected->freq);
                if (!(ifsta->flags & IEEE80211_STA_SSID_SET))
                        ieee80211_sta_set_ssid(dev, selected->ssid,
                                               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;
@@ -3550,6 +3558,7 @@ static int ieee80211_sta_create_ibss(struct net_device *dev,
        struct ieee80211_supported_band *sband;
        u8 bssid[ETH_ALEN], *pos;
        int i;
+       int ret;
        DECLARE_MAC_BUF(mac);
 
 #if 0
@@ -3579,7 +3588,7 @@ static int ieee80211_sta_create_ibss(struct net_device *dev,
        sband = local->hw.wiphy->bands[bss->band];
 
        if (local->hw.conf.beacon_int == 0)
-               local->hw.conf.beacon_int = 10000;
+               local->hw.conf.beacon_int = 100;
        bss->beacon_int = local->hw.conf.beacon_int;
        bss->last_update = jiffies;
        bss->capability = WLAN_CAPABILITY_IBSS;
@@ -3596,7 +3605,9 @@ static int ieee80211_sta_create_ibss(struct net_device *dev,
                *pos++ = (u8) (rate / 5);
        }
 
-       return ieee80211_sta_join_ibss(dev, ifsta, bss);
+       ret = ieee80211_sta_join_ibss(dev, ifsta, bss);
+       ieee80211_rx_bss_put(local, bss);
+       return ret;
 }
 
 
@@ -3637,17 +3648,22 @@ 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,
                                        local->hw.conf.channel->center_freq,
                                        ifsta->ssid, ifsta->ssid_len))) {
+               int ret;
                printk(KERN_DEBUG "%s: Selected IBSS BSSID %s"
                       " based on configured SSID\n",
                       dev->name, print_mac(mac, bssid));
-               return ieee80211_sta_join_ibss(dev, ifsta, bss);
+               ret = ieee80211_sta_join_ibss(dev, ifsta, bss);
+               ieee80211_rx_bss_put(local, bss);
+               return ret;
        }
 #ifdef CONFIG_MAC80211_IBSS_DEBUG
        printk(KERN_DEBUG "   did not try to join ibss\n");
@@ -3697,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;
 }
 
@@ -3744,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);
@@ -3767,7 +3805,7 @@ static void ieee80211_send_nullfunc(struct ieee80211_local *local,
 {
        struct sk_buff *skb;
        struct ieee80211_hdr *nullfunc;
-       u16 fc;
+       __le16 fc;
 
        skb = dev_alloc_skb(local->hw.extra_tx_headroom + 24);
        if (!skb) {
@@ -3779,11 +3817,11 @@ static void ieee80211_send_nullfunc(struct ieee80211_local *local,
 
        nullfunc = (struct ieee80211_hdr *) skb_put(skb, 24);
        memset(nullfunc, 0, 24);
-       fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_NULLFUNC |
-            IEEE80211_FCTL_TODS;
+       fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_NULLFUNC |
+                        IEEE80211_FCTL_TODS);
        if (powersave)
-               fc |= IEEE80211_FCTL_PM;
-       nullfunc->frame_control = cpu_to_le16(fc);
+               fc |= cpu_to_le16(IEEE80211_FCTL_PM);
+       nullfunc->frame_control = fc;
        memcpy(nullfunc->addr1, sdata->u.sta.bssid, ETH_ALEN);
        memcpy(nullfunc->addr2, sdata->dev->dev_addr, ETH_ALEN);
        memcpy(nullfunc->addr3, sdata->u.sta.bssid, ETH_ALEN);
@@ -3831,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,
@@ -3838,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)
@@ -4012,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))
@@ -4036,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 */
@@ -4077,6 +4108,7 @@ int ieee80211_sta_req_scan(struct net_device *dev, u8 *ssid, size_t ssid_len)
 
 static char *
 ieee80211_sta_scan_result(struct net_device *dev,
+                         struct iw_request_info *info,
                          struct ieee80211_sta_bss *bss,
                          char *current_ev, char *end_buf)
 {
@@ -4091,7 +4123,7 @@ ieee80211_sta_scan_result(struct net_device *dev,
        iwe.cmd = SIOCGIWAP;
        iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
        memcpy(iwe.u.ap_addr.sa_data, bss->bssid, ETH_ALEN);
-       current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe,
+       current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe,
                                          IW_EV_ADDR_LEN);
 
        memset(&iwe, 0, sizeof(iwe));
@@ -4099,13 +4131,13 @@ ieee80211_sta_scan_result(struct net_device *dev,
        if (bss_mesh_cfg(bss)) {
                iwe.u.data.length = bss_mesh_id_len(bss);
                iwe.u.data.flags = 1;
-               current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe,
-                                                 bss_mesh_id(bss));
+               current_ev = iwe_stream_add_point(info, current_ev, end_buf,
+                                                 &iwe, bss_mesh_id(bss));
        } else {
                iwe.u.data.length = bss->ssid_len;
                iwe.u.data.flags = 1;
-               current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe,
-                                                 bss->ssid);
+               current_ev = iwe_stream_add_point(info, current_ev, end_buf,
+                                                 &iwe, bss->ssid);
        }
 
        if (bss->capability & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS)
@@ -4118,31 +4150,30 @@ ieee80211_sta_scan_result(struct net_device *dev,
                        iwe.u.mode = IW_MODE_MASTER;
                else
                        iwe.u.mode = IW_MODE_ADHOC;
-               current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe,
-                                                 IW_EV_UINT_LEN);
+               current_ev = iwe_stream_add_event(info, current_ev, end_buf,
+                                                 &iwe, IW_EV_UINT_LEN);
        }
 
        memset(&iwe, 0, sizeof(iwe));
        iwe.cmd = SIOCGIWFREQ;
-       iwe.u.freq.m = bss->freq;
-       iwe.u.freq.e = 6;
-       current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe,
+       iwe.u.freq.m = ieee80211_frequency_to_channel(bss->freq);
+       iwe.u.freq.e = 0;
+       current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe,
                                          IW_EV_FREQ_LEN);
 
        memset(&iwe, 0, sizeof(iwe));
        iwe.cmd = SIOCGIWFREQ;
-       iwe.u.freq.m = ieee80211_frequency_to_channel(bss->freq);
-       iwe.u.freq.e = 0;
-       current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe,
+       iwe.u.freq.m = bss->freq;
+       iwe.u.freq.e = 6;
+       current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe,
                                          IW_EV_FREQ_LEN);
-
        memset(&iwe, 0, sizeof(iwe));
        iwe.cmd = IWEVQUAL;
        iwe.u.qual.qual = bss->qual;
        iwe.u.qual.level = bss->signal;
        iwe.u.qual.noise = bss->noise;
        iwe.u.qual.updated = local->wstats_flags;
-       current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe,
+       current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe,
                                          IW_EV_QUAL_LEN);
 
        memset(&iwe, 0, sizeof(iwe));
@@ -4152,35 +4183,36 @@ ieee80211_sta_scan_result(struct net_device *dev,
        else
                iwe.u.data.flags = IW_ENCODE_DISABLED;
        iwe.u.data.length = 0;
-       current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, "");
+       current_ev = iwe_stream_add_point(info, current_ev, end_buf,
+                                         &iwe, "");
 
        if (bss && bss->wpa_ie) {
                memset(&iwe, 0, sizeof(iwe));
                iwe.cmd = IWEVGENIE;
                iwe.u.data.length = bss->wpa_ie_len;
-               current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe,
-                                                 bss->wpa_ie);
+               current_ev = iwe_stream_add_point(info, current_ev, end_buf,
+                                                 &iwe, bss->wpa_ie);
        }
 
        if (bss && bss->rsn_ie) {
                memset(&iwe, 0, sizeof(iwe));
                iwe.cmd = IWEVGENIE;
                iwe.u.data.length = bss->rsn_ie_len;
-               current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe,
-                                                 bss->rsn_ie);
+               current_ev = iwe_stream_add_point(info, current_ev, end_buf,
+                                                 &iwe, bss->rsn_ie);
        }
 
        if (bss && bss->ht_ie) {
                memset(&iwe, 0, sizeof(iwe));
                iwe.cmd = IWEVGENIE;
                iwe.u.data.length = bss->ht_ie_len;
-               current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe,
-                                                 bss->ht_ie);
+               current_ev = iwe_stream_add_point(info, current_ev, end_buf,
+                                                 &iwe, bss->ht_ie);
        }
 
        if (bss && bss->supp_rates_len > 0) {
                /* display all supported rates in readable format */
-               char *p = current_ev + IW_EV_LCP_LEN;
+               char *p = current_ev + iwe_stream_lcp_len(info);
                int i;
 
                memset(&iwe, 0, sizeof(iwe));
@@ -4191,7 +4223,7 @@ ieee80211_sta_scan_result(struct net_device *dev,
                for (i = 0; i < bss->supp_rates_len; i++) {
                        iwe.u.bitrate.value = ((bss->supp_rates[i] &
                                                        0x7f) * 500000);
-                       p = iwe_stream_add_value(current_ev, p,
+                       p = iwe_stream_add_value(info, current_ev, p,
                                        end_buf, &iwe, IW_EV_PARAM_LEN);
                }
                current_ev = p;
@@ -4205,8 +4237,16 @@ ieee80211_sta_scan_result(struct net_device *dev,
                        iwe.cmd = IWEVCUSTOM;
                        sprintf(buf, "tsf=%016llx", (unsigned long long)(bss->timestamp));
                        iwe.u.data.length = strlen(buf);
-                       current_ev = iwe_stream_add_point(current_ev, end_buf,
+                       current_ev = iwe_stream_add_point(info, current_ev,
+                                                         end_buf,
                                                          &iwe, buf);
+                       memset(&iwe, 0, sizeof(iwe));
+                       iwe.cmd = IWEVCUSTOM;
+                       sprintf(buf, " Last beacon: %dms ago",
+                               jiffies_to_msecs(jiffies - bss->last_update));
+                       iwe.u.data.length = strlen(buf);
+                       current_ev = iwe_stream_add_point(info, current_ev,
+                                                         end_buf, &iwe, buf);
                        kfree(buf);
                }
        }
@@ -4220,31 +4260,36 @@ ieee80211_sta_scan_result(struct net_device *dev,
                        iwe.cmd = IWEVCUSTOM;
                        sprintf(buf, "Mesh network (version %d)", cfg[0]);
                        iwe.u.data.length = strlen(buf);
-                       current_ev = iwe_stream_add_point(current_ev, end_buf,
+                       current_ev = iwe_stream_add_point(info, current_ev,
+                                                         end_buf,
                                                          &iwe, buf);
                        sprintf(buf, "Path Selection Protocol ID: "
                                "0x%02X%02X%02X%02X", cfg[1], cfg[2], cfg[3],
                                                        cfg[4]);
                        iwe.u.data.length = strlen(buf);
-                       current_ev = iwe_stream_add_point(current_ev, end_buf,
+                       current_ev = iwe_stream_add_point(info, current_ev,
+                                                         end_buf,
                                                          &iwe, buf);
                        sprintf(buf, "Path Selection Metric ID: "
                                "0x%02X%02X%02X%02X", cfg[5], cfg[6], cfg[7],
                                                        cfg[8]);
                        iwe.u.data.length = strlen(buf);
-                       current_ev = iwe_stream_add_point(current_ev, end_buf,
+                       current_ev = iwe_stream_add_point(info, current_ev,
+                                                         end_buf,
                                                          &iwe, buf);
                        sprintf(buf, "Congestion Control Mode ID: "
                                "0x%02X%02X%02X%02X", cfg[9], cfg[10],
                                                        cfg[11], cfg[12]);
                        iwe.u.data.length = strlen(buf);
-                       current_ev = iwe_stream_add_point(current_ev, end_buf,
+                       current_ev = iwe_stream_add_point(info, current_ev,
+                                                         end_buf,
                                                          &iwe, buf);
                        sprintf(buf, "Channel Precedence: "
                                "0x%02X%02X%02X%02X", cfg[13], cfg[14],
                                                        cfg[15], cfg[16]);
                        iwe.u.data.length = strlen(buf);
-                       current_ev = iwe_stream_add_point(current_ev, end_buf,
+                       current_ev = iwe_stream_add_point(info, current_ev,
+                                                         end_buf,
                                                          &iwe, buf);
                        kfree(buf);
                }
@@ -4254,7 +4299,9 @@ ieee80211_sta_scan_result(struct net_device *dev,
 }
 
 
-int ieee80211_sta_scan_results(struct net_device *dev, char *buf, size_t len)
+int ieee80211_sta_scan_results(struct net_device *dev,
+                              struct iw_request_info *info,
+                              char *buf, size_t len)
 {
        struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
        char *current_ev = buf;
@@ -4267,8 +4314,8 @@ int ieee80211_sta_scan_results(struct net_device *dev, char *buf, size_t len)
                        spin_unlock_bh(&local->sta_bss_lock);
                        return -E2BIG;
                }
-               current_ev = ieee80211_sta_scan_result(dev, bss, current_ev,
-                                                      end_buf);
+               current_ev = ieee80211_sta_scan_result(dev, info, bss,
+                                                      current_ev, end_buf);
        }
        spin_unlock_bh(&local->sta_bss_lock);
        return current_ev - buf;
@@ -4299,12 +4346,13 @@ int ieee80211_sta_set_extra_ie(struct net_device *dev, char *ie, size_t len)
 
 struct sta_info *ieee80211_ibss_add_sta(struct net_device *dev,
                                        struct sk_buff *skb, u8 *bssid,
-                                       u8 *addr)
+                                       u8 *addr, u64 supp_rates)
 {
        struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
        struct sta_info *sta;
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        DECLARE_MAC_BUF(mac);
+       int band = local->hw.conf.channel->band;
 
        /* TODO: Could consider removing the least recently used entry and
         * allow new one to be added. */
@@ -4316,8 +4364,13 @@ struct sta_info *ieee80211_ibss_add_sta(struct net_device *dev,
                return NULL;
        }
 
+       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)
@@ -4325,8 +4378,10 @@ struct sta_info *ieee80211_ibss_add_sta(struct net_device *dev,
 
        set_sta_flags(sta, WLAN_STA_AUTHORIZED);
 
-       sta->supp_rates[local->hw.conf.channel->band] =
-               sdata->u.sta.supp_rates_bits[local->hw.conf.channel->band];
+       if (supp_rates)
+               sta->supp_rates[band] = supp_rates;
+       else
+               sta->supp_rates[band] = sdata->u.sta.supp_rates_bits[band];
 
        rate_control_rate_init(sta, local);
 
@@ -4342,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 &&
@@ -4360,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)
@@ -4384,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;