]> err.no Git - linux-2.6/blobdiff - net/mac80211/ieee80211_sta.c
mac80211: add beacon configuration via cfg80211
[linux-2.6] / net / mac80211 / ieee80211_sta.c
index d5a7683fab3a395531b8f85d5c53f7b3bcc2bc26..b1e7d17ee253b3e91a44f3990a2e0989e5dd490e 100644 (file)
@@ -63,6 +63,8 @@
 #define IEEE80211_ADDBA_PARAM_POLICY_MASK 0x0002
 #define IEEE80211_ADDBA_PARAM_TID_MASK 0x003C
 #define IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK 0xFFA0
+#define IEEE80211_DELBA_PARAM_TID_MASK 0xF000
+#define IEEE80211_DELBA_PARAM_INITIATOR_MASK 0x0800
 
 /* next values represent the buffer size for A-MPDU frame.
  * According to IEEE802.11n spec size varies from 8K to 64K (in powers of 2) */
@@ -469,7 +471,7 @@ static void ieee80211_set_associated(struct net_device *dev,
                ifsta->flags |= IEEE80211_STA_ASSOCIATED;
 
                sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-               if (sdata->type != IEEE80211_IF_TYPE_STA)
+               if (sdata->vif.type != IEEE80211_IF_TYPE_STA)
                        return;
 
                bss = ieee80211_rx_bss_get(dev, ifsta->bssid,
@@ -1023,7 +1025,7 @@ static void ieee80211_send_addba_resp(struct net_device *dev, u8 *da, u16 tid,
        memset(mgmt, 0, 24);
        memcpy(mgmt->da, da, ETH_ALEN);
        memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN);
-       if (sdata->type == IEEE80211_IF_TYPE_AP)
+       if (sdata->vif.type == IEEE80211_IF_TYPE_AP)
                memcpy(mgmt->bssid, dev->dev_addr, ETH_ALEN);
        else
                memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN);
@@ -1182,7 +1184,7 @@ void ieee80211_send_delba(struct net_device *dev, const u8 *da, u16 tid,
        memset(mgmt, 0, 24);
        memcpy(mgmt->da, da, ETH_ALEN);
        memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN);
-       if (sdata->type == IEEE80211_IF_TYPE_AP)
+       if (sdata->vif.type == IEEE80211_IF_TYPE_AP)
                memcpy(mgmt->bssid, dev->dev_addr, ETH_ALEN);
        else
                memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN);
@@ -1208,7 +1210,7 @@ void ieee80211_sta_stop_rx_ba_session(struct net_device *dev, u8 *ra, u16 tid,
        struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
        struct ieee80211_hw *hw = &local->hw;
        struct sta_info *sta;
-       int ret;
+       int ret, i;
 
        sta = sta_info_get(local, ra);
        if (!sta)
@@ -1250,12 +1252,50 @@ void ieee80211_sta_stop_rx_ba_session(struct net_device *dev, u8 *ra, u16 tid,
                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]) {
+                       /* 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;
+               }
+       }
        kfree(sta->ampdu_mlme.tid_rx[tid].reorder_buf);
 
        sta->ampdu_mlme.tid_rx[tid].state = HT_AGG_STATE_IDLE;
        sta_info_put(sta);
 }
 
+static void ieee80211_sta_process_delba(struct net_device *dev,
+                       struct ieee80211_mgmt *mgmt, size_t len)
+{
+       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+       struct sta_info *sta;
+       u16 tid, params;
+       u16 initiator;
+       DECLARE_MAC_BUF(mac);
+
+       sta = sta_info_get(local, mgmt->sa);
+       if (!sta)
+               return;
+
+       params = le16_to_cpu(mgmt->u.action.u.delba.params);
+       tid = (params & IEEE80211_DELBA_PARAM_TID_MASK) >> 12;
+       initiator = (params & IEEE80211_DELBA_PARAM_INITIATOR_MASK) >> 11;
+
+#ifdef CONFIG_MAC80211_HT_DEBUG
+       if (net_ratelimit())
+               printk(KERN_DEBUG "delba from %s on tid %d reason code %d\n",
+                       print_mac(mac, mgmt->sa), tid,
+                       mgmt->u.action.u.delba.reason_code);
+#endif /* CONFIG_MAC80211_HT_DEBUG */
+
+       if (initiator == WLAN_BACK_INITIATOR)
+               ieee80211_sta_stop_rx_ba_session(dev, sta->addr, tid,
+                                                WLAN_BACK_INITIATOR, 0);
+       sta_info_put(sta);
+}
+
 /*
  * After receiving Block Ack Request (BAR) we activated a
  * timer after each frame arrives from the originator.
@@ -1289,7 +1329,7 @@ static void ieee80211_rx_mgmt_auth(struct net_device *dev,
        DECLARE_MAC_BUF(mac);
 
        if (ifsta->state != IEEE80211_AUTHENTICATE &&
-           sdata->type != IEEE80211_IF_TYPE_IBSS) {
+           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));
@@ -1303,7 +1343,7 @@ static void ieee80211_rx_mgmt_auth(struct net_device *dev,
                return;
        }
 
-       if (sdata->type != IEEE80211_IF_TYPE_IBSS &&
+       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) - "
@@ -1312,7 +1352,7 @@ static void ieee80211_rx_mgmt_auth(struct net_device *dev,
                return;
        }
 
-       if (sdata->type != IEEE80211_IF_TYPE_IBSS &&
+       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) - "
@@ -1330,7 +1370,7 @@ static void ieee80211_rx_mgmt_auth(struct net_device *dev,
               dev->name, print_mac(mac, mgmt->sa), auth_alg,
               auth_transaction, status_code);
 
-       if (sdata->type == IEEE80211_IF_TYPE_IBSS) {
+       if (sdata->vif.type == IEEE80211_IF_TYPE_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
@@ -1809,7 +1849,7 @@ static void ieee80211_rx_bss_info(struct net_device *dev,
 
        timestamp = le64_to_cpu(mgmt->u.beacon.timestamp);
 
-       if (sdata->type == IEEE80211_IF_TYPE_IBSS && beacon &&
+       if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS && beacon &&
            memcmp(mgmt->bssid, sdata->u.sta.bssid, ETH_ALEN) == 0) {
 #ifdef CONFIG_MAC80211_IBSS_DEBUG
                static unsigned long last_tsf_debug = 0;
@@ -1834,7 +1874,7 @@ static void ieee80211_rx_bss_info(struct net_device *dev,
 
        ieee802_11_parse_elems(mgmt->u.beacon.variable, len - baselen, &elems);
 
-       if (sdata->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))) {
                struct ieee80211_hw_mode *mode;
@@ -2063,7 +2103,7 @@ static void ieee80211_rx_mgmt_beacon(struct net_device *dev,
        ieee80211_rx_bss_info(dev, mgmt, len, rx_status, 1);
 
        sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-       if (sdata->type != IEEE80211_IF_TYPE_STA)
+       if (sdata->vif.type != IEEE80211_IF_TYPE_STA)
                return;
        ifsta = &sdata->u.sta;
 
@@ -2123,7 +2163,7 @@ static void ieee80211_rx_mgmt_probe_req(struct net_device *dev,
        DECLARE_MAC_BUF(mac3);
 #endif
 
-       if (sdata->type != IEEE80211_IF_TYPE_IBSS ||
+       if (sdata->vif.type != IEEE80211_IF_TYPE_IBSS ||
            ifsta->state != IEEE80211_IBSS_JOINED ||
            len < 24 + 2 || !ifsta->probe_resp)
                return;
@@ -2196,9 +2236,15 @@ static void ieee80211_rx_mgmt_action(struct net_device *dev,
                                break;
                        ieee80211_sta_process_addba_request(dev, mgmt, len);
                        break;
+               case WLAN_ACTION_DELBA:
+                       if (len < (IEEE80211_MIN_ACTION_SIZE +
+                                  sizeof(mgmt->u.action.u.delba)))
+                               break;
+                       ieee80211_sta_process_delba(dev, mgmt, len);
+                       break;
                default:
                        if (net_ratelimit())
-                          printk(KERN_DEBUG "%s: received unsupported BACK\n",
+                          printk(KERN_DEBUG "%s: Rx unknown A-MPDU action\n",
                                        dev->name);
                        break;
                }
@@ -2428,10 +2474,10 @@ void ieee80211_sta_work(struct work_struct *work)
        if (local->sta_sw_scanning || local->sta_hw_scanning)
                return;
 
-       if (sdata->type != IEEE80211_IF_TYPE_STA &&
-           sdata->type != IEEE80211_IF_TYPE_IBSS) {
+       if (sdata->vif.type != IEEE80211_IF_TYPE_STA &&
+           sdata->vif.type != IEEE80211_IF_TYPE_IBSS) {
                printk(KERN_DEBUG "%s: ieee80211_sta_work: non-STA interface "
-                      "(type=%d)\n", dev->name, sdata->type);
+                      "(type=%d)\n", dev->name, sdata->vif.type);
                return;
        }
        ifsta = &sdata->u.sta;
@@ -2526,7 +2572,7 @@ void ieee80211_sta_req_auth(struct net_device *dev,
        struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
-       if (sdata->type != IEEE80211_IF_TYPE_STA)
+       if (sdata->vif.type != IEEE80211_IF_TYPE_STA)
                return;
 
        if ((ifsta->flags & (IEEE80211_STA_BSSID_SET |
@@ -2993,7 +3039,7 @@ int ieee80211_sta_set_ssid(struct net_device *dev, char *ssid, size_t len)
                ifsta->flags |= IEEE80211_STA_SSID_SET;
        else
                ifsta->flags &= ~IEEE80211_STA_SSID_SET;
-       if (sdata->type == IEEE80211_IF_TYPE_IBSS &&
+       if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS &&
            !(ifsta->flags & IEEE80211_STA_BSSID_SET)) {
                ifsta->ibss_join_req = jiffies;
                ifsta->state = IEEE80211_IBSS_SEARCH;
@@ -3111,7 +3157,7 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw)
                if (sdata->dev == local->mdev)
                        continue;
 
-               if (sdata->type == IEEE80211_IF_TYPE_STA) {
+               if (sdata->vif.type == IEEE80211_IF_TYPE_STA) {
                        if (sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED)
                                ieee80211_send_nullfunc(local, sdata, 0);
                        ieee80211_sta_timer((unsigned long)sdata);
@@ -3123,7 +3169,7 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw)
 
 done:
        sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-       if (sdata->type == IEEE80211_IF_TYPE_IBSS) {
+       if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS) {
                struct ieee80211_if_sta *ifsta = &sdata->u.sta;
                if (!(ifsta->flags & IEEE80211_STA_BSSID_SET) ||
                    (!ifsta->state == IEEE80211_IBSS_JOINED &&
@@ -3158,7 +3204,7 @@ void ieee80211_sta_scan_work(struct work_struct *work)
                skip = !(local->enabled_modes & (1 << mode->mode));
                chan = &mode->channels[local->scan_channel_idx];
                if (!(chan->flag & IEEE80211_CHAN_W_SCAN) ||
-                   (sdata->type == IEEE80211_IF_TYPE_IBSS &&
+                   (sdata->vif.type == IEEE80211_IF_TYPE_IBSS &&
                     !(chan->flag & IEEE80211_CHAN_W_IBSS)) ||
                    (local->hw_modes & local->enabled_modes &
                     (1 << MODE_IEEE80211G) && mode->mode == MODE_IEEE80211B))
@@ -3266,7 +3312,7 @@ static int ieee80211_sta_start_scan(struct net_device *dev,
                        continue;
 
                netif_stop_queue(sdata->dev);
-               if (sdata->type == IEEE80211_IF_TYPE_STA &&
+               if (sdata->vif.type == IEEE80211_IF_TYPE_STA &&
                    (sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED))
                        ieee80211_send_nullfunc(local, sdata, 1);
        }
@@ -3307,7 +3353,7 @@ int ieee80211_sta_req_scan(struct net_device *dev, u8 *ssid, size_t ssid_len)
        struct ieee80211_if_sta *ifsta = &sdata->u.sta;
        struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
 
-       if (sdata->type != IEEE80211_IF_TYPE_STA)
+       if (sdata->vif.type != IEEE80211_IF_TYPE_STA)
                return ieee80211_sta_start_scan(dev, ssid, ssid_len);
 
        if (local->sta_sw_scanning || local->sta_hw_scanning) {
@@ -3530,8 +3576,8 @@ int ieee80211_sta_deauthenticate(struct net_device *dev, u16 reason)
        printk(KERN_DEBUG "%s: deauthenticate(reason=%d)\n",
               dev->name, reason);
 
-       if (sdata->type != IEEE80211_IF_TYPE_STA &&
-           sdata->type != IEEE80211_IF_TYPE_IBSS)
+       if (sdata->vif.type != IEEE80211_IF_TYPE_STA &&
+           sdata->vif.type != IEEE80211_IF_TYPE_IBSS)
                return -EINVAL;
 
        ieee80211_send_deauth(dev, ifsta, reason);
@@ -3548,7 +3594,7 @@ int ieee80211_sta_disassociate(struct net_device *dev, u16 reason)
        printk(KERN_DEBUG "%s: disassociate(reason=%d)\n",
               dev->name, reason);
 
-       if (sdata->type != IEEE80211_IF_TYPE_STA)
+       if (sdata->vif.type != IEEE80211_IF_TYPE_STA)
                return -EINVAL;
 
        if (!(ifsta->flags & IEEE80211_STA_ASSOCIATED))