diff options
Diffstat (limited to 'net/mac80211/ht.c')
| -rw-r--r-- | net/mac80211/ht.c | 106 |
1 files changed, 93 insertions, 13 deletions
diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c index d7dcee680728..9d101fb33861 100644 --- a/net/mac80211/ht.c +++ b/net/mac80211/ht.c | |||
| @@ -6,7 +6,7 @@ | |||
| 6 | * Copyright 2005-2006, Devicescape Software, Inc. | 6 | * Copyright 2005-2006, Devicescape Software, Inc. |
| 7 | * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz> | 7 | * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz> |
| 8 | * Copyright 2007, Michael Wu <flamingice@sourmilk.net> | 8 | * Copyright 2007, Michael Wu <flamingice@sourmilk.net> |
| 9 | * Copyright 2007-2008, Intel Corporation | 9 | * Copyright 2007-2010, Intel Corporation |
| 10 | * | 10 | * |
| 11 | * This program is free software; you can redistribute it and/or modify | 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 | 12 | * it under the terms of the GNU General Public License version 2 as |
| @@ -29,7 +29,7 @@ void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_supported_band *sband, | |||
| 29 | 29 | ||
| 30 | memset(ht_cap, 0, sizeof(*ht_cap)); | 30 | memset(ht_cap, 0, sizeof(*ht_cap)); |
| 31 | 31 | ||
| 32 | if (!ht_cap_ie) | 32 | if (!ht_cap_ie || !sband->ht_cap.ht_supported) |
| 33 | return; | 33 | return; |
| 34 | 34 | ||
| 35 | ht_cap->ht_supported = true; | 35 | ht_cap->ht_supported = true; |
| @@ -105,6 +105,8 @@ void ieee80211_sta_tear_down_BA_sessions(struct sta_info *sta) | |||
| 105 | { | 105 | { |
| 106 | int i; | 106 | int i; |
| 107 | 107 | ||
| 108 | cancel_work_sync(&sta->ampdu_mlme.work); | ||
| 109 | |||
| 108 | for (i = 0; i < STA_TID_NUM; i++) { | 110 | for (i = 0; i < STA_TID_NUM; i++) { |
| 109 | __ieee80211_stop_tx_ba_session(sta, i, WLAN_BACK_INITIATOR); | 111 | __ieee80211_stop_tx_ba_session(sta, i, WLAN_BACK_INITIATOR); |
| 110 | __ieee80211_stop_rx_ba_session(sta, i, WLAN_BACK_RECIPIENT, | 112 | __ieee80211_stop_rx_ba_session(sta, i, WLAN_BACK_RECIPIENT, |
| @@ -112,6 +114,43 @@ void ieee80211_sta_tear_down_BA_sessions(struct sta_info *sta) | |||
| 112 | } | 114 | } |
| 113 | } | 115 | } |
| 114 | 116 | ||
| 117 | void ieee80211_ba_session_work(struct work_struct *work) | ||
| 118 | { | ||
| 119 | struct sta_info *sta = | ||
| 120 | container_of(work, struct sta_info, ampdu_mlme.work); | ||
| 121 | struct tid_ampdu_tx *tid_tx; | ||
| 122 | int tid; | ||
| 123 | |||
| 124 | /* | ||
| 125 | * When this flag is set, new sessions should be | ||
| 126 | * blocked, and existing sessions will be torn | ||
| 127 | * down by the code that set the flag, so this | ||
| 128 | * need not run. | ||
| 129 | */ | ||
| 130 | if (test_sta_flags(sta, WLAN_STA_BLOCK_BA)) | ||
| 131 | return; | ||
| 132 | |||
| 133 | mutex_lock(&sta->ampdu_mlme.mtx); | ||
| 134 | for (tid = 0; tid < STA_TID_NUM; tid++) { | ||
| 135 | if (test_and_clear_bit(tid, sta->ampdu_mlme.tid_rx_timer_expired)) | ||
| 136 | ___ieee80211_stop_rx_ba_session( | ||
| 137 | sta, tid, WLAN_BACK_RECIPIENT, | ||
| 138 | WLAN_REASON_QSTA_TIMEOUT); | ||
| 139 | |||
| 140 | tid_tx = sta->ampdu_mlme.tid_tx[tid]; | ||
| 141 | if (!tid_tx) | ||
| 142 | continue; | ||
| 143 | |||
| 144 | if (test_bit(HT_AGG_STATE_WANT_START, &tid_tx->state)) | ||
| 145 | ieee80211_tx_ba_session_handle_start(sta, tid); | ||
| 146 | else if (test_and_clear_bit(HT_AGG_STATE_WANT_STOP, | ||
| 147 | &tid_tx->state)) | ||
| 148 | ___ieee80211_stop_tx_ba_session(sta, tid, | ||
| 149 | WLAN_BACK_INITIATOR); | ||
| 150 | } | ||
| 151 | mutex_unlock(&sta->ampdu_mlme.mtx); | ||
| 152 | } | ||
| 153 | |||
| 115 | void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata, | 154 | void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata, |
| 116 | const u8 *da, u16 tid, | 155 | const u8 *da, u16 tid, |
| 117 | u16 initiator, u16 reason_code) | 156 | u16 initiator, u16 reason_code) |
| @@ -125,7 +164,7 @@ void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata, | |||
| 125 | 164 | ||
| 126 | if (!skb) { | 165 | if (!skb) { |
| 127 | printk(KERN_ERR "%s: failed to allocate buffer " | 166 | printk(KERN_ERR "%s: failed to allocate buffer " |
| 128 | "for delba frame\n", sdata->dev->name); | 167 | "for delba frame\n", sdata->name); |
| 129 | return; | 168 | return; |
| 130 | } | 169 | } |
| 131 | 170 | ||
| @@ -133,10 +172,10 @@ void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata, | |||
| 133 | mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); | 172 | mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); |
| 134 | memset(mgmt, 0, 24); | 173 | memset(mgmt, 0, 24); |
| 135 | memcpy(mgmt->da, da, ETH_ALEN); | 174 | memcpy(mgmt->da, da, ETH_ALEN); |
| 136 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); | 175 | memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); |
| 137 | if (sdata->vif.type == NL80211_IFTYPE_AP || | 176 | if (sdata->vif.type == NL80211_IFTYPE_AP || |
| 138 | sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | 177 | sdata->vif.type == NL80211_IFTYPE_AP_VLAN) |
| 139 | memcpy(mgmt->bssid, sdata->dev->dev_addr, ETH_ALEN); | 178 | memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN); |
| 140 | else if (sdata->vif.type == NL80211_IFTYPE_STATION) | 179 | else if (sdata->vif.type == NL80211_IFTYPE_STATION) |
| 141 | memcpy(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN); | 180 | memcpy(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN); |
| 142 | 181 | ||
| @@ -175,13 +214,54 @@ void ieee80211_process_delba(struct ieee80211_sub_if_data *sdata, | |||
| 175 | #endif /* CONFIG_MAC80211_HT_DEBUG */ | 214 | #endif /* CONFIG_MAC80211_HT_DEBUG */ |
| 176 | 215 | ||
| 177 | if (initiator == WLAN_BACK_INITIATOR) | 216 | if (initiator == WLAN_BACK_INITIATOR) |
| 178 | ieee80211_sta_stop_rx_ba_session(sdata, sta->sta.addr, tid, | 217 | __ieee80211_stop_rx_ba_session(sta, tid, WLAN_BACK_INITIATOR, 0); |
| 179 | WLAN_BACK_INITIATOR, 0); | 218 | else |
| 180 | else { /* WLAN_BACK_RECIPIENT */ | 219 | __ieee80211_stop_tx_ba_session(sta, tid, WLAN_BACK_RECIPIENT); |
| 181 | spin_lock_bh(&sta->lock); | 220 | } |
| 182 | if (sta->ampdu_mlme.tid_state_tx[tid] & HT_ADDBA_REQUESTED_MSK) | 221 | |
| 183 | ___ieee80211_stop_tx_ba_session(sta, tid, | 222 | int ieee80211_send_smps_action(struct ieee80211_sub_if_data *sdata, |
| 184 | WLAN_BACK_RECIPIENT); | 223 | enum ieee80211_smps_mode smps, const u8 *da, |
| 185 | spin_unlock_bh(&sta->lock); | 224 | const u8 *bssid) |
| 225 | { | ||
| 226 | struct ieee80211_local *local = sdata->local; | ||
| 227 | struct sk_buff *skb; | ||
| 228 | struct ieee80211_mgmt *action_frame; | ||
| 229 | |||
| 230 | /* 27 = header + category + action + smps mode */ | ||
| 231 | skb = dev_alloc_skb(27 + local->hw.extra_tx_headroom); | ||
| 232 | if (!skb) | ||
| 233 | return -ENOMEM; | ||
| 234 | |||
| 235 | skb_reserve(skb, local->hw.extra_tx_headroom); | ||
| 236 | action_frame = (void *)skb_put(skb, 27); | ||
| 237 | memcpy(action_frame->da, da, ETH_ALEN); | ||
| 238 | memcpy(action_frame->sa, sdata->dev->dev_addr, ETH_ALEN); | ||
| 239 | memcpy(action_frame->bssid, bssid, ETH_ALEN); | ||
| 240 | action_frame->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | ||
| 241 | IEEE80211_STYPE_ACTION); | ||
| 242 | action_frame->u.action.category = WLAN_CATEGORY_HT; | ||
| 243 | action_frame->u.action.u.ht_smps.action = WLAN_HT_ACTION_SMPS; | ||
| 244 | switch (smps) { | ||
| 245 | case IEEE80211_SMPS_AUTOMATIC: | ||
| 246 | case IEEE80211_SMPS_NUM_MODES: | ||
| 247 | WARN_ON(1); | ||
| 248 | case IEEE80211_SMPS_OFF: | ||
| 249 | action_frame->u.action.u.ht_smps.smps_control = | ||
| 250 | WLAN_HT_SMPS_CONTROL_DISABLED; | ||
| 251 | break; | ||
| 252 | case IEEE80211_SMPS_STATIC: | ||
| 253 | action_frame->u.action.u.ht_smps.smps_control = | ||
| 254 | WLAN_HT_SMPS_CONTROL_STATIC; | ||
| 255 | break; | ||
| 256 | case IEEE80211_SMPS_DYNAMIC: | ||
| 257 | action_frame->u.action.u.ht_smps.smps_control = | ||
| 258 | WLAN_HT_SMPS_CONTROL_DYNAMIC; | ||
| 259 | break; | ||
| 186 | } | 260 | } |
| 261 | |||
| 262 | /* we'll do more on status of this frame */ | ||
| 263 | IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS; | ||
| 264 | ieee80211_tx_skb(sdata, skb); | ||
| 265 | |||
| 266 | return 0; | ||
| 187 | } | 267 | } |
