diff options
Diffstat (limited to 'net/mac80211/ht.c')
| -rw-r--r-- | net/mac80211/ht.c | 53 |
1 files changed, 50 insertions, 3 deletions
diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c index d7dcee680728..bb677a73b7c9 100644 --- a/net/mac80211/ht.c +++ b/net/mac80211/ht.c | |||
| @@ -125,7 +125,7 @@ void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata, | |||
| 125 | 125 | ||
| 126 | if (!skb) { | 126 | if (!skb) { |
| 127 | printk(KERN_ERR "%s: failed to allocate buffer " | 127 | printk(KERN_ERR "%s: failed to allocate buffer " |
| 128 | "for delba frame\n", sdata->dev->name); | 128 | "for delba frame\n", sdata->name); |
| 129 | return; | 129 | return; |
| 130 | } | 130 | } |
| 131 | 131 | ||
| @@ -133,10 +133,10 @@ void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata, | |||
| 133 | mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); | 133 | mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); |
| 134 | memset(mgmt, 0, 24); | 134 | memset(mgmt, 0, 24); |
| 135 | memcpy(mgmt->da, da, ETH_ALEN); | 135 | memcpy(mgmt->da, da, ETH_ALEN); |
| 136 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); | 136 | memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); |
| 137 | if (sdata->vif.type == NL80211_IFTYPE_AP || | 137 | if (sdata->vif.type == NL80211_IFTYPE_AP || |
| 138 | sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | 138 | sdata->vif.type == NL80211_IFTYPE_AP_VLAN) |
| 139 | memcpy(mgmt->bssid, sdata->dev->dev_addr, ETH_ALEN); | 139 | memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN); |
| 140 | else if (sdata->vif.type == NL80211_IFTYPE_STATION) | 140 | else if (sdata->vif.type == NL80211_IFTYPE_STATION) |
| 141 | memcpy(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN); | 141 | memcpy(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN); |
| 142 | 142 | ||
| @@ -185,3 +185,50 @@ void ieee80211_process_delba(struct ieee80211_sub_if_data *sdata, | |||
| 185 | spin_unlock_bh(&sta->lock); | 185 | spin_unlock_bh(&sta->lock); |
| 186 | } | 186 | } |
| 187 | } | 187 | } |
| 188 | |||
| 189 | int ieee80211_send_smps_action(struct ieee80211_sub_if_data *sdata, | ||
| 190 | enum ieee80211_smps_mode smps, const u8 *da, | ||
| 191 | const u8 *bssid) | ||
| 192 | { | ||
| 193 | struct ieee80211_local *local = sdata->local; | ||
| 194 | struct sk_buff *skb; | ||
| 195 | struct ieee80211_mgmt *action_frame; | ||
| 196 | |||
| 197 | /* 27 = header + category + action + smps mode */ | ||
| 198 | skb = dev_alloc_skb(27 + local->hw.extra_tx_headroom); | ||
| 199 | if (!skb) | ||
| 200 | return -ENOMEM; | ||
| 201 | |||
| 202 | skb_reserve(skb, local->hw.extra_tx_headroom); | ||
| 203 | action_frame = (void *)skb_put(skb, 27); | ||
| 204 | memcpy(action_frame->da, da, ETH_ALEN); | ||
| 205 | memcpy(action_frame->sa, sdata->dev->dev_addr, ETH_ALEN); | ||
| 206 | memcpy(action_frame->bssid, bssid, ETH_ALEN); | ||
| 207 | action_frame->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | ||
| 208 | IEEE80211_STYPE_ACTION); | ||
| 209 | action_frame->u.action.category = WLAN_CATEGORY_HT; | ||
| 210 | action_frame->u.action.u.ht_smps.action = WLAN_HT_ACTION_SMPS; | ||
| 211 | switch (smps) { | ||
| 212 | case IEEE80211_SMPS_AUTOMATIC: | ||
| 213 | case IEEE80211_SMPS_NUM_MODES: | ||
| 214 | WARN_ON(1); | ||
| 215 | case IEEE80211_SMPS_OFF: | ||
| 216 | action_frame->u.action.u.ht_smps.smps_control = | ||
| 217 | WLAN_HT_SMPS_CONTROL_DISABLED; | ||
| 218 | break; | ||
| 219 | case IEEE80211_SMPS_STATIC: | ||
| 220 | action_frame->u.action.u.ht_smps.smps_control = | ||
| 221 | WLAN_HT_SMPS_CONTROL_STATIC; | ||
| 222 | break; | ||
| 223 | case IEEE80211_SMPS_DYNAMIC: | ||
| 224 | action_frame->u.action.u.ht_smps.smps_control = | ||
| 225 | WLAN_HT_SMPS_CONTROL_DYNAMIC; | ||
| 226 | break; | ||
| 227 | } | ||
| 228 | |||
| 229 | /* we'll do more on status of this frame */ | ||
| 230 | IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS; | ||
| 231 | ieee80211_tx_skb(sdata, skb); | ||
| 232 | |||
| 233 | return 0; | ||
| 234 | } | ||
