]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - net/mac80211/ieee80211_sta.c
mac80211: notify mac from low level driver (iwlwifi)
[linux-2.6-omap-h63xx.git] / net / mac80211 / ieee80211_sta.c
index 8b991ebcbb4ed7b682fd1dbad4663d3a6ca3c466..89481c919cb6b4ebe01f049d1328857f95b273dd 100644 (file)
@@ -57,8 +57,6 @@
 #define IEEE80211_IBSS_MAX_STA_ENTRIES 128
 
 
-#define IEEE80211_FC(type, stype) cpu_to_le16(type | stype)
-
 #define ERP_INFO_USE_PROTECTION BIT(1)
 
 /* mgmt header + 1 byte action code */
@@ -220,6 +218,60 @@ static int ecw2cw(int ecw)
        return (1 << ecw) - 1;
 }
 
+
+static void ieee80211_sta_def_wmm_params(struct net_device *dev,
+                                        struct ieee80211_sta_bss *bss,
+                                        int ibss)
+{
+       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+       struct ieee80211_local *local = sdata->local;
+       int i, have_higher_than_11mbit = 0;
+
+
+       /* cf. IEEE 802.11 9.2.12 */
+       for (i = 0; i < bss->supp_rates_len; i++)
+               if ((bss->supp_rates[i] & 0x7f) * 5 > 110)
+                       have_higher_than_11mbit = 1;
+
+       if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ &&
+           have_higher_than_11mbit)
+               sdata->flags |= IEEE80211_SDATA_OPERATING_GMODE;
+       else
+               sdata->flags &= ~IEEE80211_SDATA_OPERATING_GMODE;
+
+
+       if (local->ops->conf_tx) {
+               struct ieee80211_tx_queue_params qparam;
+
+               memset(&qparam, 0, sizeof(qparam));
+
+               qparam.aifs = 2;
+
+               if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ &&
+                   !(sdata->flags & IEEE80211_SDATA_OPERATING_GMODE))
+                       qparam.cw_min = 31;
+               else
+                       qparam.cw_min = 15;
+
+               qparam.cw_max = 1023;
+               qparam.txop = 0;
+
+               for (i = IEEE80211_TX_QUEUE_DATA0; i < NUM_TX_DATA_QUEUES; i++)
+                       local->ops->conf_tx(local_to_hw(local),
+                                          i + IEEE80211_TX_QUEUE_DATA0,
+                                          &qparam);
+
+               if (ibss) {
+                       /* IBSS uses different parameters for Beacon sending */
+                       qparam.cw_min++;
+                       qparam.cw_min *= 2;
+                       qparam.cw_min--;
+                       local->ops->conf_tx(local_to_hw(local),
+                                          IEEE80211_TX_QUEUE_BEACON, &qparam);
+               }
+       }
+}
+
 static void ieee80211_sta_wmm_params(struct net_device *dev,
                                     struct ieee80211_if_sta *ifsta,
                                     u8 *wmm_param, size_t wmm_param_len)
@@ -305,7 +357,7 @@ static u32 ieee80211_handle_erp_ie(struct ieee80211_sub_if_data *sdata,
        struct ieee80211_bss_conf *bss_conf = &sdata->bss_conf;
        struct ieee80211_if_sta *ifsta = &sdata->u.sta;
        bool use_protection = (erp_value & WLAN_ERP_USE_PROTECTION) != 0;
-       bool preamble_mode = (erp_value & WLAN_ERP_BARKER_PREAMBLE) != 0;
+       bool use_short_preamble = (erp_value & WLAN_ERP_BARKER_PREAMBLE) == 0;
        DECLARE_MAC_BUF(mac);
        u32 changed = 0;
 
@@ -321,16 +373,15 @@ static u32 ieee80211_handle_erp_ie(struct ieee80211_sub_if_data *sdata,
                changed |= BSS_CHANGED_ERP_CTS_PROT;
        }
 
-       if (preamble_mode != bss_conf->use_short_preamble) {
+       if (use_short_preamble != bss_conf->use_short_preamble) {
                if (net_ratelimit()) {
                        printk(KERN_DEBUG "%s: switched to %s barker preamble"
                               " (BSSID=%s)\n",
                               sdata->dev->name,
-                              (preamble_mode == WLAN_ERP_PREAMBLE_SHORT) ?
-                                       "short" : "long",
+                              use_short_preamble ? "short" : "long",
                               print_mac(mac, ifsta->bssid));
                }
-               bss_conf->use_short_preamble = preamble_mode;
+               bss_conf->use_short_preamble = use_short_preamble;
                changed |= BSS_CHANGED_ERP_PREAMBLE;
        }
 
@@ -440,6 +491,7 @@ static void ieee80211_set_associated(struct net_device *dev,
 {
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        struct ieee80211_local *local = sdata->local;
+       struct ieee80211_conf *conf = &local_to_hw(local)->conf;
        union iwreq_data wrqu;
        u32 changed = BSS_CHANGED_ASSOC;
 
@@ -452,34 +504,51 @@ static void ieee80211_set_associated(struct net_device *dev,
                        return;
 
                bss = ieee80211_rx_bss_get(dev, ifsta->bssid,
-                                          local->hw.conf.channel->center_freq,
+                                          conf->channel->center_freq,
                                           ifsta->ssid, ifsta->ssid_len);
                if (bss) {
+                       /* set timing information */
+                       sdata->bss_conf.beacon_int = bss->beacon_int;
+                       sdata->bss_conf.timestamp = bss->timestamp;
+
                        if (bss->has_erp_value)
                                changed |= ieee80211_handle_erp_ie(
                                                sdata, bss->erp_value);
+
                        ieee80211_rx_bss_put(dev, bss);
                }
 
+               if (conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) {
+                       changed |= BSS_CHANGED_HT;
+                       sdata->bss_conf.assoc_ht = 1;
+                       sdata->bss_conf.ht_conf = &conf->ht_conf;
+                       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 {
+               ieee80211_sta_tear_down_BA_sessions(dev, ifsta->bssid);
                ifsta->flags &= ~IEEE80211_STA_ASSOCIATED;
-
                netif_carrier_off(dev);
                ieee80211_reset_erp_info(dev);
+
+               sdata->bss_conf.assoc_ht = 0;
+               sdata->bss_conf.ht_conf = NULL;
+               sdata->bss_conf.ht_bss_conf = NULL;
+
                memset(wrqu.ap_addr.sa_data, 0, ETH_ALEN);
        }
-       wrqu.ap_addr.sa_family = ARPHRD_ETHER;
-       wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
        ifsta->last_probe = jiffies;
        ieee80211_led_assoc(local, assoc);
 
        sdata->bss_conf.assoc = assoc;
        ieee80211_bss_info_change_notify(sdata, changed);
+       wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+       wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
 }
 
 static void ieee80211_set_disassoc(struct net_device *dev,
@@ -884,7 +953,6 @@ static void ieee80211_associated(struct net_device *dev,
        rcu_read_unlock();
 
        if (disassoc && sta) {
-               synchronize_rcu();
                rtnl_lock();
                sta_info_destroy(sta);
                rtnl_unlock();
@@ -1145,7 +1213,7 @@ static void ieee80211_sta_process_addba_request(struct net_device *dev,
                status = WLAN_STATUS_INVALID_QOS_PARAM;
 #ifdef CONFIG_MAC80211_HT_DEBUG
                if (net_ratelimit())
-                       printk(KERN_DEBUG "Block Ack Req with bad params from "
+                       printk(KERN_DEBUG "AddBA Req with bad params from "
                                "%s on tid %u. policy %d, buffer size %d\n",
                                print_mac(mac, mgmt->sa), tid, ba_policy,
                                buf_size);
@@ -1161,21 +1229,38 @@ static void ieee80211_sta_process_addba_request(struct net_device *dev,
                buf_size = buf_size << sband->ht_info.ampdu_factor;
        }
 
-       tid_agg_rx = &sta->ampdu_mlme.tid_rx[tid];
 
        /* examine state machine */
        spin_lock_bh(&sta->ampdu_mlme.ampdu_rx);
 
-       if (tid_agg_rx->state != HT_AGG_STATE_IDLE) {
+       if (sta->ampdu_mlme.tid_state_rx[tid] != HT_AGG_STATE_IDLE) {
 #ifdef CONFIG_MAC80211_HT_DEBUG
                if (net_ratelimit())
-                       printk(KERN_DEBUG "unexpected Block Ack Req from "
+                       printk(KERN_DEBUG "unexpected AddBA Req from "
                                "%s on tid %u\n",
                                print_mac(mac, mgmt->sa), tid);
 #endif /* CONFIG_MAC80211_HT_DEBUG */
                goto end;
        }
 
+       /* prepare A-MPDU MLME for Rx aggregation */
+       sta->ampdu_mlme.tid_rx[tid] =
+                       kmalloc(sizeof(struct tid_ampdu_rx), GFP_ATOMIC);
+       if (!sta->ampdu_mlme.tid_rx[tid]) {
+               if (net_ratelimit())
+                       printk(KERN_ERR "allocate rx mlme to tid %d failed\n",
+                                       tid);
+               goto end;
+       }
+       /* rx timer */
+       sta->ampdu_mlme.tid_rx[tid]->session_timer.function =
+                               sta_rx_agg_session_timer_expired;
+       sta->ampdu_mlme.tid_rx[tid]->session_timer.data =
+                               (unsigned long)&sta->timer_to_tid[tid];
+       init_timer(&sta->ampdu_mlme.tid_rx[tid]->session_timer);
+
+       tid_agg_rx = sta->ampdu_mlme.tid_rx[tid];
+
        /* prepare reordering buffer */
        tid_agg_rx->reorder_buf =
                kmalloc(buf_size * sizeof(struct sk_buf *), GFP_ATOMIC);
@@ -1183,6 +1268,7 @@ static void ieee80211_sta_process_addba_request(struct net_device *dev,
                if (net_ratelimit())
                        printk(KERN_ERR "can not allocate reordering buffer "
                               "to tid %d\n", tid);
+               kfree(sta->ampdu_mlme.tid_rx[tid]);
                goto end;
        }
        memset(tid_agg_rx->reorder_buf, 0,
@@ -1197,11 +1283,13 @@ static void ieee80211_sta_process_addba_request(struct net_device *dev,
 
        if (ret) {
                kfree(tid_agg_rx->reorder_buf);
+               kfree(tid_agg_rx);
+               sta->ampdu_mlme.tid_rx[tid] = NULL;
                goto end;
        }
 
        /* change state and send addba resp */
-       tid_agg_rx->state = HT_AGG_STATE_OPERATIONAL;
+       sta->ampdu_mlme.tid_state_rx[tid] = HT_AGG_STATE_OPERATIONAL;
        tid_agg_rx->dialog_token = dialog_token;
        tid_agg_rx->ssn = start_seq_num;
        tid_agg_rx->head_seq_num = start_seq_num;
@@ -1240,39 +1328,37 @@ static void ieee80211_sta_process_addba_resp(struct net_device *dev,
        capab = le16_to_cpu(mgmt->u.action.u.addba_resp.capab);
        tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2;
 
-       state = &sta->ampdu_mlme.tid_tx[tid].state;
+       state = &sta->ampdu_mlme.tid_state_tx[tid];
 
        spin_lock_bh(&sta->ampdu_mlme.ampdu_tx);
 
+       if (!(*state & HT_ADDBA_REQUESTED_MSK)) {
+               spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
+               printk(KERN_DEBUG "state not HT_ADDBA_REQUESTED_MSK:"
+                       "%d\n", *state);
+               goto addba_resp_exit;
+       }
+
        if (mgmt->u.action.u.addba_resp.dialog_token !=
-               sta->ampdu_mlme.tid_tx[tid].dialog_token) {
+               sta->ampdu_mlme.tid_tx[tid]->dialog_token) {
                spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
 #ifdef CONFIG_MAC80211_HT_DEBUG
                printk(KERN_DEBUG "wrong addBA response token, tid %d\n", tid);
 #endif /* CONFIG_MAC80211_HT_DEBUG */
-               rcu_read_unlock();
-               return;
+               goto addba_resp_exit;
        }
 
-       del_timer_sync(&sta->ampdu_mlme.tid_tx[tid].addba_resp_timer);
+       del_timer_sync(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer);
 #ifdef CONFIG_MAC80211_HT_DEBUG
        printk(KERN_DEBUG "switched off addBA timer for tid %d \n", tid);
 #endif /* CONFIG_MAC80211_HT_DEBUG */
        if (le16_to_cpu(mgmt->u.action.u.addba_resp.status)
                        == WLAN_STATUS_SUCCESS) {
-               if (!(*state & HT_ADDBA_REQUESTED_MSK)) {
-                       spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
-                       printk(KERN_DEBUG "state not HT_ADDBA_REQUESTED_MSK:"
-                               "%d\n", *state);
-                       rcu_read_unlock();
-                       return;
-               }
-
                if (*state & HT_ADDBA_RECEIVED_MSK)
                        printk(KERN_DEBUG "double addBA response\n");
 
                *state |= HT_ADDBA_RECEIVED_MSK;
-               sta->ampdu_mlme.tid_tx[tid].addba_req_num = 0;
+               sta->ampdu_mlme.addba_req_num[tid] = 0;
 
                if (*state == HT_AGG_STATE_OPERATIONAL) {
                        printk(KERN_DEBUG "Aggregation on for tid %d \n", tid);
@@ -1284,13 +1370,15 @@ static void ieee80211_sta_process_addba_resp(struct net_device *dev,
        } else {
                printk(KERN_DEBUG "recipient rejected agg: tid %d \n", tid);
 
-               sta->ampdu_mlme.tid_tx[tid].addba_req_num++;
+               sta->ampdu_mlme.addba_req_num[tid]++;
                /* this will allow the state check in stop_BA_session */
                *state = HT_AGG_STATE_OPERATIONAL;
                spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
                ieee80211_stop_tx_ba_session(hw, sta->addr, tid,
                                             WLAN_BACK_INITIATOR);
        }
+
+addba_resp_exit:
        rcu_read_unlock();
 }
 
@@ -1356,13 +1444,13 @@ void ieee80211_sta_stop_rx_ba_session(struct net_device *dev, u8 *ra, u16 tid,
 
        /* check if TID is in operational state */
        spin_lock_bh(&sta->ampdu_mlme.ampdu_rx);
-       if (sta->ampdu_mlme.tid_rx[tid].state
+       if (sta->ampdu_mlme.tid_state_rx[tid]
                                != HT_AGG_STATE_OPERATIONAL) {
                spin_unlock_bh(&sta->ampdu_mlme.ampdu_rx);
                rcu_read_unlock();
                return;
        }
-       sta->ampdu_mlme.tid_rx[tid].state =
+       sta->ampdu_mlme.tid_state_rx[tid] =
                HT_AGG_STATE_REQ_STOP_BA_MSK |
                (initiator << HT_AGG_STATE_INITIATOR_SHIFT);
                spin_unlock_bh(&sta->ampdu_mlme.ampdu_rx);
@@ -1379,25 +1467,27 @@ void ieee80211_sta_stop_rx_ba_session(struct net_device *dev, u8 *ra, u16 tid,
 
        /* shutdown timer has not expired */
        if (initiator != WLAN_BACK_TIMER)
-               del_timer_sync(&sta->ampdu_mlme.tid_rx[tid].
-                                       session_timer);
+               del_timer_sync(&sta->ampdu_mlme.tid_rx[tid]->session_timer);
 
        /* check if this is a self generated aggregation halt */
        if (initiator == WLAN_BACK_RECIPIENT || initiator == WLAN_BACK_TIMER)
                ieee80211_send_delba(dev, ra, tid, 0, reason);
 
        /* free the reordering buffer */
-       for (i = 0; i < sta->ampdu_mlme.tid_rx[tid].buf_size; i++) {
-               if (sta->ampdu_mlme.tid_rx[tid].reorder_buf[i]) {
+       for (i = 0; i < sta->ampdu_mlme.tid_rx[tid]->buf_size; i++) {
+               if (sta->ampdu_mlme.tid_rx[tid]->reorder_buf[i]) {
                        /* release the reordered frames */
-                       dev_kfree_skb(sta->ampdu_mlme.tid_rx[tid].reorder_buf[i]);
-                       sta->ampdu_mlme.tid_rx[tid].stored_mpdu_num--;
-                       sta->ampdu_mlme.tid_rx[tid].reorder_buf[i] = NULL;
+                       dev_kfree_skb(sta->ampdu_mlme.tid_rx[tid]->reorder_buf[i]);
+                       sta->ampdu_mlme.tid_rx[tid]->stored_mpdu_num--;
+                       sta->ampdu_mlme.tid_rx[tid]->reorder_buf[i] = NULL;
                }
        }
-       kfree(sta->ampdu_mlme.tid_rx[tid].reorder_buf);
+       /* free resources */
+       kfree(sta->ampdu_mlme.tid_rx[tid]->reorder_buf);
+       kfree(sta->ampdu_mlme.tid_rx[tid]);
+       sta->ampdu_mlme.tid_rx[tid] = NULL;
+       sta->ampdu_mlme.tid_state_rx[tid] = HT_AGG_STATE_IDLE;
 
-       sta->ampdu_mlme.tid_rx[tid].state = HT_AGG_STATE_IDLE;
        rcu_read_unlock();
 }
 
@@ -1427,7 +1517,7 @@ static void ieee80211_sta_process_delba(struct net_device *dev,
        if (net_ratelimit())
                printk(KERN_DEBUG "delba from %s (%s) tid %d reason code %d\n",
                        print_mac(mac, mgmt->sa),
-                       initiator ? "recipient" : "initiator", tid,
+                       initiator ? "initiator" : "recipient", tid,
                        mgmt->u.action.u.delba.reason_code);
 #endif /* CONFIG_MAC80211_HT_DEBUG */
 
@@ -1436,7 +1526,7 @@ static void ieee80211_sta_process_delba(struct net_device *dev,
                                                 WLAN_BACK_INITIATOR, 0);
        else { /* WLAN_BACK_RECIPIENT */
                spin_lock_bh(&sta->ampdu_mlme.ampdu_tx);
-               sta->ampdu_mlme.tid_tx[tid].state =
+               sta->ampdu_mlme.tid_state_tx[tid] =
                                HT_AGG_STATE_OPERATIONAL;
                spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
                ieee80211_stop_tx_ba_session(&local->hw, sta->addr, tid,
@@ -1473,7 +1563,7 @@ void sta_addba_resp_timer_expired(unsigned long data)
                return;
        }
 
-       state = &sta->ampdu_mlme.tid_tx[tid].state;
+       state = &sta->ampdu_mlme.tid_state_tx[tid];
        /* check if the TID waits for addBA response */
        spin_lock_bh(&sta->ampdu_mlme.ampdu_tx);
        if (!(*state & HT_ADDBA_REQUESTED_MSK)) {
@@ -1497,8 +1587,8 @@ timer_expired_exit:
 }
 
 /*
- * After receiving Block Ack Request (BAR) we activated a
- * timer after each frame arrives from the originator.
+ * After accepting the AddBA Request we activated a timer,
+ * resetting it after each frame that arrives from the originator.
  * if this timer expires ieee80211_sta_stop_rx_ba_session will be executed.
  */
 void sta_rx_agg_session_timer_expired(unsigned long data)
@@ -1518,6 +1608,19 @@ void sta_rx_agg_session_timer_expired(unsigned long data)
                                         WLAN_REASON_QSTA_TIMEOUT);
 }
 
+void ieee80211_sta_tear_down_BA_sessions(struct net_device *dev, u8 *addr)
+{
+       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+       int i;
+
+       for (i = 0; i <  STA_TID_NUM; i++) {
+               ieee80211_stop_tx_ba_session(&local->hw, addr, i,
+                                            WLAN_BACK_INITIATOR);
+               ieee80211_sta_stop_rx_ba_session(dev, addr, i,
+                                                WLAN_BACK_RECIPIENT,
+                                                WLAN_REASON_QSTA_LEAVE_QBSS);
+       }
+}
 
 static void ieee80211_rx_mgmt_auth(struct net_device *dev,
                                   struct ieee80211_if_sta *ifsta,
@@ -1852,7 +1955,6 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
                if (err) {
                        printk(KERN_DEBUG "%s: failed to insert STA entry for"
                               " the AP (error %d)\n", dev->name, err);
-                       sta_info_destroy(sta);
                        rcu_read_unlock();
                        return;
                }
@@ -1913,17 +2015,15 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
        else
                sdata->flags &= ~IEEE80211_SDATA_OPERATING_GMODE;
 
-       if (elems.ht_cap_elem && elems.ht_info_elem && elems.wmm_param &&
-           local->ops->conf_ht) {
+       if (elems.ht_cap_elem && elems.ht_info_elem && elems.wmm_param) {
                struct ieee80211_ht_bss_info bss_info;
-
                ieee80211_ht_cap_ie_to_ht_info(
                                (struct ieee80211_ht_cap *)
                                elems.ht_cap_elem, &sta->ht_info);
                ieee80211_ht_addt_info_ie_to_ht_bss_info(
                                (struct ieee80211_ht_addt_info *)
                                elems.ht_info_elem, &bss_info);
-               ieee80211_hw_config_ht(local, 1, &sta->ht_info, &bss_info);
+               ieee80211_handle_ht(local, 1, &sta->ht_info, &bss_info);
        }
 
        rate_control_rate_init(sta, local);
@@ -1936,8 +2036,10 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
        } else
                rcu_read_unlock();
 
-       /* set AID, ieee80211_set_associated() will tell the driver */
+       /* set AID and assoc capability,
+        * ieee80211_set_associated() will tell the driver */
        bss_conf->aid = aid;
+       bss_conf->assoc_capability = capab_info;
        ieee80211_set_associated(dev, ifsta, 1);
 
        ieee80211_associated(dev, ifsta);
@@ -2063,11 +2165,14 @@ ieee80211_rx_mesh_bss_get(struct net_device *dev, u8 *mesh_id, int mesh_id_len,
 
 static struct ieee80211_sta_bss *
 ieee80211_rx_mesh_bss_add(struct net_device *dev, u8 *mesh_id, int mesh_id_len,
-                         u8 *mesh_cfg, int freq)
+                         u8 *mesh_cfg, int mesh_config_len, int freq)
 {
        struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
        struct ieee80211_sta_bss *bss;
 
+       if (mesh_config_len != MESH_CFG_LEN)
+               return NULL;
+
        bss = kzalloc(sizeof(*bss), GFP_ATOMIC);
        if (!bss)
                return NULL;
@@ -2163,8 +2268,10 @@ static int ieee80211_sta_join_ibss(struct net_device *dev,
 
        sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
 
+       sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
        /* Remove possible STA entries from other IBSS networks. */
-       sta_info_flush(local, NULL);
+       sta_info_flush_delayed(sdata);
 
        if (local->ops->reset_tsf) {
                /* Reset own TSF to allow time synchronization work. */
@@ -2177,7 +2284,6 @@ static int ieee80211_sta_join_ibss(struct net_device *dev,
 
        local->hw.conf.beacon_int = bss->beacon_int >= 10 ? bss->beacon_int : 10;
 
-       sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        sdata->drop_unencrypted = bss->capability &
                WLAN_CAPABILITY_PRIVACY ? 1 : 0;
 
@@ -2289,6 +2395,8 @@ static int ieee80211_sta_join_ibss(struct net_device *dev,
                                        rates |= BIT(j);
                }
                ifsta->supp_rates_bits[local->hw.conf.channel->band] = rates;
+
+               ieee80211_sta_def_wmm_params(dev, bss, 1);
        } while (0);
 
        if (skb) {
@@ -2356,6 +2464,7 @@ static void ieee80211_rx_bss_info(struct net_device *dev,
        struct sta_info *sta;
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        u64 beacon_timestamp, rx_timestamp;
+       struct ieee80211_channel *channel;
        DECLARE_MAC_BUF(mac);
        DECLARE_MAC_BUF(mac2);
 
@@ -2420,6 +2529,11 @@ static void ieee80211_rx_bss_info(struct net_device *dev,
        else
                freq = rx_status->freq;
 
+       channel = ieee80211_get_channel(local->hw.wiphy, freq);
+
+       if (!channel || channel->flags & IEEE80211_CHAN_DISABLED)
+               return;
+
 #ifdef CONFIG_MAC80211_MESH
        if (elems.mesh_config)
                bss = ieee80211_rx_mesh_bss_get(dev, elems.mesh_id,
@@ -2432,7 +2546,8 @@ static void ieee80211_rx_bss_info(struct net_device *dev,
 #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, freq);
+                               elems.mesh_id_len, elems.mesh_config,
+                               elems.mesh_config_len, freq);
                else
 #endif
                        bss = ieee80211_rx_bss_add(dev, mgmt->bssid, freq,
@@ -2661,20 +2776,14 @@ static void ieee80211_rx_mgmt_beacon(struct net_device *dev,
                changed |= ieee80211_handle_erp_ie(sdata, elems.erp_info[0]);
 
        if (elems.ht_cap_elem && elems.ht_info_elem &&
-           elems.wmm_param && local->ops->conf_ht &&
-           conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) {
+           elems.wmm_param && conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) {
                struct ieee80211_ht_bss_info bss_info;
 
                ieee80211_ht_addt_info_ie_to_ht_bss_info(
                                (struct ieee80211_ht_addt_info *)
                                elems.ht_info_elem, &bss_info);
-               /* check if AP changed bss inforamation */
-               if ((conf->ht_bss_conf.primary_channel !=
-                    bss_info.primary_channel) ||
-                   (conf->ht_bss_conf.bss_cap != bss_info.bss_cap) ||
-                   (conf->ht_bss_conf.bss_op_mode != bss_info.bss_op_mode))
-                       ieee80211_hw_config_ht(local, 1, &conf->ht_conf,
-                                               &bss_info);
+               changed |= ieee80211_handle_ht(local, 1, &conf->ht_conf,
+                                              &bss_info);
        }
 
        if (elems.wmm_param && (ifsta->flags & IEEE80211_STA_WMM_ENABLED)) {
@@ -2983,7 +3092,7 @@ static void ieee80211_sta_expire(struct net_device *dev, unsigned long exp_time)
                if (time_after(jiffies, sta->last_rx + exp_time)) {
                        printk(KERN_DEBUG "%s: expiring inactive STA %s\n",
                               dev->name, print_mac(mac, sta->addr));
-                       sta_info_unlink(&sta);
+                       __sta_info_unlink(&sta);
                        if (sta)
                                list_add(&sta->list, &tmp_list);
                }
@@ -3274,6 +3383,7 @@ static int ieee80211_sta_config_auth(struct net_device *dev,
                        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);
                ifsta->state = IEEE80211_AUTHENTICATE;
                ieee80211_sta_reset_auth(dev, ifsta);
@@ -3448,43 +3558,10 @@ 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;
-       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
 
        if (len > IEEE80211_MAX_SSID_LEN)
                return -EINVAL;
 
-       /* TODO: This should always be done for IBSS, even if IEEE80211_QOS is
-        * not defined. */
-       if (local->ops->conf_tx) {
-               struct ieee80211_tx_queue_params qparam;
-               int i;
-
-               memset(&qparam, 0, sizeof(qparam));
-
-               qparam.aifs = 2;
-
-               if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ &&
-                   !(sdata->flags & IEEE80211_SDATA_OPERATING_GMODE))
-                       qparam.cw_min = 31;
-               else
-                       qparam.cw_min = 15;
-
-               qparam.cw_max = 1023;
-               qparam.txop = 0;
-
-               for (i = IEEE80211_TX_QUEUE_DATA0; i < NUM_TX_DATA_QUEUES; i++)
-                       local->ops->conf_tx(local_to_hw(local),
-                                          i + IEEE80211_TX_QUEUE_DATA0,
-                                          &qparam);
-
-               /* IBSS uses different parameters for Beacon sending */
-               qparam.cw_min++;
-               qparam.cw_min *= 2;
-               qparam.cw_min--;
-               local->ops->conf_tx(local_to_hw(local),
-                                  IEEE80211_TX_QUEUE_BEACON, &qparam);
-       }
-
        ifsta = &sdata->u.sta;
 
        if (ifsta->ssid_len != len || memcmp(ifsta->ssid, ssid, len) != 0)
@@ -3596,6 +3673,9 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw)
 
        if (local->sta_hw_scanning) {
                local->sta_hw_scanning = 0;
+               if (ieee80211_hw_config(local))
+                       printk(KERN_DEBUG "%s: failed to restore operational "
+                              "channel after scan\n", dev->name);
                /* Restart STA timer for HW scan case */
                rcu_read_lock();
                list_for_each_entry_rcu(sdata, &local->interfaces, list)
@@ -4102,10 +4182,8 @@ struct sta_info * ieee80211_ibss_add_sta(struct net_device *dev,
 
        rate_control_rate_init(sta, local);
 
-       if (sta_info_insert(sta)) {
-               sta_info_destroy(sta);
+       if (sta_info_insert(sta))
                return NULL;
-       }
 
        return sta;
 }
@@ -4147,3 +4225,26 @@ int ieee80211_sta_disassociate(struct net_device *dev, u16 reason)
        ieee80211_set_disassoc(dev, ifsta, 0);
        return 0;
 }
+
+void ieee80211_notify_mac(struct ieee80211_hw *hw,
+                         enum ieee80211_notification_types  notif_type)
+{
+       struct ieee80211_local *local = hw_to_local(hw);
+       struct ieee80211_sub_if_data *sdata;
+
+       switch (notif_type) {
+       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) {
+                               ieee80211_sta_req_auth(sdata->dev,
+                                                      &sdata->u.sta);
+                       }
+
+               }
+               rcu_read_unlock();
+               break;
+       }
+}
+EXPORT_SYMBOL(ieee80211_notify_mac);