linux/net/mac80211/ht.c
<<
>>
Prefs
   1/*
   2 * HT handling
   3 *
   4 * Copyright 2003, Jouni Malinen <jkmaline@cc.hut.fi>
   5 * Copyright 2002-2005, Instant802 Networks, Inc.
   6 * Copyright 2005-2006, Devicescape Software, Inc.
   7 * Copyright 2006-2007  Jiri Benc <jbenc@suse.cz>
   8 * Copyright 2007, Michael Wu <flamingice@sourmilk.net>
   9 * Copyright 2007-2008, Intel Corporation
  10 *
  11 * This program is free software; you can redistribute it and/or modify
  12 * it under the terms of the GNU General Public License version 2 as
  13 * published by the Free Software Foundation.
  14 */
  15
  16#include <linux/ieee80211.h>
  17#include <net/mac80211.h>
  18#include "ieee80211_i.h"
  19#include "rate.h"
  20
  21void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_supported_band *sband,
  22                                       struct ieee80211_ht_cap *ht_cap_ie,
  23                                       struct ieee80211_sta_ht_cap *ht_cap)
  24{
  25        u8 ampdu_info, tx_mcs_set_cap;
  26        int i, max_tx_streams;
  27
  28        BUG_ON(!ht_cap);
  29
  30        memset(ht_cap, 0, sizeof(*ht_cap));
  31
  32        if (!ht_cap_ie)
  33                return;
  34
  35        ht_cap->ht_supported = true;
  36
  37        ht_cap->cap = le16_to_cpu(ht_cap_ie->cap_info) & sband->ht_cap.cap;
  38        ht_cap->cap &= ~IEEE80211_HT_CAP_SM_PS;
  39        ht_cap->cap |= sband->ht_cap.cap & IEEE80211_HT_CAP_SM_PS;
  40
  41        ampdu_info = ht_cap_ie->ampdu_params_info;
  42        ht_cap->ampdu_factor =
  43                ampdu_info & IEEE80211_HT_AMPDU_PARM_FACTOR;
  44        ht_cap->ampdu_density =
  45                (ampdu_info & IEEE80211_HT_AMPDU_PARM_DENSITY) >> 2;
  46
  47        /* own MCS TX capabilities */
  48        tx_mcs_set_cap = sband->ht_cap.mcs.tx_params;
  49
  50        /* can we TX with MCS rates? */
  51        if (!(tx_mcs_set_cap & IEEE80211_HT_MCS_TX_DEFINED))
  52                return;
  53
  54        /* Counting from 0, therefore +1 */
  55        if (tx_mcs_set_cap & IEEE80211_HT_MCS_TX_RX_DIFF)
  56                max_tx_streams =
  57                        ((tx_mcs_set_cap & IEEE80211_HT_MCS_TX_MAX_STREAMS_MASK)
  58                                >> IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT) + 1;
  59        else
  60                max_tx_streams = IEEE80211_HT_MCS_TX_MAX_STREAMS;
  61
  62        /*
  63         * 802.11n D5.0 20.3.5 / 20.6 says:
  64         * - indices 0 to 7 and 32 are single spatial stream
  65         * - 8 to 31 are multiple spatial streams using equal modulation
  66         *   [8..15 for two streams, 16..23 for three and 24..31 for four]
  67         * - remainder are multiple spatial streams using unequal modulation
  68         */
  69        for (i = 0; i < max_tx_streams; i++)
  70                ht_cap->mcs.rx_mask[i] =
  71                        sband->ht_cap.mcs.rx_mask[i] & ht_cap_ie->mcs.rx_mask[i];
  72
  73        if (tx_mcs_set_cap & IEEE80211_HT_MCS_TX_UNEQUAL_MODULATION)
  74                for (i = IEEE80211_HT_MCS_UNEQUAL_MODULATION_START_BYTE;
  75                     i < IEEE80211_HT_MCS_MASK_LEN; i++)
  76                        ht_cap->mcs.rx_mask[i] =
  77                                sband->ht_cap.mcs.rx_mask[i] &
  78                                        ht_cap_ie->mcs.rx_mask[i];
  79
  80        /* handle MCS rate 32 too */
  81        if (sband->ht_cap.mcs.rx_mask[32/8] & ht_cap_ie->mcs.rx_mask[32/8] & 1)
  82                ht_cap->mcs.rx_mask[32/8] |= 1;
  83}
  84
  85void ieee80211_sta_tear_down_BA_sessions(struct sta_info *sta)
  86{
  87        int i;
  88
  89        for (i = 0; i <  STA_TID_NUM; i++) {
  90                __ieee80211_stop_tx_ba_session(sta, i, WLAN_BACK_INITIATOR);
  91                __ieee80211_stop_rx_ba_session(sta, i, WLAN_BACK_RECIPIENT,
  92                                               WLAN_REASON_QSTA_LEAVE_QBSS);
  93        }
  94}
  95
  96void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata,
  97                          const u8 *da, u16 tid,
  98                          u16 initiator, u16 reason_code)
  99{
 100        struct ieee80211_local *local = sdata->local;
 101        struct sk_buff *skb;
 102        struct ieee80211_mgmt *mgmt;
 103        u16 params;
 104
 105        skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom);
 106
 107        if (!skb) {
 108                printk(KERN_ERR "%s: failed to allocate buffer "
 109                                        "for delba frame\n", sdata->dev->name);
 110                return;
 111        }
 112
 113        skb_reserve(skb, local->hw.extra_tx_headroom);
 114        mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);
 115        memset(mgmt, 0, 24);
 116        memcpy(mgmt->da, da, ETH_ALEN);
 117        memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
 118        if (sdata->vif.type == NL80211_IFTYPE_AP ||
 119            sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
 120                memcpy(mgmt->bssid, sdata->dev->dev_addr, ETH_ALEN);
 121        else if (sdata->vif.type == NL80211_IFTYPE_STATION)
 122                memcpy(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN);
 123
 124        mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
 125                                          IEEE80211_STYPE_ACTION);
 126
 127        skb_put(skb, 1 + sizeof(mgmt->u.action.u.delba));
 128
 129        mgmt->u.action.category = WLAN_CATEGORY_BACK;
 130        mgmt->u.action.u.delba.action_code = WLAN_ACTION_DELBA;
 131        params = (u16)(initiator << 11);        /* bit 11 initiator */
 132        params |= (u16)(tid << 12);             /* bit 15:12 TID number */
 133
 134        mgmt->u.action.u.delba.params = cpu_to_le16(params);
 135        mgmt->u.action.u.delba.reason_code = cpu_to_le16(reason_code);
 136
 137        ieee80211_tx_skb(sdata, skb, 1);
 138}
 139
 140void ieee80211_process_delba(struct ieee80211_sub_if_data *sdata,
 141                             struct sta_info *sta,
 142                             struct ieee80211_mgmt *mgmt, size_t len)
 143{
 144        u16 tid, params;
 145        u16 initiator;
 146
 147        params = le16_to_cpu(mgmt->u.action.u.delba.params);
 148        tid = (params & IEEE80211_DELBA_PARAM_TID_MASK) >> 12;
 149        initiator = (params & IEEE80211_DELBA_PARAM_INITIATOR_MASK) >> 11;
 150
 151#ifdef CONFIG_MAC80211_HT_DEBUG
 152        if (net_ratelimit())
 153                printk(KERN_DEBUG "delba from %pM (%s) tid %d reason code %d\n",
 154                        mgmt->sa, initiator ? "initiator" : "recipient", tid,
 155                        le16_to_cpu(mgmt->u.action.u.delba.reason_code));
 156#endif /* CONFIG_MAC80211_HT_DEBUG */
 157
 158        if (initiator == WLAN_BACK_INITIATOR)
 159                ieee80211_sta_stop_rx_ba_session(sdata, sta->sta.addr, tid,
 160                                                 WLAN_BACK_INITIATOR, 0);
 161        else { /* WLAN_BACK_RECIPIENT */
 162                spin_lock_bh(&sta->lock);
 163                if (sta->ampdu_mlme.tid_state_tx[tid] & HT_ADDBA_REQUESTED_MSK)
 164                        ___ieee80211_stop_tx_ba_session(sta, tid,
 165                                                        WLAN_BACK_RECIPIENT);
 166                spin_unlock_bh(&sta->lock);
 167        }
 168}
 169
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.