diff options
Diffstat (limited to 'net/mac80211')
42 files changed, 4461 insertions, 2474 deletions
diff --git a/net/mac80211/Kconfig b/net/mac80211/Kconfig index a10d508b07e1..a952b7f8c648 100644 --- a/net/mac80211/Kconfig +++ b/net/mac80211/Kconfig | |||
| @@ -96,18 +96,6 @@ menuconfig MAC80211_DEBUG_MENU | |||
| 96 | ---help--- | 96 | ---help--- |
| 97 | This option collects various mac80211 debug settings. | 97 | This option collects various mac80211 debug settings. |
| 98 | 98 | ||
| 99 | config MAC80211_DEBUG_PACKET_ALIGNMENT | ||
| 100 | bool "Enable packet alignment debugging" | ||
| 101 | depends on MAC80211_DEBUG_MENU | ||
| 102 | ---help--- | ||
| 103 | This option is recommended for driver authors and strongly | ||
| 104 | discouraged for everybody else, it will trigger a warning | ||
| 105 | when a driver hands mac80211 a buffer that is aligned in | ||
| 106 | a way that will cause problems with the IP stack on some | ||
| 107 | architectures. | ||
| 108 | |||
| 109 | Say N unless you're writing a mac80211 based driver. | ||
| 110 | |||
| 111 | config MAC80211_NOINLINE | 99 | config MAC80211_NOINLINE |
| 112 | bool "Do not inline TX/RX handlers" | 100 | bool "Do not inline TX/RX handlers" |
| 113 | depends on MAC80211_DEBUG_MENU | 101 | depends on MAC80211_DEBUG_MENU |
diff --git a/net/mac80211/Makefile b/net/mac80211/Makefile index 298cfcc1bf8d..04420291e7ad 100644 --- a/net/mac80211/Makefile +++ b/net/mac80211/Makefile | |||
| @@ -6,10 +6,10 @@ mac80211-y := \ | |||
| 6 | sta_info.o \ | 6 | sta_info.o \ |
| 7 | wep.o \ | 7 | wep.o \ |
| 8 | wpa.o \ | 8 | wpa.o \ |
| 9 | scan.o \ | 9 | scan.o offchannel.o \ |
| 10 | ht.o agg-tx.o agg-rx.o \ | 10 | ht.o agg-tx.o agg-rx.o \ |
| 11 | ibss.o \ | 11 | ibss.o \ |
| 12 | mlme.o \ | 12 | mlme.o work.o \ |
| 13 | iface.o \ | 13 | iface.o \ |
| 14 | rate.o \ | 14 | rate.o \ |
| 15 | michael.o \ | 15 | michael.o \ |
diff --git a/net/mac80211/agg-rx.c b/net/mac80211/agg-rx.c index 51c7dc3c4c3b..a978e666ed6f 100644 --- a/net/mac80211/agg-rx.c +++ b/net/mac80211/agg-rx.c | |||
| @@ -41,8 +41,7 @@ void __ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid, | |||
| 41 | sta->sta.addr, tid); | 41 | sta->sta.addr, tid); |
| 42 | #endif /* CONFIG_MAC80211_HT_DEBUG */ | 42 | #endif /* CONFIG_MAC80211_HT_DEBUG */ |
| 43 | 43 | ||
| 44 | if (drv_ampdu_action(local, &sta->sdata->vif, | 44 | if (drv_ampdu_action(local, sta->sdata, IEEE80211_AMPDU_RX_STOP, |
| 45 | IEEE80211_AMPDU_RX_STOP, | ||
| 46 | &sta->sta, tid, NULL)) | 45 | &sta->sta, tid, NULL)) |
| 47 | printk(KERN_DEBUG "HW problem - can not stop rx " | 46 | printk(KERN_DEBUG "HW problem - can not stop rx " |
| 48 | "aggregation for tid %d\n", tid); | 47 | "aggregation for tid %d\n", tid); |
| @@ -83,12 +82,11 @@ void __ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid, | |||
| 83 | void ieee80211_sta_stop_rx_ba_session(struct ieee80211_sub_if_data *sdata, u8 *ra, u16 tid, | 82 | void ieee80211_sta_stop_rx_ba_session(struct ieee80211_sub_if_data *sdata, u8 *ra, u16 tid, |
| 84 | u16 initiator, u16 reason) | 83 | u16 initiator, u16 reason) |
| 85 | { | 84 | { |
| 86 | struct ieee80211_local *local = sdata->local; | ||
| 87 | struct sta_info *sta; | 85 | struct sta_info *sta; |
| 88 | 86 | ||
| 89 | rcu_read_lock(); | 87 | rcu_read_lock(); |
| 90 | 88 | ||
| 91 | sta = sta_info_get(local, ra); | 89 | sta = sta_info_get(sdata, ra); |
| 92 | if (!sta) { | 90 | if (!sta) { |
| 93 | rcu_read_unlock(); | 91 | rcu_read_unlock(); |
| 94 | return; | 92 | return; |
| @@ -136,7 +134,7 @@ static void ieee80211_send_addba_resp(struct ieee80211_sub_if_data *sdata, u8 *d | |||
| 136 | 134 | ||
| 137 | if (!skb) { | 135 | if (!skb) { |
| 138 | printk(KERN_DEBUG "%s: failed to allocate buffer " | 136 | printk(KERN_DEBUG "%s: failed to allocate buffer " |
| 139 | "for addba resp frame\n", sdata->dev->name); | 137 | "for addba resp frame\n", sdata->name); |
| 140 | return; | 138 | return; |
| 141 | } | 139 | } |
| 142 | 140 | ||
| @@ -144,10 +142,10 @@ static void ieee80211_send_addba_resp(struct ieee80211_sub_if_data *sdata, u8 *d | |||
| 144 | mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); | 142 | mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); |
| 145 | memset(mgmt, 0, 24); | 143 | memset(mgmt, 0, 24); |
| 146 | memcpy(mgmt->da, da, ETH_ALEN); | 144 | memcpy(mgmt->da, da, ETH_ALEN); |
| 147 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); | 145 | memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); |
| 148 | if (sdata->vif.type == NL80211_IFTYPE_AP || | 146 | if (sdata->vif.type == NL80211_IFTYPE_AP || |
| 149 | sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | 147 | sdata->vif.type == NL80211_IFTYPE_AP_VLAN) |
| 150 | memcpy(mgmt->bssid, sdata->dev->dev_addr, ETH_ALEN); | 148 | memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN); |
| 151 | else if (sdata->vif.type == NL80211_IFTYPE_STATION) | 149 | else if (sdata->vif.type == NL80211_IFTYPE_STATION) |
| 152 | memcpy(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN); | 150 | memcpy(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN); |
| 153 | 151 | ||
| @@ -281,8 +279,7 @@ void ieee80211_process_addba_request(struct ieee80211_local *local, | |||
| 281 | goto end; | 279 | goto end; |
| 282 | } | 280 | } |
| 283 | 281 | ||
| 284 | ret = drv_ampdu_action(local, &sta->sdata->vif, | 282 | ret = drv_ampdu_action(local, sta->sdata, IEEE80211_AMPDU_RX_START, |
| 285 | IEEE80211_AMPDU_RX_START, | ||
| 286 | &sta->sta, tid, &start_seq_num); | 283 | &sta->sta, tid, &start_seq_num); |
| 287 | #ifdef CONFIG_MAC80211_HT_DEBUG | 284 | #ifdef CONFIG_MAC80211_HT_DEBUG |
| 288 | printk(KERN_DEBUG "Rx A-MPDU request on tid %d result %d\n", tid, ret); | 285 | printk(KERN_DEBUG "Rx A-MPDU request on tid %d result %d\n", tid, ret); |
diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c index 5e3a7eccef5a..5538e1b4a697 100644 --- a/net/mac80211/agg-tx.c +++ b/net/mac80211/agg-tx.c | |||
| @@ -58,17 +58,17 @@ static void ieee80211_send_addba_request(struct ieee80211_sub_if_data *sdata, | |||
| 58 | 58 | ||
| 59 | if (!skb) { | 59 | if (!skb) { |
| 60 | printk(KERN_ERR "%s: failed to allocate buffer " | 60 | printk(KERN_ERR "%s: failed to allocate buffer " |
| 61 | "for addba request frame\n", sdata->dev->name); | 61 | "for addba request frame\n", sdata->name); |
| 62 | return; | 62 | return; |
| 63 | } | 63 | } |
| 64 | skb_reserve(skb, local->hw.extra_tx_headroom); | 64 | skb_reserve(skb, local->hw.extra_tx_headroom); |
| 65 | mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); | 65 | mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); |
| 66 | memset(mgmt, 0, 24); | 66 | memset(mgmt, 0, 24); |
| 67 | memcpy(mgmt->da, da, ETH_ALEN); | 67 | memcpy(mgmt->da, da, ETH_ALEN); |
| 68 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); | 68 | memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); |
| 69 | if (sdata->vif.type == NL80211_IFTYPE_AP || | 69 | if (sdata->vif.type == NL80211_IFTYPE_AP || |
| 70 | sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | 70 | sdata->vif.type == NL80211_IFTYPE_AP_VLAN) |
| 71 | memcpy(mgmt->bssid, sdata->dev->dev_addr, ETH_ALEN); | 71 | memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN); |
| 72 | else if (sdata->vif.type == NL80211_IFTYPE_STATION) | 72 | else if (sdata->vif.type == NL80211_IFTYPE_STATION) |
| 73 | memcpy(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN); | 73 | memcpy(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN); |
| 74 | 74 | ||
| @@ -104,7 +104,7 @@ void ieee80211_send_bar(struct ieee80211_sub_if_data *sdata, u8 *ra, u16 tid, u1 | |||
| 104 | skb = dev_alloc_skb(sizeof(*bar) + local->hw.extra_tx_headroom); | 104 | skb = dev_alloc_skb(sizeof(*bar) + local->hw.extra_tx_headroom); |
| 105 | if (!skb) { | 105 | if (!skb) { |
| 106 | printk(KERN_ERR "%s: failed to allocate buffer for " | 106 | printk(KERN_ERR "%s: failed to allocate buffer for " |
| 107 | "bar frame\n", sdata->dev->name); | 107 | "bar frame\n", sdata->name); |
| 108 | return; | 108 | return; |
| 109 | } | 109 | } |
| 110 | skb_reserve(skb, local->hw.extra_tx_headroom); | 110 | skb_reserve(skb, local->hw.extra_tx_headroom); |
| @@ -113,7 +113,7 @@ void ieee80211_send_bar(struct ieee80211_sub_if_data *sdata, u8 *ra, u16 tid, u1 | |||
| 113 | bar->frame_control = cpu_to_le16(IEEE80211_FTYPE_CTL | | 113 | bar->frame_control = cpu_to_le16(IEEE80211_FTYPE_CTL | |
| 114 | IEEE80211_STYPE_BACK_REQ); | 114 | IEEE80211_STYPE_BACK_REQ); |
| 115 | memcpy(bar->ra, ra, ETH_ALEN); | 115 | memcpy(bar->ra, ra, ETH_ALEN); |
| 116 | memcpy(bar->ta, sdata->dev->dev_addr, ETH_ALEN); | 116 | memcpy(bar->ta, sdata->vif.addr, ETH_ALEN); |
| 117 | bar_control |= (u16)IEEE80211_BAR_CTRL_ACK_POLICY_NORMAL; | 117 | bar_control |= (u16)IEEE80211_BAR_CTRL_ACK_POLICY_NORMAL; |
| 118 | bar_control |= (u16)IEEE80211_BAR_CTRL_CBMTID_COMPRESSED_BA; | 118 | bar_control |= (u16)IEEE80211_BAR_CTRL_CBMTID_COMPRESSED_BA; |
| 119 | bar_control |= (u16)(tid << 12); | 119 | bar_control |= (u16)(tid << 12); |
| @@ -144,7 +144,7 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, | |||
| 144 | *state = HT_AGG_STATE_REQ_STOP_BA_MSK | | 144 | *state = HT_AGG_STATE_REQ_STOP_BA_MSK | |
| 145 | (initiator << HT_AGG_STATE_INITIATOR_SHIFT); | 145 | (initiator << HT_AGG_STATE_INITIATOR_SHIFT); |
| 146 | 146 | ||
| 147 | ret = drv_ampdu_action(local, &sta->sdata->vif, | 147 | ret = drv_ampdu_action(local, sta->sdata, |
| 148 | IEEE80211_AMPDU_TX_STOP, | 148 | IEEE80211_AMPDU_TX_STOP, |
| 149 | &sta->sta, tid, NULL); | 149 | &sta->sta, tid, NULL); |
| 150 | 150 | ||
| @@ -179,7 +179,8 @@ static void sta_addba_resp_timer_expired(unsigned long data) | |||
| 179 | 179 | ||
| 180 | /* check if the TID waits for addBA response */ | 180 | /* check if the TID waits for addBA response */ |
| 181 | spin_lock_bh(&sta->lock); | 181 | spin_lock_bh(&sta->lock); |
| 182 | if ((*state & (HT_ADDBA_REQUESTED_MSK | HT_ADDBA_RECEIVED_MSK)) != | 182 | if ((*state & (HT_ADDBA_REQUESTED_MSK | HT_ADDBA_RECEIVED_MSK | |
| 183 | HT_AGG_STATE_REQ_STOP_BA_MSK)) != | ||
| 183 | HT_ADDBA_REQUESTED_MSK) { | 184 | HT_ADDBA_REQUESTED_MSK) { |
| 184 | spin_unlock_bh(&sta->lock); | 185 | spin_unlock_bh(&sta->lock); |
| 185 | *state = HT_AGG_STATE_IDLE; | 186 | *state = HT_AGG_STATE_IDLE; |
| @@ -236,6 +237,14 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid) | |||
| 236 | sdata->vif.type != NL80211_IFTYPE_AP) | 237 | sdata->vif.type != NL80211_IFTYPE_AP) |
| 237 | return -EINVAL; | 238 | return -EINVAL; |
| 238 | 239 | ||
| 240 | if (test_sta_flags(sta, WLAN_STA_DISASSOC)) { | ||
| 241 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
| 242 | printk(KERN_DEBUG "Disassociation is in progress. " | ||
| 243 | "Denying BA session request\n"); | ||
| 244 | #endif | ||
| 245 | return -EINVAL; | ||
| 246 | } | ||
| 247 | |||
| 239 | if (test_sta_flags(sta, WLAN_STA_SUSPEND)) { | 248 | if (test_sta_flags(sta, WLAN_STA_SUSPEND)) { |
| 240 | #ifdef CONFIG_MAC80211_HT_DEBUG | 249 | #ifdef CONFIG_MAC80211_HT_DEBUG |
| 241 | printk(KERN_DEBUG "Suspend in progress. " | 250 | printk(KERN_DEBUG "Suspend in progress. " |
| @@ -301,10 +310,9 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid) | |||
| 301 | * call back right away, it must see that the flow has begun */ | 310 | * call back right away, it must see that the flow has begun */ |
| 302 | *state |= HT_ADDBA_REQUESTED_MSK; | 311 | *state |= HT_ADDBA_REQUESTED_MSK; |
| 303 | 312 | ||
| 304 | start_seq_num = sta->tid_seq[tid]; | 313 | start_seq_num = sta->tid_seq[tid] >> 4; |
| 305 | 314 | ||
| 306 | ret = drv_ampdu_action(local, &sdata->vif, | 315 | ret = drv_ampdu_action(local, sdata, IEEE80211_AMPDU_TX_START, |
| 307 | IEEE80211_AMPDU_TX_START, | ||
| 308 | pubsta, tid, &start_seq_num); | 316 | pubsta, tid, &start_seq_num); |
| 309 | 317 | ||
| 310 | if (ret) { | 318 | if (ret) { |
| @@ -420,7 +428,7 @@ static void ieee80211_agg_tx_operational(struct ieee80211_local *local, | |||
| 420 | ieee80211_agg_splice_finish(local, sta, tid); | 428 | ieee80211_agg_splice_finish(local, sta, tid); |
| 421 | spin_unlock(&local->ampdu_lock); | 429 | spin_unlock(&local->ampdu_lock); |
| 422 | 430 | ||
| 423 | drv_ampdu_action(local, &sta->sdata->vif, | 431 | drv_ampdu_action(local, sta->sdata, |
| 424 | IEEE80211_AMPDU_TX_OPERATIONAL, | 432 | IEEE80211_AMPDU_TX_OPERATIONAL, |
| 425 | &sta->sta, tid, NULL); | 433 | &sta->sta, tid, NULL); |
| 426 | } | 434 | } |
| @@ -441,7 +449,7 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u16 tid) | |||
| 441 | } | 449 | } |
| 442 | 450 | ||
| 443 | rcu_read_lock(); | 451 | rcu_read_lock(); |
| 444 | sta = sta_info_get(local, ra); | 452 | sta = sta_info_get(sdata, ra); |
| 445 | if (!sta) { | 453 | if (!sta) { |
| 446 | rcu_read_unlock(); | 454 | rcu_read_unlock(); |
| 447 | #ifdef CONFIG_MAC80211_HT_DEBUG | 455 | #ifdef CONFIG_MAC80211_HT_DEBUG |
| @@ -489,7 +497,7 @@ void ieee80211_start_tx_ba_cb_irqsafe(struct ieee80211_vif *vif, | |||
| 489 | #ifdef CONFIG_MAC80211_HT_DEBUG | 497 | #ifdef CONFIG_MAC80211_HT_DEBUG |
| 490 | if (net_ratelimit()) | 498 | if (net_ratelimit()) |
| 491 | printk(KERN_WARNING "%s: Not enough memory, " | 499 | printk(KERN_WARNING "%s: Not enough memory, " |
| 492 | "dropping start BA session", skb->dev->name); | 500 | "dropping start BA session", sdata->name); |
| 493 | #endif | 501 | #endif |
| 494 | return; | 502 | return; |
| 495 | } | 503 | } |
| @@ -564,7 +572,7 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u8 tid) | |||
| 564 | #endif /* CONFIG_MAC80211_HT_DEBUG */ | 572 | #endif /* CONFIG_MAC80211_HT_DEBUG */ |
| 565 | 573 | ||
| 566 | rcu_read_lock(); | 574 | rcu_read_lock(); |
| 567 | sta = sta_info_get(local, ra); | 575 | sta = sta_info_get(sdata, ra); |
| 568 | if (!sta) { | 576 | if (!sta) { |
| 569 | #ifdef CONFIG_MAC80211_HT_DEBUG | 577 | #ifdef CONFIG_MAC80211_HT_DEBUG |
| 570 | printk(KERN_DEBUG "Could not find station: %pM\n", ra); | 578 | printk(KERN_DEBUG "Could not find station: %pM\n", ra); |
| @@ -621,7 +629,7 @@ void ieee80211_stop_tx_ba_cb_irqsafe(struct ieee80211_vif *vif, | |||
| 621 | #ifdef CONFIG_MAC80211_HT_DEBUG | 629 | #ifdef CONFIG_MAC80211_HT_DEBUG |
| 622 | if (net_ratelimit()) | 630 | if (net_ratelimit()) |
| 623 | printk(KERN_WARNING "%s: Not enough memory, " | 631 | printk(KERN_WARNING "%s: Not enough memory, " |
| 624 | "dropping stop BA session", skb->dev->name); | 632 | "dropping stop BA session", sdata->name); |
| 625 | #endif | 633 | #endif |
| 626 | return; | 634 | return; |
| 627 | } | 635 | } |
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 9ae1a4760b58..b7116ef84a3b 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * mac80211 configuration hooks for cfg80211 | 2 | * mac80211 configuration hooks for cfg80211 |
| 3 | * | 3 | * |
| 4 | * Copyright 2006, 2007 Johannes Berg <johannes@sipsolutions.net> | 4 | * Copyright 2006-2010 Johannes Berg <johannes@sipsolutions.net> |
| 5 | * | 5 | * |
| 6 | * This file is GPLv2 as found in COPYING. | 6 | * This file is GPLv2 as found in COPYING. |
| 7 | */ | 7 | */ |
| @@ -78,17 +78,15 @@ static int ieee80211_change_iface(struct wiphy *wiphy, | |||
| 78 | enum nl80211_iftype type, u32 *flags, | 78 | enum nl80211_iftype type, u32 *flags, |
| 79 | struct vif_params *params) | 79 | struct vif_params *params) |
| 80 | { | 80 | { |
| 81 | struct ieee80211_sub_if_data *sdata; | 81 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
| 82 | int ret; | 82 | int ret; |
| 83 | 83 | ||
| 84 | if (netif_running(dev)) | 84 | if (ieee80211_sdata_running(sdata)) |
| 85 | return -EBUSY; | 85 | return -EBUSY; |
| 86 | 86 | ||
| 87 | if (!nl80211_params_check(type, params)) | 87 | if (!nl80211_params_check(type, params)) |
| 88 | return -EINVAL; | 88 | return -EINVAL; |
| 89 | 89 | ||
| 90 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
| 91 | |||
| 92 | ret = ieee80211_if_change_type(sdata, type); | 90 | ret = ieee80211_if_change_type(sdata, type); |
| 93 | if (ret) | 91 | if (ret) |
| 94 | return ret; | 92 | return ret; |
| @@ -150,7 +148,7 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev, | |||
| 150 | rcu_read_lock(); | 148 | rcu_read_lock(); |
| 151 | 149 | ||
| 152 | if (mac_addr) { | 150 | if (mac_addr) { |
| 153 | sta = sta_info_get(sdata->local, mac_addr); | 151 | sta = sta_info_get_bss(sdata, mac_addr); |
| 154 | if (!sta) { | 152 | if (!sta) { |
| 155 | ieee80211_key_free(key); | 153 | ieee80211_key_free(key); |
| 156 | err = -ENOENT; | 154 | err = -ENOENT; |
| @@ -181,7 +179,7 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev, | |||
| 181 | if (mac_addr) { | 179 | if (mac_addr) { |
| 182 | ret = -ENOENT; | 180 | ret = -ENOENT; |
| 183 | 181 | ||
| 184 | sta = sta_info_get(sdata->local, mac_addr); | 182 | sta = sta_info_get_bss(sdata, mac_addr); |
| 185 | if (!sta) | 183 | if (!sta) |
| 186 | goto out_unlock; | 184 | goto out_unlock; |
| 187 | 185 | ||
| @@ -228,7 +226,7 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev, | |||
| 228 | rcu_read_lock(); | 226 | rcu_read_lock(); |
| 229 | 227 | ||
| 230 | if (mac_addr) { | 228 | if (mac_addr) { |
| 231 | sta = sta_info_get(sdata->local, mac_addr); | 229 | sta = sta_info_get_bss(sdata, mac_addr); |
| 232 | if (!sta) | 230 | if (!sta) |
| 233 | goto out; | 231 | goto out; |
| 234 | 232 | ||
| @@ -415,15 +413,13 @@ static int ieee80211_dump_station(struct wiphy *wiphy, struct net_device *dev, | |||
| 415 | static int ieee80211_get_station(struct wiphy *wiphy, struct net_device *dev, | 413 | static int ieee80211_get_station(struct wiphy *wiphy, struct net_device *dev, |
| 416 | u8 *mac, struct station_info *sinfo) | 414 | u8 *mac, struct station_info *sinfo) |
| 417 | { | 415 | { |
| 418 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 416 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
| 419 | struct sta_info *sta; | 417 | struct sta_info *sta; |
| 420 | int ret = -ENOENT; | 418 | int ret = -ENOENT; |
| 421 | 419 | ||
| 422 | rcu_read_lock(); | 420 | rcu_read_lock(); |
| 423 | 421 | ||
| 424 | /* XXX: verify sta->dev == dev */ | 422 | sta = sta_info_get_bss(sdata, mac); |
| 425 | |||
| 426 | sta = sta_info_get(local, mac); | ||
| 427 | if (sta) { | 423 | if (sta) { |
| 428 | ret = 0; | 424 | ret = 0; |
| 429 | sta_set_sinfo(sta, sinfo); | 425 | sta_set_sinfo(sta, sinfo); |
| @@ -519,6 +515,8 @@ static int ieee80211_config_beacon(struct ieee80211_sub_if_data *sdata, | |||
| 519 | if (old) | 515 | if (old) |
| 520 | memcpy(new->tail, old->tail, new_tail_len); | 516 | memcpy(new->tail, old->tail, new_tail_len); |
| 521 | 517 | ||
| 518 | sdata->vif.bss_conf.dtim_period = new->dtim_period; | ||
| 519 | |||
| 522 | rcu_assign_pointer(sdata->u.ap.beacon, new); | 520 | rcu_assign_pointer(sdata->u.ap.beacon, new); |
| 523 | 521 | ||
| 524 | synchronize_rcu(); | 522 | synchronize_rcu(); |
| @@ -732,7 +730,7 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev, | |||
| 732 | } else | 730 | } else |
| 733 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 731 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
| 734 | 732 | ||
| 735 | if (compare_ether_addr(mac, dev->dev_addr) == 0) | 733 | if (compare_ether_addr(mac, sdata->vif.addr) == 0) |
| 736 | return -EINVAL; | 734 | return -EINVAL; |
| 737 | 735 | ||
| 738 | if (is_multicast_ether_addr(mac)) | 736 | if (is_multicast_ether_addr(mac)) |
| @@ -751,9 +749,7 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev, | |||
| 751 | layer2_update = sdata->vif.type == NL80211_IFTYPE_AP_VLAN || | 749 | layer2_update = sdata->vif.type == NL80211_IFTYPE_AP_VLAN || |
| 752 | sdata->vif.type == NL80211_IFTYPE_AP; | 750 | sdata->vif.type == NL80211_IFTYPE_AP; |
| 753 | 751 | ||
| 754 | rcu_read_lock(); | 752 | err = sta_info_insert_rcu(sta); |
| 755 | |||
| 756 | err = sta_info_insert(sta); | ||
| 757 | if (err) { | 753 | if (err) { |
| 758 | rcu_read_unlock(); | 754 | rcu_read_unlock(); |
| 759 | return err; | 755 | return err; |
| @@ -772,27 +768,13 @@ static int ieee80211_del_station(struct wiphy *wiphy, struct net_device *dev, | |||
| 772 | { | 768 | { |
| 773 | struct ieee80211_local *local = wiphy_priv(wiphy); | 769 | struct ieee80211_local *local = wiphy_priv(wiphy); |
| 774 | struct ieee80211_sub_if_data *sdata; | 770 | struct ieee80211_sub_if_data *sdata; |
| 775 | struct sta_info *sta; | ||
| 776 | 771 | ||
| 777 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 772 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
| 778 | 773 | ||
| 779 | if (mac) { | 774 | if (mac) |
| 780 | rcu_read_lock(); | 775 | return sta_info_destroy_addr_bss(sdata, mac); |
| 781 | |||
| 782 | /* XXX: get sta belonging to dev */ | ||
| 783 | sta = sta_info_get(local, mac); | ||
| 784 | if (!sta) { | ||
| 785 | rcu_read_unlock(); | ||
| 786 | return -ENOENT; | ||
| 787 | } | ||
| 788 | |||
| 789 | sta_info_unlink(&sta); | ||
| 790 | rcu_read_unlock(); | ||
| 791 | |||
| 792 | sta_info_destroy(sta); | ||
| 793 | } else | ||
| 794 | sta_info_flush(local, sdata); | ||
| 795 | 776 | ||
| 777 | sta_info_flush(local, sdata); | ||
| 796 | return 0; | 778 | return 0; |
| 797 | } | 779 | } |
| 798 | 780 | ||
| @@ -801,14 +783,14 @@ static int ieee80211_change_station(struct wiphy *wiphy, | |||
| 801 | u8 *mac, | 783 | u8 *mac, |
| 802 | struct station_parameters *params) | 784 | struct station_parameters *params) |
| 803 | { | 785 | { |
| 786 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
| 804 | struct ieee80211_local *local = wiphy_priv(wiphy); | 787 | struct ieee80211_local *local = wiphy_priv(wiphy); |
| 805 | struct sta_info *sta; | 788 | struct sta_info *sta; |
| 806 | struct ieee80211_sub_if_data *vlansdata; | 789 | struct ieee80211_sub_if_data *vlansdata; |
| 807 | 790 | ||
| 808 | rcu_read_lock(); | 791 | rcu_read_lock(); |
| 809 | 792 | ||
| 810 | /* XXX: get sta belonging to dev */ | 793 | sta = sta_info_get_bss(sdata, mac); |
| 811 | sta = sta_info_get(local, mac); | ||
| 812 | if (!sta) { | 794 | if (!sta) { |
| 813 | rcu_read_unlock(); | 795 | rcu_read_unlock(); |
| 814 | return -ENOENT; | 796 | return -ENOENT; |
| @@ -847,7 +829,6 @@ static int ieee80211_change_station(struct wiphy *wiphy, | |||
| 847 | static int ieee80211_add_mpath(struct wiphy *wiphy, struct net_device *dev, | 829 | static int ieee80211_add_mpath(struct wiphy *wiphy, struct net_device *dev, |
| 848 | u8 *dst, u8 *next_hop) | 830 | u8 *dst, u8 *next_hop) |
| 849 | { | 831 | { |
| 850 | struct ieee80211_local *local = wiphy_priv(wiphy); | ||
| 851 | struct ieee80211_sub_if_data *sdata; | 832 | struct ieee80211_sub_if_data *sdata; |
| 852 | struct mesh_path *mpath; | 833 | struct mesh_path *mpath; |
| 853 | struct sta_info *sta; | 834 | struct sta_info *sta; |
| @@ -856,7 +837,7 @@ static int ieee80211_add_mpath(struct wiphy *wiphy, struct net_device *dev, | |||
| 856 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 837 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
| 857 | 838 | ||
| 858 | rcu_read_lock(); | 839 | rcu_read_lock(); |
| 859 | sta = sta_info_get(local, next_hop); | 840 | sta = sta_info_get(sdata, next_hop); |
| 860 | if (!sta) { | 841 | if (!sta) { |
| 861 | rcu_read_unlock(); | 842 | rcu_read_unlock(); |
| 862 | return -ENOENT; | 843 | return -ENOENT; |
| @@ -895,7 +876,6 @@ static int ieee80211_change_mpath(struct wiphy *wiphy, | |||
| 895 | struct net_device *dev, | 876 | struct net_device *dev, |
| 896 | u8 *dst, u8 *next_hop) | 877 | u8 *dst, u8 *next_hop) |
| 897 | { | 878 | { |
| 898 | struct ieee80211_local *local = wiphy_priv(wiphy); | ||
| 899 | struct ieee80211_sub_if_data *sdata; | 879 | struct ieee80211_sub_if_data *sdata; |
| 900 | struct mesh_path *mpath; | 880 | struct mesh_path *mpath; |
| 901 | struct sta_info *sta; | 881 | struct sta_info *sta; |
| @@ -904,7 +884,7 @@ static int ieee80211_change_mpath(struct wiphy *wiphy, | |||
| 904 | 884 | ||
| 905 | rcu_read_lock(); | 885 | rcu_read_lock(); |
| 906 | 886 | ||
| 907 | sta = sta_info_get(local, next_hop); | 887 | sta = sta_info_get(sdata, next_hop); |
| 908 | if (!sta) { | 888 | if (!sta) { |
| 909 | rcu_read_unlock(); | 889 | rcu_read_unlock(); |
| 910 | return -ENOENT; | 890 | return -ENOENT; |
| @@ -1092,6 +1072,13 @@ static int ieee80211_change_bss(struct wiphy *wiphy, | |||
| 1092 | params->use_short_preamble; | 1072 | params->use_short_preamble; |
| 1093 | changed |= BSS_CHANGED_ERP_PREAMBLE; | 1073 | changed |= BSS_CHANGED_ERP_PREAMBLE; |
| 1094 | } | 1074 | } |
| 1075 | |||
| 1076 | if (!sdata->vif.bss_conf.use_short_slot && | ||
| 1077 | sdata->local->hw.conf.channel->band == IEEE80211_BAND_5GHZ) { | ||
| 1078 | sdata->vif.bss_conf.use_short_slot = true; | ||
| 1079 | changed |= BSS_CHANGED_ERP_SLOT; | ||
| 1080 | } | ||
| 1081 | |||
| 1095 | if (params->use_short_slot_time >= 0) { | 1082 | if (params->use_short_slot_time >= 0) { |
| 1096 | sdata->vif.bss_conf.use_short_slot = | 1083 | sdata->vif.bss_conf.use_short_slot = |
| 1097 | params->use_short_slot_time; | 1084 | params->use_short_slot_time; |
| @@ -1135,6 +1122,13 @@ static int ieee80211_set_txq_params(struct wiphy *wiphy, | |||
| 1135 | p.cw_max = params->cwmax; | 1122 | p.cw_max = params->cwmax; |
| 1136 | p.cw_min = params->cwmin; | 1123 | p.cw_min = params->cwmin; |
| 1137 | p.txop = params->txop; | 1124 | p.txop = params->txop; |
| 1125 | |||
| 1126 | /* | ||
| 1127 | * Setting tx queue params disables u-apsd because it's only | ||
| 1128 | * called in master mode. | ||
| 1129 | */ | ||
| 1130 | p.uapsd = false; | ||
| 1131 | |||
| 1138 | if (drv_conf_tx(local, params->queue, &p)) { | 1132 | if (drv_conf_tx(local, params->queue, &p)) { |
| 1139 | printk(KERN_DEBUG "%s: failed to set TX queue " | 1133 | printk(KERN_DEBUG "%s: failed to set TX queue " |
| 1140 | "parameters for queue %d\n", | 1134 | "parameters for queue %d\n", |
| @@ -1237,6 +1231,13 @@ static int ieee80211_set_wiphy_params(struct wiphy *wiphy, u32 changed) | |||
| 1237 | struct ieee80211_local *local = wiphy_priv(wiphy); | 1231 | struct ieee80211_local *local = wiphy_priv(wiphy); |
| 1238 | int err; | 1232 | int err; |
| 1239 | 1233 | ||
| 1234 | if (changed & WIPHY_PARAM_COVERAGE_CLASS) { | ||
| 1235 | err = drv_set_coverage_class(local, wiphy->coverage_class); | ||
| 1236 | |||
| 1237 | if (err) | ||
| 1238 | return err; | ||
| 1239 | } | ||
| 1240 | |||
| 1240 | if (changed & WIPHY_PARAM_RTS_THRESHOLD) { | 1241 | if (changed & WIPHY_PARAM_RTS_THRESHOLD) { |
| 1241 | err = drv_set_rts_threshold(local, wiphy->rts_threshold); | 1242 | err = drv_set_rts_threshold(local, wiphy->rts_threshold); |
| 1242 | 1243 | ||
| @@ -1324,6 +1325,50 @@ static int ieee80211_testmode_cmd(struct wiphy *wiphy, void *data, int len) | |||
| 1324 | } | 1325 | } |
| 1325 | #endif | 1326 | #endif |
| 1326 | 1327 | ||
| 1328 | int __ieee80211_request_smps(struct ieee80211_sub_if_data *sdata, | ||
| 1329 | enum ieee80211_smps_mode smps_mode) | ||
| 1330 | { | ||
| 1331 | const u8 *ap; | ||
| 1332 | enum ieee80211_smps_mode old_req; | ||
| 1333 | int err; | ||
| 1334 | |||
| 1335 | old_req = sdata->u.mgd.req_smps; | ||
| 1336 | sdata->u.mgd.req_smps = smps_mode; | ||
| 1337 | |||
| 1338 | if (old_req == smps_mode && | ||
| 1339 | smps_mode != IEEE80211_SMPS_AUTOMATIC) | ||
| 1340 | return 0; | ||
| 1341 | |||
| 1342 | /* | ||
| 1343 | * If not associated, or current association is not an HT | ||
| 1344 | * association, there's no need to send an action frame. | ||
| 1345 | */ | ||
| 1346 | if (!sdata->u.mgd.associated || | ||
| 1347 | sdata->local->oper_channel_type == NL80211_CHAN_NO_HT) { | ||
| 1348 | mutex_lock(&sdata->local->iflist_mtx); | ||
| 1349 | ieee80211_recalc_smps(sdata->local, sdata); | ||
| 1350 | mutex_unlock(&sdata->local->iflist_mtx); | ||
| 1351 | return 0; | ||
| 1352 | } | ||
| 1353 | |||
| 1354 | ap = sdata->u.mgd.associated->bssid; | ||
| 1355 | |||
| 1356 | if (smps_mode == IEEE80211_SMPS_AUTOMATIC) { | ||
| 1357 | if (sdata->u.mgd.powersave) | ||
| 1358 | smps_mode = IEEE80211_SMPS_DYNAMIC; | ||
| 1359 | else | ||
| 1360 | smps_mode = IEEE80211_SMPS_OFF; | ||
| 1361 | } | ||
| 1362 | |||
| 1363 | /* send SM PS frame to AP */ | ||
| 1364 | err = ieee80211_send_smps_action(sdata, smps_mode, | ||
| 1365 | ap, ap); | ||
| 1366 | if (err) | ||
| 1367 | sdata->u.mgd.req_smps = old_req; | ||
| 1368 | |||
| 1369 | return err; | ||
| 1370 | } | ||
| 1371 | |||
| 1327 | static int ieee80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev, | 1372 | static int ieee80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev, |
| 1328 | bool enabled, int timeout) | 1373 | bool enabled, int timeout) |
| 1329 | { | 1374 | { |
| @@ -1344,6 +1389,11 @@ static int ieee80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev, | |||
| 1344 | sdata->u.mgd.powersave = enabled; | 1389 | sdata->u.mgd.powersave = enabled; |
| 1345 | conf->dynamic_ps_timeout = timeout; | 1390 | conf->dynamic_ps_timeout = timeout; |
| 1346 | 1391 | ||
| 1392 | /* no change, but if automatic follow powersave */ | ||
| 1393 | mutex_lock(&sdata->u.mgd.mtx); | ||
| 1394 | __ieee80211_request_smps(sdata, sdata->u.mgd.req_smps); | ||
| 1395 | mutex_unlock(&sdata->u.mgd.mtx); | ||
| 1396 | |||
| 1347 | if (local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS) | 1397 | if (local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS) |
| 1348 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); | 1398 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); |
| 1349 | 1399 | ||
| @@ -1359,39 +1409,52 @@ static int ieee80211_set_bitrate_mask(struct wiphy *wiphy, | |||
| 1359 | { | 1409 | { |
| 1360 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 1410 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
| 1361 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 1411 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); |
| 1362 | int i, err = -EINVAL; | 1412 | int i; |
| 1363 | u32 target_rate; | 1413 | |
| 1364 | struct ieee80211_supported_band *sband; | 1414 | /* |
| 1415 | * This _could_ be supported by providing a hook for | ||
| 1416 | * drivers for this function, but at this point it | ||
| 1417 | * doesn't seem worth bothering. | ||
| 1418 | */ | ||
| 1419 | if (local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL) | ||
| 1420 | return -EOPNOTSUPP; | ||
| 1365 | 1421 | ||
| 1366 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | ||
| 1367 | 1422 | ||
| 1368 | /* target_rate = -1, rate->fixed = 0 means auto only, so use all rates | 1423 | for (i = 0; i < IEEE80211_NUM_BANDS; i++) |
| 1369 | * target_rate = X, rate->fixed = 1 means only rate X | 1424 | sdata->rc_rateidx_mask[i] = mask->control[i].legacy; |
| 1370 | * target_rate = X, rate->fixed = 0 means all rates <= X */ | ||
| 1371 | sdata->max_ratectrl_rateidx = -1; | ||
| 1372 | sdata->force_unicast_rateidx = -1; | ||
| 1373 | 1425 | ||
| 1374 | if (mask->fixed) | 1426 | return 0; |
| 1375 | target_rate = mask->fixed / 100; | 1427 | } |
| 1376 | else if (mask->maxrate) | ||
| 1377 | target_rate = mask->maxrate / 100; | ||
| 1378 | else | ||
| 1379 | return 0; | ||
| 1380 | 1428 | ||
| 1381 | for (i=0; i< sband->n_bitrates; i++) { | 1429 | static int ieee80211_remain_on_channel(struct wiphy *wiphy, |
| 1382 | struct ieee80211_rate *brate = &sband->bitrates[i]; | 1430 | struct net_device *dev, |
| 1383 | int this_rate = brate->bitrate; | 1431 | struct ieee80211_channel *chan, |
| 1432 | enum nl80211_channel_type channel_type, | ||
| 1433 | unsigned int duration, | ||
| 1434 | u64 *cookie) | ||
| 1435 | { | ||
| 1436 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
| 1384 | 1437 | ||
| 1385 | if (target_rate == this_rate) { | 1438 | return ieee80211_wk_remain_on_channel(sdata, chan, channel_type, |
| 1386 | sdata->max_ratectrl_rateidx = i; | 1439 | duration, cookie); |
| 1387 | if (mask->fixed) | 1440 | } |
| 1388 | sdata->force_unicast_rateidx = i; | ||
| 1389 | err = 0; | ||
| 1390 | break; | ||
| 1391 | } | ||
| 1392 | } | ||
| 1393 | 1441 | ||
| 1394 | return err; | 1442 | static int ieee80211_cancel_remain_on_channel(struct wiphy *wiphy, |
| 1443 | struct net_device *dev, | ||
| 1444 | u64 cookie) | ||
| 1445 | { | ||
| 1446 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
| 1447 | |||
| 1448 | return ieee80211_wk_cancel_remain_on_channel(sdata, cookie); | ||
| 1449 | } | ||
| 1450 | |||
| 1451 | static int ieee80211_action(struct wiphy *wiphy, struct net_device *dev, | ||
| 1452 | struct ieee80211_channel *chan, | ||
| 1453 | enum nl80211_channel_type channel_type, | ||
| 1454 | const u8 *buf, size_t len, u64 *cookie) | ||
| 1455 | { | ||
| 1456 | return ieee80211_mgd_action(IEEE80211_DEV_TO_SUB_IF(dev), chan, | ||
| 1457 | channel_type, buf, len, cookie); | ||
| 1395 | } | 1458 | } |
| 1396 | 1459 | ||
| 1397 | struct cfg80211_ops mac80211_config_ops = { | 1460 | struct cfg80211_ops mac80211_config_ops = { |
| @@ -1440,4 +1503,7 @@ struct cfg80211_ops mac80211_config_ops = { | |||
| 1440 | CFG80211_TESTMODE_CMD(ieee80211_testmode_cmd) | 1503 | CFG80211_TESTMODE_CMD(ieee80211_testmode_cmd) |
| 1441 | .set_power_mgmt = ieee80211_set_power_mgmt, | 1504 | .set_power_mgmt = ieee80211_set_power_mgmt, |
| 1442 | .set_bitrate_mask = ieee80211_set_bitrate_mask, | 1505 | .set_bitrate_mask = ieee80211_set_bitrate_mask, |
| 1506 | .remain_on_channel = ieee80211_remain_on_channel, | ||
| 1507 | .cancel_remain_on_channel = ieee80211_cancel_remain_on_channel, | ||
| 1508 | .action = ieee80211_action, | ||
| 1443 | }; | 1509 | }; |
diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c index e4b54093d41b..637929b65ccc 100644 --- a/net/mac80211/debugfs.c +++ b/net/mac80211/debugfs.c | |||
| @@ -158,6 +158,130 @@ static const struct file_operations noack_ops = { | |||
| 158 | .open = mac80211_open_file_generic | 158 | .open = mac80211_open_file_generic |
| 159 | }; | 159 | }; |
| 160 | 160 | ||
| 161 | static ssize_t uapsd_queues_read(struct file *file, char __user *user_buf, | ||
| 162 | size_t count, loff_t *ppos) | ||
| 163 | { | ||
| 164 | struct ieee80211_local *local = file->private_data; | ||
| 165 | int res; | ||
| 166 | char buf[10]; | ||
| 167 | |||
| 168 | res = scnprintf(buf, sizeof(buf), "0x%x\n", local->uapsd_queues); | ||
| 169 | |||
| 170 | return simple_read_from_buffer(user_buf, count, ppos, buf, res); | ||
| 171 | } | ||
| 172 | |||
| 173 | static ssize_t uapsd_queues_write(struct file *file, | ||
| 174 | const char __user *user_buf, | ||
| 175 | size_t count, loff_t *ppos) | ||
| 176 | { | ||
| 177 | struct ieee80211_local *local = file->private_data; | ||
| 178 | unsigned long val; | ||
| 179 | char buf[10]; | ||
| 180 | size_t len; | ||
| 181 | int ret; | ||
| 182 | |||
| 183 | len = min(count, sizeof(buf) - 1); | ||
| 184 | if (copy_from_user(buf, user_buf, len)) | ||
| 185 | return -EFAULT; | ||
| 186 | buf[len] = '\0'; | ||
| 187 | |||
| 188 | ret = strict_strtoul(buf, 0, &val); | ||
| 189 | |||
| 190 | if (ret) | ||
| 191 | return -EINVAL; | ||
| 192 | |||
| 193 | if (val & ~IEEE80211_WMM_IE_STA_QOSINFO_AC_MASK) | ||
| 194 | return -ERANGE; | ||
| 195 | |||
| 196 | local->uapsd_queues = val; | ||
| 197 | |||
| 198 | return count; | ||
| 199 | } | ||
| 200 | |||
| 201 | static const struct file_operations uapsd_queues_ops = { | ||
| 202 | .read = uapsd_queues_read, | ||
| 203 | .write = uapsd_queues_write, | ||
| 204 | .open = mac80211_open_file_generic | ||
| 205 | }; | ||
| 206 | |||
| 207 | static ssize_t uapsd_max_sp_len_read(struct file *file, char __user *user_buf, | ||
| 208 | size_t count, loff_t *ppos) | ||
| 209 | { | ||
| 210 | struct ieee80211_local *local = file->private_data; | ||
| 211 | int res; | ||
| 212 | char buf[10]; | ||
| 213 | |||
| 214 | res = scnprintf(buf, sizeof(buf), "0x%x\n", local->uapsd_max_sp_len); | ||
| 215 | |||
| 216 | return simple_read_from_buffer(user_buf, count, ppos, buf, res); | ||
| 217 | } | ||
| 218 | |||
| 219 | static ssize_t uapsd_max_sp_len_write(struct file *file, | ||
| 220 | const char __user *user_buf, | ||
| 221 | size_t count, loff_t *ppos) | ||
| 222 | { | ||
| 223 | struct ieee80211_local *local = file->private_data; | ||
| 224 | unsigned long val; | ||
| 225 | char buf[10]; | ||
| 226 | size_t len; | ||
| 227 | int ret; | ||
| 228 | |||
| 229 | len = min(count, sizeof(buf) - 1); | ||
| 230 | if (copy_from_user(buf, user_buf, len)) | ||
| 231 | return -EFAULT; | ||
| 232 | buf[len] = '\0'; | ||
| 233 | |||
| 234 | ret = strict_strtoul(buf, 0, &val); | ||
| 235 | |||
| 236 | if (ret) | ||
| 237 | return -EINVAL; | ||
| 238 | |||
| 239 | if (val & ~IEEE80211_WMM_IE_STA_QOSINFO_SP_MASK) | ||
| 240 | return -ERANGE; | ||
| 241 | |||
| 242 | local->uapsd_max_sp_len = val; | ||
| 243 | |||
| 244 | return count; | ||
| 245 | } | ||
| 246 | |||
| 247 | static const struct file_operations uapsd_max_sp_len_ops = { | ||
| 248 | .read = uapsd_max_sp_len_read, | ||
| 249 | .write = uapsd_max_sp_len_write, | ||
| 250 | .open = mac80211_open_file_generic | ||
| 251 | }; | ||
| 252 | |||
| 253 | static ssize_t channel_type_read(struct file *file, char __user *user_buf, | ||
| 254 | size_t count, loff_t *ppos) | ||
| 255 | { | ||
| 256 | struct ieee80211_local *local = file->private_data; | ||
| 257 | const char *buf; | ||
| 258 | |||
| 259 | switch (local->hw.conf.channel_type) { | ||
| 260 | case NL80211_CHAN_NO_HT: | ||
| 261 | buf = "no ht\n"; | ||
| 262 | break; | ||
| 263 | case NL80211_CHAN_HT20: | ||
| 264 | buf = "ht20\n"; | ||
| 265 | break; | ||
| 266 | case NL80211_CHAN_HT40MINUS: | ||
| 267 | buf = "ht40-\n"; | ||
| 268 | break; | ||
| 269 | case NL80211_CHAN_HT40PLUS: | ||
| 270 | buf = "ht40+\n"; | ||
| 271 | break; | ||
| 272 | default: | ||
| 273 | buf = "???"; | ||
| 274 | break; | ||
| 275 | } | ||
| 276 | |||
| 277 | return simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf)); | ||
| 278 | } | ||
| 279 | |||
| 280 | static const struct file_operations channel_type_ops = { | ||
| 281 | .read = channel_type_read, | ||
| 282 | .open = mac80211_open_file_generic | ||
| 283 | }; | ||
| 284 | |||
| 161 | static ssize_t queues_read(struct file *file, char __user *user_buf, | 285 | static ssize_t queues_read(struct file *file, char __user *user_buf, |
| 162 | size_t count, loff_t *ppos) | 286 | size_t count, loff_t *ppos) |
| 163 | { | 287 | { |
| @@ -314,6 +438,9 @@ void debugfs_hw_add(struct ieee80211_local *local) | |||
| 314 | DEBUGFS_ADD(queues); | 438 | DEBUGFS_ADD(queues); |
| 315 | DEBUGFS_ADD_MODE(reset, 0200); | 439 | DEBUGFS_ADD_MODE(reset, 0200); |
| 316 | DEBUGFS_ADD(noack); | 440 | DEBUGFS_ADD(noack); |
| 441 | DEBUGFS_ADD(uapsd_queues); | ||
| 442 | DEBUGFS_ADD(uapsd_max_sp_len); | ||
| 443 | DEBUGFS_ADD(channel_type); | ||
| 317 | 444 | ||
| 318 | statsd = debugfs_create_dir("statistics", phyd); | 445 | statsd = debugfs_create_dir("statistics", phyd); |
| 319 | 446 | ||
diff --git a/net/mac80211/debugfs_key.c b/net/mac80211/debugfs_key.c index e0f5224630da..d12e743cb4e1 100644 --- a/net/mac80211/debugfs_key.c +++ b/net/mac80211/debugfs_key.c | |||
| @@ -56,7 +56,7 @@ KEY_CONF_FILE(keyidx, D); | |||
| 56 | KEY_CONF_FILE(hw_key_idx, D); | 56 | KEY_CONF_FILE(hw_key_idx, D); |
| 57 | KEY_FILE(flags, X); | 57 | KEY_FILE(flags, X); |
| 58 | KEY_FILE(tx_rx_count, D); | 58 | KEY_FILE(tx_rx_count, D); |
| 59 | KEY_READ(ifindex, sdata->dev->ifindex, 20, "%d\n"); | 59 | KEY_READ(ifindex, sdata->name, IFNAMSIZ + 2, "%s\n"); |
| 60 | KEY_OPS(ifindex); | 60 | KEY_OPS(ifindex); |
| 61 | 61 | ||
| 62 | static ssize_t key_algorithm_read(struct file *file, | 62 | static ssize_t key_algorithm_read(struct file *file, |
diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c index 472b2039906c..b4ddb2f83914 100644 --- a/net/mac80211/debugfs_netdev.c +++ b/net/mac80211/debugfs_netdev.c | |||
| @@ -41,6 +41,34 @@ static ssize_t ieee80211_if_read( | |||
| 41 | return ret; | 41 | return ret; |
| 42 | } | 42 | } |
| 43 | 43 | ||
| 44 | static ssize_t ieee80211_if_write( | ||
| 45 | struct ieee80211_sub_if_data *sdata, | ||
| 46 | const char __user *userbuf, | ||
| 47 | size_t count, loff_t *ppos, | ||
| 48 | ssize_t (*write)(struct ieee80211_sub_if_data *, const char *, int)) | ||
| 49 | { | ||
| 50 | u8 *buf; | ||
| 51 | ssize_t ret; | ||
| 52 | |||
| 53 | buf = kmalloc(count, GFP_KERNEL); | ||
| 54 | if (!buf) | ||
| 55 | return -ENOMEM; | ||
| 56 | |||
| 57 | ret = -EFAULT; | ||
| 58 | if (copy_from_user(buf, userbuf, count)) | ||
| 59 | goto freebuf; | ||
| 60 | |||
| 61 | ret = -ENODEV; | ||
| 62 | rtnl_lock(); | ||
| 63 | if (sdata->dev->reg_state == NETREG_REGISTERED) | ||
| 64 | ret = (*write)(sdata, buf, count); | ||
| 65 | rtnl_unlock(); | ||
| 66 | |||
| 67 | freebuf: | ||
| 68 | kfree(buf); | ||
| 69 | return ret; | ||
| 70 | } | ||
| 71 | |||
| 44 | #define IEEE80211_IF_FMT(name, field, format_string) \ | 72 | #define IEEE80211_IF_FMT(name, field, format_string) \ |
| 45 | static ssize_t ieee80211_if_fmt_##name( \ | 73 | static ssize_t ieee80211_if_fmt_##name( \ |
| 46 | const struct ieee80211_sub_if_data *sdata, char *buf, \ | 74 | const struct ieee80211_sub_if_data *sdata, char *buf, \ |
| @@ -71,7 +99,7 @@ static ssize_t ieee80211_if_fmt_##name( \ | |||
| 71 | return scnprintf(buf, buflen, "%pM\n", sdata->field); \ | 99 | return scnprintf(buf, buflen, "%pM\n", sdata->field); \ |
| 72 | } | 100 | } |
| 73 | 101 | ||
| 74 | #define __IEEE80211_IF_FILE(name) \ | 102 | #define __IEEE80211_IF_FILE(name, _write) \ |
| 75 | static ssize_t ieee80211_if_read_##name(struct file *file, \ | 103 | static ssize_t ieee80211_if_read_##name(struct file *file, \ |
| 76 | char __user *userbuf, \ | 104 | char __user *userbuf, \ |
| 77 | size_t count, loff_t *ppos) \ | 105 | size_t count, loff_t *ppos) \ |
| @@ -82,22 +110,99 @@ static ssize_t ieee80211_if_read_##name(struct file *file, \ | |||
| 82 | } \ | 110 | } \ |
| 83 | static const struct file_operations name##_ops = { \ | 111 | static const struct file_operations name##_ops = { \ |
| 84 | .read = ieee80211_if_read_##name, \ | 112 | .read = ieee80211_if_read_##name, \ |
| 113 | .write = (_write), \ | ||
| 85 | .open = mac80211_open_file_generic, \ | 114 | .open = mac80211_open_file_generic, \ |
| 86 | } | 115 | } |
| 87 | 116 | ||
| 117 | #define __IEEE80211_IF_FILE_W(name) \ | ||
| 118 | static ssize_t ieee80211_if_write_##name(struct file *file, \ | ||
| 119 | const char __user *userbuf, \ | ||
| 120 | size_t count, loff_t *ppos) \ | ||
| 121 | { \ | ||
| 122 | return ieee80211_if_write(file->private_data, userbuf, count, \ | ||
| 123 | ppos, ieee80211_if_parse_##name); \ | ||
| 124 | } \ | ||
| 125 | __IEEE80211_IF_FILE(name, ieee80211_if_write_##name) | ||
| 126 | |||
| 127 | |||
| 88 | #define IEEE80211_IF_FILE(name, field, format) \ | 128 | #define IEEE80211_IF_FILE(name, field, format) \ |
| 89 | IEEE80211_IF_FMT_##format(name, field) \ | 129 | IEEE80211_IF_FMT_##format(name, field) \ |
| 90 | __IEEE80211_IF_FILE(name) | 130 | __IEEE80211_IF_FILE(name, NULL) |
| 91 | 131 | ||
| 92 | /* common attributes */ | 132 | /* common attributes */ |
| 93 | IEEE80211_IF_FILE(drop_unencrypted, drop_unencrypted, DEC); | 133 | IEEE80211_IF_FILE(drop_unencrypted, drop_unencrypted, DEC); |
| 94 | IEEE80211_IF_FILE(force_unicast_rateidx, force_unicast_rateidx, DEC); | 134 | IEEE80211_IF_FILE(rc_rateidx_mask_2ghz, rc_rateidx_mask[IEEE80211_BAND_2GHZ], |
| 95 | IEEE80211_IF_FILE(max_ratectrl_rateidx, max_ratectrl_rateidx, DEC); | 135 | HEX); |
| 136 | IEEE80211_IF_FILE(rc_rateidx_mask_5ghz, rc_rateidx_mask[IEEE80211_BAND_5GHZ], | ||
| 137 | HEX); | ||
| 96 | 138 | ||
| 97 | /* STA attributes */ | 139 | /* STA attributes */ |
| 98 | IEEE80211_IF_FILE(bssid, u.mgd.bssid, MAC); | 140 | IEEE80211_IF_FILE(bssid, u.mgd.bssid, MAC); |
| 99 | IEEE80211_IF_FILE(aid, u.mgd.aid, DEC); | 141 | IEEE80211_IF_FILE(aid, u.mgd.aid, DEC); |
| 100 | IEEE80211_IF_FILE(capab, u.mgd.capab, HEX); | 142 | |
| 143 | static int ieee80211_set_smps(struct ieee80211_sub_if_data *sdata, | ||
| 144 | enum ieee80211_smps_mode smps_mode) | ||
| 145 | { | ||
| 146 | struct ieee80211_local *local = sdata->local; | ||
| 147 | int err; | ||
| 148 | |||
| 149 | if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_STATIC_SMPS) && | ||
| 150 | smps_mode == IEEE80211_SMPS_STATIC) | ||
| 151 | return -EINVAL; | ||
| 152 | |||
| 153 | /* auto should be dynamic if in PS mode */ | ||
| 154 | if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS) && | ||
| 155 | (smps_mode == IEEE80211_SMPS_DYNAMIC || | ||
| 156 | smps_mode == IEEE80211_SMPS_AUTOMATIC)) | ||
| 157 | return -EINVAL; | ||
| 158 | |||
| 159 | /* supported only on managed interfaces for now */ | ||
| 160 | if (sdata->vif.type != NL80211_IFTYPE_STATION) | ||
| 161 | return -EOPNOTSUPP; | ||
| 162 | |||
| 163 | mutex_lock(&local->iflist_mtx); | ||
| 164 | err = __ieee80211_request_smps(sdata, smps_mode); | ||
| 165 | mutex_unlock(&local->iflist_mtx); | ||
| 166 | |||
| 167 | return err; | ||
| 168 | } | ||
| 169 | |||
| 170 | static const char *smps_modes[IEEE80211_SMPS_NUM_MODES] = { | ||
| 171 | [IEEE80211_SMPS_AUTOMATIC] = "auto", | ||
| 172 | [IEEE80211_SMPS_OFF] = "off", | ||
| 173 | [IEEE80211_SMPS_STATIC] = "static", | ||
| 174 | [IEEE80211_SMPS_DYNAMIC] = "dynamic", | ||
| 175 | }; | ||
| 176 | |||
| 177 | static ssize_t ieee80211_if_fmt_smps(const struct ieee80211_sub_if_data *sdata, | ||
| 178 | char *buf, int buflen) | ||
| 179 | { | ||
| 180 | if (sdata->vif.type != NL80211_IFTYPE_STATION) | ||
| 181 | return -EOPNOTSUPP; | ||
| 182 | |||
| 183 | return snprintf(buf, buflen, "request: %s\nused: %s\n", | ||
| 184 | smps_modes[sdata->u.mgd.req_smps], | ||
| 185 | smps_modes[sdata->u.mgd.ap_smps]); | ||
| 186 | } | ||
| 187 | |||
| 188 | static ssize_t ieee80211_if_parse_smps(struct ieee80211_sub_if_data *sdata, | ||
| 189 | const char *buf, int buflen) | ||
| 190 | { | ||
| 191 | enum ieee80211_smps_mode mode; | ||
| 192 | |||
| 193 | for (mode = 0; mode < IEEE80211_SMPS_NUM_MODES; mode++) { | ||
| 194 | if (strncmp(buf, smps_modes[mode], buflen) == 0) { | ||
| 195 | int err = ieee80211_set_smps(sdata, mode); | ||
| 196 | if (!err) | ||
| 197 | return buflen; | ||
| 198 | return err; | ||
| 199 | } | ||
| 200 | } | ||
| 201 | |||
| 202 | return -EINVAL; | ||
| 203 | } | ||
| 204 | |||
| 205 | __IEEE80211_IF_FILE_W(smps); | ||
| 101 | 206 | ||
| 102 | /* AP attributes */ | 207 | /* AP attributes */ |
| 103 | IEEE80211_IF_FILE(num_sta_ps, u.ap.num_sta_ps, ATOMIC); | 208 | IEEE80211_IF_FILE(num_sta_ps, u.ap.num_sta_ps, ATOMIC); |
| @@ -109,7 +214,7 @@ static ssize_t ieee80211_if_fmt_num_buffered_multicast( | |||
| 109 | return scnprintf(buf, buflen, "%u\n", | 214 | return scnprintf(buf, buflen, "%u\n", |
| 110 | skb_queue_len(&sdata->u.ap.ps_bc_buf)); | 215 | skb_queue_len(&sdata->u.ap.ps_bc_buf)); |
| 111 | } | 216 | } |
| 112 | __IEEE80211_IF_FILE(num_buffered_multicast); | 217 | __IEEE80211_IF_FILE(num_buffered_multicast, NULL); |
| 113 | 218 | ||
| 114 | /* WDS attributes */ | 219 | /* WDS attributes */ |
| 115 | IEEE80211_IF_FILE(peer, u.wds.remote_addr, MAC); | 220 | IEEE80211_IF_FILE(peer, u.wds.remote_addr, MAC); |
| @@ -154,46 +259,50 @@ IEEE80211_IF_FILE(dot11MeshHWMPRootMode, | |||
| 154 | #endif | 259 | #endif |
| 155 | 260 | ||
| 156 | 261 | ||
| 157 | #define DEBUGFS_ADD(name, type) \ | 262 | #define DEBUGFS_ADD(name) \ |
| 158 | debugfs_create_file(#name, 0400, sdata->debugfs.dir, \ | 263 | debugfs_create_file(#name, 0400, sdata->debugfs.dir, \ |
| 159 | sdata, &name##_ops); | 264 | sdata, &name##_ops); |
| 160 | 265 | ||
| 266 | #define DEBUGFS_ADD_MODE(name, mode) \ | ||
| 267 | debugfs_create_file(#name, mode, sdata->debugfs.dir, \ | ||
| 268 | sdata, &name##_ops); | ||
| 269 | |||
| 161 | static void add_sta_files(struct ieee80211_sub_if_data *sdata) | 270 | static void add_sta_files(struct ieee80211_sub_if_data *sdata) |
| 162 | { | 271 | { |
| 163 | DEBUGFS_ADD(drop_unencrypted, sta); | 272 | DEBUGFS_ADD(drop_unencrypted); |
| 164 | DEBUGFS_ADD(force_unicast_rateidx, sta); | 273 | DEBUGFS_ADD(rc_rateidx_mask_2ghz); |
| 165 | DEBUGFS_ADD(max_ratectrl_rateidx, sta); | 274 | DEBUGFS_ADD(rc_rateidx_mask_5ghz); |
| 166 | 275 | ||
| 167 | DEBUGFS_ADD(bssid, sta); | 276 | DEBUGFS_ADD(bssid); |
| 168 | DEBUGFS_ADD(aid, sta); | 277 | DEBUGFS_ADD(aid); |
| 169 | DEBUGFS_ADD(capab, sta); | 278 | DEBUGFS_ADD_MODE(smps, 0600); |
| 170 | } | 279 | } |
| 171 | 280 | ||
| 172 | static void add_ap_files(struct ieee80211_sub_if_data *sdata) | 281 | static void add_ap_files(struct ieee80211_sub_if_data *sdata) |
| 173 | { | 282 | { |
| 174 | DEBUGFS_ADD(drop_unencrypted, ap); | 283 | DEBUGFS_ADD(drop_unencrypted); |
| 175 | DEBUGFS_ADD(force_unicast_rateidx, ap); | 284 | DEBUGFS_ADD(rc_rateidx_mask_2ghz); |
| 176 | DEBUGFS_ADD(max_ratectrl_rateidx, ap); | 285 | DEBUGFS_ADD(rc_rateidx_mask_5ghz); |
| 177 | 286 | ||
| 178 | DEBUGFS_ADD(num_sta_ps, ap); | 287 | DEBUGFS_ADD(num_sta_ps); |
| 179 | DEBUGFS_ADD(dtim_count, ap); | 288 | DEBUGFS_ADD(dtim_count); |
| 180 | DEBUGFS_ADD(num_buffered_multicast, ap); | 289 | DEBUGFS_ADD(num_buffered_multicast); |
| 181 | } | 290 | } |
| 182 | 291 | ||
| 183 | static void add_wds_files(struct ieee80211_sub_if_data *sdata) | 292 | static void add_wds_files(struct ieee80211_sub_if_data *sdata) |
| 184 | { | 293 | { |
| 185 | DEBUGFS_ADD(drop_unencrypted, wds); | 294 | DEBUGFS_ADD(drop_unencrypted); |
| 186 | DEBUGFS_ADD(force_unicast_rateidx, wds); | 295 | DEBUGFS_ADD(rc_rateidx_mask_2ghz); |
| 187 | DEBUGFS_ADD(max_ratectrl_rateidx, wds); | 296 | DEBUGFS_ADD(rc_rateidx_mask_5ghz); |
| 188 | 297 | ||
| 189 | DEBUGFS_ADD(peer, wds); | 298 | DEBUGFS_ADD(peer); |
| 190 | } | 299 | } |
| 191 | 300 | ||
| 192 | static void add_vlan_files(struct ieee80211_sub_if_data *sdata) | 301 | static void add_vlan_files(struct ieee80211_sub_if_data *sdata) |
| 193 | { | 302 | { |
| 194 | DEBUGFS_ADD(drop_unencrypted, vlan); | 303 | DEBUGFS_ADD(drop_unencrypted); |
| 195 | DEBUGFS_ADD(force_unicast_rateidx, vlan); | 304 | DEBUGFS_ADD(rc_rateidx_mask_2ghz); |
| 196 | DEBUGFS_ADD(max_ratectrl_rateidx, vlan); | 305 | DEBUGFS_ADD(rc_rateidx_mask_5ghz); |
| 197 | } | 306 | } |
| 198 | 307 | ||
| 199 | static void add_monitor_files(struct ieee80211_sub_if_data *sdata) | 308 | static void add_monitor_files(struct ieee80211_sub_if_data *sdata) |
| @@ -280,16 +389,11 @@ static void add_files(struct ieee80211_sub_if_data *sdata) | |||
| 280 | } | 389 | } |
| 281 | } | 390 | } |
| 282 | 391 | ||
| 283 | static int notif_registered; | ||
| 284 | |||
| 285 | void ieee80211_debugfs_add_netdev(struct ieee80211_sub_if_data *sdata) | 392 | void ieee80211_debugfs_add_netdev(struct ieee80211_sub_if_data *sdata) |
| 286 | { | 393 | { |
| 287 | char buf[10+IFNAMSIZ]; | 394 | char buf[10+IFNAMSIZ]; |
| 288 | 395 | ||
| 289 | if (!notif_registered) | 396 | sprintf(buf, "netdev:%s", sdata->name); |
| 290 | return; | ||
| 291 | |||
| 292 | sprintf(buf, "netdev:%s", sdata->dev->name); | ||
| 293 | sdata->debugfs.dir = debugfs_create_dir(buf, | 397 | sdata->debugfs.dir = debugfs_create_dir(buf, |
| 294 | sdata->local->hw.wiphy->debugfsdir); | 398 | sdata->local->hw.wiphy->debugfsdir); |
| 295 | add_files(sdata); | 399 | add_files(sdata); |
| @@ -304,58 +408,18 @@ void ieee80211_debugfs_remove_netdev(struct ieee80211_sub_if_data *sdata) | |||
| 304 | sdata->debugfs.dir = NULL; | 408 | sdata->debugfs.dir = NULL; |
| 305 | } | 409 | } |
| 306 | 410 | ||
| 307 | static int netdev_notify(struct notifier_block *nb, | 411 | void ieee80211_debugfs_rename_netdev(struct ieee80211_sub_if_data *sdata) |
| 308 | unsigned long state, | ||
| 309 | void *ndev) | ||
| 310 | { | 412 | { |
| 311 | struct net_device *dev = ndev; | ||
| 312 | struct dentry *dir; | 413 | struct dentry *dir; |
| 313 | struct ieee80211_sub_if_data *sdata; | 414 | char buf[10 + IFNAMSIZ]; |
| 314 | char buf[10+IFNAMSIZ]; | ||
| 315 | |||
| 316 | if (state != NETDEV_CHANGENAME) | ||
| 317 | return 0; | ||
| 318 | |||
| 319 | if (!dev->ieee80211_ptr || !dev->ieee80211_ptr->wiphy) | ||
| 320 | return 0; | ||
| 321 | |||
| 322 | if (dev->ieee80211_ptr->wiphy->privid != mac80211_wiphy_privid) | ||
| 323 | return 0; | ||
| 324 | |||
| 325 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
| 326 | 415 | ||
| 327 | dir = sdata->debugfs.dir; | 416 | dir = sdata->debugfs.dir; |
| 328 | 417 | ||
| 329 | if (!dir) | 418 | if (!dir) |
| 330 | return 0; | 419 | return; |
| 331 | 420 | ||
| 332 | sprintf(buf, "netdev:%s", dev->name); | 421 | sprintf(buf, "netdev:%s", sdata->name); |
| 333 | if (!debugfs_rename(dir->d_parent, dir, dir->d_parent, buf)) | 422 | if (!debugfs_rename(dir->d_parent, dir, dir->d_parent, buf)) |
| 334 | printk(KERN_ERR "mac80211: debugfs: failed to rename debugfs " | 423 | printk(KERN_ERR "mac80211: debugfs: failed to rename debugfs " |
| 335 | "dir to %s\n", buf); | 424 | "dir to %s\n", buf); |
| 336 | |||
| 337 | return 0; | ||
| 338 | } | ||
| 339 | |||
| 340 | static struct notifier_block mac80211_debugfs_netdev_notifier = { | ||
| 341 | .notifier_call = netdev_notify, | ||
| 342 | }; | ||
| 343 | |||
| 344 | void ieee80211_debugfs_netdev_init(void) | ||
| 345 | { | ||
| 346 | int err; | ||
| 347 | |||
| 348 | err = register_netdevice_notifier(&mac80211_debugfs_netdev_notifier); | ||
| 349 | if (err) { | ||
| 350 | printk(KERN_ERR | ||
| 351 | "mac80211: failed to install netdev notifier," | ||
| 352 | " disabling per-netdev debugfs!\n"); | ||
| 353 | } else | ||
| 354 | notif_registered = 1; | ||
| 355 | } | ||
| 356 | |||
| 357 | void ieee80211_debugfs_netdev_exit(void) | ||
| 358 | { | ||
| 359 | unregister_netdevice_notifier(&mac80211_debugfs_netdev_notifier); | ||
| 360 | notif_registered = 0; | ||
| 361 | } | 425 | } |
diff --git a/net/mac80211/debugfs_netdev.h b/net/mac80211/debugfs_netdev.h index 7af731f0b731..79025e79f4d6 100644 --- a/net/mac80211/debugfs_netdev.h +++ b/net/mac80211/debugfs_netdev.h | |||
| @@ -6,8 +6,7 @@ | |||
| 6 | #ifdef CONFIG_MAC80211_DEBUGFS | 6 | #ifdef CONFIG_MAC80211_DEBUGFS |
| 7 | void ieee80211_debugfs_add_netdev(struct ieee80211_sub_if_data *sdata); | 7 | void ieee80211_debugfs_add_netdev(struct ieee80211_sub_if_data *sdata); |
| 8 | void ieee80211_debugfs_remove_netdev(struct ieee80211_sub_if_data *sdata); | 8 | void ieee80211_debugfs_remove_netdev(struct ieee80211_sub_if_data *sdata); |
| 9 | void ieee80211_debugfs_netdev_init(void); | 9 | void ieee80211_debugfs_rename_netdev(struct ieee80211_sub_if_data *sdata); |
| 10 | void ieee80211_debugfs_netdev_exit(void); | ||
| 11 | #else | 10 | #else |
| 12 | static inline void ieee80211_debugfs_add_netdev( | 11 | static inline void ieee80211_debugfs_add_netdev( |
| 13 | struct ieee80211_sub_if_data *sdata) | 12 | struct ieee80211_sub_if_data *sdata) |
| @@ -15,10 +14,8 @@ static inline void ieee80211_debugfs_add_netdev( | |||
| 15 | static inline void ieee80211_debugfs_remove_netdev( | 14 | static inline void ieee80211_debugfs_remove_netdev( |
| 16 | struct ieee80211_sub_if_data *sdata) | 15 | struct ieee80211_sub_if_data *sdata) |
| 17 | {} | 16 | {} |
| 18 | static inline void ieee80211_debugfs_netdev_init(void) | 17 | static inline void ieee80211_debugfs_rename_netdev( |
| 19 | {} | 18 | struct ieee80211_sub_if_data *sdata) |
| 20 | |||
| 21 | static inline void ieee80211_debugfs_netdev_exit(void) | ||
| 22 | {} | 19 | {} |
| 23 | #endif | 20 | #endif |
| 24 | 21 | ||
diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c index 3f41608c8081..d92800bb2d2f 100644 --- a/net/mac80211/debugfs_sta.c +++ b/net/mac80211/debugfs_sta.c | |||
| @@ -44,7 +44,7 @@ static const struct file_operations sta_ ##name## _ops = { \ | |||
| 44 | STA_OPS(name) | 44 | STA_OPS(name) |
| 45 | 45 | ||
| 46 | STA_FILE(aid, sta.aid, D); | 46 | STA_FILE(aid, sta.aid, D); |
| 47 | STA_FILE(dev, sdata->dev->name, S); | 47 | STA_FILE(dev, sdata->name, S); |
| 48 | STA_FILE(rx_packets, rx_packets, LU); | 48 | STA_FILE(rx_packets, rx_packets, LU); |
| 49 | STA_FILE(tx_packets, tx_packets, LU); | 49 | STA_FILE(tx_packets, tx_packets, LU); |
| 50 | STA_FILE(rx_bytes, rx_bytes, LU); | 50 | STA_FILE(rx_bytes, rx_bytes, LU); |
| @@ -120,36 +120,38 @@ STA_OPS(last_seq_ctrl); | |||
| 120 | static ssize_t sta_agg_status_read(struct file *file, char __user *userbuf, | 120 | static ssize_t sta_agg_status_read(struct file *file, char __user *userbuf, |
| 121 | size_t count, loff_t *ppos) | 121 | size_t count, loff_t *ppos) |
| 122 | { | 122 | { |
| 123 | char buf[30 + STA_TID_NUM * 70], *p = buf; | 123 | char buf[64 + STA_TID_NUM * 40], *p = buf; |
| 124 | int i; | 124 | int i; |
| 125 | struct sta_info *sta = file->private_data; | 125 | struct sta_info *sta = file->private_data; |
| 126 | 126 | ||
| 127 | spin_lock_bh(&sta->lock); | 127 | spin_lock_bh(&sta->lock); |
| 128 | p += scnprintf(p, sizeof(buf)+buf-p, "next dialog_token is %#02x\n", | 128 | p += scnprintf(p, sizeof(buf) + buf - p, "next dialog_token: %#02x\n", |
| 129 | sta->ampdu_mlme.dialog_token_allocator + 1); | 129 | sta->ampdu_mlme.dialog_token_allocator + 1); |
| 130 | p += scnprintf(p, sizeof(buf) + buf - p, | ||
| 131 | "TID\t\tRX\tDTKN\tSSN\t\tTX\tDTKN\tSSN\tpending\n"); | ||
| 130 | for (i = 0; i < STA_TID_NUM; i++) { | 132 | for (i = 0; i < STA_TID_NUM; i++) { |
| 131 | p += scnprintf(p, sizeof(buf)+buf-p, "TID %02d:", i); | 133 | p += scnprintf(p, sizeof(buf) + buf - p, "%02d", i); |
| 132 | p += scnprintf(p, sizeof(buf)+buf-p, " RX=%x", | 134 | p += scnprintf(p, sizeof(buf) + buf - p, "\t\t%x", |
| 133 | sta->ampdu_mlme.tid_state_rx[i]); | 135 | sta->ampdu_mlme.tid_state_rx[i]); |
| 134 | p += scnprintf(p, sizeof(buf)+buf-p, "/DTKN=%#.2x", | 136 | p += scnprintf(p, sizeof(buf) + buf - p, "\t%#.2x", |
| 135 | sta->ampdu_mlme.tid_state_rx[i] ? | 137 | sta->ampdu_mlme.tid_state_rx[i] ? |
| 136 | sta->ampdu_mlme.tid_rx[i]->dialog_token : 0); | 138 | sta->ampdu_mlme.tid_rx[i]->dialog_token : 0); |
| 137 | p += scnprintf(p, sizeof(buf)+buf-p, "/SSN=%#.3x", | 139 | p += scnprintf(p, sizeof(buf) + buf - p, "\t%#.3x", |
| 138 | sta->ampdu_mlme.tid_state_rx[i] ? | 140 | sta->ampdu_mlme.tid_state_rx[i] ? |
| 139 | sta->ampdu_mlme.tid_rx[i]->ssn : 0); | 141 | sta->ampdu_mlme.tid_rx[i]->ssn : 0); |
| 140 | 142 | ||
| 141 | p += scnprintf(p, sizeof(buf)+buf-p, " TX=%x", | 143 | p += scnprintf(p, sizeof(buf) + buf - p, "\t\t%x", |
| 142 | sta->ampdu_mlme.tid_state_tx[i]); | 144 | sta->ampdu_mlme.tid_state_tx[i]); |
| 143 | p += scnprintf(p, sizeof(buf)+buf-p, "/DTKN=%#.2x", | 145 | p += scnprintf(p, sizeof(buf) + buf - p, "\t%#.2x", |
| 144 | sta->ampdu_mlme.tid_state_tx[i] ? | 146 | sta->ampdu_mlme.tid_state_tx[i] ? |
| 145 | sta->ampdu_mlme.tid_tx[i]->dialog_token : 0); | 147 | sta->ampdu_mlme.tid_tx[i]->dialog_token : 0); |
| 146 | p += scnprintf(p, sizeof(buf)+buf-p, "/SSN=%#.3x", | 148 | p += scnprintf(p, sizeof(buf) + buf - p, "\t%#.3x", |
| 147 | sta->ampdu_mlme.tid_state_tx[i] ? | 149 | sta->ampdu_mlme.tid_state_tx[i] ? |
| 148 | sta->ampdu_mlme.tid_tx[i]->ssn : 0); | 150 | sta->ampdu_mlme.tid_tx[i]->ssn : 0); |
| 149 | p += scnprintf(p, sizeof(buf)+buf-p, "/pending=%03d", | 151 | p += scnprintf(p, sizeof(buf) + buf - p, "\t%03d", |
| 150 | sta->ampdu_mlme.tid_state_tx[i] ? | 152 | sta->ampdu_mlme.tid_state_tx[i] ? |
| 151 | skb_queue_len(&sta->ampdu_mlme.tid_tx[i]->pending) : 0); | 153 | skb_queue_len(&sta->ampdu_mlme.tid_tx[i]->pending) : 0); |
| 152 | p += scnprintf(p, sizeof(buf)+buf-p, "\n"); | 154 | p += scnprintf(p, sizeof(buf) + buf - p, "\n"); |
| 153 | } | 155 | } |
| 154 | spin_unlock_bh(&sta->lock); | 156 | spin_unlock_bh(&sta->lock); |
| 155 | 157 | ||
| @@ -160,7 +162,12 @@ STA_OPS(agg_status); | |||
| 160 | static ssize_t sta_ht_capa_read(struct file *file, char __user *userbuf, | 162 | static ssize_t sta_ht_capa_read(struct file *file, char __user *userbuf, |
| 161 | size_t count, loff_t *ppos) | 163 | size_t count, loff_t *ppos) |
| 162 | { | 164 | { |
| 163 | char buf[200], *p = buf; | 165 | #define PRINT_HT_CAP(_cond, _str) \ |
| 166 | do { \ | ||
| 167 | if (_cond) \ | ||
| 168 | p += scnprintf(p, sizeof(buf)+buf-p, "\t" _str "\n"); \ | ||
| 169 | } while (0) | ||
| 170 | char buf[512], *p = buf; | ||
| 164 | int i; | 171 | int i; |
| 165 | struct sta_info *sta = file->private_data; | 172 | struct sta_info *sta = file->private_data; |
| 166 | struct ieee80211_sta_ht_cap *htc = &sta->sta.ht_cap; | 173 | struct ieee80211_sta_ht_cap *htc = &sta->sta.ht_cap; |
| @@ -168,15 +175,64 @@ static ssize_t sta_ht_capa_read(struct file *file, char __user *userbuf, | |||
| 168 | p += scnprintf(p, sizeof(buf) + buf - p, "ht %ssupported\n", | 175 | p += scnprintf(p, sizeof(buf) + buf - p, "ht %ssupported\n", |
| 169 | htc->ht_supported ? "" : "not "); | 176 | htc->ht_supported ? "" : "not "); |
| 170 | if (htc->ht_supported) { | 177 | if (htc->ht_supported) { |
| 171 | p += scnprintf(p, sizeof(buf)+buf-p, "cap: %#.2x\n", htc->cap); | 178 | p += scnprintf(p, sizeof(buf)+buf-p, "cap: %#.4x\n", htc->cap); |
| 179 | |||
| 180 | PRINT_HT_CAP((htc->cap & BIT(0)), "RX LDCP"); | ||
| 181 | PRINT_HT_CAP((htc->cap & BIT(1)), "HT20/HT40"); | ||
| 182 | PRINT_HT_CAP(!(htc->cap & BIT(1)), "HT20"); | ||
| 183 | |||
| 184 | PRINT_HT_CAP(((htc->cap >> 2) & 0x3) == 0, "Static SM Power Save"); | ||
| 185 | PRINT_HT_CAP(((htc->cap >> 2) & 0x3) == 1, "Dynamic SM Power Save"); | ||
| 186 | PRINT_HT_CAP(((htc->cap >> 2) & 0x3) == 3, "SM Power Save disabled"); | ||
| 187 | |||
| 188 | PRINT_HT_CAP((htc->cap & BIT(4)), "RX Greenfield"); | ||
| 189 | PRINT_HT_CAP((htc->cap & BIT(5)), "RX HT20 SGI"); | ||
| 190 | PRINT_HT_CAP((htc->cap & BIT(6)), "RX HT40 SGI"); | ||
| 191 | PRINT_HT_CAP((htc->cap & BIT(7)), "TX STBC"); | ||
| 192 | |||
| 193 | PRINT_HT_CAP(((htc->cap >> 8) & 0x3) == 0, "No RX STBC"); | ||
| 194 | PRINT_HT_CAP(((htc->cap >> 8) & 0x3) == 1, "RX STBC 1-stream"); | ||
| 195 | PRINT_HT_CAP(((htc->cap >> 8) & 0x3) == 2, "RX STBC 2-streams"); | ||
| 196 | PRINT_HT_CAP(((htc->cap >> 8) & 0x3) == 3, "RX STBC 3-streams"); | ||
| 197 | |||
| 198 | PRINT_HT_CAP((htc->cap & BIT(10)), "HT Delayed Block Ack"); | ||
| 199 | |||
| 200 | PRINT_HT_CAP((htc->cap & BIT(11)), "Max AMSDU length: " | ||
| 201 | "3839 bytes"); | ||
| 202 | PRINT_HT_CAP(!(htc->cap & BIT(11)), "Max AMSDU length: " | ||
| 203 | "7935 bytes"); | ||
| 204 | |||
| 205 | /* | ||
| 206 | * For beacons and probe response this would mean the BSS | ||
| 207 | * does or does not allow the usage of DSSS/CCK HT40. | ||
| 208 | * Otherwise it means the STA does or does not use | ||
| 209 | * DSSS/CCK HT40. | ||
| 210 | */ | ||
| 211 | PRINT_HT_CAP((htc->cap & BIT(12)), "DSSS/CCK HT40"); | ||
| 212 | PRINT_HT_CAP(!(htc->cap & BIT(12)), "No DSSS/CCK HT40"); | ||
| 213 | |||
| 214 | /* BIT(13) is reserved */ | ||
| 215 | |||
| 216 | PRINT_HT_CAP((htc->cap & BIT(14)), "40 MHz Intolerant"); | ||
| 217 | |||
| 218 | PRINT_HT_CAP((htc->cap & BIT(15)), "L-SIG TXOP protection"); | ||
| 219 | |||
| 172 | p += scnprintf(p, sizeof(buf)+buf-p, "ampdu factor/density: %d/%d\n", | 220 | p += scnprintf(p, sizeof(buf)+buf-p, "ampdu factor/density: %d/%d\n", |
| 173 | htc->ampdu_factor, htc->ampdu_density); | 221 | htc->ampdu_factor, htc->ampdu_density); |
| 174 | p += scnprintf(p, sizeof(buf)+buf-p, "MCS mask:"); | 222 | p += scnprintf(p, sizeof(buf)+buf-p, "MCS mask:"); |
| 223 | |||
| 175 | for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++) | 224 | for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++) |
| 176 | p += scnprintf(p, sizeof(buf)+buf-p, " %.2x", | 225 | p += scnprintf(p, sizeof(buf)+buf-p, " %.2x", |
| 177 | htc->mcs.rx_mask[i]); | 226 | htc->mcs.rx_mask[i]); |
| 178 | p += scnprintf(p, sizeof(buf)+buf-p, "\nMCS rx highest: %d\n", | 227 | p += scnprintf(p, sizeof(buf)+buf-p, "\n"); |
| 179 | le16_to_cpu(htc->mcs.rx_highest)); | 228 | |
| 229 | /* If not set this is meaningless */ | ||
| 230 | if (le16_to_cpu(htc->mcs.rx_highest)) { | ||
| 231 | p += scnprintf(p, sizeof(buf)+buf-p, | ||
| 232 | "MCS rx highest: %d Mbps\n", | ||
| 233 | le16_to_cpu(htc->mcs.rx_highest)); | ||
| 234 | } | ||
| 235 | |||
| 180 | p += scnprintf(p, sizeof(buf)+buf-p, "MCS tx params: %x\n", | 236 | p += scnprintf(p, sizeof(buf)+buf-p, "MCS tx params: %x\n", |
| 181 | htc->mcs.tx_params); | 237 | htc->mcs.tx_params); |
| 182 | } | 238 | } |
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index 921dd9c9ff62..c3d844093a2f 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h | |||
| @@ -14,6 +14,8 @@ static inline int drv_start(struct ieee80211_local *local) | |||
| 14 | { | 14 | { |
| 15 | int ret; | 15 | int ret; |
| 16 | 16 | ||
| 17 | might_sleep(); | ||
| 18 | |||
| 17 | local->started = true; | 19 | local->started = true; |
| 18 | smp_mb(); | 20 | smp_mb(); |
| 19 | ret = local->ops->start(&local->hw); | 21 | ret = local->ops->start(&local->hw); |
| @@ -23,6 +25,8 @@ static inline int drv_start(struct ieee80211_local *local) | |||
| 23 | 25 | ||
| 24 | static inline void drv_stop(struct ieee80211_local *local) | 26 | static inline void drv_stop(struct ieee80211_local *local) |
| 25 | { | 27 | { |
| 28 | might_sleep(); | ||
| 29 | |||
| 26 | local->ops->stop(&local->hw); | 30 | local->ops->stop(&local->hw); |
| 27 | trace_drv_stop(local); | 31 | trace_drv_stop(local); |
| 28 | 32 | ||
| @@ -36,35 +40,47 @@ static inline void drv_stop(struct ieee80211_local *local) | |||
| 36 | } | 40 | } |
| 37 | 41 | ||
| 38 | static inline int drv_add_interface(struct ieee80211_local *local, | 42 | static inline int drv_add_interface(struct ieee80211_local *local, |
| 39 | struct ieee80211_if_init_conf *conf) | 43 | struct ieee80211_vif *vif) |
| 40 | { | 44 | { |
| 41 | int ret = local->ops->add_interface(&local->hw, conf); | 45 | int ret; |
| 42 | trace_drv_add_interface(local, conf->mac_addr, conf->vif, ret); | 46 | |
| 47 | might_sleep(); | ||
| 48 | |||
| 49 | ret = local->ops->add_interface(&local->hw, vif); | ||
| 50 | trace_drv_add_interface(local, vif_to_sdata(vif), ret); | ||
| 43 | return ret; | 51 | return ret; |
| 44 | } | 52 | } |
| 45 | 53 | ||
| 46 | static inline void drv_remove_interface(struct ieee80211_local *local, | 54 | static inline void drv_remove_interface(struct ieee80211_local *local, |
| 47 | struct ieee80211_if_init_conf *conf) | 55 | struct ieee80211_vif *vif) |
| 48 | { | 56 | { |
| 49 | local->ops->remove_interface(&local->hw, conf); | 57 | might_sleep(); |
| 50 | trace_drv_remove_interface(local, conf->mac_addr, conf->vif); | 58 | |
| 59 | local->ops->remove_interface(&local->hw, vif); | ||
| 60 | trace_drv_remove_interface(local, vif_to_sdata(vif)); | ||
| 51 | } | 61 | } |
| 52 | 62 | ||
| 53 | static inline int drv_config(struct ieee80211_local *local, u32 changed) | 63 | static inline int drv_config(struct ieee80211_local *local, u32 changed) |
| 54 | { | 64 | { |
| 55 | int ret = local->ops->config(&local->hw, changed); | 65 | int ret; |
| 66 | |||
| 67 | might_sleep(); | ||
| 68 | |||
| 69 | ret = local->ops->config(&local->hw, changed); | ||
| 56 | trace_drv_config(local, changed, ret); | 70 | trace_drv_config(local, changed, ret); |
| 57 | return ret; | 71 | return ret; |
| 58 | } | 72 | } |
| 59 | 73 | ||
| 60 | static inline void drv_bss_info_changed(struct ieee80211_local *local, | 74 | static inline void drv_bss_info_changed(struct ieee80211_local *local, |
| 61 | struct ieee80211_vif *vif, | 75 | struct ieee80211_sub_if_data *sdata, |
| 62 | struct ieee80211_bss_conf *info, | 76 | struct ieee80211_bss_conf *info, |
| 63 | u32 changed) | 77 | u32 changed) |
| 64 | { | 78 | { |
| 79 | might_sleep(); | ||
| 80 | |||
| 65 | if (local->ops->bss_info_changed) | 81 | if (local->ops->bss_info_changed) |
| 66 | local->ops->bss_info_changed(&local->hw, vif, info, changed); | 82 | local->ops->bss_info_changed(&local->hw, &sdata->vif, info, changed); |
| 67 | trace_drv_bss_info_changed(local, vif, info, changed); | 83 | trace_drv_bss_info_changed(local, sdata, info, changed); |
| 68 | } | 84 | } |
| 69 | 85 | ||
| 70 | static inline u64 drv_prepare_multicast(struct ieee80211_local *local, | 86 | static inline u64 drv_prepare_multicast(struct ieee80211_local *local, |
| @@ -106,36 +122,53 @@ static inline int drv_set_tim(struct ieee80211_local *local, | |||
| 106 | } | 122 | } |
| 107 | 123 | ||
| 108 | static inline int drv_set_key(struct ieee80211_local *local, | 124 | static inline int drv_set_key(struct ieee80211_local *local, |
| 109 | enum set_key_cmd cmd, struct ieee80211_vif *vif, | 125 | enum set_key_cmd cmd, |
| 126 | struct ieee80211_sub_if_data *sdata, | ||
| 110 | struct ieee80211_sta *sta, | 127 | struct ieee80211_sta *sta, |
| 111 | struct ieee80211_key_conf *key) | 128 | struct ieee80211_key_conf *key) |
| 112 | { | 129 | { |
| 113 | int ret = local->ops->set_key(&local->hw, cmd, vif, sta, key); | 130 | int ret; |
| 114 | trace_drv_set_key(local, cmd, vif, sta, key, ret); | 131 | |
| 132 | might_sleep(); | ||
| 133 | |||
| 134 | ret = local->ops->set_key(&local->hw, cmd, &sdata->vif, sta, key); | ||
| 135 | trace_drv_set_key(local, cmd, sdata, sta, key, ret); | ||
| 115 | return ret; | 136 | return ret; |
| 116 | } | 137 | } |
| 117 | 138 | ||
| 118 | static inline void drv_update_tkip_key(struct ieee80211_local *local, | 139 | static inline void drv_update_tkip_key(struct ieee80211_local *local, |
| 140 | struct ieee80211_sub_if_data *sdata, | ||
| 119 | struct ieee80211_key_conf *conf, | 141 | struct ieee80211_key_conf *conf, |
| 120 | const u8 *address, u32 iv32, | 142 | struct sta_info *sta, u32 iv32, |
| 121 | u16 *phase1key) | 143 | u16 *phase1key) |
| 122 | { | 144 | { |
| 145 | struct ieee80211_sta *ista = NULL; | ||
| 146 | |||
| 147 | if (sta) | ||
| 148 | ista = &sta->sta; | ||
| 149 | |||
| 123 | if (local->ops->update_tkip_key) | 150 | if (local->ops->update_tkip_key) |
| 124 | local->ops->update_tkip_key(&local->hw, conf, address, | 151 | local->ops->update_tkip_key(&local->hw, &sdata->vif, conf, |
| 125 | iv32, phase1key); | 152 | ista, iv32, phase1key); |
| 126 | trace_drv_update_tkip_key(local, conf, address, iv32); | 153 | trace_drv_update_tkip_key(local, sdata, conf, ista, iv32); |
| 127 | } | 154 | } |
| 128 | 155 | ||
| 129 | static inline int drv_hw_scan(struct ieee80211_local *local, | 156 | static inline int drv_hw_scan(struct ieee80211_local *local, |
| 130 | struct cfg80211_scan_request *req) | 157 | struct cfg80211_scan_request *req) |
| 131 | { | 158 | { |
| 132 | int ret = local->ops->hw_scan(&local->hw, req); | 159 | int ret; |
| 160 | |||
| 161 | might_sleep(); | ||
| 162 | |||
| 163 | ret = local->ops->hw_scan(&local->hw, req); | ||
| 133 | trace_drv_hw_scan(local, req, ret); | 164 | trace_drv_hw_scan(local, req, ret); |
| 134 | return ret; | 165 | return ret; |
| 135 | } | 166 | } |
| 136 | 167 | ||
| 137 | static inline void drv_sw_scan_start(struct ieee80211_local *local) | 168 | static inline void drv_sw_scan_start(struct ieee80211_local *local) |
| 138 | { | 169 | { |
| 170 | might_sleep(); | ||
| 171 | |||
| 139 | if (local->ops->sw_scan_start) | 172 | if (local->ops->sw_scan_start) |
| 140 | local->ops->sw_scan_start(&local->hw); | 173 | local->ops->sw_scan_start(&local->hw); |
| 141 | trace_drv_sw_scan_start(local); | 174 | trace_drv_sw_scan_start(local); |
| @@ -143,6 +176,8 @@ static inline void drv_sw_scan_start(struct ieee80211_local *local) | |||
| 143 | 176 | ||
| 144 | static inline void drv_sw_scan_complete(struct ieee80211_local *local) | 177 | static inline void drv_sw_scan_complete(struct ieee80211_local *local) |
| 145 | { | 178 | { |
| 179 | might_sleep(); | ||
| 180 | |||
| 146 | if (local->ops->sw_scan_complete) | 181 | if (local->ops->sw_scan_complete) |
| 147 | local->ops->sw_scan_complete(&local->hw); | 182 | local->ops->sw_scan_complete(&local->hw); |
| 148 | trace_drv_sw_scan_complete(local); | 183 | trace_drv_sw_scan_complete(local); |
| @@ -153,6 +188,8 @@ static inline int drv_get_stats(struct ieee80211_local *local, | |||
| 153 | { | 188 | { |
| 154 | int ret = -EOPNOTSUPP; | 189 | int ret = -EOPNOTSUPP; |
| 155 | 190 | ||
| 191 | might_sleep(); | ||
| 192 | |||
| 156 | if (local->ops->get_stats) | 193 | if (local->ops->get_stats) |
| 157 | ret = local->ops->get_stats(&local->hw, stats); | 194 | ret = local->ops->get_stats(&local->hw, stats); |
| 158 | trace_drv_get_stats(local, stats, ret); | 195 | trace_drv_get_stats(local, stats, ret); |
| @@ -172,43 +209,93 @@ static inline int drv_set_rts_threshold(struct ieee80211_local *local, | |||
| 172 | u32 value) | 209 | u32 value) |
| 173 | { | 210 | { |
| 174 | int ret = 0; | 211 | int ret = 0; |
| 212 | |||
| 213 | might_sleep(); | ||
| 214 | |||
| 175 | if (local->ops->set_rts_threshold) | 215 | if (local->ops->set_rts_threshold) |
| 176 | ret = local->ops->set_rts_threshold(&local->hw, value); | 216 | ret = local->ops->set_rts_threshold(&local->hw, value); |
| 177 | trace_drv_set_rts_threshold(local, value, ret); | 217 | trace_drv_set_rts_threshold(local, value, ret); |
| 178 | return ret; | 218 | return ret; |
| 179 | } | 219 | } |
| 180 | 220 | ||
| 221 | static inline int drv_set_coverage_class(struct ieee80211_local *local, | ||
| 222 | u8 value) | ||
| 223 | { | ||
| 224 | int ret = 0; | ||
| 225 | might_sleep(); | ||
| 226 | |||
| 227 | if (local->ops->set_coverage_class) | ||
| 228 | local->ops->set_coverage_class(&local->hw, value); | ||
| 229 | else | ||
| 230 | ret = -EOPNOTSUPP; | ||
| 231 | |||
| 232 | trace_drv_set_coverage_class(local, value, ret); | ||
| 233 | return ret; | ||
| 234 | } | ||
| 235 | |||
| 181 | static inline void drv_sta_notify(struct ieee80211_local *local, | 236 | static inline void drv_sta_notify(struct ieee80211_local *local, |
| 182 | struct ieee80211_vif *vif, | 237 | struct ieee80211_sub_if_data *sdata, |
| 183 | enum sta_notify_cmd cmd, | 238 | enum sta_notify_cmd cmd, |
| 184 | struct ieee80211_sta *sta) | 239 | struct ieee80211_sta *sta) |
| 185 | { | 240 | { |
| 186 | if (local->ops->sta_notify) | 241 | if (local->ops->sta_notify) |
| 187 | local->ops->sta_notify(&local->hw, vif, cmd, sta); | 242 | local->ops->sta_notify(&local->hw, &sdata->vif, cmd, sta); |
| 188 | trace_drv_sta_notify(local, vif, cmd, sta); | 243 | trace_drv_sta_notify(local, sdata, cmd, sta); |
| 244 | } | ||
| 245 | |||
| 246 | static inline int drv_sta_add(struct ieee80211_local *local, | ||
| 247 | struct ieee80211_sub_if_data *sdata, | ||
| 248 | struct ieee80211_sta *sta) | ||
| 249 | { | ||
| 250 | int ret = 0; | ||
| 251 | |||
| 252 | might_sleep(); | ||
| 253 | |||
| 254 | if (local->ops->sta_add) | ||
| 255 | ret = local->ops->sta_add(&local->hw, &sdata->vif, sta); | ||
| 256 | else if (local->ops->sta_notify) | ||
| 257 | local->ops->sta_notify(&local->hw, &sdata->vif, | ||
| 258 | STA_NOTIFY_ADD, sta); | ||
| 259 | |||
| 260 | trace_drv_sta_add(local, sdata, sta, ret); | ||
| 261 | |||
| 262 | return ret; | ||
| 263 | } | ||
| 264 | |||
| 265 | static inline void drv_sta_remove(struct ieee80211_local *local, | ||
| 266 | struct ieee80211_sub_if_data *sdata, | ||
| 267 | struct ieee80211_sta *sta) | ||
| 268 | { | ||
| 269 | might_sleep(); | ||
| 270 | |||
| 271 | if (local->ops->sta_remove) | ||
| 272 | local->ops->sta_remove(&local->hw, &sdata->vif, sta); | ||
| 273 | else if (local->ops->sta_notify) | ||
| 274 | local->ops->sta_notify(&local->hw, &sdata->vif, | ||
| 275 | STA_NOTIFY_REMOVE, sta); | ||
| 276 | |||
| 277 | trace_drv_sta_remove(local, sdata, sta); | ||
| 189 | } | 278 | } |
| 190 | 279 | ||
| 191 | static inline int drv_conf_tx(struct ieee80211_local *local, u16 queue, | 280 | static inline int drv_conf_tx(struct ieee80211_local *local, u16 queue, |
| 192 | const struct ieee80211_tx_queue_params *params) | 281 | const struct ieee80211_tx_queue_params *params) |
| 193 | { | 282 | { |
| 194 | int ret = -EOPNOTSUPP; | 283 | int ret = -EOPNOTSUPP; |
| 284 | |||
| 285 | might_sleep(); | ||
| 286 | |||
| 195 | if (local->ops->conf_tx) | 287 | if (local->ops->conf_tx) |
| 196 | ret = local->ops->conf_tx(&local->hw, queue, params); | 288 | ret = local->ops->conf_tx(&local->hw, queue, params); |
| 197 | trace_drv_conf_tx(local, queue, params, ret); | 289 | trace_drv_conf_tx(local, queue, params, ret); |
| 198 | return ret; | 290 | return ret; |
| 199 | } | 291 | } |
| 200 | 292 | ||
| 201 | static inline int drv_get_tx_stats(struct ieee80211_local *local, | ||
| 202 | struct ieee80211_tx_queue_stats *stats) | ||
| 203 | { | ||
| 204 | int ret = local->ops->get_tx_stats(&local->hw, stats); | ||
| 205 | trace_drv_get_tx_stats(local, stats, ret); | ||
| 206 | return ret; | ||
| 207 | } | ||
| 208 | |||
| 209 | static inline u64 drv_get_tsf(struct ieee80211_local *local) | 293 | static inline u64 drv_get_tsf(struct ieee80211_local *local) |
| 210 | { | 294 | { |
| 211 | u64 ret = -1ULL; | 295 | u64 ret = -1ULL; |
| 296 | |||
| 297 | might_sleep(); | ||
| 298 | |||
| 212 | if (local->ops->get_tsf) | 299 | if (local->ops->get_tsf) |
| 213 | ret = local->ops->get_tsf(&local->hw); | 300 | ret = local->ops->get_tsf(&local->hw); |
| 214 | trace_drv_get_tsf(local, ret); | 301 | trace_drv_get_tsf(local, ret); |
| @@ -217,6 +304,8 @@ static inline u64 drv_get_tsf(struct ieee80211_local *local) | |||
| 217 | 304 | ||
| 218 | static inline void drv_set_tsf(struct ieee80211_local *local, u64 tsf) | 305 | static inline void drv_set_tsf(struct ieee80211_local *local, u64 tsf) |
| 219 | { | 306 | { |
| 307 | might_sleep(); | ||
| 308 | |||
| 220 | if (local->ops->set_tsf) | 309 | if (local->ops->set_tsf) |
| 221 | local->ops->set_tsf(&local->hw, tsf); | 310 | local->ops->set_tsf(&local->hw, tsf); |
| 222 | trace_drv_set_tsf(local, tsf); | 311 | trace_drv_set_tsf(local, tsf); |
| @@ -224,6 +313,8 @@ static inline void drv_set_tsf(struct ieee80211_local *local, u64 tsf) | |||
| 224 | 313 | ||
| 225 | static inline void drv_reset_tsf(struct ieee80211_local *local) | 314 | static inline void drv_reset_tsf(struct ieee80211_local *local) |
| 226 | { | 315 | { |
| 316 | might_sleep(); | ||
| 317 | |||
| 227 | if (local->ops->reset_tsf) | 318 | if (local->ops->reset_tsf) |
| 228 | local->ops->reset_tsf(&local->hw); | 319 | local->ops->reset_tsf(&local->hw); |
| 229 | trace_drv_reset_tsf(local); | 320 | trace_drv_reset_tsf(local); |
| @@ -232,6 +323,9 @@ static inline void drv_reset_tsf(struct ieee80211_local *local) | |||
| 232 | static inline int drv_tx_last_beacon(struct ieee80211_local *local) | 323 | static inline int drv_tx_last_beacon(struct ieee80211_local *local) |
| 233 | { | 324 | { |
| 234 | int ret = 1; | 325 | int ret = 1; |
| 326 | |||
| 327 | might_sleep(); | ||
| 328 | |||
| 235 | if (local->ops->tx_last_beacon) | 329 | if (local->ops->tx_last_beacon) |
| 236 | ret = local->ops->tx_last_beacon(&local->hw); | 330 | ret = local->ops->tx_last_beacon(&local->hw); |
| 237 | trace_drv_tx_last_beacon(local, ret); | 331 | trace_drv_tx_last_beacon(local, ret); |
| @@ -239,23 +333,34 @@ static inline int drv_tx_last_beacon(struct ieee80211_local *local) | |||
| 239 | } | 333 | } |
| 240 | 334 | ||
| 241 | static inline int drv_ampdu_action(struct ieee80211_local *local, | 335 | static inline int drv_ampdu_action(struct ieee80211_local *local, |
| 242 | struct ieee80211_vif *vif, | 336 | struct ieee80211_sub_if_data *sdata, |
| 243 | enum ieee80211_ampdu_mlme_action action, | 337 | enum ieee80211_ampdu_mlme_action action, |
| 244 | struct ieee80211_sta *sta, u16 tid, | 338 | struct ieee80211_sta *sta, u16 tid, |
| 245 | u16 *ssn) | 339 | u16 *ssn) |
| 246 | { | 340 | { |
| 247 | int ret = -EOPNOTSUPP; | 341 | int ret = -EOPNOTSUPP; |
| 248 | if (local->ops->ampdu_action) | 342 | if (local->ops->ampdu_action) |
| 249 | ret = local->ops->ampdu_action(&local->hw, vif, action, | 343 | ret = local->ops->ampdu_action(&local->hw, &sdata->vif, action, |
| 250 | sta, tid, ssn); | 344 | sta, tid, ssn); |
| 251 | trace_drv_ampdu_action(local, vif, action, sta, tid, ssn, ret); | 345 | trace_drv_ampdu_action(local, sdata, action, sta, tid, ssn, ret); |
| 252 | return ret; | 346 | return ret; |
| 253 | } | 347 | } |
| 254 | 348 | ||
| 255 | 349 | ||
| 256 | static inline void drv_rfkill_poll(struct ieee80211_local *local) | 350 | static inline void drv_rfkill_poll(struct ieee80211_local *local) |
| 257 | { | 351 | { |
| 352 | might_sleep(); | ||
| 353 | |||
| 258 | if (local->ops->rfkill_poll) | 354 | if (local->ops->rfkill_poll) |
| 259 | local->ops->rfkill_poll(&local->hw); | 355 | local->ops->rfkill_poll(&local->hw); |
| 260 | } | 356 | } |
| 357 | |||
| 358 | static inline void drv_flush(struct ieee80211_local *local, bool drop) | ||
| 359 | { | ||
| 360 | might_sleep(); | ||
| 361 | |||
| 362 | trace_drv_flush(local, drop); | ||
| 363 | if (local->ops->flush) | ||
| 364 | local->ops->flush(&local->hw, drop); | ||
| 365 | } | ||
| 261 | #endif /* __MAC80211_DRIVER_OPS */ | 366 | #endif /* __MAC80211_DRIVER_OPS */ |
diff --git a/net/mac80211/driver-trace.h b/net/mac80211/driver-trace.h index da8497ef7063..41baf730a5c7 100644 --- a/net/mac80211/driver-trace.h +++ b/net/mac80211/driver-trace.h | |||
| @@ -25,10 +25,12 @@ static inline void trace_ ## name(proto) {} | |||
| 25 | #define STA_PR_FMT " sta:%pM" | 25 | #define STA_PR_FMT " sta:%pM" |
| 26 | #define STA_PR_ARG __entry->sta_addr | 26 | #define STA_PR_ARG __entry->sta_addr |
| 27 | 27 | ||
| 28 | #define VIF_ENTRY __field(enum nl80211_iftype, vif_type) __field(void *, vif) | 28 | #define VIF_ENTRY __field(enum nl80211_iftype, vif_type) __field(void *, sdata) \ |
| 29 | #define VIF_ASSIGN __entry->vif_type = vif ? vif->type : 0; __entry->vif = vif | 29 | __string(vif_name, sdata->dev ? sdata->dev->name : "<nodev>") |
| 30 | #define VIF_PR_FMT " vif:%p(%d)" | 30 | #define VIF_ASSIGN __entry->vif_type = sdata->vif.type; __entry->sdata = sdata; \ |
| 31 | #define VIF_PR_ARG __entry->vif, __entry->vif_type | 31 | __assign_str(vif_name, sdata->dev ? sdata->dev->name : "<nodev>") |
| 32 | #define VIF_PR_FMT " vif:%s(%d)" | ||
| 33 | #define VIF_PR_ARG __get_str(vif_name), __entry->vif_type | ||
| 32 | 34 | ||
| 33 | TRACE_EVENT(drv_start, | 35 | TRACE_EVENT(drv_start, |
| 34 | TP_PROTO(struct ieee80211_local *local, int ret), | 36 | TP_PROTO(struct ieee80211_local *local, int ret), |
| @@ -70,11 +72,10 @@ TRACE_EVENT(drv_stop, | |||
| 70 | 72 | ||
| 71 | TRACE_EVENT(drv_add_interface, | 73 | TRACE_EVENT(drv_add_interface, |
| 72 | TP_PROTO(struct ieee80211_local *local, | 74 | TP_PROTO(struct ieee80211_local *local, |
| 73 | const u8 *addr, | 75 | struct ieee80211_sub_if_data *sdata, |
| 74 | struct ieee80211_vif *vif, | ||
| 75 | int ret), | 76 | int ret), |
| 76 | 77 | ||
| 77 | TP_ARGS(local, addr, vif, ret), | 78 | TP_ARGS(local, sdata, ret), |
| 78 | 79 | ||
| 79 | TP_STRUCT__entry( | 80 | TP_STRUCT__entry( |
| 80 | LOCAL_ENTRY | 81 | LOCAL_ENTRY |
| @@ -86,7 +87,7 @@ TRACE_EVENT(drv_add_interface, | |||
| 86 | TP_fast_assign( | 87 | TP_fast_assign( |
| 87 | LOCAL_ASSIGN; | 88 | LOCAL_ASSIGN; |
| 88 | VIF_ASSIGN; | 89 | VIF_ASSIGN; |
| 89 | memcpy(__entry->addr, addr, 6); | 90 | memcpy(__entry->addr, sdata->vif.addr, 6); |
| 90 | __entry->ret = ret; | 91 | __entry->ret = ret; |
| 91 | ), | 92 | ), |
| 92 | 93 | ||
| @@ -97,10 +98,9 @@ TRACE_EVENT(drv_add_interface, | |||
| 97 | ); | 98 | ); |
| 98 | 99 | ||
| 99 | TRACE_EVENT(drv_remove_interface, | 100 | TRACE_EVENT(drv_remove_interface, |
| 100 | TP_PROTO(struct ieee80211_local *local, | 101 | TP_PROTO(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata), |
| 101 | const u8 *addr, struct ieee80211_vif *vif), | ||
| 102 | 102 | ||
| 103 | TP_ARGS(local, addr, vif), | 103 | TP_ARGS(local, sdata), |
| 104 | 104 | ||
| 105 | TP_STRUCT__entry( | 105 | TP_STRUCT__entry( |
| 106 | LOCAL_ENTRY | 106 | LOCAL_ENTRY |
| @@ -111,7 +111,7 @@ TRACE_EVENT(drv_remove_interface, | |||
| 111 | TP_fast_assign( | 111 | TP_fast_assign( |
| 112 | LOCAL_ASSIGN; | 112 | LOCAL_ASSIGN; |
| 113 | VIF_ASSIGN; | 113 | VIF_ASSIGN; |
| 114 | memcpy(__entry->addr, addr, 6); | 114 | memcpy(__entry->addr, sdata->vif.addr, 6); |
| 115 | ), | 115 | ), |
| 116 | 116 | ||
| 117 | TP_printk( | 117 | TP_printk( |
| @@ -140,6 +140,7 @@ TRACE_EVENT(drv_config, | |||
| 140 | __field(u8, short_frame_max_tx_count) | 140 | __field(u8, short_frame_max_tx_count) |
| 141 | __field(int, center_freq) | 141 | __field(int, center_freq) |
| 142 | __field(int, channel_type) | 142 | __field(int, channel_type) |
| 143 | __field(int, smps) | ||
| 143 | ), | 144 | ), |
| 144 | 145 | ||
| 145 | TP_fast_assign( | 146 | TP_fast_assign( |
| @@ -155,6 +156,7 @@ TRACE_EVENT(drv_config, | |||
| 155 | __entry->short_frame_max_tx_count = local->hw.conf.short_frame_max_tx_count; | 156 | __entry->short_frame_max_tx_count = local->hw.conf.short_frame_max_tx_count; |
| 156 | __entry->center_freq = local->hw.conf.channel->center_freq; | 157 | __entry->center_freq = local->hw.conf.channel->center_freq; |
| 157 | __entry->channel_type = local->hw.conf.channel_type; | 158 | __entry->channel_type = local->hw.conf.channel_type; |
| 159 | __entry->smps = local->hw.conf.smps_mode; | ||
| 158 | ), | 160 | ), |
| 159 | 161 | ||
| 160 | TP_printk( | 162 | TP_printk( |
| @@ -165,11 +167,11 @@ TRACE_EVENT(drv_config, | |||
| 165 | 167 | ||
| 166 | TRACE_EVENT(drv_bss_info_changed, | 168 | TRACE_EVENT(drv_bss_info_changed, |
| 167 | TP_PROTO(struct ieee80211_local *local, | 169 | TP_PROTO(struct ieee80211_local *local, |
| 168 | struct ieee80211_vif *vif, | 170 | struct ieee80211_sub_if_data *sdata, |
| 169 | struct ieee80211_bss_conf *info, | 171 | struct ieee80211_bss_conf *info, |
| 170 | u32 changed), | 172 | u32 changed), |
| 171 | 173 | ||
| 172 | TP_ARGS(local, vif, info, changed), | 174 | TP_ARGS(local, sdata, info, changed), |
| 173 | 175 | ||
| 174 | TP_STRUCT__entry( | 176 | TP_STRUCT__entry( |
| 175 | LOCAL_ENTRY | 177 | LOCAL_ENTRY |
| @@ -293,11 +295,11 @@ TRACE_EVENT(drv_set_tim, | |||
| 293 | 295 | ||
| 294 | TRACE_EVENT(drv_set_key, | 296 | TRACE_EVENT(drv_set_key, |
| 295 | TP_PROTO(struct ieee80211_local *local, | 297 | TP_PROTO(struct ieee80211_local *local, |
| 296 | enum set_key_cmd cmd, struct ieee80211_vif *vif, | 298 | enum set_key_cmd cmd, struct ieee80211_sub_if_data *sdata, |
| 297 | struct ieee80211_sta *sta, | 299 | struct ieee80211_sta *sta, |
| 298 | struct ieee80211_key_conf *key, int ret), | 300 | struct ieee80211_key_conf *key, int ret), |
| 299 | 301 | ||
| 300 | TP_ARGS(local, cmd, vif, sta, key, ret), | 302 | TP_ARGS(local, cmd, sdata, sta, key, ret), |
| 301 | 303 | ||
| 302 | TP_STRUCT__entry( | 304 | TP_STRUCT__entry( |
| 303 | LOCAL_ENTRY | 305 | LOCAL_ENTRY |
| @@ -329,26 +331,29 @@ TRACE_EVENT(drv_set_key, | |||
| 329 | 331 | ||
| 330 | TRACE_EVENT(drv_update_tkip_key, | 332 | TRACE_EVENT(drv_update_tkip_key, |
| 331 | TP_PROTO(struct ieee80211_local *local, | 333 | TP_PROTO(struct ieee80211_local *local, |
| 334 | struct ieee80211_sub_if_data *sdata, | ||
| 332 | struct ieee80211_key_conf *conf, | 335 | struct ieee80211_key_conf *conf, |
| 333 | const u8 *address, u32 iv32), | 336 | struct ieee80211_sta *sta, u32 iv32), |
| 334 | 337 | ||
| 335 | TP_ARGS(local, conf, address, iv32), | 338 | TP_ARGS(local, sdata, conf, sta, iv32), |
| 336 | 339 | ||
| 337 | TP_STRUCT__entry( | 340 | TP_STRUCT__entry( |
| 338 | LOCAL_ENTRY | 341 | LOCAL_ENTRY |
| 339 | __array(u8, addr, 6) | 342 | VIF_ENTRY |
| 343 | STA_ENTRY | ||
| 340 | __field(u32, iv32) | 344 | __field(u32, iv32) |
| 341 | ), | 345 | ), |
| 342 | 346 | ||
| 343 | TP_fast_assign( | 347 | TP_fast_assign( |
| 344 | LOCAL_ASSIGN; | 348 | LOCAL_ASSIGN; |
| 345 | memcpy(__entry->addr, address, 6); | 349 | VIF_ASSIGN; |
| 350 | STA_ASSIGN; | ||
| 346 | __entry->iv32 = iv32; | 351 | __entry->iv32 = iv32; |
| 347 | ), | 352 | ), |
| 348 | 353 | ||
| 349 | TP_printk( | 354 | TP_printk( |
| 350 | LOCAL_PR_FMT " addr:%pM iv32:%#x", | 355 | LOCAL_PR_FMT VIF_PR_FMT STA_PR_FMT " iv32:%#x", |
| 351 | LOCAL_PR_ARG, __entry->addr, __entry->iv32 | 356 | LOCAL_PR_ARG,VIF_PR_ARG,STA_PR_ARG, __entry->iv32 |
| 352 | ) | 357 | ) |
| 353 | ); | 358 | ); |
| 354 | 359 | ||
| @@ -489,13 +494,36 @@ TRACE_EVENT(drv_set_rts_threshold, | |||
| 489 | ) | 494 | ) |
| 490 | ); | 495 | ); |
| 491 | 496 | ||
| 497 | TRACE_EVENT(drv_set_coverage_class, | ||
| 498 | TP_PROTO(struct ieee80211_local *local, u8 value, int ret), | ||
| 499 | |||
| 500 | TP_ARGS(local, value, ret), | ||
| 501 | |||
| 502 | TP_STRUCT__entry( | ||
| 503 | LOCAL_ENTRY | ||
| 504 | __field(u8, value) | ||
| 505 | __field(int, ret) | ||
| 506 | ), | ||
| 507 | |||
| 508 | TP_fast_assign( | ||
| 509 | LOCAL_ASSIGN; | ||
| 510 | __entry->ret = ret; | ||
| 511 | __entry->value = value; | ||
| 512 | ), | ||
| 513 | |||
| 514 | TP_printk( | ||
| 515 | LOCAL_PR_FMT " value:%d ret:%d", | ||
| 516 | LOCAL_PR_ARG, __entry->value, __entry->ret | ||
| 517 | ) | ||
| 518 | ); | ||
| 519 | |||
| 492 | TRACE_EVENT(drv_sta_notify, | 520 | TRACE_EVENT(drv_sta_notify, |
| 493 | TP_PROTO(struct ieee80211_local *local, | 521 | TP_PROTO(struct ieee80211_local *local, |
| 494 | struct ieee80211_vif *vif, | 522 | struct ieee80211_sub_if_data *sdata, |
| 495 | enum sta_notify_cmd cmd, | 523 | enum sta_notify_cmd cmd, |
| 496 | struct ieee80211_sta *sta), | 524 | struct ieee80211_sta *sta), |
| 497 | 525 | ||
| 498 | TP_ARGS(local, vif, cmd, sta), | 526 | TP_ARGS(local, sdata, cmd, sta), |
| 499 | 527 | ||
| 500 | TP_STRUCT__entry( | 528 | TP_STRUCT__entry( |
| 501 | LOCAL_ENTRY | 529 | LOCAL_ENTRY |
| @@ -517,59 +545,88 @@ TRACE_EVENT(drv_sta_notify, | |||
| 517 | ) | 545 | ) |
| 518 | ); | 546 | ); |
| 519 | 547 | ||
| 520 | TRACE_EVENT(drv_conf_tx, | 548 | TRACE_EVENT(drv_sta_add, |
| 521 | TP_PROTO(struct ieee80211_local *local, u16 queue, | 549 | TP_PROTO(struct ieee80211_local *local, |
| 522 | const struct ieee80211_tx_queue_params *params, | 550 | struct ieee80211_sub_if_data *sdata, |
| 523 | int ret), | 551 | struct ieee80211_sta *sta, int ret), |
| 524 | 552 | ||
| 525 | TP_ARGS(local, queue, params, ret), | 553 | TP_ARGS(local, sdata, sta, ret), |
| 526 | 554 | ||
| 527 | TP_STRUCT__entry( | 555 | TP_STRUCT__entry( |
| 528 | LOCAL_ENTRY | 556 | LOCAL_ENTRY |
| 529 | __field(u16, queue) | 557 | VIF_ENTRY |
| 530 | __field(u16, txop) | 558 | STA_ENTRY |
| 531 | __field(u16, cw_min) | ||
| 532 | __field(u16, cw_max) | ||
| 533 | __field(u8, aifs) | ||
| 534 | __field(int, ret) | 559 | __field(int, ret) |
| 535 | ), | 560 | ), |
| 536 | 561 | ||
| 537 | TP_fast_assign( | 562 | TP_fast_assign( |
| 538 | LOCAL_ASSIGN; | 563 | LOCAL_ASSIGN; |
| 539 | __entry->queue = queue; | 564 | VIF_ASSIGN; |
| 565 | STA_ASSIGN; | ||
| 540 | __entry->ret = ret; | 566 | __entry->ret = ret; |
| 541 | __entry->txop = params->txop; | ||
| 542 | __entry->cw_max = params->cw_max; | ||
| 543 | __entry->cw_min = params->cw_min; | ||
| 544 | __entry->aifs = params->aifs; | ||
| 545 | ), | 567 | ), |
| 546 | 568 | ||
| 547 | TP_printk( | 569 | TP_printk( |
| 548 | LOCAL_PR_FMT " queue:%d ret:%d", | 570 | LOCAL_PR_FMT VIF_PR_FMT STA_PR_FMT " ret:%d", |
| 549 | LOCAL_PR_ARG, __entry->queue, __entry->ret | 571 | LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG, __entry->ret |
| 550 | ) | 572 | ) |
| 551 | ); | 573 | ); |
| 552 | 574 | ||
| 553 | TRACE_EVENT(drv_get_tx_stats, | 575 | TRACE_EVENT(drv_sta_remove, |
| 554 | TP_PROTO(struct ieee80211_local *local, | 576 | TP_PROTO(struct ieee80211_local *local, |
| 555 | struct ieee80211_tx_queue_stats *stats, | 577 | struct ieee80211_sub_if_data *sdata, |
| 578 | struct ieee80211_sta *sta), | ||
| 579 | |||
| 580 | TP_ARGS(local, sdata, sta), | ||
| 581 | |||
| 582 | TP_STRUCT__entry( | ||
| 583 | LOCAL_ENTRY | ||
| 584 | VIF_ENTRY | ||
| 585 | STA_ENTRY | ||
| 586 | ), | ||
| 587 | |||
| 588 | TP_fast_assign( | ||
| 589 | LOCAL_ASSIGN; | ||
| 590 | VIF_ASSIGN; | ||
| 591 | STA_ASSIGN; | ||
| 592 | ), | ||
| 593 | |||
| 594 | TP_printk( | ||
| 595 | LOCAL_PR_FMT VIF_PR_FMT STA_PR_FMT, | ||
| 596 | LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG | ||
| 597 | ) | ||
| 598 | ); | ||
| 599 | |||
| 600 | TRACE_EVENT(drv_conf_tx, | ||
| 601 | TP_PROTO(struct ieee80211_local *local, u16 queue, | ||
| 602 | const struct ieee80211_tx_queue_params *params, | ||
| 556 | int ret), | 603 | int ret), |
| 557 | 604 | ||
| 558 | TP_ARGS(local, stats, ret), | 605 | TP_ARGS(local, queue, params, ret), |
| 559 | 606 | ||
| 560 | TP_STRUCT__entry( | 607 | TP_STRUCT__entry( |
| 561 | LOCAL_ENTRY | 608 | LOCAL_ENTRY |
| 609 | __field(u16, queue) | ||
| 610 | __field(u16, txop) | ||
| 611 | __field(u16, cw_min) | ||
| 612 | __field(u16, cw_max) | ||
| 613 | __field(u8, aifs) | ||
| 562 | __field(int, ret) | 614 | __field(int, ret) |
| 563 | ), | 615 | ), |
| 564 | 616 | ||
| 565 | TP_fast_assign( | 617 | TP_fast_assign( |
| 566 | LOCAL_ASSIGN; | 618 | LOCAL_ASSIGN; |
| 619 | __entry->queue = queue; | ||
| 567 | __entry->ret = ret; | 620 | __entry->ret = ret; |
| 621 | __entry->txop = params->txop; | ||
| 622 | __entry->cw_max = params->cw_max; | ||
| 623 | __entry->cw_min = params->cw_min; | ||
| 624 | __entry->aifs = params->aifs; | ||
| 568 | ), | 625 | ), |
| 569 | 626 | ||
| 570 | TP_printk( | 627 | TP_printk( |
| 571 | LOCAL_PR_FMT " ret:%d", | 628 | LOCAL_PR_FMT " queue:%d ret:%d", |
| 572 | LOCAL_PR_ARG, __entry->ret | 629 | LOCAL_PR_ARG, __entry->queue, __entry->ret |
| 573 | ) | 630 | ) |
| 574 | ); | 631 | ); |
| 575 | 632 | ||
| @@ -656,12 +713,12 @@ TRACE_EVENT(drv_tx_last_beacon, | |||
| 656 | 713 | ||
| 657 | TRACE_EVENT(drv_ampdu_action, | 714 | TRACE_EVENT(drv_ampdu_action, |
| 658 | TP_PROTO(struct ieee80211_local *local, | 715 | TP_PROTO(struct ieee80211_local *local, |
| 659 | struct ieee80211_vif *vif, | 716 | struct ieee80211_sub_if_data *sdata, |
| 660 | enum ieee80211_ampdu_mlme_action action, | 717 | enum ieee80211_ampdu_mlme_action action, |
| 661 | struct ieee80211_sta *sta, u16 tid, | 718 | struct ieee80211_sta *sta, u16 tid, |
| 662 | u16 *ssn, int ret), | 719 | u16 *ssn, int ret), |
| 663 | 720 | ||
| 664 | TP_ARGS(local, vif, action, sta, tid, ssn, ret), | 721 | TP_ARGS(local, sdata, action, sta, tid, ssn, ret), |
| 665 | 722 | ||
| 666 | TP_STRUCT__entry( | 723 | TP_STRUCT__entry( |
| 667 | LOCAL_ENTRY | 724 | LOCAL_ENTRY |
| @@ -688,6 +745,27 @@ TRACE_EVENT(drv_ampdu_action, | |||
| 688 | LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG, __entry->action, __entry->tid, __entry->ret | 745 | LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG, __entry->action, __entry->tid, __entry->ret |
| 689 | ) | 746 | ) |
| 690 | ); | 747 | ); |
| 748 | |||
| 749 | TRACE_EVENT(drv_flush, | ||
| 750 | TP_PROTO(struct ieee80211_local *local, bool drop), | ||
| 751 | |||
| 752 | TP_ARGS(local, drop), | ||
| 753 | |||
| 754 | TP_STRUCT__entry( | ||
| 755 | LOCAL_ENTRY | ||
| 756 | __field(bool, drop) | ||
| 757 | ), | ||
| 758 | |||
| 759 | TP_fast_assign( | ||
| 760 | LOCAL_ASSIGN; | ||
| 761 | __entry->drop = drop; | ||
| 762 | ), | ||
| 763 | |||
| 764 | TP_printk( | ||
| 765 | LOCAL_PR_FMT " drop:%d", | ||
| 766 | LOCAL_PR_ARG, __entry->drop | ||
| 767 | ) | ||
| 768 | ); | ||
| 691 | #endif /* !__MAC80211_DRIVER_TRACE || TRACE_HEADER_MULTI_READ */ | 769 | #endif /* !__MAC80211_DRIVER_TRACE || TRACE_HEADER_MULTI_READ */ |
| 692 | 770 | ||
| 693 | #undef TRACE_INCLUDE_PATH | 771 | #undef TRACE_INCLUDE_PATH |
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 | } | ||
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 22f0c2aa7a89..f3e942486749 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c | |||
| @@ -117,7 +117,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | |||
| 117 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | 117 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | |
| 118 | IEEE80211_STYPE_PROBE_RESP); | 118 | IEEE80211_STYPE_PROBE_RESP); |
| 119 | memset(mgmt->da, 0xff, ETH_ALEN); | 119 | memset(mgmt->da, 0xff, ETH_ALEN); |
| 120 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); | 120 | memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); |
| 121 | memcpy(mgmt->bssid, ifibss->bssid, ETH_ALEN); | 121 | memcpy(mgmt->bssid, ifibss->bssid, ETH_ALEN); |
| 122 | mgmt->u.beacon.beacon_int = cpu_to_le16(beacon_int); | 122 | mgmt->u.beacon.beacon_int = cpu_to_le16(beacon_int); |
| 123 | mgmt->u.beacon.timestamp = cpu_to_le64(tsf); | 123 | mgmt->u.beacon.timestamp = cpu_to_le64(tsf); |
| @@ -187,15 +187,17 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | |||
| 187 | static void ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | 187 | static void ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, |
| 188 | struct ieee80211_bss *bss) | 188 | struct ieee80211_bss *bss) |
| 189 | { | 189 | { |
| 190 | struct cfg80211_bss *cbss = | ||
| 191 | container_of((void *)bss, struct cfg80211_bss, priv); | ||
| 190 | struct ieee80211_supported_band *sband; | 192 | struct ieee80211_supported_band *sband; |
| 191 | u32 basic_rates; | 193 | u32 basic_rates; |
| 192 | int i, j; | 194 | int i, j; |
| 193 | u16 beacon_int = bss->cbss.beacon_interval; | 195 | u16 beacon_int = cbss->beacon_interval; |
| 194 | 196 | ||
| 195 | if (beacon_int < 10) | 197 | if (beacon_int < 10) |
| 196 | beacon_int = 10; | 198 | beacon_int = 10; |
| 197 | 199 | ||
| 198 | sband = sdata->local->hw.wiphy->bands[bss->cbss.channel->band]; | 200 | sband = sdata->local->hw.wiphy->bands[cbss->channel->band]; |
| 199 | 201 | ||
| 200 | basic_rates = 0; | 202 | basic_rates = 0; |
| 201 | 203 | ||
| @@ -212,12 +214,12 @@ static void ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | |||
| 212 | } | 214 | } |
| 213 | } | 215 | } |
| 214 | 216 | ||
| 215 | __ieee80211_sta_join_ibss(sdata, bss->cbss.bssid, | 217 | __ieee80211_sta_join_ibss(sdata, cbss->bssid, |
| 216 | beacon_int, | 218 | beacon_int, |
| 217 | bss->cbss.channel, | 219 | cbss->channel, |
| 218 | basic_rates, | 220 | basic_rates, |
| 219 | bss->cbss.capability, | 221 | cbss->capability, |
| 220 | bss->cbss.tsf); | 222 | cbss->tsf); |
| 221 | } | 223 | } |
| 222 | 224 | ||
| 223 | static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | 225 | static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, |
| @@ -229,6 +231,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | |||
| 229 | { | 231 | { |
| 230 | struct ieee80211_local *local = sdata->local; | 232 | struct ieee80211_local *local = sdata->local; |
| 231 | int freq; | 233 | int freq; |
| 234 | struct cfg80211_bss *cbss; | ||
| 232 | struct ieee80211_bss *bss; | 235 | struct ieee80211_bss *bss; |
| 233 | struct sta_info *sta; | 236 | struct sta_info *sta; |
| 234 | struct ieee80211_channel *channel; | 237 | struct ieee80211_channel *channel; |
| @@ -252,7 +255,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | |||
| 252 | 255 | ||
| 253 | rcu_read_lock(); | 256 | rcu_read_lock(); |
| 254 | 257 | ||
| 255 | sta = sta_info_get(local, mgmt->sa); | 258 | sta = sta_info_get(sdata, mgmt->sa); |
| 256 | if (sta) { | 259 | if (sta) { |
| 257 | u32 prev_rates; | 260 | u32 prev_rates; |
| 258 | 261 | ||
| @@ -266,16 +269,18 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | |||
| 266 | printk(KERN_DEBUG "%s: updated supp_rates set " | 269 | printk(KERN_DEBUG "%s: updated supp_rates set " |
| 267 | "for %pM based on beacon info (0x%llx | " | 270 | "for %pM based on beacon info (0x%llx | " |
| 268 | "0x%llx -> 0x%llx)\n", | 271 | "0x%llx -> 0x%llx)\n", |
| 269 | sdata->dev->name, | 272 | sdata->name, |
| 270 | sta->sta.addr, | 273 | sta->sta.addr, |
| 271 | (unsigned long long) prev_rates, | 274 | (unsigned long long) prev_rates, |
| 272 | (unsigned long long) supp_rates, | 275 | (unsigned long long) supp_rates, |
| 273 | (unsigned long long) sta->sta.supp_rates[band]); | 276 | (unsigned long long) sta->sta.supp_rates[band]); |
| 274 | #endif | 277 | #endif |
| 275 | } else | 278 | rcu_read_unlock(); |
| 276 | ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa, supp_rates); | 279 | } else { |
| 277 | 280 | rcu_read_unlock(); | |
| 278 | rcu_read_unlock(); | 281 | ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa, |
| 282 | supp_rates, GFP_KERNEL); | ||
| 283 | } | ||
| 279 | } | 284 | } |
| 280 | 285 | ||
| 281 | bss = ieee80211_bss_info_update(local, rx_status, mgmt, len, elems, | 286 | bss = ieee80211_bss_info_update(local, rx_status, mgmt, len, elems, |
| @@ -283,25 +288,23 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | |||
| 283 | if (!bss) | 288 | if (!bss) |
| 284 | return; | 289 | return; |
| 285 | 290 | ||
| 291 | cbss = container_of((void *)bss, struct cfg80211_bss, priv); | ||
| 292 | |||
| 286 | /* was just updated in ieee80211_bss_info_update */ | 293 | /* was just updated in ieee80211_bss_info_update */ |
| 287 | beacon_timestamp = bss->cbss.tsf; | 294 | beacon_timestamp = cbss->tsf; |
| 288 | 295 | ||
| 289 | /* check if we need to merge IBSS */ | 296 | /* check if we need to merge IBSS */ |
| 290 | 297 | ||
| 291 | /* merge only on beacons (???) */ | ||
| 292 | if (!beacon) | ||
| 293 | goto put_bss; | ||
| 294 | |||
| 295 | /* we use a fixed BSSID */ | 298 | /* we use a fixed BSSID */ |
| 296 | if (sdata->u.ibss.bssid) | 299 | if (sdata->u.ibss.fixed_bssid) |
| 297 | goto put_bss; | 300 | goto put_bss; |
| 298 | 301 | ||
| 299 | /* not an IBSS */ | 302 | /* not an IBSS */ |
| 300 | if (!(bss->cbss.capability & WLAN_CAPABILITY_IBSS)) | 303 | if (!(cbss->capability & WLAN_CAPABILITY_IBSS)) |
| 301 | goto put_bss; | 304 | goto put_bss; |
| 302 | 305 | ||
| 303 | /* different channel */ | 306 | /* different channel */ |
| 304 | if (bss->cbss.channel != local->oper_channel) | 307 | if (cbss->channel != local->oper_channel) |
| 305 | goto put_bss; | 308 | goto put_bss; |
| 306 | 309 | ||
| 307 | /* different SSID */ | 310 | /* different SSID */ |
| @@ -311,7 +314,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | |||
| 311 | goto put_bss; | 314 | goto put_bss; |
| 312 | 315 | ||
| 313 | /* same BSSID */ | 316 | /* same BSSID */ |
| 314 | if (memcmp(bss->cbss.bssid, sdata->u.ibss.bssid, ETH_ALEN) == 0) | 317 | if (memcmp(cbss->bssid, sdata->u.ibss.bssid, ETH_ALEN) == 0) |
| 315 | goto put_bss; | 318 | goto put_bss; |
| 316 | 319 | ||
| 317 | if (rx_status->flag & RX_FLAG_TSFT) { | 320 | if (rx_status->flag & RX_FLAG_TSFT) { |
| @@ -364,10 +367,11 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | |||
| 364 | #ifdef CONFIG_MAC80211_IBSS_DEBUG | 367 | #ifdef CONFIG_MAC80211_IBSS_DEBUG |
| 365 | printk(KERN_DEBUG "%s: beacon TSF higher than " | 368 | printk(KERN_DEBUG "%s: beacon TSF higher than " |
| 366 | "local TSF - IBSS merge with BSSID %pM\n", | 369 | "local TSF - IBSS merge with BSSID %pM\n", |
| 367 | sdata->dev->name, mgmt->bssid); | 370 | sdata->name, mgmt->bssid); |
| 368 | #endif | 371 | #endif |
| 369 | ieee80211_sta_join_ibss(sdata, bss); | 372 | ieee80211_sta_join_ibss(sdata, bss); |
| 370 | ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa, supp_rates); | 373 | ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa, |
| 374 | supp_rates, GFP_KERNEL); | ||
| 371 | } | 375 | } |
| 372 | 376 | ||
| 373 | put_bss: | 377 | put_bss: |
| @@ -380,7 +384,8 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | |||
| 380 | * must be callable in atomic context. | 384 | * must be callable in atomic context. |
| 381 | */ | 385 | */ |
| 382 | struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, | 386 | struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, |
| 383 | u8 *bssid,u8 *addr, u32 supp_rates) | 387 | u8 *bssid,u8 *addr, u32 supp_rates, |
| 388 | gfp_t gfp) | ||
| 384 | { | 389 | { |
| 385 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; | 390 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; |
| 386 | struct ieee80211_local *local = sdata->local; | 391 | struct ieee80211_local *local = sdata->local; |
| @@ -394,7 +399,7 @@ struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, | |||
| 394 | if (local->num_sta >= IEEE80211_IBSS_MAX_STA_ENTRIES) { | 399 | if (local->num_sta >= IEEE80211_IBSS_MAX_STA_ENTRIES) { |
| 395 | if (net_ratelimit()) | 400 | if (net_ratelimit()) |
| 396 | printk(KERN_DEBUG "%s: No room for a new IBSS STA entry %pM\n", | 401 | printk(KERN_DEBUG "%s: No room for a new IBSS STA entry %pM\n", |
| 397 | sdata->dev->name, addr); | 402 | sdata->name, addr); |
| 398 | return NULL; | 403 | return NULL; |
| 399 | } | 404 | } |
| 400 | 405 | ||
| @@ -406,10 +411,10 @@ struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, | |||
| 406 | 411 | ||
| 407 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | 412 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG |
| 408 | printk(KERN_DEBUG "%s: Adding new IBSS station %pM (dev=%s)\n", | 413 | printk(KERN_DEBUG "%s: Adding new IBSS station %pM (dev=%s)\n", |
| 409 | wiphy_name(local->hw.wiphy), addr, sdata->dev->name); | 414 | wiphy_name(local->hw.wiphy), addr, sdata->name); |
| 410 | #endif | 415 | #endif |
| 411 | 416 | ||
| 412 | sta = sta_info_alloc(sdata, addr, GFP_ATOMIC); | 417 | sta = sta_info_alloc(sdata, addr, gfp); |
| 413 | if (!sta) | 418 | if (!sta) |
| 414 | return NULL; | 419 | return NULL; |
| 415 | 420 | ||
| @@ -421,9 +426,9 @@ struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, | |||
| 421 | 426 | ||
| 422 | rate_control_rate_init(sta); | 427 | rate_control_rate_init(sta); |
| 423 | 428 | ||
| 429 | /* If it fails, maybe we raced another insertion? */ | ||
| 424 | if (sta_info_insert(sta)) | 430 | if (sta_info_insert(sta)) |
| 425 | return NULL; | 431 | return sta_info_get(sdata, addr); |
| 426 | |||
| 427 | return sta; | 432 | return sta; |
| 428 | } | 433 | } |
| 429 | 434 | ||
| @@ -449,6 +454,9 @@ static int ieee80211_sta_active_ibss(struct ieee80211_sub_if_data *sdata) | |||
| 449 | return active; | 454 | return active; |
| 450 | } | 455 | } |
| 451 | 456 | ||
| 457 | /* | ||
| 458 | * This function is called with state == IEEE80211_IBSS_MLME_JOINED | ||
| 459 | */ | ||
| 452 | 460 | ||
| 453 | static void ieee80211_sta_merge_ibss(struct ieee80211_sub_if_data *sdata) | 461 | static void ieee80211_sta_merge_ibss(struct ieee80211_sub_if_data *sdata) |
| 454 | { | 462 | { |
| @@ -470,7 +478,7 @@ static void ieee80211_sta_merge_ibss(struct ieee80211_sub_if_data *sdata) | |||
| 470 | return; | 478 | return; |
| 471 | 479 | ||
| 472 | printk(KERN_DEBUG "%s: No active IBSS STAs - trying to scan for other " | 480 | printk(KERN_DEBUG "%s: No active IBSS STAs - trying to scan for other " |
| 473 | "IBSS networks with same SSID (merge)\n", sdata->dev->name); | 481 | "IBSS networks with same SSID (merge)\n", sdata->name); |
| 474 | 482 | ||
| 475 | ieee80211_request_internal_scan(sdata, ifibss->ssid, ifibss->ssid_len); | 483 | ieee80211_request_internal_scan(sdata, ifibss->ssid, ifibss->ssid_len); |
| 476 | } | 484 | } |
| @@ -492,13 +500,13 @@ static void ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata) | |||
| 492 | * random number generator get different BSSID. */ | 500 | * random number generator get different BSSID. */ |
| 493 | get_random_bytes(bssid, ETH_ALEN); | 501 | get_random_bytes(bssid, ETH_ALEN); |
| 494 | for (i = 0; i < ETH_ALEN; i++) | 502 | for (i = 0; i < ETH_ALEN; i++) |
| 495 | bssid[i] ^= sdata->dev->dev_addr[i]; | 503 | bssid[i] ^= sdata->vif.addr[i]; |
| 496 | bssid[0] &= ~0x01; | 504 | bssid[0] &= ~0x01; |
| 497 | bssid[0] |= 0x02; | 505 | bssid[0] |= 0x02; |
| 498 | } | 506 | } |
| 499 | 507 | ||
| 500 | printk(KERN_DEBUG "%s: Creating new IBSS network, BSSID %pM\n", | 508 | printk(KERN_DEBUG "%s: Creating new IBSS network, BSSID %pM\n", |
| 501 | sdata->dev->name, bssid); | 509 | sdata->name, bssid); |
| 502 | 510 | ||
| 503 | sband = local->hw.wiphy->bands[ifibss->channel->band]; | 511 | sband = local->hw.wiphy->bands[ifibss->channel->band]; |
| 504 | 512 | ||
| @@ -514,11 +522,15 @@ static void ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata) | |||
| 514 | capability, 0); | 522 | capability, 0); |
| 515 | } | 523 | } |
| 516 | 524 | ||
| 525 | /* | ||
| 526 | * This function is called with state == IEEE80211_IBSS_MLME_SEARCH | ||
| 527 | */ | ||
| 528 | |||
| 517 | static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata) | 529 | static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata) |
| 518 | { | 530 | { |
| 519 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; | 531 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; |
| 520 | struct ieee80211_local *local = sdata->local; | 532 | struct ieee80211_local *local = sdata->local; |
| 521 | struct ieee80211_bss *bss; | 533 | struct cfg80211_bss *cbss; |
| 522 | struct ieee80211_channel *chan = NULL; | 534 | struct ieee80211_channel *chan = NULL; |
| 523 | const u8 *bssid = NULL; | 535 | const u8 *bssid = NULL; |
| 524 | int active_ibss; | 536 | int active_ibss; |
| @@ -527,7 +539,7 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata) | |||
| 527 | active_ibss = ieee80211_sta_active_ibss(sdata); | 539 | active_ibss = ieee80211_sta_active_ibss(sdata); |
| 528 | #ifdef CONFIG_MAC80211_IBSS_DEBUG | 540 | #ifdef CONFIG_MAC80211_IBSS_DEBUG |
| 529 | printk(KERN_DEBUG "%s: sta_find_ibss (active_ibss=%d)\n", | 541 | printk(KERN_DEBUG "%s: sta_find_ibss (active_ibss=%d)\n", |
| 530 | sdata->dev->name, active_ibss); | 542 | sdata->name, active_ibss); |
| 531 | #endif /* CONFIG_MAC80211_IBSS_DEBUG */ | 543 | #endif /* CONFIG_MAC80211_IBSS_DEBUG */ |
| 532 | 544 | ||
| 533 | if (active_ibss) | 545 | if (active_ibss) |
| @@ -542,21 +554,23 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata) | |||
| 542 | chan = ifibss->channel; | 554 | chan = ifibss->channel; |
| 543 | if (!is_zero_ether_addr(ifibss->bssid)) | 555 | if (!is_zero_ether_addr(ifibss->bssid)) |
| 544 | bssid = ifibss->bssid; | 556 | bssid = ifibss->bssid; |
| 545 | bss = (void *)cfg80211_get_bss(local->hw.wiphy, chan, bssid, | 557 | cbss = cfg80211_get_bss(local->hw.wiphy, chan, bssid, |
| 546 | ifibss->ssid, ifibss->ssid_len, | 558 | ifibss->ssid, ifibss->ssid_len, |
| 547 | WLAN_CAPABILITY_IBSS | | 559 | WLAN_CAPABILITY_IBSS | WLAN_CAPABILITY_PRIVACY, |
| 548 | WLAN_CAPABILITY_PRIVACY, | 560 | capability); |
| 549 | capability); | 561 | |
| 562 | if (cbss) { | ||
| 563 | struct ieee80211_bss *bss; | ||
| 550 | 564 | ||
| 551 | if (bss) { | 565 | bss = (void *)cbss->priv; |
| 552 | #ifdef CONFIG_MAC80211_IBSS_DEBUG | 566 | #ifdef CONFIG_MAC80211_IBSS_DEBUG |
| 553 | printk(KERN_DEBUG " sta_find_ibss: selected %pM current " | 567 | printk(KERN_DEBUG " sta_find_ibss: selected %pM current " |
| 554 | "%pM\n", bss->cbss.bssid, ifibss->bssid); | 568 | "%pM\n", cbss->bssid, ifibss->bssid); |
| 555 | #endif /* CONFIG_MAC80211_IBSS_DEBUG */ | 569 | #endif /* CONFIG_MAC80211_IBSS_DEBUG */ |
| 556 | 570 | ||
| 557 | printk(KERN_DEBUG "%s: Selected IBSS BSSID %pM" | 571 | printk(KERN_DEBUG "%s: Selected IBSS BSSID %pM" |
| 558 | " based on configured SSID\n", | 572 | " based on configured SSID\n", |
| 559 | sdata->dev->name, bss->cbss.bssid); | 573 | sdata->name, cbss->bssid); |
| 560 | 574 | ||
| 561 | ieee80211_sta_join_ibss(sdata, bss); | 575 | ieee80211_sta_join_ibss(sdata, bss); |
| 562 | ieee80211_rx_bss_put(local, bss); | 576 | ieee80211_rx_bss_put(local, bss); |
| @@ -568,18 +582,14 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata) | |||
| 568 | #endif /* CONFIG_MAC80211_IBSS_DEBUG */ | 582 | #endif /* CONFIG_MAC80211_IBSS_DEBUG */ |
| 569 | 583 | ||
| 570 | /* Selected IBSS not found in current scan results - try to scan */ | 584 | /* Selected IBSS not found in current scan results - try to scan */ |
| 571 | if (ifibss->state == IEEE80211_IBSS_MLME_JOINED && | 585 | if (time_after(jiffies, ifibss->last_scan_completed + |
| 572 | !ieee80211_sta_active_ibss(sdata)) { | ||
| 573 | mod_timer(&ifibss->timer, | ||
| 574 | round_jiffies(jiffies + IEEE80211_IBSS_MERGE_INTERVAL)); | ||
| 575 | } else if (time_after(jiffies, ifibss->last_scan_completed + | ||
| 576 | IEEE80211_SCAN_INTERVAL)) { | 586 | IEEE80211_SCAN_INTERVAL)) { |
| 577 | printk(KERN_DEBUG "%s: Trigger new scan to find an IBSS to " | 587 | printk(KERN_DEBUG "%s: Trigger new scan to find an IBSS to " |
| 578 | "join\n", sdata->dev->name); | 588 | "join\n", sdata->name); |
| 579 | 589 | ||
| 580 | ieee80211_request_internal_scan(sdata, ifibss->ssid, | 590 | ieee80211_request_internal_scan(sdata, ifibss->ssid, |
| 581 | ifibss->ssid_len); | 591 | ifibss->ssid_len); |
| 582 | } else if (ifibss->state != IEEE80211_IBSS_MLME_JOINED) { | 592 | } else { |
| 583 | int interval = IEEE80211_SCAN_INTERVAL; | 593 | int interval = IEEE80211_SCAN_INTERVAL; |
| 584 | 594 | ||
| 585 | if (time_after(jiffies, ifibss->ibss_join_req + | 595 | if (time_after(jiffies, ifibss->ibss_join_req + |
| @@ -589,7 +599,7 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata) | |||
| 589 | return; | 599 | return; |
| 590 | } | 600 | } |
| 591 | printk(KERN_DEBUG "%s: IBSS not allowed on" | 601 | printk(KERN_DEBUG "%s: IBSS not allowed on" |
| 592 | " %d MHz\n", sdata->dev->name, | 602 | " %d MHz\n", sdata->name, |
| 593 | local->hw.conf.channel->center_freq); | 603 | local->hw.conf.channel->center_freq); |
| 594 | 604 | ||
| 595 | /* No IBSS found - decrease scan interval and continue | 605 | /* No IBSS found - decrease scan interval and continue |
| @@ -597,7 +607,6 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata) | |||
| 597 | interval = IEEE80211_SCAN_INTERVAL_SLOW; | 607 | interval = IEEE80211_SCAN_INTERVAL_SLOW; |
| 598 | } | 608 | } |
| 599 | 609 | ||
| 600 | ifibss->state = IEEE80211_IBSS_MLME_SEARCH; | ||
| 601 | mod_timer(&ifibss->timer, | 610 | mod_timer(&ifibss->timer, |
| 602 | round_jiffies(jiffies + interval)); | 611 | round_jiffies(jiffies + interval)); |
| 603 | } | 612 | } |
| @@ -623,7 +632,7 @@ static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata, | |||
| 623 | #ifdef CONFIG_MAC80211_IBSS_DEBUG | 632 | #ifdef CONFIG_MAC80211_IBSS_DEBUG |
| 624 | printk(KERN_DEBUG "%s: RX ProbeReq SA=%pM DA=%pM BSSID=%pM" | 633 | printk(KERN_DEBUG "%s: RX ProbeReq SA=%pM DA=%pM BSSID=%pM" |
| 625 | " (tx_last_beacon=%d)\n", | 634 | " (tx_last_beacon=%d)\n", |
| 626 | sdata->dev->name, mgmt->sa, mgmt->da, | 635 | sdata->name, mgmt->sa, mgmt->da, |
| 627 | mgmt->bssid, tx_last_beacon); | 636 | mgmt->bssid, tx_last_beacon); |
| 628 | #endif /* CONFIG_MAC80211_IBSS_DEBUG */ | 637 | #endif /* CONFIG_MAC80211_IBSS_DEBUG */ |
| 629 | 638 | ||
| @@ -641,7 +650,7 @@ static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata, | |||
| 641 | #ifdef CONFIG_MAC80211_IBSS_DEBUG | 650 | #ifdef CONFIG_MAC80211_IBSS_DEBUG |
| 642 | printk(KERN_DEBUG "%s: Invalid SSID IE in ProbeReq " | 651 | printk(KERN_DEBUG "%s: Invalid SSID IE in ProbeReq " |
| 643 | "from %pM\n", | 652 | "from %pM\n", |
| 644 | sdata->dev->name, mgmt->sa); | 653 | sdata->name, mgmt->sa); |
| 645 | #endif | 654 | #endif |
| 646 | return; | 655 | return; |
| 647 | } | 656 | } |
| @@ -661,7 +670,7 @@ static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata, | |||
| 661 | memcpy(resp->da, mgmt->sa, ETH_ALEN); | 670 | memcpy(resp->da, mgmt->sa, ETH_ALEN); |
| 662 | #ifdef CONFIG_MAC80211_IBSS_DEBUG | 671 | #ifdef CONFIG_MAC80211_IBSS_DEBUG |
| 663 | printk(KERN_DEBUG "%s: Sending ProbeResp to %pM\n", | 672 | printk(KERN_DEBUG "%s: Sending ProbeResp to %pM\n", |
| 664 | sdata->dev->name, resp->da); | 673 | sdata->name, resp->da); |
| 665 | #endif /* CONFIG_MAC80211_IBSS_DEBUG */ | 674 | #endif /* CONFIG_MAC80211_IBSS_DEBUG */ |
| 666 | IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; | 675 | IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; |
| 667 | ieee80211_tx_skb(sdata, skb); | 676 | ieee80211_tx_skb(sdata, skb); |
| @@ -675,7 +684,7 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata, | |||
| 675 | size_t baselen; | 684 | size_t baselen; |
| 676 | struct ieee802_11_elems elems; | 685 | struct ieee802_11_elems elems; |
| 677 | 686 | ||
| 678 | if (memcmp(mgmt->da, sdata->dev->dev_addr, ETH_ALEN)) | 687 | if (memcmp(mgmt->da, sdata->vif.addr, ETH_ALEN)) |
| 679 | return; /* ignore ProbeResp to foreign address */ | 688 | return; /* ignore ProbeResp to foreign address */ |
| 680 | 689 | ||
| 681 | baselen = (u8 *) mgmt->u.probe_resp.variable - (u8 *) mgmt; | 690 | baselen = (u8 *) mgmt->u.probe_resp.variable - (u8 *) mgmt; |
| @@ -748,7 +757,7 @@ static void ieee80211_ibss_work(struct work_struct *work) | |||
| 748 | if (WARN_ON(local->suspended)) | 757 | if (WARN_ON(local->suspended)) |
| 749 | return; | 758 | return; |
| 750 | 759 | ||
| 751 | if (!netif_running(sdata->dev)) | 760 | if (!ieee80211_sdata_running(sdata)) |
| 752 | return; | 761 | return; |
| 753 | 762 | ||
| 754 | if (local->scanning) | 763 | if (local->scanning) |
| @@ -831,7 +840,7 @@ void ieee80211_ibss_notify_scan_completed(struct ieee80211_local *local) | |||
| 831 | 840 | ||
| 832 | mutex_lock(&local->iflist_mtx); | 841 | mutex_lock(&local->iflist_mtx); |
| 833 | list_for_each_entry(sdata, &local->interfaces, list) { | 842 | list_for_each_entry(sdata, &local->interfaces, list) { |
| 834 | if (!netif_running(sdata->dev)) | 843 | if (!ieee80211_sdata_running(sdata)) |
| 835 | continue; | 844 | continue; |
| 836 | if (sdata->vif.type != NL80211_IFTYPE_ADHOC) | 845 | if (sdata->vif.type != NL80211_IFTYPE_ADHOC) |
| 837 | continue; | 846 | continue; |
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 91dc8636d644..241533e1bc03 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
| @@ -2,7 +2,7 @@ | |||
| 2 | * Copyright 2002-2005, Instant802 Networks, Inc. | 2 | * Copyright 2002-2005, Instant802 Networks, Inc. |
| 3 | * Copyright 2005, Devicescape Software, Inc. | 3 | * Copyright 2005, Devicescape Software, Inc. |
| 4 | * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz> | 4 | * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz> |
| 5 | * Copyright 2007-2008 Johannes Berg <johannes@sipsolutions.net> | 5 | * Copyright 2007-2010 Johannes Berg <johannes@sipsolutions.net> |
| 6 | * | 6 | * |
| 7 | * This program is free software; you can redistribute it and/or modify | 7 | * This program is free software; you can redistribute it and/or modify |
| 8 | * it under the terms of the GNU General Public License version 2 as | 8 | * it under the terms of the GNU General Public License version 2 as |
| @@ -58,6 +58,15 @@ struct ieee80211_local; | |||
| 58 | 58 | ||
| 59 | #define TU_TO_EXP_TIME(x) (jiffies + usecs_to_jiffies((x) * 1024)) | 59 | #define TU_TO_EXP_TIME(x) (jiffies + usecs_to_jiffies((x) * 1024)) |
| 60 | 60 | ||
| 61 | #define IEEE80211_DEFAULT_UAPSD_QUEUES \ | ||
| 62 | (IEEE80211_WMM_IE_STA_QOSINFO_AC_BK | \ | ||
| 63 | IEEE80211_WMM_IE_STA_QOSINFO_AC_BE | \ | ||
| 64 | IEEE80211_WMM_IE_STA_QOSINFO_AC_VI | \ | ||
| 65 | IEEE80211_WMM_IE_STA_QOSINFO_AC_VO) | ||
| 66 | |||
| 67 | #define IEEE80211_DEFAULT_MAX_SP_LEN \ | ||
| 68 | IEEE80211_WMM_IE_STA_QOSINFO_SP_ALL | ||
| 69 | |||
| 61 | struct ieee80211_fragment_entry { | 70 | struct ieee80211_fragment_entry { |
| 62 | unsigned long first_frag_time; | 71 | unsigned long first_frag_time; |
| 63 | unsigned int seq; | 72 | unsigned int seq; |
| @@ -71,9 +80,6 @@ struct ieee80211_fragment_entry { | |||
| 71 | 80 | ||
| 72 | 81 | ||
| 73 | struct ieee80211_bss { | 82 | struct ieee80211_bss { |
| 74 | /* Yes, this is a hack */ | ||
| 75 | struct cfg80211_bss cbss; | ||
| 76 | |||
| 77 | /* don't want to look up all the time */ | 83 | /* don't want to look up all the time */ |
| 78 | size_t ssid_len; | 84 | size_t ssid_len; |
| 79 | u8 ssid[IEEE80211_MAX_SSID_LEN]; | 85 | u8 ssid[IEEE80211_MAX_SSID_LEN]; |
| @@ -81,6 +87,7 @@ struct ieee80211_bss { | |||
| 81 | u8 dtim_period; | 87 | u8 dtim_period; |
| 82 | 88 | ||
| 83 | bool wmm_used; | 89 | bool wmm_used; |
| 90 | bool uapsd_supported; | ||
| 84 | 91 | ||
| 85 | unsigned long last_probe_resp; | 92 | unsigned long last_probe_resp; |
| 86 | 93 | ||
| @@ -140,7 +147,6 @@ typedef unsigned __bitwise__ ieee80211_tx_result; | |||
| 140 | 147 | ||
| 141 | struct ieee80211_tx_data { | 148 | struct ieee80211_tx_data { |
| 142 | struct sk_buff *skb; | 149 | struct sk_buff *skb; |
| 143 | struct net_device *dev; | ||
| 144 | struct ieee80211_local *local; | 150 | struct ieee80211_local *local; |
| 145 | struct ieee80211_sub_if_data *sdata; | 151 | struct ieee80211_sub_if_data *sdata; |
| 146 | struct sta_info *sta; | 152 | struct sta_info *sta; |
| @@ -228,31 +234,77 @@ struct mesh_preq_queue { | |||
| 228 | u8 flags; | 234 | u8 flags; |
| 229 | }; | 235 | }; |
| 230 | 236 | ||
| 231 | enum ieee80211_mgd_state { | 237 | enum ieee80211_work_type { |
| 232 | IEEE80211_MGD_STATE_IDLE, | 238 | IEEE80211_WORK_ABORT, |
| 233 | IEEE80211_MGD_STATE_PROBE, | 239 | IEEE80211_WORK_DIRECT_PROBE, |
| 234 | IEEE80211_MGD_STATE_AUTH, | 240 | IEEE80211_WORK_AUTH, |
| 235 | IEEE80211_MGD_STATE_ASSOC, | 241 | IEEE80211_WORK_ASSOC, |
| 242 | IEEE80211_WORK_REMAIN_ON_CHANNEL, | ||
| 236 | }; | 243 | }; |
| 237 | 244 | ||
| 238 | struct ieee80211_mgd_work { | 245 | /** |
| 246 | * enum work_done_result - indicates what to do after work was done | ||
| 247 | * | ||
| 248 | * @WORK_DONE_DESTROY: This work item is no longer needed, destroy. | ||
| 249 | * @WORK_DONE_REQUEUE: This work item was reset to be reused, and | ||
| 250 | * should be requeued. | ||
| 251 | */ | ||
| 252 | enum work_done_result { | ||
| 253 | WORK_DONE_DESTROY, | ||
| 254 | WORK_DONE_REQUEUE, | ||
| 255 | }; | ||
| 256 | |||
| 257 | struct ieee80211_work { | ||
| 239 | struct list_head list; | 258 | struct list_head list; |
| 240 | struct ieee80211_bss *bss; | 259 | |
| 241 | int ie_len; | 260 | struct rcu_head rcu_head; |
| 242 | u8 prev_bssid[ETH_ALEN]; | 261 | |
| 243 | u8 ssid[IEEE80211_MAX_SSID_LEN]; | 262 | struct ieee80211_sub_if_data *sdata; |
| 244 | u8 ssid_len; | 263 | |
| 264 | enum work_done_result (*done)(struct ieee80211_work *wk, | ||
| 265 | struct sk_buff *skb); | ||
| 266 | |||
| 267 | struct ieee80211_channel *chan; | ||
| 268 | enum nl80211_channel_type chan_type; | ||
| 269 | |||
| 245 | unsigned long timeout; | 270 | unsigned long timeout; |
| 246 | enum ieee80211_mgd_state state; | 271 | enum ieee80211_work_type type; |
| 247 | u16 auth_alg, auth_transaction; | 272 | |
| 273 | u8 filter_ta[ETH_ALEN]; | ||
| 248 | 274 | ||
| 249 | int tries; | 275 | bool started; |
| 250 | 276 | ||
| 251 | u8 key[WLAN_KEY_LEN_WEP104]; | 277 | union { |
| 252 | u8 key_len, key_idx; | 278 | struct { |
| 279 | int tries; | ||
| 280 | u16 algorithm, transaction; | ||
| 281 | u8 ssid[IEEE80211_MAX_SSID_LEN]; | ||
| 282 | u8 ssid_len; | ||
| 283 | u8 key[WLAN_KEY_LEN_WEP104]; | ||
| 284 | u8 key_len, key_idx; | ||
| 285 | bool privacy; | ||
| 286 | } probe_auth; | ||
| 287 | struct { | ||
| 288 | struct cfg80211_bss *bss; | ||
| 289 | const u8 *supp_rates; | ||
| 290 | const u8 *ht_information_ie; | ||
| 291 | enum ieee80211_smps_mode smps; | ||
| 292 | int tries; | ||
| 293 | u16 capability; | ||
| 294 | u8 prev_bssid[ETH_ALEN]; | ||
| 295 | u8 ssid[IEEE80211_MAX_SSID_LEN]; | ||
| 296 | u8 ssid_len; | ||
| 297 | u8 supp_rates_len; | ||
| 298 | bool wmm_used, use_11n, uapsd_used; | ||
| 299 | } assoc; | ||
| 300 | struct { | ||
| 301 | u32 duration; | ||
| 302 | } remain; | ||
| 303 | }; | ||
| 253 | 304 | ||
| 305 | int ie_len; | ||
| 254 | /* must be last */ | 306 | /* must be last */ |
| 255 | u8 ie[0]; /* for auth or assoc frame, not probe */ | 307 | u8 ie[0]; |
| 256 | }; | 308 | }; |
| 257 | 309 | ||
| 258 | /* flags used in struct ieee80211_if_managed.flags */ | 310 | /* flags used in struct ieee80211_if_managed.flags */ |
| @@ -260,15 +312,11 @@ enum ieee80211_sta_flags { | |||
| 260 | IEEE80211_STA_BEACON_POLL = BIT(0), | 312 | IEEE80211_STA_BEACON_POLL = BIT(0), |
| 261 | IEEE80211_STA_CONNECTION_POLL = BIT(1), | 313 | IEEE80211_STA_CONNECTION_POLL = BIT(1), |
| 262 | IEEE80211_STA_CONTROL_PORT = BIT(2), | 314 | IEEE80211_STA_CONTROL_PORT = BIT(2), |
| 263 | IEEE80211_STA_WMM_ENABLED = BIT(3), | ||
| 264 | IEEE80211_STA_DISABLE_11N = BIT(4), | 315 | IEEE80211_STA_DISABLE_11N = BIT(4), |
| 265 | IEEE80211_STA_CSA_RECEIVED = BIT(5), | 316 | IEEE80211_STA_CSA_RECEIVED = BIT(5), |
| 266 | IEEE80211_STA_MFP_ENABLED = BIT(6), | 317 | IEEE80211_STA_MFP_ENABLED = BIT(6), |
| 267 | }; | 318 | IEEE80211_STA_UAPSD_ENABLED = BIT(7), |
| 268 | 319 | IEEE80211_STA_NULLFUNC_ACKED = BIT(8), | |
| 269 | /* flags for MLME request */ | ||
| 270 | enum ieee80211_sta_request { | ||
| 271 | IEEE80211_STA_REQ_SCAN, | ||
| 272 | }; | 320 | }; |
| 273 | 321 | ||
| 274 | struct ieee80211_if_managed { | 322 | struct ieee80211_if_managed { |
| @@ -285,21 +333,18 @@ struct ieee80211_if_managed { | |||
| 285 | int probe_send_count; | 333 | int probe_send_count; |
| 286 | 334 | ||
| 287 | struct mutex mtx; | 335 | struct mutex mtx; |
| 288 | struct ieee80211_bss *associated; | 336 | struct cfg80211_bss *associated; |
| 289 | struct ieee80211_mgd_work *old_associate_work; | ||
| 290 | struct list_head work_list; | ||
| 291 | 337 | ||
| 292 | u8 bssid[ETH_ALEN]; | 338 | u8 bssid[ETH_ALEN]; |
| 293 | 339 | ||
| 294 | u16 aid; | 340 | u16 aid; |
| 295 | u16 capab; | ||
| 296 | 341 | ||
| 297 | struct sk_buff_head skb_queue; | 342 | struct sk_buff_head skb_queue; |
| 298 | 343 | ||
| 299 | unsigned long timers_running; /* used for quiesce/restart */ | 344 | unsigned long timers_running; /* used for quiesce/restart */ |
| 300 | bool powersave; /* powersave requested for this iface */ | 345 | bool powersave; /* powersave requested for this iface */ |
| 301 | 346 | enum ieee80211_smps_mode req_smps, /* requested smps mode */ | |
| 302 | unsigned long request; | 347 | ap_smps; /* smps mode AP thinks we're in */ |
| 303 | 348 | ||
| 304 | unsigned int flags; | 349 | unsigned int flags; |
| 305 | 350 | ||
| @@ -433,6 +478,8 @@ struct ieee80211_sub_if_data { | |||
| 433 | 478 | ||
| 434 | int drop_unencrypted; | 479 | int drop_unencrypted; |
| 435 | 480 | ||
| 481 | char name[IFNAMSIZ]; | ||
| 482 | |||
| 436 | /* | 483 | /* |
| 437 | * keep track of whether the HT opmode (stored in | 484 | * keep track of whether the HT opmode (stored in |
| 438 | * vif.bss_info.ht_operation_mode) is valid. | 485 | * vif.bss_info.ht_operation_mode) is valid. |
| @@ -458,8 +505,8 @@ struct ieee80211_sub_if_data { | |||
| 458 | */ | 505 | */ |
| 459 | struct ieee80211_if_ap *bss; | 506 | struct ieee80211_if_ap *bss; |
| 460 | 507 | ||
| 461 | int force_unicast_rateidx; /* forced TX rateidx for unicast frames */ | 508 | /* bitmap of allowed (non-MCS) rate indexes for rate control */ |
| 462 | int max_ratectrl_rateidx; /* max TX rateidx for rate control */ | 509 | u32 rc_rateidx_mask[IEEE80211_NUM_BANDS]; |
| 463 | 510 | ||
| 464 | union { | 511 | union { |
| 465 | struct ieee80211_if_ap ap; | 512 | struct ieee80211_if_ap ap; |
| @@ -565,6 +612,15 @@ struct ieee80211_local { | |||
| 565 | const struct ieee80211_ops *ops; | 612 | const struct ieee80211_ops *ops; |
| 566 | 613 | ||
| 567 | /* | 614 | /* |
| 615 | * work stuff, potentially off-channel (in the future) | ||
| 616 | */ | ||
| 617 | struct mutex work_mtx; | ||
| 618 | struct list_head work_list; | ||
| 619 | struct timer_list work_timer; | ||
| 620 | struct work_struct work_work; | ||
| 621 | struct sk_buff_head work_skb_queue; | ||
| 622 | |||
| 623 | /* | ||
| 568 | * private workqueue to mac80211. mac80211 makes this accessible | 624 | * private workqueue to mac80211. mac80211 makes this accessible |
| 569 | * via ieee80211_queue_work() | 625 | * via ieee80211_queue_work() |
| 570 | */ | 626 | */ |
| @@ -586,6 +642,9 @@ struct ieee80211_local { | |||
| 586 | /* used for uploading changed mc list */ | 642 | /* used for uploading changed mc list */ |
| 587 | struct work_struct reconfig_filter; | 643 | struct work_struct reconfig_filter; |
| 588 | 644 | ||
| 645 | /* used to reconfigure hardware SM PS */ | ||
| 646 | struct work_struct recalc_smps; | ||
| 647 | |||
| 589 | /* aggregated multicast list */ | 648 | /* aggregated multicast list */ |
| 590 | struct dev_addr_list *mc_list; | 649 | struct dev_addr_list *mc_list; |
| 591 | int mc_count; | 650 | int mc_count; |
| @@ -630,15 +689,18 @@ struct ieee80211_local { | |||
| 630 | 689 | ||
| 631 | /* Station data */ | 690 | /* Station data */ |
| 632 | /* | 691 | /* |
| 633 | * The lock only protects the list, hash, timer and counter | 692 | * The mutex only protects the list and counter, |
| 634 | * against manipulation, reads are done in RCU. Additionally, | 693 | * reads are done in RCU. |
| 635 | * the lock protects each BSS's TIM bitmap. | 694 | * Additionally, the lock protects the hash table, |
| 695 | * the pending list and each BSS's TIM bitmap. | ||
| 636 | */ | 696 | */ |
| 697 | struct mutex sta_mtx; | ||
| 637 | spinlock_t sta_lock; | 698 | spinlock_t sta_lock; |
| 638 | unsigned long num_sta; | 699 | unsigned long num_sta; |
| 639 | struct list_head sta_list; | 700 | struct list_head sta_list, sta_pending_list; |
| 640 | struct sta_info *sta_hash[STA_HASH_SIZE]; | 701 | struct sta_info *sta_hash[STA_HASH_SIZE]; |
| 641 | struct timer_list sta_cleanup; | 702 | struct timer_list sta_cleanup; |
| 703 | struct work_struct sta_finish_work; | ||
| 642 | int sta_generation; | 704 | int sta_generation; |
| 643 | 705 | ||
| 644 | struct sk_buff_head pending[IEEE80211_MAX_QUEUES]; | 706 | struct sk_buff_head pending[IEEE80211_MAX_QUEUES]; |
| @@ -689,6 +751,10 @@ struct ieee80211_local { | |||
| 689 | enum nl80211_channel_type oper_channel_type; | 751 | enum nl80211_channel_type oper_channel_type; |
| 690 | struct ieee80211_channel *oper_channel, *csa_channel; | 752 | struct ieee80211_channel *oper_channel, *csa_channel; |
| 691 | 753 | ||
| 754 | /* Temporary remain-on-channel for off-channel operations */ | ||
| 755 | struct ieee80211_channel *tmp_channel; | ||
| 756 | enum nl80211_channel_type tmp_channel_type; | ||
| 757 | |||
| 692 | /* SNMP counters */ | 758 | /* SNMP counters */ |
| 693 | /* dot11CountersTable */ | 759 | /* dot11CountersTable */ |
| 694 | u32 dot11TransmittedFragmentCount; | 760 | u32 dot11TransmittedFragmentCount; |
| @@ -708,10 +774,6 @@ struct ieee80211_local { | |||
| 708 | assoc_led_name[32], radio_led_name[32]; | 774 | assoc_led_name[32], radio_led_name[32]; |
| 709 | #endif | 775 | #endif |
| 710 | 776 | ||
| 711 | #ifdef CONFIG_MAC80211_DEBUGFS | ||
| 712 | struct work_struct sta_debugfs_add; | ||
| 713 | #endif | ||
| 714 | |||
| 715 | #ifdef CONFIG_MAC80211_DEBUG_COUNTERS | 777 | #ifdef CONFIG_MAC80211_DEBUG_COUNTERS |
| 716 | /* TX/RX handler statistics */ | 778 | /* TX/RX handler statistics */ |
| 717 | unsigned int tx_handlers_drop; | 779 | unsigned int tx_handlers_drop; |
| @@ -745,8 +807,22 @@ struct ieee80211_local { | |||
| 745 | int wifi_wme_noack_test; | 807 | int wifi_wme_noack_test; |
| 746 | unsigned int wmm_acm; /* bit field of ACM bits (BIT(802.1D tag)) */ | 808 | unsigned int wmm_acm; /* bit field of ACM bits (BIT(802.1D tag)) */ |
| 747 | 809 | ||
| 810 | /* | ||
| 811 | * Bitmask of enabled u-apsd queues, | ||
| 812 | * IEEE80211_WMM_IE_STA_QOSINFO_AC_BE & co. Needs a new association | ||
| 813 | * to take effect. | ||
| 814 | */ | ||
| 815 | unsigned int uapsd_queues; | ||
| 816 | |||
| 817 | /* | ||
| 818 | * Maximum number of buffered frames AP can deliver during a | ||
| 819 | * service period, IEEE80211_WMM_IE_STA_QOSINFO_SP_ALL or similar. | ||
| 820 | * Needs a new association to take effect. | ||
| 821 | */ | ||
| 822 | unsigned int uapsd_max_sp_len; | ||
| 823 | |||
| 748 | bool pspolling; | 824 | bool pspolling; |
| 749 | bool scan_ps_enabled; | 825 | bool offchannel_ps_enabled; |
| 750 | /* | 826 | /* |
| 751 | * PS can only be enabled when we have exactly one managed | 827 | * PS can only be enabled when we have exactly one managed |
| 752 | * interface (and monitors) in PS, this then points there. | 828 | * interface (and monitors) in PS, this then points there. |
| @@ -760,6 +836,8 @@ struct ieee80211_local { | |||
| 760 | int user_power_level; /* in dBm */ | 836 | int user_power_level; /* in dBm */ |
| 761 | int power_constr_level; /* in dBm */ | 837 | int power_constr_level; /* in dBm */ |
| 762 | 838 | ||
| 839 | enum ieee80211_smps_mode smps_mode; | ||
| 840 | |||
| 763 | struct work_struct restart_work; | 841 | struct work_struct restart_work; |
| 764 | 842 | ||
| 765 | #ifdef CONFIG_MAC80211_DEBUGFS | 843 | #ifdef CONFIG_MAC80211_DEBUGFS |
| @@ -874,6 +952,8 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata, | |||
| 874 | void ieee80211_configure_filter(struct ieee80211_local *local); | 952 | void ieee80211_configure_filter(struct ieee80211_local *local); |
| 875 | u32 ieee80211_reset_erp_info(struct ieee80211_sub_if_data *sdata); | 953 | u32 ieee80211_reset_erp_info(struct ieee80211_sub_if_data *sdata); |
| 876 | 954 | ||
| 955 | extern bool ieee80211_disable_40mhz_24ghz; | ||
| 956 | |||
| 877 | /* STA code */ | 957 | /* STA code */ |
| 878 | void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata); | 958 | void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata); |
| 879 | int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, | 959 | int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, |
| @@ -886,6 +966,10 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, | |||
| 886 | int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata, | 966 | int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata, |
| 887 | struct cfg80211_disassoc_request *req, | 967 | struct cfg80211_disassoc_request *req, |
| 888 | void *cookie); | 968 | void *cookie); |
| 969 | int ieee80211_mgd_action(struct ieee80211_sub_if_data *sdata, | ||
| 970 | struct ieee80211_channel *chan, | ||
| 971 | enum nl80211_channel_type channel_type, | ||
| 972 | const u8 *buf, size_t len, u64 *cookie); | ||
| 889 | ieee80211_rx_result ieee80211_sta_rx_mgmt(struct ieee80211_sub_if_data *sdata, | 973 | ieee80211_rx_result ieee80211_sta_rx_mgmt(struct ieee80211_sub_if_data *sdata, |
| 890 | struct sk_buff *skb); | 974 | struct sk_buff *skb); |
| 891 | void ieee80211_send_pspoll(struct ieee80211_local *local, | 975 | void ieee80211_send_pspoll(struct ieee80211_local *local, |
| @@ -905,7 +989,8 @@ void ieee80211_ibss_setup_sdata(struct ieee80211_sub_if_data *sdata); | |||
| 905 | ieee80211_rx_result | 989 | ieee80211_rx_result |
| 906 | ieee80211_ibss_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb); | 990 | ieee80211_ibss_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb); |
| 907 | struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, | 991 | struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, |
| 908 | u8 *bssid, u8 *addr, u32 supp_rates); | 992 | u8 *bssid, u8 *addr, u32 supp_rates, |
| 993 | gfp_t gfp); | ||
| 909 | int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata, | 994 | int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata, |
| 910 | struct cfg80211_ibss_params *params); | 995 | struct cfg80211_ibss_params *params); |
| 911 | int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata); | 996 | int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata); |
| @@ -937,7 +1022,15 @@ ieee80211_rx_bss_get(struct ieee80211_local *local, u8 *bssid, int freq, | |||
| 937 | void ieee80211_rx_bss_put(struct ieee80211_local *local, | 1022 | void ieee80211_rx_bss_put(struct ieee80211_local *local, |
| 938 | struct ieee80211_bss *bss); | 1023 | struct ieee80211_bss *bss); |
| 939 | 1024 | ||
| 1025 | /* off-channel helpers */ | ||
| 1026 | void ieee80211_offchannel_stop_beaconing(struct ieee80211_local *local); | ||
| 1027 | void ieee80211_offchannel_stop_station(struct ieee80211_local *local); | ||
| 1028 | void ieee80211_offchannel_return(struct ieee80211_local *local, | ||
| 1029 | bool enable_beaconing); | ||
| 1030 | |||
| 940 | /* interface handling */ | 1031 | /* interface handling */ |
| 1032 | int ieee80211_iface_init(void); | ||
| 1033 | void ieee80211_iface_exit(void); | ||
| 941 | int ieee80211_if_add(struct ieee80211_local *local, const char *name, | 1034 | int ieee80211_if_add(struct ieee80211_local *local, const char *name, |
| 942 | struct net_device **new_dev, enum nl80211_iftype type, | 1035 | struct net_device **new_dev, enum nl80211_iftype type, |
| 943 | struct vif_params *params); | 1036 | struct vif_params *params); |
| @@ -948,6 +1041,11 @@ void ieee80211_remove_interfaces(struct ieee80211_local *local); | |||
| 948 | u32 __ieee80211_recalc_idle(struct ieee80211_local *local); | 1041 | u32 __ieee80211_recalc_idle(struct ieee80211_local *local); |
| 949 | void ieee80211_recalc_idle(struct ieee80211_local *local); | 1042 | void ieee80211_recalc_idle(struct ieee80211_local *local); |
| 950 | 1043 | ||
| 1044 | static inline bool ieee80211_sdata_running(struct ieee80211_sub_if_data *sdata) | ||
| 1045 | { | ||
| 1046 | return netif_running(sdata->dev); | ||
| 1047 | } | ||
| 1048 | |||
| 951 | /* tx handling */ | 1049 | /* tx handling */ |
| 952 | void ieee80211_clear_tx_pending(struct ieee80211_local *local); | 1050 | void ieee80211_clear_tx_pending(struct ieee80211_local *local); |
| 953 | void ieee80211_tx_pending(unsigned long data); | 1051 | void ieee80211_tx_pending(unsigned long data); |
| @@ -976,6 +1074,9 @@ void ieee80211_send_bar(struct ieee80211_sub_if_data *sdata, u8 *ra, u16 tid, u1 | |||
| 976 | void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata, | 1074 | void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata, |
| 977 | const u8 *da, u16 tid, | 1075 | const u8 *da, u16 tid, |
| 978 | u16 initiator, u16 reason_code); | 1076 | u16 initiator, u16 reason_code); |
| 1077 | int ieee80211_send_smps_action(struct ieee80211_sub_if_data *sdata, | ||
| 1078 | enum ieee80211_smps_mode smps, const u8 *da, | ||
| 1079 | const u8 *bssid); | ||
| 979 | 1080 | ||
| 980 | void ieee80211_sta_stop_rx_ba_session(struct ieee80211_sub_if_data *sdata, u8 *da, | 1081 | void ieee80211_sta_stop_rx_ba_session(struct ieee80211_sub_if_data *sdata, u8 *da, |
| 981 | u16 tid, u16 initiator, u16 reason); | 1082 | u16 tid, u16 initiator, u16 reason); |
| @@ -1086,6 +1187,28 @@ void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata, | |||
| 1086 | u32 ieee80211_sta_get_rates(struct ieee80211_local *local, | 1187 | u32 ieee80211_sta_get_rates(struct ieee80211_local *local, |
| 1087 | struct ieee802_11_elems *elems, | 1188 | struct ieee802_11_elems *elems, |
| 1088 | enum ieee80211_band band); | 1189 | enum ieee80211_band band); |
| 1190 | int __ieee80211_request_smps(struct ieee80211_sub_if_data *sdata, | ||
| 1191 | enum ieee80211_smps_mode smps_mode); | ||
| 1192 | void ieee80211_recalc_smps(struct ieee80211_local *local, | ||
| 1193 | struct ieee80211_sub_if_data *forsdata); | ||
| 1194 | |||
| 1195 | size_t ieee80211_ie_split(const u8 *ies, size_t ielen, | ||
| 1196 | const u8 *ids, int n_ids, size_t offset); | ||
| 1197 | size_t ieee80211_ie_split_vendor(const u8 *ies, size_t ielen, size_t offset); | ||
| 1198 | |||
| 1199 | /* internal work items */ | ||
| 1200 | void ieee80211_work_init(struct ieee80211_local *local); | ||
| 1201 | void ieee80211_add_work(struct ieee80211_work *wk); | ||
| 1202 | void free_work(struct ieee80211_work *wk); | ||
| 1203 | void ieee80211_work_purge(struct ieee80211_sub_if_data *sdata); | ||
| 1204 | ieee80211_rx_result ieee80211_work_rx_mgmt(struct ieee80211_sub_if_data *sdata, | ||
| 1205 | struct sk_buff *skb); | ||
| 1206 | int ieee80211_wk_remain_on_channel(struct ieee80211_sub_if_data *sdata, | ||
| 1207 | struct ieee80211_channel *chan, | ||
| 1208 | enum nl80211_channel_type channel_type, | ||
| 1209 | unsigned int duration, u64 *cookie); | ||
| 1210 | int ieee80211_wk_cancel_remain_on_channel( | ||
| 1211 | struct ieee80211_sub_if_data *sdata, u64 cookie); | ||
| 1089 | 1212 | ||
| 1090 | #ifdef CONFIG_MAC80211_NOINLINE | 1213 | #ifdef CONFIG_MAC80211_NOINLINE |
| 1091 | #define debug_noinline noinline | 1214 | #define debug_noinline noinline |
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 32abae3ce32a..0793d7a8d743 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c | |||
| @@ -62,6 +62,23 @@ static int ieee80211_change_mtu(struct net_device *dev, int new_mtu) | |||
| 62 | return 0; | 62 | return 0; |
| 63 | } | 63 | } |
| 64 | 64 | ||
| 65 | static int ieee80211_change_mac(struct net_device *dev, void *addr) | ||
| 66 | { | ||
| 67 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
| 68 | struct sockaddr *sa = addr; | ||
| 69 | int ret; | ||
| 70 | |||
| 71 | if (ieee80211_sdata_running(sdata)) | ||
| 72 | return -EBUSY; | ||
| 73 | |||
| 74 | ret = eth_mac_addr(dev, sa); | ||
| 75 | |||
| 76 | if (ret == 0) | ||
| 77 | memcpy(sdata->vif.addr, sa->sa_data, ETH_ALEN); | ||
| 78 | |||
| 79 | return ret; | ||
| 80 | } | ||
| 81 | |||
| 65 | static inline int identical_mac_addr_allowed(int type1, int type2) | 82 | static inline int identical_mac_addr_allowed(int type1, int type2) |
| 66 | { | 83 | { |
| 67 | return type1 == NL80211_IFTYPE_MONITOR || | 84 | return type1 == NL80211_IFTYPE_MONITOR || |
| @@ -82,7 +99,6 @@ static int ieee80211_open(struct net_device *dev) | |||
| 82 | struct ieee80211_sub_if_data *nsdata; | 99 | struct ieee80211_sub_if_data *nsdata; |
| 83 | struct ieee80211_local *local = sdata->local; | 100 | struct ieee80211_local *local = sdata->local; |
| 84 | struct sta_info *sta; | 101 | struct sta_info *sta; |
| 85 | struct ieee80211_if_init_conf conf; | ||
| 86 | u32 changed = 0; | 102 | u32 changed = 0; |
| 87 | int res; | 103 | int res; |
| 88 | u32 hw_reconf_flags = 0; | 104 | u32 hw_reconf_flags = 0; |
| @@ -97,7 +113,7 @@ static int ieee80211_open(struct net_device *dev) | |||
| 97 | list_for_each_entry(nsdata, &local->interfaces, list) { | 113 | list_for_each_entry(nsdata, &local->interfaces, list) { |
| 98 | struct net_device *ndev = nsdata->dev; | 114 | struct net_device *ndev = nsdata->dev; |
| 99 | 115 | ||
| 100 | if (ndev != dev && netif_running(ndev)) { | 116 | if (ndev != dev && ieee80211_sdata_running(nsdata)) { |
| 101 | /* | 117 | /* |
| 102 | * Allow only a single IBSS interface to be up at any | 118 | * Allow only a single IBSS interface to be up at any |
| 103 | * time. This is restricted because beacon distribution | 119 | * time. This is restricted because beacon distribution |
| @@ -183,7 +199,7 @@ static int ieee80211_open(struct net_device *dev) | |||
| 183 | struct net_device *ndev = nsdata->dev; | 199 | struct net_device *ndev = nsdata->dev; |
| 184 | 200 | ||
| 185 | /* | 201 | /* |
| 186 | * No need to check netif_running since we do not allow | 202 | * No need to check running since we do not allow |
| 187 | * it to start up with this invalid address. | 203 | * it to start up with this invalid address. |
| 188 | */ | 204 | */ |
| 189 | if (compare_ether_addr(null_addr, ndev->dev_addr) == 0) { | 205 | if (compare_ether_addr(null_addr, ndev->dev_addr) == 0) { |
| @@ -234,10 +250,7 @@ static int ieee80211_open(struct net_device *dev) | |||
| 234 | ieee80211_configure_filter(local); | 250 | ieee80211_configure_filter(local); |
| 235 | break; | 251 | break; |
| 236 | default: | 252 | default: |
| 237 | conf.vif = &sdata->vif; | 253 | res = drv_add_interface(local, &sdata->vif); |
| 238 | conf.type = sdata->vif.type; | ||
| 239 | conf.mac_addr = dev->dev_addr; | ||
| 240 | res = drv_add_interface(local, &conf); | ||
| 241 | if (res) | 254 | if (res) |
| 242 | goto err_stop; | 255 | goto err_stop; |
| 243 | 256 | ||
| @@ -320,7 +333,7 @@ static int ieee80211_open(struct net_device *dev) | |||
| 320 | 333 | ||
| 321 | return 0; | 334 | return 0; |
| 322 | err_del_interface: | 335 | err_del_interface: |
| 323 | drv_remove_interface(local, &conf); | 336 | drv_remove_interface(local, &sdata->vif); |
| 324 | err_stop: | 337 | err_stop: |
| 325 | if (!local->open_count) | 338 | if (!local->open_count) |
| 326 | drv_stop(local); | 339 | drv_stop(local); |
| @@ -335,7 +348,6 @@ static int ieee80211_stop(struct net_device *dev) | |||
| 335 | { | 348 | { |
| 336 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 349 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
| 337 | struct ieee80211_local *local = sdata->local; | 350 | struct ieee80211_local *local = sdata->local; |
| 338 | struct ieee80211_if_init_conf conf; | ||
| 339 | struct sta_info *sta; | 351 | struct sta_info *sta; |
| 340 | unsigned long flags; | 352 | unsigned long flags; |
| 341 | struct sk_buff *skb, *tmp; | 353 | struct sk_buff *skb, *tmp; |
| @@ -348,6 +360,11 @@ static int ieee80211_stop(struct net_device *dev) | |||
| 348 | netif_tx_stop_all_queues(dev); | 360 | netif_tx_stop_all_queues(dev); |
| 349 | 361 | ||
| 350 | /* | 362 | /* |
| 363 | * Purge work for this interface. | ||
| 364 | */ | ||
| 365 | ieee80211_work_purge(sdata); | ||
| 366 | |||
| 367 | /* | ||
| 351 | * Now delete all active aggregation sessions. | 368 | * Now delete all active aggregation sessions. |
| 352 | */ | 369 | */ |
| 353 | rcu_read_lock(); | 370 | rcu_read_lock(); |
| @@ -514,12 +531,9 @@ static int ieee80211_stop(struct net_device *dev) | |||
| 514 | BSS_CHANGED_BEACON_ENABLED); | 531 | BSS_CHANGED_BEACON_ENABLED); |
| 515 | } | 532 | } |
| 516 | 533 | ||
| 517 | conf.vif = &sdata->vif; | ||
| 518 | conf.type = sdata->vif.type; | ||
| 519 | conf.mac_addr = dev->dev_addr; | ||
| 520 | /* disable all keys for as long as this netdev is down */ | 534 | /* disable all keys for as long as this netdev is down */ |
| 521 | ieee80211_disable_keys(sdata); | 535 | ieee80211_disable_keys(sdata); |
| 522 | drv_remove_interface(local, &conf); | 536 | drv_remove_interface(local, &sdata->vif); |
| 523 | } | 537 | } |
| 524 | 538 | ||
| 525 | sdata->bss = NULL; | 539 | sdata->bss = NULL; |
| @@ -659,7 +673,7 @@ static const struct net_device_ops ieee80211_dataif_ops = { | |||
| 659 | .ndo_start_xmit = ieee80211_subif_start_xmit, | 673 | .ndo_start_xmit = ieee80211_subif_start_xmit, |
| 660 | .ndo_set_multicast_list = ieee80211_set_multicast_list, | 674 | .ndo_set_multicast_list = ieee80211_set_multicast_list, |
| 661 | .ndo_change_mtu = ieee80211_change_mtu, | 675 | .ndo_change_mtu = ieee80211_change_mtu, |
| 662 | .ndo_set_mac_address = eth_mac_addr, | 676 | .ndo_set_mac_address = ieee80211_change_mac, |
| 663 | .ndo_select_queue = ieee80211_netdev_select_queue, | 677 | .ndo_select_queue = ieee80211_netdev_select_queue, |
| 664 | }; | 678 | }; |
| 665 | 679 | ||
| @@ -681,10 +695,14 @@ static u16 ieee80211_monitor_select_queue(struct net_device *dev, | |||
| 681 | 695 | ||
| 682 | hdr = (void *)((u8 *)skb->data + le16_to_cpu(rtap->it_len)); | 696 | hdr = (void *)((u8 *)skb->data + le16_to_cpu(rtap->it_len)); |
| 683 | 697 | ||
| 684 | if (!ieee80211_is_data_qos(hdr->frame_control)) { | 698 | if (!ieee80211_is_data(hdr->frame_control)) { |
| 685 | skb->priority = 7; | 699 | skb->priority = 7; |
| 686 | return ieee802_1d_to_ac[skb->priority]; | 700 | return ieee802_1d_to_ac[skb->priority]; |
| 687 | } | 701 | } |
| 702 | if (!ieee80211_is_data_qos(hdr->frame_control)) { | ||
| 703 | skb->priority = 0; | ||
| 704 | return ieee802_1d_to_ac[skb->priority]; | ||
| 705 | } | ||
| 688 | 706 | ||
| 689 | p = ieee80211_get_qos_ctl(hdr); | 707 | p = ieee80211_get_qos_ctl(hdr); |
| 690 | skb->priority = *p & IEEE80211_QOS_CTL_TAG1D_MASK; | 708 | skb->priority = *p & IEEE80211_QOS_CTL_TAG1D_MASK; |
| @@ -779,7 +797,7 @@ int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata, | |||
| 779 | * and goes into the requested mode. | 797 | * and goes into the requested mode. |
| 780 | */ | 798 | */ |
| 781 | 799 | ||
| 782 | if (netif_running(sdata->dev)) | 800 | if (ieee80211_sdata_running(sdata)) |
| 783 | return -EBUSY; | 801 | return -EBUSY; |
| 784 | 802 | ||
| 785 | /* Purge and reset type-dependent state. */ | 803 | /* Purge and reset type-dependent state. */ |
| @@ -833,6 +851,8 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name, | |||
| 833 | /* don't use IEEE80211_DEV_TO_SUB_IF because it checks too much */ | 851 | /* don't use IEEE80211_DEV_TO_SUB_IF because it checks too much */ |
| 834 | sdata = netdev_priv(ndev); | 852 | sdata = netdev_priv(ndev); |
| 835 | ndev->ieee80211_ptr = &sdata->wdev; | 853 | ndev->ieee80211_ptr = &sdata->wdev; |
| 854 | memcpy(sdata->vif.addr, ndev->dev_addr, ETH_ALEN); | ||
| 855 | memcpy(sdata->name, ndev->name, IFNAMSIZ); | ||
| 836 | 856 | ||
| 837 | /* initialise type-independent data */ | 857 | /* initialise type-independent data */ |
| 838 | sdata->wdev.wiphy = local->hw.wiphy; | 858 | sdata->wdev.wiphy = local->hw.wiphy; |
| @@ -844,8 +864,12 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name, | |||
| 844 | 864 | ||
| 845 | INIT_LIST_HEAD(&sdata->key_list); | 865 | INIT_LIST_HEAD(&sdata->key_list); |
| 846 | 866 | ||
| 847 | sdata->force_unicast_rateidx = -1; | 867 | for (i = 0; i < IEEE80211_NUM_BANDS; i++) { |
| 848 | sdata->max_ratectrl_rateidx = -1; | 868 | struct ieee80211_supported_band *sband; |
| 869 | sband = local->hw.wiphy->bands[i]; | ||
| 870 | sdata->rc_rateidx_mask[i] = | ||
| 871 | sband ? (1 << sband->n_bitrates) - 1 : 0; | ||
| 872 | } | ||
| 849 | 873 | ||
| 850 | /* setup type-dependent data */ | 874 | /* setup type-dependent data */ |
| 851 | ieee80211_setup_sdata(sdata, type); | 875 | ieee80211_setup_sdata(sdata, type); |
| @@ -938,6 +962,8 @@ static u32 ieee80211_idle_on(struct ieee80211_local *local) | |||
| 938 | wiphy_name(local->hw.wiphy)); | 962 | wiphy_name(local->hw.wiphy)); |
| 939 | #endif | 963 | #endif |
| 940 | 964 | ||
| 965 | drv_flush(local, false); | ||
| 966 | |||
| 941 | local->hw.conf.flags |= IEEE80211_CONF_IDLE; | 967 | local->hw.conf.flags |= IEEE80211_CONF_IDLE; |
| 942 | return IEEE80211_CONF_CHANGE_IDLE; | 968 | return IEEE80211_CONF_CHANGE_IDLE; |
| 943 | } | 969 | } |
| @@ -947,16 +973,18 @@ u32 __ieee80211_recalc_idle(struct ieee80211_local *local) | |||
| 947 | struct ieee80211_sub_if_data *sdata; | 973 | struct ieee80211_sub_if_data *sdata; |
| 948 | int count = 0; | 974 | int count = 0; |
| 949 | 975 | ||
| 976 | if (!list_empty(&local->work_list)) | ||
| 977 | return ieee80211_idle_off(local, "working"); | ||
| 978 | |||
| 950 | if (local->scanning) | 979 | if (local->scanning) |
| 951 | return ieee80211_idle_off(local, "scanning"); | 980 | return ieee80211_idle_off(local, "scanning"); |
| 952 | 981 | ||
| 953 | list_for_each_entry(sdata, &local->interfaces, list) { | 982 | list_for_each_entry(sdata, &local->interfaces, list) { |
| 954 | if (!netif_running(sdata->dev)) | 983 | if (!ieee80211_sdata_running(sdata)) |
| 955 | continue; | 984 | continue; |
| 956 | /* do not count disabled managed interfaces */ | 985 | /* do not count disabled managed interfaces */ |
| 957 | if (sdata->vif.type == NL80211_IFTYPE_STATION && | 986 | if (sdata->vif.type == NL80211_IFTYPE_STATION && |
| 958 | !sdata->u.mgd.associated && | 987 | !sdata->u.mgd.associated) |
| 959 | list_empty(&sdata->u.mgd.work_list)) | ||
| 960 | continue; | 988 | continue; |
| 961 | /* do not count unused IBSS interfaces */ | 989 | /* do not count unused IBSS interfaces */ |
| 962 | if (sdata->vif.type == NL80211_IFTYPE_ADHOC && | 990 | if (sdata->vif.type == NL80211_IFTYPE_ADHOC && |
| @@ -984,3 +1012,41 @@ void ieee80211_recalc_idle(struct ieee80211_local *local) | |||
| 984 | if (chg) | 1012 | if (chg) |
| 985 | ieee80211_hw_config(local, chg); | 1013 | ieee80211_hw_config(local, chg); |
| 986 | } | 1014 | } |
| 1015 | |||
| 1016 | static int netdev_notify(struct notifier_block *nb, | ||
| 1017 | unsigned long state, | ||
| 1018 | void *ndev) | ||
| 1019 | { | ||
| 1020 | struct net_device *dev = ndev; | ||
| 1021 | struct ieee80211_sub_if_data *sdata; | ||
| 1022 | |||
| 1023 | if (state != NETDEV_CHANGENAME) | ||
| 1024 | return 0; | ||
| 1025 | |||
| 1026 | if (!dev->ieee80211_ptr || !dev->ieee80211_ptr->wiphy) | ||
| 1027 | return 0; | ||
| 1028 | |||
| 1029 | if (dev->ieee80211_ptr->wiphy->privid != mac80211_wiphy_privid) | ||
| 1030 | return 0; | ||
| 1031 | |||
| 1032 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
| 1033 | |||
| 1034 | memcpy(sdata->name, dev->name, IFNAMSIZ); | ||
| 1035 | |||
| 1036 | ieee80211_debugfs_rename_netdev(sdata); | ||
| 1037 | return 0; | ||
| 1038 | } | ||
| 1039 | |||
| 1040 | static struct notifier_block mac80211_netdev_notifier = { | ||
| 1041 | .notifier_call = netdev_notify, | ||
| 1042 | }; | ||
| 1043 | |||
| 1044 | int ieee80211_iface_init(void) | ||
| 1045 | { | ||
| 1046 | return register_netdevice_notifier(&mac80211_netdev_notifier); | ||
| 1047 | } | ||
| 1048 | |||
| 1049 | void ieee80211_iface_exit(void) | ||
| 1050 | { | ||
| 1051 | unregister_netdevice_notifier(&mac80211_netdev_notifier); | ||
| 1052 | } | ||
diff --git a/net/mac80211/key.c b/net/mac80211/key.c index 659a42d529e3..8160d9c5372e 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c | |||
| @@ -139,7 +139,7 @@ static void ieee80211_key_enable_hw_accel(struct ieee80211_key *key) | |||
| 139 | struct ieee80211_sub_if_data, | 139 | struct ieee80211_sub_if_data, |
| 140 | u.ap); | 140 | u.ap); |
| 141 | 141 | ||
| 142 | ret = drv_set_key(key->local, SET_KEY, &sdata->vif, sta, &key->conf); | 142 | ret = drv_set_key(key->local, SET_KEY, sdata, sta, &key->conf); |
| 143 | 143 | ||
| 144 | if (!ret) { | 144 | if (!ret) { |
| 145 | spin_lock_bh(&todo_lock); | 145 | spin_lock_bh(&todo_lock); |
| @@ -181,7 +181,7 @@ static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key) | |||
| 181 | struct ieee80211_sub_if_data, | 181 | struct ieee80211_sub_if_data, |
| 182 | u.ap); | 182 | u.ap); |
| 183 | 183 | ||
| 184 | ret = drv_set_key(key->local, DISABLE_KEY, &sdata->vif, | 184 | ret = drv_set_key(key->local, DISABLE_KEY, sdata, |
| 185 | sta, &key->conf); | 185 | sta, &key->conf); |
| 186 | 186 | ||
| 187 | if (ret) | 187 | if (ret) |
| @@ -421,7 +421,7 @@ void ieee80211_key_link(struct ieee80211_key *key, | |||
| 421 | */ | 421 | */ |
| 422 | 422 | ||
| 423 | /* same here, the AP could be using QoS */ | 423 | /* same here, the AP could be using QoS */ |
| 424 | ap = sta_info_get(key->local, key->sdata->u.mgd.bssid); | 424 | ap = sta_info_get(key->sdata, key->sdata->u.mgd.bssid); |
| 425 | if (ap) { | 425 | if (ap) { |
| 426 | if (test_sta_flags(ap, WLAN_STA_WME)) | 426 | if (test_sta_flags(ap, WLAN_STA_WME)) |
| 427 | key->conf.flags |= | 427 | key->conf.flags |= |
| @@ -443,7 +443,7 @@ void ieee80211_key_link(struct ieee80211_key *key, | |||
| 443 | add_todo(old_key, KEY_FLAG_TODO_DELETE); | 443 | add_todo(old_key, KEY_FLAG_TODO_DELETE); |
| 444 | 444 | ||
| 445 | add_todo(key, KEY_FLAG_TODO_ADD_DEBUGFS); | 445 | add_todo(key, KEY_FLAG_TODO_ADD_DEBUGFS); |
| 446 | if (netif_running(sdata->dev)) | 446 | if (ieee80211_sdata_running(sdata)) |
| 447 | add_todo(key, KEY_FLAG_TODO_HWACCEL_ADD); | 447 | add_todo(key, KEY_FLAG_TODO_HWACCEL_ADD); |
| 448 | 448 | ||
| 449 | spin_unlock_irqrestore(&sdata->local->key_lock, flags); | 449 | spin_unlock_irqrestore(&sdata->local->key_lock, flags); |
| @@ -509,7 +509,7 @@ void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata) | |||
| 509 | { | 509 | { |
| 510 | ASSERT_RTNL(); | 510 | ASSERT_RTNL(); |
| 511 | 511 | ||
| 512 | if (WARN_ON(!netif_running(sdata->dev))) | 512 | if (WARN_ON(!ieee80211_sdata_running(sdata))) |
| 513 | return; | 513 | return; |
| 514 | 514 | ||
| 515 | ieee80211_todo_for_each_key(sdata, KEY_FLAG_TODO_HWACCEL_ADD); | 515 | ieee80211_todo_for_each_key(sdata, KEY_FLAG_TODO_HWACCEL_ADD); |
diff --git a/net/mac80211/key.h b/net/mac80211/key.h index a49f93b79e92..bdc2968c2bbe 100644 --- a/net/mac80211/key.h +++ b/net/mac80211/key.h | |||
| @@ -59,11 +59,17 @@ enum ieee80211_internal_key_flags { | |||
| 59 | KEY_FLAG_TODO_DEFMGMTKEY = BIT(6), | 59 | KEY_FLAG_TODO_DEFMGMTKEY = BIT(6), |
| 60 | }; | 60 | }; |
| 61 | 61 | ||
| 62 | enum ieee80211_internal_tkip_state { | ||
| 63 | TKIP_STATE_NOT_INIT, | ||
| 64 | TKIP_STATE_PHASE1_DONE, | ||
| 65 | TKIP_STATE_PHASE1_HW_UPLOADED, | ||
| 66 | }; | ||
| 67 | |||
| 62 | struct tkip_ctx { | 68 | struct tkip_ctx { |
| 63 | u32 iv32; | 69 | u32 iv32; |
| 64 | u16 iv16; | 70 | u16 iv16; |
| 65 | u16 p1k[5]; | 71 | u16 p1k[5]; |
| 66 | int initialized; | 72 | enum ieee80211_internal_tkip_state state; |
| 67 | }; | 73 | }; |
| 68 | 74 | ||
| 69 | struct ieee80211_key { | 75 | struct ieee80211_key { |
diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 0d2d94881f1f..06c33b68d8e5 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c | |||
| @@ -17,7 +17,6 @@ | |||
| 17 | #include <linux/skbuff.h> | 17 | #include <linux/skbuff.h> |
| 18 | #include <linux/etherdevice.h> | 18 | #include <linux/etherdevice.h> |
| 19 | #include <linux/if_arp.h> | 19 | #include <linux/if_arp.h> |
| 20 | #include <linux/wireless.h> | ||
| 21 | #include <linux/rtnetlink.h> | 20 | #include <linux/rtnetlink.h> |
| 22 | #include <linux/bitmap.h> | 21 | #include <linux/bitmap.h> |
| 23 | #include <linux/pm_qos_params.h> | 22 | #include <linux/pm_qos_params.h> |
| @@ -32,7 +31,12 @@ | |||
| 32 | #include "led.h" | 31 | #include "led.h" |
| 33 | #include "cfg.h" | 32 | #include "cfg.h" |
| 34 | #include "debugfs.h" | 33 | #include "debugfs.h" |
| 35 | #include "debugfs_netdev.h" | 34 | |
| 35 | |||
| 36 | bool ieee80211_disable_40mhz_24ghz; | ||
| 37 | module_param(ieee80211_disable_40mhz_24ghz, bool, 0644); | ||
| 38 | MODULE_PARM_DESC(ieee80211_disable_40mhz_24ghz, | ||
| 39 | "Disable 40MHz support in the 2.4GHz band"); | ||
| 36 | 40 | ||
| 37 | void ieee80211_configure_filter(struct ieee80211_local *local) | 41 | void ieee80211_configure_filter(struct ieee80211_local *local) |
| 38 | { | 42 | { |
| @@ -102,6 +106,9 @@ int ieee80211_hw_config(struct ieee80211_local *local, u32 changed) | |||
| 102 | if (scan_chan) { | 106 | if (scan_chan) { |
| 103 | chan = scan_chan; | 107 | chan = scan_chan; |
| 104 | channel_type = NL80211_CHAN_NO_HT; | 108 | channel_type = NL80211_CHAN_NO_HT; |
| 109 | } else if (local->tmp_channel) { | ||
| 110 | chan = scan_chan = local->tmp_channel; | ||
| 111 | channel_type = local->tmp_channel_type; | ||
| 105 | } else { | 112 | } else { |
| 106 | chan = local->oper_channel; | 113 | chan = local->oper_channel; |
| 107 | channel_type = local->oper_channel_type; | 114 | channel_type = local->oper_channel_type; |
| @@ -114,6 +121,18 @@ int ieee80211_hw_config(struct ieee80211_local *local, u32 changed) | |||
| 114 | changed |= IEEE80211_CONF_CHANGE_CHANNEL; | 121 | changed |= IEEE80211_CONF_CHANGE_CHANNEL; |
| 115 | } | 122 | } |
| 116 | 123 | ||
| 124 | if (!conf_is_ht(&local->hw.conf)) { | ||
| 125 | /* | ||
| 126 | * mac80211.h documents that this is only valid | ||
| 127 | * when the channel is set to an HT type, and | ||
| 128 | * that otherwise STATIC is used. | ||
| 129 | */ | ||
| 130 | local->hw.conf.smps_mode = IEEE80211_SMPS_STATIC; | ||
| 131 | } else if (local->hw.conf.smps_mode != local->smps_mode) { | ||
| 132 | local->hw.conf.smps_mode = local->smps_mode; | ||
| 133 | changed |= IEEE80211_CONF_CHANGE_SMPS; | ||
| 134 | } | ||
| 135 | |||
| 117 | if (scan_chan) | 136 | if (scan_chan) |
| 118 | power = chan->max_power; | 137 | power = chan->max_power; |
| 119 | else | 138 | else |
| @@ -173,7 +192,7 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata, | |||
| 173 | } else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) | 192 | } else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) |
| 174 | sdata->vif.bss_conf.bssid = sdata->u.ibss.bssid; | 193 | sdata->vif.bss_conf.bssid = sdata->u.ibss.bssid; |
| 175 | else if (sdata->vif.type == NL80211_IFTYPE_AP) | 194 | else if (sdata->vif.type == NL80211_IFTYPE_AP) |
| 176 | sdata->vif.bss_conf.bssid = sdata->dev->dev_addr; | 195 | sdata->vif.bss_conf.bssid = sdata->vif.addr; |
| 177 | else if (ieee80211_vif_is_mesh(&sdata->vif)) { | 196 | else if (ieee80211_vif_is_mesh(&sdata->vif)) { |
| 178 | sdata->vif.bss_conf.bssid = zero; | 197 | sdata->vif.bss_conf.bssid = zero; |
| 179 | } else { | 198 | } else { |
| @@ -195,7 +214,7 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata, | |||
| 195 | } | 214 | } |
| 196 | 215 | ||
| 197 | if (changed & BSS_CHANGED_BEACON_ENABLED) { | 216 | if (changed & BSS_CHANGED_BEACON_ENABLED) { |
| 198 | if (local->quiescing || !netif_running(sdata->dev) || | 217 | if (local->quiescing || !ieee80211_sdata_running(sdata) || |
| 199 | test_bit(SCAN_SW_SCANNING, &local->scanning)) { | 218 | test_bit(SCAN_SW_SCANNING, &local->scanning)) { |
| 200 | sdata->vif.bss_conf.enable_beacon = false; | 219 | sdata->vif.bss_conf.enable_beacon = false; |
| 201 | } else { | 220 | } else { |
| @@ -223,8 +242,7 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata, | |||
| 223 | } | 242 | } |
| 224 | } | 243 | } |
| 225 | 244 | ||
| 226 | drv_bss_info_changed(local, &sdata->vif, | 245 | drv_bss_info_changed(local, sdata, &sdata->vif.bss_conf, changed); |
| 227 | &sdata->vif.bss_conf, changed); | ||
| 228 | } | 246 | } |
| 229 | 247 | ||
| 230 | u32 ieee80211_reset_erp_info(struct ieee80211_sub_if_data *sdata) | 248 | u32 ieee80211_reset_erp_info(struct ieee80211_sub_if_data *sdata) |
| @@ -299,6 +317,16 @@ void ieee80211_restart_hw(struct ieee80211_hw *hw) | |||
| 299 | } | 317 | } |
| 300 | EXPORT_SYMBOL(ieee80211_restart_hw); | 318 | EXPORT_SYMBOL(ieee80211_restart_hw); |
| 301 | 319 | ||
| 320 | static void ieee80211_recalc_smps_work(struct work_struct *work) | ||
| 321 | { | ||
| 322 | struct ieee80211_local *local = | ||
| 323 | container_of(work, struct ieee80211_local, recalc_smps); | ||
| 324 | |||
| 325 | mutex_lock(&local->iflist_mtx); | ||
| 326 | ieee80211_recalc_smps(local, NULL); | ||
| 327 | mutex_unlock(&local->iflist_mtx); | ||
| 328 | } | ||
| 329 | |||
| 302 | struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | 330 | struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, |
| 303 | const struct ieee80211_ops *ops) | 331 | const struct ieee80211_ops *ops) |
| 304 | { | 332 | { |
| @@ -333,9 +361,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
| 333 | WIPHY_FLAG_4ADDR_STATION; | 361 | WIPHY_FLAG_4ADDR_STATION; |
| 334 | wiphy->privid = mac80211_wiphy_privid; | 362 | wiphy->privid = mac80211_wiphy_privid; |
| 335 | 363 | ||
| 336 | /* Yes, putting cfg80211_bss into ieee80211_bss is a hack */ | 364 | wiphy->bss_priv_size = sizeof(struct ieee80211_bss); |
| 337 | wiphy->bss_priv_size = sizeof(struct ieee80211_bss) - | ||
| 338 | sizeof(struct cfg80211_bss); | ||
| 339 | 365 | ||
| 340 | local = wiphy_priv(wiphy); | 366 | local = wiphy_priv(wiphy); |
| 341 | 367 | ||
| @@ -358,6 +384,8 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
| 358 | local->hw.conf.long_frame_max_tx_count = wiphy->retry_long; | 384 | local->hw.conf.long_frame_max_tx_count = wiphy->retry_long; |
| 359 | local->hw.conf.short_frame_max_tx_count = wiphy->retry_short; | 385 | local->hw.conf.short_frame_max_tx_count = wiphy->retry_short; |
| 360 | local->user_power_level = -1; | 386 | local->user_power_level = -1; |
| 387 | local->uapsd_queues = IEEE80211_DEFAULT_UAPSD_QUEUES; | ||
| 388 | local->uapsd_max_sp_len = IEEE80211_DEFAULT_MAX_SP_LEN; | ||
| 361 | 389 | ||
| 362 | INIT_LIST_HEAD(&local->interfaces); | 390 | INIT_LIST_HEAD(&local->interfaces); |
| 363 | mutex_init(&local->iflist_mtx); | 391 | mutex_init(&local->iflist_mtx); |
| @@ -369,9 +397,13 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
| 369 | 397 | ||
| 370 | INIT_DELAYED_WORK(&local->scan_work, ieee80211_scan_work); | 398 | INIT_DELAYED_WORK(&local->scan_work, ieee80211_scan_work); |
| 371 | 399 | ||
| 400 | ieee80211_work_init(local); | ||
| 401 | |||
| 372 | INIT_WORK(&local->restart_work, ieee80211_restart_work); | 402 | INIT_WORK(&local->restart_work, ieee80211_restart_work); |
| 373 | 403 | ||
| 374 | INIT_WORK(&local->reconfig_filter, ieee80211_reconfig_filter); | 404 | INIT_WORK(&local->reconfig_filter, ieee80211_reconfig_filter); |
| 405 | INIT_WORK(&local->recalc_smps, ieee80211_recalc_smps_work); | ||
| 406 | local->smps_mode = IEEE80211_SMPS_OFF; | ||
| 375 | 407 | ||
| 376 | INIT_WORK(&local->dynamic_ps_enable_work, | 408 | INIT_WORK(&local->dynamic_ps_enable_work, |
| 377 | ieee80211_dynamic_ps_enable_work); | 409 | ieee80211_dynamic_ps_enable_work); |
| @@ -461,6 +493,10 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
| 461 | else if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC) | 493 | else if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC) |
| 462 | local->hw.wiphy->signal_type = CFG80211_SIGNAL_TYPE_UNSPEC; | 494 | local->hw.wiphy->signal_type = CFG80211_SIGNAL_TYPE_UNSPEC; |
| 463 | 495 | ||
| 496 | WARN((local->hw.flags & IEEE80211_HW_SUPPORTS_UAPSD) | ||
| 497 | && (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK), | ||
| 498 | "U-APSD not supported with HW_PS_NULLFUNC_STACK\n"); | ||
| 499 | |||
| 464 | /* | 500 | /* |
| 465 | * Calculate scan IE length -- we need this to alloc | 501 | * Calculate scan IE length -- we need this to alloc |
| 466 | * memory and to subtract from the driver limit. It | 502 | * memory and to subtract from the driver limit. It |
| @@ -522,8 +558,12 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
| 522 | 558 | ||
| 523 | debugfs_hw_add(local); | 559 | debugfs_hw_add(local); |
| 524 | 560 | ||
| 561 | /* | ||
| 562 | * if the driver doesn't specify a max listen interval we | ||
| 563 | * use 5 which should be a safe default | ||
| 564 | */ | ||
| 525 | if (local->hw.max_listen_interval == 0) | 565 | if (local->hw.max_listen_interval == 0) |
| 526 | local->hw.max_listen_interval = 1; | 566 | local->hw.max_listen_interval = 5; |
| 527 | 567 | ||
| 528 | local->hw.conf.listen_interval = local->hw.max_listen_interval; | 568 | local->hw.conf.listen_interval = local->hw.max_listen_interval; |
| 529 | 569 | ||
| @@ -674,11 +714,19 @@ static int __init ieee80211_init(void) | |||
| 674 | 714 | ||
| 675 | ret = rc80211_pid_init(); | 715 | ret = rc80211_pid_init(); |
| 676 | if (ret) | 716 | if (ret) |
| 677 | return ret; | 717 | goto err_pid; |
| 678 | 718 | ||
| 679 | ieee80211_debugfs_netdev_init(); | 719 | ret = ieee80211_iface_init(); |
| 720 | if (ret) | ||
| 721 | goto err_netdev; | ||
| 680 | 722 | ||
| 681 | return 0; | 723 | return 0; |
| 724 | err_netdev: | ||
| 725 | rc80211_pid_exit(); | ||
| 726 | err_pid: | ||
| 727 | rc80211_minstrel_exit(); | ||
| 728 | |||
| 729 | return ret; | ||
| 682 | } | 730 | } |
| 683 | 731 | ||
| 684 | static void __exit ieee80211_exit(void) | 732 | static void __exit ieee80211_exit(void) |
| @@ -695,7 +743,7 @@ static void __exit ieee80211_exit(void) | |||
| 695 | if (mesh_allocated) | 743 | if (mesh_allocated) |
| 696 | ieee80211s_stop(); | 744 | ieee80211s_stop(); |
| 697 | 745 | ||
| 698 | ieee80211_debugfs_netdev_exit(); | 746 | ieee80211_iface_exit(); |
| 699 | } | 747 | } |
| 700 | 748 | ||
| 701 | 749 | ||
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index 6a4331429598..61080c5fad50 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c | |||
| @@ -457,7 +457,7 @@ static void ieee80211_mesh_housekeeping(struct ieee80211_sub_if_data *sdata, | |||
| 457 | 457 | ||
| 458 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | 458 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG |
| 459 | printk(KERN_DEBUG "%s: running mesh housekeeping\n", | 459 | printk(KERN_DEBUG "%s: running mesh housekeeping\n", |
| 460 | sdata->dev->name); | 460 | sdata->name); |
| 461 | #endif | 461 | #endif |
| 462 | 462 | ||
| 463 | ieee80211_sta_expire(sdata, IEEE80211_MESH_PEER_INACTIVITY_LIMIT); | 463 | ieee80211_sta_expire(sdata, IEEE80211_MESH_PEER_INACTIVITY_LIMIT); |
| @@ -565,7 +565,7 @@ static void ieee80211_mesh_rx_bcn_presp(struct ieee80211_sub_if_data *sdata, | |||
| 565 | 565 | ||
| 566 | /* ignore ProbeResp to foreign address */ | 566 | /* ignore ProbeResp to foreign address */ |
| 567 | if (stype == IEEE80211_STYPE_PROBE_RESP && | 567 | if (stype == IEEE80211_STYPE_PROBE_RESP && |
| 568 | compare_ether_addr(mgmt->da, sdata->dev->dev_addr)) | 568 | compare_ether_addr(mgmt->da, sdata->vif.addr)) |
| 569 | return; | 569 | return; |
| 570 | 570 | ||
| 571 | baselen = (u8 *) mgmt->u.probe_resp.variable - (u8 *) mgmt; | 571 | baselen = (u8 *) mgmt->u.probe_resp.variable - (u8 *) mgmt; |
| @@ -645,7 +645,7 @@ static void ieee80211_mesh_work(struct work_struct *work) | |||
| 645 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | 645 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; |
| 646 | struct sk_buff *skb; | 646 | struct sk_buff *skb; |
| 647 | 647 | ||
| 648 | if (!netif_running(sdata->dev)) | 648 | if (!ieee80211_sdata_running(sdata)) |
| 649 | return; | 649 | return; |
| 650 | 650 | ||
| 651 | if (local->scanning) | 651 | if (local->scanning) |
diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index d28acb6b1f81..ce84237ebad3 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c | |||
| @@ -128,9 +128,9 @@ static int mesh_path_sel_frame_tx(enum mpath_frame_type action, u8 flags, | |||
| 128 | IEEE80211_STYPE_ACTION); | 128 | IEEE80211_STYPE_ACTION); |
| 129 | 129 | ||
| 130 | memcpy(mgmt->da, da, ETH_ALEN); | 130 | memcpy(mgmt->da, da, ETH_ALEN); |
| 131 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); | 131 | memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); |
| 132 | /* BSSID == SA */ | 132 | /* BSSID == SA */ |
| 133 | memcpy(mgmt->bssid, sdata->dev->dev_addr, ETH_ALEN); | 133 | memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN); |
| 134 | mgmt->u.action.category = MESH_PATH_SEL_CATEGORY; | 134 | mgmt->u.action.category = MESH_PATH_SEL_CATEGORY; |
| 135 | mgmt->u.action.u.mesh_action.action_code = MESH_PATH_SEL_ACTION; | 135 | mgmt->u.action.u.mesh_action.action_code = MESH_PATH_SEL_ACTION; |
| 136 | 136 | ||
| @@ -222,7 +222,7 @@ int mesh_path_error_tx(u8 ttl, u8 *target, __le32 target_sn, | |||
| 222 | IEEE80211_STYPE_ACTION); | 222 | IEEE80211_STYPE_ACTION); |
| 223 | 223 | ||
| 224 | memcpy(mgmt->da, ra, ETH_ALEN); | 224 | memcpy(mgmt->da, ra, ETH_ALEN); |
| 225 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); | 225 | memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); |
| 226 | /* BSSID is left zeroed, wildcard value */ | 226 | /* BSSID is left zeroed, wildcard value */ |
| 227 | mgmt->u.action.category = MESH_PATH_SEL_CATEGORY; | 227 | mgmt->u.action.category = MESH_PATH_SEL_CATEGORY; |
| 228 | mgmt->u.action.u.mesh_action.action_code = MESH_PATH_SEL_ACTION; | 228 | mgmt->u.action.u.mesh_action.action_code = MESH_PATH_SEL_ACTION; |
| @@ -335,7 +335,7 @@ static u32 hwmp_route_info_get(struct ieee80211_sub_if_data *sdata, | |||
| 335 | bool process = true; | 335 | bool process = true; |
| 336 | 336 | ||
| 337 | rcu_read_lock(); | 337 | rcu_read_lock(); |
| 338 | sta = sta_info_get(local, mgmt->sa); | 338 | sta = sta_info_get(sdata, mgmt->sa); |
| 339 | if (!sta) { | 339 | if (!sta) { |
| 340 | rcu_read_unlock(); | 340 | rcu_read_unlock(); |
| 341 | return 0; | 341 | return 0; |
| @@ -374,7 +374,7 @@ static u32 hwmp_route_info_get(struct ieee80211_sub_if_data *sdata, | |||
| 374 | new_metric = MAX_METRIC; | 374 | new_metric = MAX_METRIC; |
| 375 | exp_time = TU_TO_EXP_TIME(orig_lifetime); | 375 | exp_time = TU_TO_EXP_TIME(orig_lifetime); |
| 376 | 376 | ||
| 377 | if (memcmp(orig_addr, sdata->dev->dev_addr, ETH_ALEN) == 0) { | 377 | if (memcmp(orig_addr, sdata->vif.addr, ETH_ALEN) == 0) { |
| 378 | /* This MP is the originator, we are not interested in this | 378 | /* This MP is the originator, we are not interested in this |
| 379 | * frame, except for updating transmitter's path info. | 379 | * frame, except for updating transmitter's path info. |
| 380 | */ | 380 | */ |
| @@ -486,7 +486,7 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata, | |||
| 486 | 486 | ||
| 487 | mhwmp_dbg("received PREQ from %pM\n", orig_addr); | 487 | mhwmp_dbg("received PREQ from %pM\n", orig_addr); |
| 488 | 488 | ||
| 489 | if (memcmp(target_addr, sdata->dev->dev_addr, ETH_ALEN) == 0) { | 489 | if (memcmp(target_addr, sdata->vif.addr, ETH_ALEN) == 0) { |
| 490 | mhwmp_dbg("PREQ is for us\n"); | 490 | mhwmp_dbg("PREQ is for us\n"); |
| 491 | forward = false; | 491 | forward = false; |
| 492 | reply = true; | 492 | reply = true; |
| @@ -579,7 +579,7 @@ static void hwmp_prep_frame_process(struct ieee80211_sub_if_data *sdata, | |||
| 579 | * replies | 579 | * replies |
| 580 | */ | 580 | */ |
| 581 | target_addr = PREP_IE_TARGET_ADDR(prep_elem); | 581 | target_addr = PREP_IE_TARGET_ADDR(prep_elem); |
| 582 | if (memcmp(target_addr, sdata->dev->dev_addr, ETH_ALEN) == 0) | 582 | if (memcmp(target_addr, sdata->vif.addr, ETH_ALEN) == 0) |
| 583 | /* destination, no forwarding required */ | 583 | /* destination, no forwarding required */ |
| 584 | return; | 584 | return; |
| 585 | 585 | ||
| @@ -890,7 +890,7 @@ void mesh_path_start_discovery(struct ieee80211_sub_if_data *sdata) | |||
| 890 | target_flags = MP_F_RF; | 890 | target_flags = MP_F_RF; |
| 891 | 891 | ||
| 892 | spin_unlock_bh(&mpath->state_lock); | 892 | spin_unlock_bh(&mpath->state_lock); |
| 893 | mesh_path_sel_frame_tx(MPATH_PREQ, 0, sdata->dev->dev_addr, | 893 | mesh_path_sel_frame_tx(MPATH_PREQ, 0, sdata->vif.addr, |
| 894 | cpu_to_le32(ifmsh->sn), target_flags, mpath->dst, | 894 | cpu_to_le32(ifmsh->sn), target_flags, mpath->dst, |
| 895 | cpu_to_le32(mpath->sn), broadcast_addr, 0, | 895 | cpu_to_le32(mpath->sn), broadcast_addr, 0, |
| 896 | ttl, cpu_to_le32(lifetime), 0, | 896 | ttl, cpu_to_le32(lifetime), 0, |
| @@ -939,7 +939,7 @@ int mesh_nexthop_lookup(struct sk_buff *skb, | |||
| 939 | if (time_after(jiffies, | 939 | if (time_after(jiffies, |
| 940 | mpath->exp_time - | 940 | mpath->exp_time - |
| 941 | msecs_to_jiffies(sdata->u.mesh.mshcfg.path_refresh_time)) && | 941 | msecs_to_jiffies(sdata->u.mesh.mshcfg.path_refresh_time)) && |
| 942 | !memcmp(sdata->dev->dev_addr, hdr->addr4, ETH_ALEN) && | 942 | !memcmp(sdata->vif.addr, hdr->addr4, ETH_ALEN) && |
| 943 | !(mpath->flags & MESH_PATH_RESOLVING) && | 943 | !(mpath->flags & MESH_PATH_RESOLVING) && |
| 944 | !(mpath->flags & MESH_PATH_FIXED)) { | 944 | !(mpath->flags & MESH_PATH_FIXED)) { |
| 945 | mesh_queue_preq(mpath, | 945 | mesh_queue_preq(mpath, |
| @@ -1010,7 +1010,7 @@ mesh_path_tx_root_frame(struct ieee80211_sub_if_data *sdata) | |||
| 1010 | { | 1010 | { |
| 1011 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | 1011 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; |
| 1012 | 1012 | ||
| 1013 | mesh_path_sel_frame_tx(MPATH_RANN, 0, sdata->dev->dev_addr, | 1013 | mesh_path_sel_frame_tx(MPATH_RANN, 0, sdata->vif.addr, |
| 1014 | cpu_to_le32(++ifmsh->sn), | 1014 | cpu_to_le32(++ifmsh->sn), |
| 1015 | 0, NULL, 0, broadcast_addr, | 1015 | 0, NULL, 0, broadcast_addr, |
| 1016 | 0, MESH_TTL, 0, 0, 0, sdata); | 1016 | 0, MESH_TTL, 0, 0, 0, sdata); |
diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c index 0192cfdacae4..2312efe04c62 100644 --- a/net/mac80211/mesh_pathtbl.c +++ b/net/mac80211/mesh_pathtbl.c | |||
| @@ -260,7 +260,7 @@ int mesh_path_add(u8 *dst, struct ieee80211_sub_if_data *sdata) | |||
| 260 | int err = 0; | 260 | int err = 0; |
| 261 | u32 hash_idx; | 261 | u32 hash_idx; |
| 262 | 262 | ||
| 263 | if (memcmp(dst, sdata->dev->dev_addr, ETH_ALEN) == 0) | 263 | if (memcmp(dst, sdata->vif.addr, ETH_ALEN) == 0) |
| 264 | /* never add ourselves as neighbours */ | 264 | /* never add ourselves as neighbours */ |
| 265 | return -ENOTSUPP; | 265 | return -ENOTSUPP; |
| 266 | 266 | ||
| @@ -377,7 +377,7 @@ int mpp_path_add(u8 *dst, u8 *mpp, struct ieee80211_sub_if_data *sdata) | |||
| 377 | int err = 0; | 377 | int err = 0; |
| 378 | u32 hash_idx; | 378 | u32 hash_idx; |
| 379 | 379 | ||
| 380 | if (memcmp(dst, sdata->dev->dev_addr, ETH_ALEN) == 0) | 380 | if (memcmp(dst, sdata->vif.addr, ETH_ALEN) == 0) |
| 381 | /* never add ourselves as neighbours */ | 381 | /* never add ourselves as neighbours */ |
| 382 | return -ENOTSUPP; | 382 | return -ENOTSUPP; |
| 383 | 383 | ||
| @@ -605,7 +605,7 @@ void mesh_path_discard_frame(struct sk_buff *skb, | |||
| 605 | struct mesh_path *mpath; | 605 | struct mesh_path *mpath; |
| 606 | u32 sn = 0; | 606 | u32 sn = 0; |
| 607 | 607 | ||
| 608 | if (memcmp(hdr->addr4, sdata->dev->dev_addr, ETH_ALEN) != 0) { | 608 | if (memcmp(hdr->addr4, sdata->vif.addr, ETH_ALEN) != 0) { |
| 609 | u8 *ra, *da; | 609 | u8 *ra, *da; |
| 610 | 610 | ||
| 611 | da = hdr->addr3; | 611 | da = hdr->addr3; |
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index 0f7c6e6a4248..1a29c4a8139e 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c | |||
| @@ -102,7 +102,7 @@ static struct sta_info *mesh_plink_alloc(struct ieee80211_sub_if_data *sdata, | |||
| 102 | if (local->num_sta >= MESH_MAX_PLINKS) | 102 | if (local->num_sta >= MESH_MAX_PLINKS) |
| 103 | return NULL; | 103 | return NULL; |
| 104 | 104 | ||
| 105 | sta = sta_info_alloc(sdata, hw_addr, GFP_ATOMIC); | 105 | sta = sta_info_alloc(sdata, hw_addr, GFP_KERNEL); |
| 106 | if (!sta) | 106 | if (!sta) |
| 107 | return NULL; | 107 | return NULL; |
| 108 | 108 | ||
| @@ -169,7 +169,7 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, | |||
| 169 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | 169 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | |
| 170 | IEEE80211_STYPE_ACTION); | 170 | IEEE80211_STYPE_ACTION); |
| 171 | memcpy(mgmt->da, da, ETH_ALEN); | 171 | memcpy(mgmt->da, da, ETH_ALEN); |
| 172 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); | 172 | memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); |
| 173 | /* BSSID is left zeroed, wildcard value */ | 173 | /* BSSID is left zeroed, wildcard value */ |
| 174 | mgmt->u.action.category = MESH_PLINK_CATEGORY; | 174 | mgmt->u.action.category = MESH_PLINK_CATEGORY; |
| 175 | mgmt->u.action.u.plink_action.action_code = action; | 175 | mgmt->u.action.u.plink_action.action_code = action; |
| @@ -234,14 +234,14 @@ void mesh_neighbour_update(u8 *hw_addr, u32 rates, struct ieee80211_sub_if_data | |||
| 234 | 234 | ||
| 235 | rcu_read_lock(); | 235 | rcu_read_lock(); |
| 236 | 236 | ||
| 237 | sta = sta_info_get(local, hw_addr); | 237 | sta = sta_info_get(sdata, hw_addr); |
| 238 | if (!sta) { | 238 | if (!sta) { |
| 239 | rcu_read_unlock(); | ||
| 240 | |||
| 239 | sta = mesh_plink_alloc(sdata, hw_addr, rates); | 241 | sta = mesh_plink_alloc(sdata, hw_addr, rates); |
| 240 | if (!sta) { | 242 | if (!sta) |
| 241 | rcu_read_unlock(); | ||
| 242 | return; | 243 | return; |
| 243 | } | 244 | if (sta_info_insert_rcu(sta)) { |
| 244 | if (sta_info_insert(sta)) { | ||
| 245 | rcu_read_unlock(); | 245 | rcu_read_unlock(); |
| 246 | return; | 246 | return; |
| 247 | } | 247 | } |
| @@ -455,7 +455,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
| 455 | 455 | ||
| 456 | rcu_read_lock(); | 456 | rcu_read_lock(); |
| 457 | 457 | ||
| 458 | sta = sta_info_get(local, mgmt->sa); | 458 | sta = sta_info_get(sdata, mgmt->sa); |
| 459 | if (!sta && ftype != PLINK_OPEN) { | 459 | if (!sta && ftype != PLINK_OPEN) { |
| 460 | mpl_dbg("Mesh plink: cls or cnf from unknown peer\n"); | 460 | mpl_dbg("Mesh plink: cls or cnf from unknown peer\n"); |
| 461 | rcu_read_unlock(); | 461 | rcu_read_unlock(); |
| @@ -485,9 +485,11 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
| 485 | } else if (!sta) { | 485 | } else if (!sta) { |
| 486 | /* ftype == PLINK_OPEN */ | 486 | /* ftype == PLINK_OPEN */ |
| 487 | u32 rates; | 487 | u32 rates; |
| 488 | |||
| 489 | rcu_read_unlock(); | ||
| 490 | |||
| 488 | if (!mesh_plink_free_count(sdata)) { | 491 | if (!mesh_plink_free_count(sdata)) { |
| 489 | mpl_dbg("Mesh plink error: no more free plinks\n"); | 492 | mpl_dbg("Mesh plink error: no more free plinks\n"); |
| 490 | rcu_read_unlock(); | ||
| 491 | return; | 493 | return; |
| 492 | } | 494 | } |
| 493 | 495 | ||
| @@ -495,10 +497,9 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
| 495 | sta = mesh_plink_alloc(sdata, mgmt->sa, rates); | 497 | sta = mesh_plink_alloc(sdata, mgmt->sa, rates); |
| 496 | if (!sta) { | 498 | if (!sta) { |
| 497 | mpl_dbg("Mesh plink error: plink table full\n"); | 499 | mpl_dbg("Mesh plink error: plink table full\n"); |
| 498 | rcu_read_unlock(); | ||
| 499 | return; | 500 | return; |
| 500 | } | 501 | } |
| 501 | if (sta_info_insert(sta)) { | 502 | if (sta_info_insert_rcu(sta)) { |
| 502 | rcu_read_unlock(); | 503 | rcu_read_unlock(); |
| 503 | return; | 504 | return; |
| 504 | } | 505 | } |
| @@ -743,7 +744,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
| 743 | break; | 744 | break; |
| 744 | default: | 745 | default: |
| 745 | /* should not get here, PLINK_BLOCKED is dealt with at the | 746 | /* should not get here, PLINK_BLOCKED is dealt with at the |
| 746 | * beggining of the function | 747 | * beginning of the function |
| 747 | */ | 748 | */ |
| 748 | spin_unlock_bh(&sta->lock); | 749 | spin_unlock_bh(&sta->lock); |
| 749 | break; | 750 | break; |
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 05a18f43e1bf..be5f723d643a 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
| @@ -27,10 +27,6 @@ | |||
| 27 | #include "rate.h" | 27 | #include "rate.h" |
| 28 | #include "led.h" | 28 | #include "led.h" |
| 29 | 29 | ||
| 30 | #define IEEE80211_AUTH_TIMEOUT (HZ / 5) | ||
| 31 | #define IEEE80211_AUTH_MAX_TRIES 3 | ||
| 32 | #define IEEE80211_ASSOC_TIMEOUT (HZ / 5) | ||
| 33 | #define IEEE80211_ASSOC_MAX_TRIES 3 | ||
| 34 | #define IEEE80211_MAX_PROBE_TRIES 5 | 30 | #define IEEE80211_MAX_PROBE_TRIES 5 |
| 35 | 31 | ||
| 36 | /* | 32 | /* |
| @@ -75,11 +71,8 @@ enum rx_mgmt_action { | |||
| 75 | /* caller must call cfg80211_send_disassoc() */ | 71 | /* caller must call cfg80211_send_disassoc() */ |
| 76 | RX_MGMT_CFG80211_DISASSOC, | 72 | RX_MGMT_CFG80211_DISASSOC, |
| 77 | 73 | ||
| 78 | /* caller must call cfg80211_auth_timeout() & free work */ | 74 | /* caller must tell cfg80211 about internal error */ |
| 79 | RX_MGMT_CFG80211_AUTH_TO, | 75 | RX_MGMT_CFG80211_ASSOC_ERROR, |
| 80 | |||
| 81 | /* caller must call cfg80211_assoc_timeout() & free work */ | ||
| 82 | RX_MGMT_CFG80211_ASSOC_TO, | ||
| 83 | }; | 76 | }; |
| 84 | 77 | ||
| 85 | /* utils */ | 78 | /* utils */ |
| @@ -122,27 +115,6 @@ static int ecw2cw(int ecw) | |||
| 122 | return (1 << ecw) - 1; | 115 | return (1 << ecw) - 1; |
| 123 | } | 116 | } |
| 124 | 117 | ||
| 125 | static int ieee80211_compatible_rates(struct ieee80211_bss *bss, | ||
| 126 | struct ieee80211_supported_band *sband, | ||
| 127 | u32 *rates) | ||
| 128 | { | ||
| 129 | int i, j, count; | ||
| 130 | *rates = 0; | ||
| 131 | count = 0; | ||
| 132 | for (i = 0; i < bss->supp_rates_len; i++) { | ||
| 133 | int rate = (bss->supp_rates[i] & 0x7F) * 5; | ||
| 134 | |||
| 135 | for (j = 0; j < sband->n_bitrates; j++) | ||
| 136 | if (sband->bitrates[j].bitrate == rate) { | ||
| 137 | *rates |= BIT(j); | ||
| 138 | count++; | ||
| 139 | break; | ||
| 140 | } | ||
| 141 | } | ||
| 142 | |||
| 143 | return count; | ||
| 144 | } | ||
| 145 | |||
| 146 | /* | 118 | /* |
| 147 | * ieee80211_enable_ht should be called only after the operating band | 119 | * ieee80211_enable_ht should be called only after the operating band |
| 148 | * has been determined as ht configuration depends on the hw's | 120 | * has been determined as ht configuration depends on the hw's |
| @@ -202,10 +174,11 @@ static u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata, | |||
| 202 | ieee80211_hw_config(local, 0); | 174 | ieee80211_hw_config(local, 0); |
| 203 | 175 | ||
| 204 | rcu_read_lock(); | 176 | rcu_read_lock(); |
| 205 | sta = sta_info_get(local, bssid); | 177 | sta = sta_info_get(sdata, bssid); |
| 206 | if (sta) | 178 | if (sta) |
| 207 | rate_control_rate_update(local, sband, sta, | 179 | rate_control_rate_update(local, sband, sta, |
| 208 | IEEE80211_RC_HT_CHANGED); | 180 | IEEE80211_RC_HT_CHANGED, |
| 181 | local->oper_channel_type); | ||
| 209 | rcu_read_unlock(); | 182 | rcu_read_unlock(); |
| 210 | } | 183 | } |
| 211 | 184 | ||
| @@ -228,209 +201,6 @@ static u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata, | |||
| 228 | 201 | ||
| 229 | /* frame sending functions */ | 202 | /* frame sending functions */ |
| 230 | 203 | ||
| 231 | static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, | ||
| 232 | struct ieee80211_mgd_work *wk) | ||
| 233 | { | ||
| 234 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
| 235 | struct ieee80211_local *local = sdata->local; | ||
| 236 | struct sk_buff *skb; | ||
| 237 | struct ieee80211_mgmt *mgmt; | ||
| 238 | u8 *pos; | ||
| 239 | const u8 *ies, *ht_ie; | ||
| 240 | int i, len, count, rates_len, supp_rates_len; | ||
| 241 | u16 capab; | ||
| 242 | int wmm = 0; | ||
| 243 | struct ieee80211_supported_band *sband; | ||
| 244 | u32 rates = 0; | ||
| 245 | |||
| 246 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + | ||
| 247 | sizeof(*mgmt) + 200 + wk->ie_len + | ||
| 248 | wk->ssid_len); | ||
| 249 | if (!skb) { | ||
| 250 | printk(KERN_DEBUG "%s: failed to allocate buffer for assoc " | ||
| 251 | "frame\n", sdata->dev->name); | ||
| 252 | return; | ||
| 253 | } | ||
| 254 | skb_reserve(skb, local->hw.extra_tx_headroom); | ||
| 255 | |||
| 256 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | ||
| 257 | |||
| 258 | capab = ifmgd->capab; | ||
| 259 | |||
| 260 | if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ) { | ||
| 261 | if (!(local->hw.flags & IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE)) | ||
| 262 | capab |= WLAN_CAPABILITY_SHORT_SLOT_TIME; | ||
| 263 | if (!(local->hw.flags & IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE)) | ||
| 264 | capab |= WLAN_CAPABILITY_SHORT_PREAMBLE; | ||
| 265 | } | ||
| 266 | |||
| 267 | if (wk->bss->cbss.capability & WLAN_CAPABILITY_PRIVACY) | ||
| 268 | capab |= WLAN_CAPABILITY_PRIVACY; | ||
| 269 | if (wk->bss->wmm_used) | ||
| 270 | wmm = 1; | ||
| 271 | |||
| 272 | /* get all rates supported by the device and the AP as | ||
| 273 | * some APs don't like getting a superset of their rates | ||
| 274 | * in the association request (e.g. D-Link DAP 1353 in | ||
| 275 | * b-only mode) */ | ||
| 276 | rates_len = ieee80211_compatible_rates(wk->bss, sband, &rates); | ||
| 277 | |||
| 278 | if ((wk->bss->cbss.capability & WLAN_CAPABILITY_SPECTRUM_MGMT) && | ||
| 279 | (local->hw.flags & IEEE80211_HW_SPECTRUM_MGMT)) | ||
| 280 | capab |= WLAN_CAPABILITY_SPECTRUM_MGMT; | ||
| 281 | |||
| 282 | mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); | ||
| 283 | memset(mgmt, 0, 24); | ||
| 284 | memcpy(mgmt->da, wk->bss->cbss.bssid, ETH_ALEN); | ||
| 285 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); | ||
| 286 | memcpy(mgmt->bssid, wk->bss->cbss.bssid, ETH_ALEN); | ||
| 287 | |||
| 288 | if (!is_zero_ether_addr(wk->prev_bssid)) { | ||
| 289 | skb_put(skb, 10); | ||
| 290 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | ||
| 291 | IEEE80211_STYPE_REASSOC_REQ); | ||
| 292 | mgmt->u.reassoc_req.capab_info = cpu_to_le16(capab); | ||
| 293 | mgmt->u.reassoc_req.listen_interval = | ||
| 294 | cpu_to_le16(local->hw.conf.listen_interval); | ||
| 295 | memcpy(mgmt->u.reassoc_req.current_ap, wk->prev_bssid, | ||
| 296 | ETH_ALEN); | ||
| 297 | } else { | ||
| 298 | skb_put(skb, 4); | ||
| 299 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | ||
| 300 | IEEE80211_STYPE_ASSOC_REQ); | ||
| 301 | mgmt->u.assoc_req.capab_info = cpu_to_le16(capab); | ||
| 302 | mgmt->u.assoc_req.listen_interval = | ||
| 303 | cpu_to_le16(local->hw.conf.listen_interval); | ||
| 304 | } | ||
| 305 | |||
| 306 | /* SSID */ | ||
| 307 | ies = pos = skb_put(skb, 2 + wk->ssid_len); | ||
| 308 | *pos++ = WLAN_EID_SSID; | ||
| 309 | *pos++ = wk->ssid_len; | ||
| 310 | memcpy(pos, wk->ssid, wk->ssid_len); | ||
| 311 | |||
| 312 | /* add all rates which were marked to be used above */ | ||
| 313 | supp_rates_len = rates_len; | ||
| 314 | if (supp_rates_len > 8) | ||
| 315 | supp_rates_len = 8; | ||
| 316 | |||
| 317 | len = sband->n_bitrates; | ||
| 318 | pos = skb_put(skb, supp_rates_len + 2); | ||
| 319 | *pos++ = WLAN_EID_SUPP_RATES; | ||
| 320 | *pos++ = supp_rates_len; | ||
| 321 | |||
| 322 | count = 0; | ||
| 323 | for (i = 0; i < sband->n_bitrates; i++) { | ||
| 324 | if (BIT(i) & rates) { | ||
| 325 | int rate = sband->bitrates[i].bitrate; | ||
| 326 | *pos++ = (u8) (rate / 5); | ||
| 327 | if (++count == 8) | ||
| 328 | break; | ||
| 329 | } | ||
| 330 | } | ||
| 331 | |||
| 332 | if (rates_len > count) { | ||
| 333 | pos = skb_put(skb, rates_len - count + 2); | ||
| 334 | *pos++ = WLAN_EID_EXT_SUPP_RATES; | ||
| 335 | *pos++ = rates_len - count; | ||
| 336 | |||
| 337 | for (i++; i < sband->n_bitrates; i++) { | ||
| 338 | if (BIT(i) & rates) { | ||
| 339 | int rate = sband->bitrates[i].bitrate; | ||
| 340 | *pos++ = (u8) (rate / 5); | ||
| 341 | } | ||
| 342 | } | ||
| 343 | } | ||
| 344 | |||
| 345 | if (capab & WLAN_CAPABILITY_SPECTRUM_MGMT) { | ||
| 346 | /* 1. power capabilities */ | ||
| 347 | pos = skb_put(skb, 4); | ||
| 348 | *pos++ = WLAN_EID_PWR_CAPABILITY; | ||
| 349 | *pos++ = 2; | ||
| 350 | *pos++ = 0; /* min tx power */ | ||
| 351 | *pos++ = local->hw.conf.channel->max_power; /* max tx power */ | ||
| 352 | |||
| 353 | /* 2. supported channels */ | ||
| 354 | /* TODO: get this in reg domain format */ | ||
| 355 | pos = skb_put(skb, 2 * sband->n_channels + 2); | ||
| 356 | *pos++ = WLAN_EID_SUPPORTED_CHANNELS; | ||
| 357 | *pos++ = 2 * sband->n_channels; | ||
| 358 | for (i = 0; i < sband->n_channels; i++) { | ||
| 359 | *pos++ = ieee80211_frequency_to_channel( | ||
| 360 | sband->channels[i].center_freq); | ||
| 361 | *pos++ = 1; /* one channel in the subband*/ | ||
| 362 | } | ||
| 363 | } | ||
| 364 | |||
| 365 | if (wk->ie_len && wk->ie) { | ||
| 366 | pos = skb_put(skb, wk->ie_len); | ||
| 367 | memcpy(pos, wk->ie, wk->ie_len); | ||
| 368 | } | ||
| 369 | |||
| 370 | if (wmm && (ifmgd->flags & IEEE80211_STA_WMM_ENABLED)) { | ||
| 371 | pos = skb_put(skb, 9); | ||
| 372 | *pos++ = WLAN_EID_VENDOR_SPECIFIC; | ||
| 373 | *pos++ = 7; /* len */ | ||
| 374 | *pos++ = 0x00; /* Microsoft OUI 00:50:F2 */ | ||
| 375 | *pos++ = 0x50; | ||
| 376 | *pos++ = 0xf2; | ||
| 377 | *pos++ = 2; /* WME */ | ||
| 378 | *pos++ = 0; /* WME info */ | ||
| 379 | *pos++ = 1; /* WME ver */ | ||
| 380 | *pos++ = 0; | ||
| 381 | } | ||
| 382 | |||
| 383 | /* wmm support is a must to HT */ | ||
| 384 | /* | ||
| 385 | * IEEE802.11n does not allow TKIP/WEP as pairwise | ||
| 386 | * ciphers in HT mode. We still associate in non-ht | ||
| 387 | * mode (11a/b/g) if any one of these ciphers is | ||
| 388 | * configured as pairwise. | ||
| 389 | */ | ||
| 390 | if (wmm && (ifmgd->flags & IEEE80211_STA_WMM_ENABLED) && | ||
| 391 | sband->ht_cap.ht_supported && | ||
| 392 | (ht_ie = ieee80211_bss_get_ie(&wk->bss->cbss, WLAN_EID_HT_INFORMATION)) && | ||
| 393 | ht_ie[1] >= sizeof(struct ieee80211_ht_info) && | ||
| 394 | (!(ifmgd->flags & IEEE80211_STA_DISABLE_11N))) { | ||
| 395 | struct ieee80211_ht_info *ht_info = | ||
| 396 | (struct ieee80211_ht_info *)(ht_ie + 2); | ||
| 397 | u16 cap = sband->ht_cap.cap; | ||
| 398 | __le16 tmp; | ||
| 399 | u32 flags = local->hw.conf.channel->flags; | ||
| 400 | |||
| 401 | switch (ht_info->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) { | ||
| 402 | case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: | ||
| 403 | if (flags & IEEE80211_CHAN_NO_HT40PLUS) { | ||
| 404 | cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; | ||
| 405 | cap &= ~IEEE80211_HT_CAP_SGI_40; | ||
| 406 | } | ||
| 407 | break; | ||
| 408 | case IEEE80211_HT_PARAM_CHA_SEC_BELOW: | ||
| 409 | if (flags & IEEE80211_CHAN_NO_HT40MINUS) { | ||
| 410 | cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; | ||
| 411 | cap &= ~IEEE80211_HT_CAP_SGI_40; | ||
| 412 | } | ||
| 413 | break; | ||
| 414 | } | ||
| 415 | |||
| 416 | tmp = cpu_to_le16(cap); | ||
| 417 | pos = skb_put(skb, sizeof(struct ieee80211_ht_cap)+2); | ||
| 418 | *pos++ = WLAN_EID_HT_CAPABILITY; | ||
| 419 | *pos++ = sizeof(struct ieee80211_ht_cap); | ||
| 420 | memset(pos, 0, sizeof(struct ieee80211_ht_cap)); | ||
| 421 | memcpy(pos, &tmp, sizeof(u16)); | ||
| 422 | pos += sizeof(u16); | ||
| 423 | /* TODO: needs a define here for << 2 */ | ||
| 424 | *pos++ = sband->ht_cap.ampdu_factor | | ||
| 425 | (sband->ht_cap.ampdu_density << 2); | ||
| 426 | memcpy(pos, &sband->ht_cap.mcs, sizeof(sband->ht_cap.mcs)); | ||
| 427 | } | ||
| 428 | |||
| 429 | IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; | ||
| 430 | ieee80211_tx_skb(sdata, skb); | ||
| 431 | } | ||
| 432 | |||
| 433 | |||
| 434 | static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata, | 204 | static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata, |
| 435 | const u8 *bssid, u16 stype, u16 reason, | 205 | const u8 *bssid, u16 stype, u16 reason, |
| 436 | void *cookie) | 206 | void *cookie) |
| @@ -443,7 +213,7 @@ static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata, | |||
| 443 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*mgmt)); | 213 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*mgmt)); |
| 444 | if (!skb) { | 214 | if (!skb) { |
| 445 | printk(KERN_DEBUG "%s: failed to allocate buffer for " | 215 | printk(KERN_DEBUG "%s: failed to allocate buffer for " |
| 446 | "deauth/disassoc frame\n", sdata->dev->name); | 216 | "deauth/disassoc frame\n", sdata->name); |
| 447 | return; | 217 | return; |
| 448 | } | 218 | } |
| 449 | skb_reserve(skb, local->hw.extra_tx_headroom); | 219 | skb_reserve(skb, local->hw.extra_tx_headroom); |
| @@ -451,7 +221,7 @@ static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata, | |||
| 451 | mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); | 221 | mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); |
| 452 | memset(mgmt, 0, 24); | 222 | memset(mgmt, 0, 24); |
| 453 | memcpy(mgmt->da, bssid, ETH_ALEN); | 223 | memcpy(mgmt->da, bssid, ETH_ALEN); |
| 454 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); | 224 | memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); |
| 455 | memcpy(mgmt->bssid, bssid, ETH_ALEN); | 225 | memcpy(mgmt->bssid, bssid, ETH_ALEN); |
| 456 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | stype); | 226 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | stype); |
| 457 | skb_put(skb, 2); | 227 | skb_put(skb, 2); |
| @@ -476,30 +246,15 @@ static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata, | |||
| 476 | void ieee80211_send_pspoll(struct ieee80211_local *local, | 246 | void ieee80211_send_pspoll(struct ieee80211_local *local, |
| 477 | struct ieee80211_sub_if_data *sdata) | 247 | struct ieee80211_sub_if_data *sdata) |
| 478 | { | 248 | { |
| 479 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
| 480 | struct ieee80211_pspoll *pspoll; | 249 | struct ieee80211_pspoll *pspoll; |
| 481 | struct sk_buff *skb; | 250 | struct sk_buff *skb; |
| 482 | u16 fc; | ||
| 483 | 251 | ||
| 484 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*pspoll)); | 252 | skb = ieee80211_pspoll_get(&local->hw, &sdata->vif); |
| 485 | if (!skb) { | 253 | if (!skb) |
| 486 | printk(KERN_DEBUG "%s: failed to allocate buffer for " | ||
| 487 | "pspoll frame\n", sdata->dev->name); | ||
| 488 | return; | 254 | return; |
| 489 | } | ||
| 490 | skb_reserve(skb, local->hw.extra_tx_headroom); | ||
| 491 | 255 | ||
| 492 | pspoll = (struct ieee80211_pspoll *) skb_put(skb, sizeof(*pspoll)); | 256 | pspoll = (struct ieee80211_pspoll *) skb->data; |
| 493 | memset(pspoll, 0, sizeof(*pspoll)); | 257 | pspoll->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM); |
| 494 | fc = IEEE80211_FTYPE_CTL | IEEE80211_STYPE_PSPOLL | IEEE80211_FCTL_PM; | ||
| 495 | pspoll->frame_control = cpu_to_le16(fc); | ||
| 496 | pspoll->aid = cpu_to_le16(ifmgd->aid); | ||
| 497 | |||
| 498 | /* aid in PS-Poll has its two MSBs each set to 1 */ | ||
| 499 | pspoll->aid |= cpu_to_le16(1 << 15 | 1 << 14); | ||
| 500 | |||
| 501 | memcpy(pspoll->bssid, ifmgd->bssid, ETH_ALEN); | ||
| 502 | memcpy(pspoll->ta, sdata->dev->dev_addr, ETH_ALEN); | ||
| 503 | 258 | ||
| 504 | IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; | 259 | IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; |
| 505 | ieee80211_tx_skb(sdata, skb); | 260 | ieee80211_tx_skb(sdata, skb); |
| @@ -510,30 +265,47 @@ void ieee80211_send_nullfunc(struct ieee80211_local *local, | |||
| 510 | int powersave) | 265 | int powersave) |
| 511 | { | 266 | { |
| 512 | struct sk_buff *skb; | 267 | struct sk_buff *skb; |
| 268 | struct ieee80211_hdr_3addr *nullfunc; | ||
| 269 | |||
| 270 | skb = ieee80211_nullfunc_get(&local->hw, &sdata->vif); | ||
| 271 | if (!skb) | ||
| 272 | return; | ||
| 273 | |||
| 274 | nullfunc = (struct ieee80211_hdr_3addr *) skb->data; | ||
| 275 | if (powersave) | ||
| 276 | nullfunc->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM); | ||
| 277 | |||
| 278 | IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; | ||
| 279 | ieee80211_tx_skb(sdata, skb); | ||
| 280 | } | ||
| 281 | |||
| 282 | static void ieee80211_send_4addr_nullfunc(struct ieee80211_local *local, | ||
| 283 | struct ieee80211_sub_if_data *sdata) | ||
| 284 | { | ||
| 285 | struct sk_buff *skb; | ||
| 513 | struct ieee80211_hdr *nullfunc; | 286 | struct ieee80211_hdr *nullfunc; |
| 514 | __le16 fc; | 287 | __le16 fc; |
| 515 | 288 | ||
| 516 | if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION)) | 289 | if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION)) |
| 517 | return; | 290 | return; |
| 518 | 291 | ||
| 519 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + 24); | 292 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + 30); |
| 520 | if (!skb) { | 293 | if (!skb) { |
| 521 | printk(KERN_DEBUG "%s: failed to allocate buffer for nullfunc " | 294 | printk(KERN_DEBUG "%s: failed to allocate buffer for 4addr " |
| 522 | "frame\n", sdata->dev->name); | 295 | "nullfunc frame\n", sdata->name); |
| 523 | return; | 296 | return; |
| 524 | } | 297 | } |
| 525 | skb_reserve(skb, local->hw.extra_tx_headroom); | 298 | skb_reserve(skb, local->hw.extra_tx_headroom); |
| 526 | 299 | ||
| 527 | nullfunc = (struct ieee80211_hdr *) skb_put(skb, 24); | 300 | nullfunc = (struct ieee80211_hdr *) skb_put(skb, 30); |
| 528 | memset(nullfunc, 0, 24); | 301 | memset(nullfunc, 0, 30); |
| 529 | fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_NULLFUNC | | 302 | fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_NULLFUNC | |
| 530 | IEEE80211_FCTL_TODS); | 303 | IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS); |
| 531 | if (powersave) | ||
| 532 | fc |= cpu_to_le16(IEEE80211_FCTL_PM); | ||
| 533 | nullfunc->frame_control = fc; | 304 | nullfunc->frame_control = fc; |
| 534 | memcpy(nullfunc->addr1, sdata->u.mgd.bssid, ETH_ALEN); | 305 | memcpy(nullfunc->addr1, sdata->u.mgd.bssid, ETH_ALEN); |
| 535 | memcpy(nullfunc->addr2, sdata->dev->dev_addr, ETH_ALEN); | 306 | memcpy(nullfunc->addr2, sdata->vif.addr, ETH_ALEN); |
| 536 | memcpy(nullfunc->addr3, sdata->u.mgd.bssid, ETH_ALEN); | 307 | memcpy(nullfunc->addr3, sdata->u.mgd.bssid, ETH_ALEN); |
| 308 | memcpy(nullfunc->addr4, sdata->vif.addr, ETH_ALEN); | ||
| 537 | 309 | ||
| 538 | IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; | 310 | IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; |
| 539 | ieee80211_tx_skb(sdata, skb); | 311 | ieee80211_tx_skb(sdata, skb); |
| @@ -546,7 +318,7 @@ static void ieee80211_chswitch_work(struct work_struct *work) | |||
| 546 | container_of(work, struct ieee80211_sub_if_data, u.mgd.chswitch_work); | 318 | container_of(work, struct ieee80211_sub_if_data, u.mgd.chswitch_work); |
| 547 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 319 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
| 548 | 320 | ||
| 549 | if (!netif_running(sdata->dev)) | 321 | if (!ieee80211_sdata_running(sdata)) |
| 550 | return; | 322 | return; |
| 551 | 323 | ||
| 552 | mutex_lock(&ifmgd->mtx); | 324 | mutex_lock(&ifmgd->mtx); |
| @@ -557,7 +329,7 @@ static void ieee80211_chswitch_work(struct work_struct *work) | |||
| 557 | ieee80211_hw_config(sdata->local, IEEE80211_CONF_CHANGE_CHANNEL); | 329 | ieee80211_hw_config(sdata->local, IEEE80211_CONF_CHANGE_CHANNEL); |
| 558 | 330 | ||
| 559 | /* XXX: shouldn't really modify cfg80211-owned data! */ | 331 | /* XXX: shouldn't really modify cfg80211-owned data! */ |
| 560 | ifmgd->associated->cbss.channel = sdata->local->oper_channel; | 332 | ifmgd->associated->channel = sdata->local->oper_channel; |
| 561 | 333 | ||
| 562 | ieee80211_wake_queues_by_reason(&sdata->local->hw, | 334 | ieee80211_wake_queues_by_reason(&sdata->local->hw, |
| 563 | IEEE80211_QUEUE_STOP_REASON_CSA); | 335 | IEEE80211_QUEUE_STOP_REASON_CSA); |
| @@ -584,6 +356,8 @@ void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, | |||
| 584 | struct ieee80211_channel_sw_ie *sw_elem, | 356 | struct ieee80211_channel_sw_ie *sw_elem, |
| 585 | struct ieee80211_bss *bss) | 357 | struct ieee80211_bss *bss) |
| 586 | { | 358 | { |
| 359 | struct cfg80211_bss *cbss = | ||
| 360 | container_of((void *)bss, struct cfg80211_bss, priv); | ||
| 587 | struct ieee80211_channel *new_ch; | 361 | struct ieee80211_channel *new_ch; |
| 588 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 362 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
| 589 | int new_freq = ieee80211_channel_to_frequency(sw_elem->new_ch_num); | 363 | int new_freq = ieee80211_channel_to_frequency(sw_elem->new_ch_num); |
| @@ -617,7 +391,7 @@ void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, | |||
| 617 | mod_timer(&ifmgd->chswitch_timer, | 391 | mod_timer(&ifmgd->chswitch_timer, |
| 618 | jiffies + | 392 | jiffies + |
| 619 | msecs_to_jiffies(sw_elem->count * | 393 | msecs_to_jiffies(sw_elem->count * |
| 620 | bss->cbss.beacon_interval)); | 394 | cbss->beacon_interval)); |
| 621 | } | 395 | } |
| 622 | } | 396 | } |
| 623 | 397 | ||
| @@ -661,6 +435,11 @@ static void ieee80211_enable_ps(struct ieee80211_local *local, | |||
| 661 | } else { | 435 | } else { |
| 662 | if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) | 436 | if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) |
| 663 | ieee80211_send_nullfunc(local, sdata, 1); | 437 | ieee80211_send_nullfunc(local, sdata, 1); |
| 438 | |||
| 439 | if ((local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) && | ||
| 440 | (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS)) | ||
| 441 | return; | ||
| 442 | |||
| 664 | conf->flags |= IEEE80211_CONF_PS; | 443 | conf->flags |= IEEE80211_CONF_PS; |
| 665 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); | 444 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); |
| 666 | } | 445 | } |
| @@ -691,8 +470,13 @@ void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency) | |||
| 691 | return; | 470 | return; |
| 692 | } | 471 | } |
| 693 | 472 | ||
| 473 | if (!list_empty(&local->work_list)) { | ||
| 474 | local->ps_sdata = NULL; | ||
| 475 | goto change; | ||
| 476 | } | ||
| 477 | |||
| 694 | list_for_each_entry(sdata, &local->interfaces, list) { | 478 | list_for_each_entry(sdata, &local->interfaces, list) { |
| 695 | if (!netif_running(sdata->dev)) | 479 | if (!ieee80211_sdata_running(sdata)) |
| 696 | continue; | 480 | continue; |
| 697 | if (sdata->vif.type != NL80211_IFTYPE_STATION) | 481 | if (sdata->vif.type != NL80211_IFTYPE_STATION) |
| 698 | continue; | 482 | continue; |
| @@ -701,7 +485,8 @@ void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency) | |||
| 701 | } | 485 | } |
| 702 | 486 | ||
| 703 | if (count == 1 && found->u.mgd.powersave && | 487 | if (count == 1 && found->u.mgd.powersave && |
| 704 | found->u.mgd.associated && list_empty(&found->u.mgd.work_list) && | 488 | found->u.mgd.associated && |
| 489 | found->u.mgd.associated->beacon_ies && | ||
| 705 | !(found->u.mgd.flags & (IEEE80211_STA_BEACON_POLL | | 490 | !(found->u.mgd.flags & (IEEE80211_STA_BEACON_POLL | |
| 706 | IEEE80211_STA_CONNECTION_POLL))) { | 491 | IEEE80211_STA_CONNECTION_POLL))) { |
| 707 | s32 beaconint_us; | 492 | s32 beaconint_us; |
| @@ -715,20 +500,29 @@ void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency) | |||
| 715 | if (beaconint_us > latency) { | 500 | if (beaconint_us > latency) { |
| 716 | local->ps_sdata = NULL; | 501 | local->ps_sdata = NULL; |
| 717 | } else { | 502 | } else { |
| 718 | u8 dtimper = found->vif.bss_conf.dtim_period; | 503 | struct ieee80211_bss *bss; |
| 719 | int maxslp = 1; | 504 | int maxslp = 1; |
| 505 | u8 dtimper; | ||
| 720 | 506 | ||
| 721 | if (dtimper > 1) | 507 | bss = (void *)found->u.mgd.associated->priv; |
| 508 | dtimper = bss->dtim_period; | ||
| 509 | |||
| 510 | /* If the TIM IE is invalid, pretend the value is 1 */ | ||
| 511 | if (!dtimper) | ||
| 512 | dtimper = 1; | ||
| 513 | else if (dtimper > 1) | ||
| 722 | maxslp = min_t(int, dtimper, | 514 | maxslp = min_t(int, dtimper, |
| 723 | latency / beaconint_us); | 515 | latency / beaconint_us); |
| 724 | 516 | ||
| 725 | local->hw.conf.max_sleep_period = maxslp; | 517 | local->hw.conf.max_sleep_period = maxslp; |
| 518 | local->hw.conf.ps_dtim_period = dtimper; | ||
| 726 | local->ps_sdata = found; | 519 | local->ps_sdata = found; |
| 727 | } | 520 | } |
| 728 | } else { | 521 | } else { |
| 729 | local->ps_sdata = NULL; | 522 | local->ps_sdata = NULL; |
| 730 | } | 523 | } |
| 731 | 524 | ||
| 525 | change: | ||
| 732 | ieee80211_change_ps(local); | 526 | ieee80211_change_ps(local); |
| 733 | } | 527 | } |
| 734 | 528 | ||
| @@ -753,6 +547,7 @@ void ieee80211_dynamic_ps_enable_work(struct work_struct *work) | |||
| 753 | container_of(work, struct ieee80211_local, | 547 | container_of(work, struct ieee80211_local, |
| 754 | dynamic_ps_enable_work); | 548 | dynamic_ps_enable_work); |
| 755 | struct ieee80211_sub_if_data *sdata = local->ps_sdata; | 549 | struct ieee80211_sub_if_data *sdata = local->ps_sdata; |
| 550 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
| 756 | 551 | ||
| 757 | /* can only happen when PS was just disabled anyway */ | 552 | /* can only happen when PS was just disabled anyway */ |
| 758 | if (!sdata) | 553 | if (!sdata) |
| @@ -761,11 +556,17 @@ void ieee80211_dynamic_ps_enable_work(struct work_struct *work) | |||
| 761 | if (local->hw.conf.flags & IEEE80211_CONF_PS) | 556 | if (local->hw.conf.flags & IEEE80211_CONF_PS) |
| 762 | return; | 557 | return; |
| 763 | 558 | ||
| 764 | if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) | 559 | if ((local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) && |
| 560 | (!(ifmgd->flags & IEEE80211_STA_NULLFUNC_ACKED))) | ||
| 765 | ieee80211_send_nullfunc(local, sdata, 1); | 561 | ieee80211_send_nullfunc(local, sdata, 1); |
| 766 | 562 | ||
| 767 | local->hw.conf.flags |= IEEE80211_CONF_PS; | 563 | if (!((local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) && |
| 768 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); | 564 | (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK)) || |
| 565 | (ifmgd->flags & IEEE80211_STA_NULLFUNC_ACKED)) { | ||
| 566 | ifmgd->flags &= ~IEEE80211_STA_NULLFUNC_ACKED; | ||
| 567 | local->hw.conf.flags |= IEEE80211_CONF_PS; | ||
| 568 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); | ||
| 569 | } | ||
| 769 | } | 570 | } |
| 770 | 571 | ||
| 771 | void ieee80211_dynamic_ps_timer(unsigned long data) | 572 | void ieee80211_dynamic_ps_timer(unsigned long data) |
| @@ -786,9 +587,9 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local, | |||
| 786 | struct ieee80211_tx_queue_params params; | 587 | struct ieee80211_tx_queue_params params; |
| 787 | size_t left; | 588 | size_t left; |
| 788 | int count; | 589 | int count; |
| 789 | u8 *pos; | 590 | u8 *pos, uapsd_queues = 0; |
| 790 | 591 | ||
| 791 | if (!(ifmgd->flags & IEEE80211_STA_WMM_ENABLED)) | 592 | if (local->hw.queues < 4) |
| 792 | return; | 593 | return; |
| 793 | 594 | ||
| 794 | if (!wmm_param) | 595 | if (!wmm_param) |
| @@ -796,6 +597,10 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local, | |||
| 796 | 597 | ||
| 797 | if (wmm_param_len < 8 || wmm_param[5] /* version */ != 1) | 598 | if (wmm_param_len < 8 || wmm_param[5] /* version */ != 1) |
| 798 | return; | 599 | return; |
| 600 | |||
| 601 | if (ifmgd->flags & IEEE80211_STA_UAPSD_ENABLED) | ||
| 602 | uapsd_queues = local->uapsd_queues; | ||
| 603 | |||
| 799 | count = wmm_param[6] & 0x0f; | 604 | count = wmm_param[6] & 0x0f; |
| 800 | if (count == ifmgd->wmm_last_param_set) | 605 | if (count == ifmgd->wmm_last_param_set) |
| 801 | return; | 606 | return; |
| @@ -810,6 +615,7 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local, | |||
| 810 | for (; left >= 4; left -= 4, pos += 4) { | 615 | for (; left >= 4; left -= 4, pos += 4) { |
| 811 | int aci = (pos[0] >> 5) & 0x03; | 616 | int aci = (pos[0] >> 5) & 0x03; |
| 812 | int acm = (pos[0] >> 4) & 0x01; | 617 | int acm = (pos[0] >> 4) & 0x01; |
| 618 | bool uapsd = false; | ||
| 813 | int queue; | 619 | int queue; |
| 814 | 620 | ||
| 815 | switch (aci) { | 621 | switch (aci) { |
| @@ -817,22 +623,30 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local, | |||
| 817 | queue = 3; | 623 | queue = 3; |
| 818 | if (acm) | 624 | if (acm) |
| 819 | local->wmm_acm |= BIT(1) | BIT(2); /* BK/- */ | 625 | local->wmm_acm |= BIT(1) | BIT(2); /* BK/- */ |
| 626 | if (uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_BK) | ||
| 627 | uapsd = true; | ||
| 820 | break; | 628 | break; |
| 821 | case 2: /* AC_VI */ | 629 | case 2: /* AC_VI */ |
| 822 | queue = 1; | 630 | queue = 1; |
| 823 | if (acm) | 631 | if (acm) |
| 824 | local->wmm_acm |= BIT(4) | BIT(5); /* CL/VI */ | 632 | local->wmm_acm |= BIT(4) | BIT(5); /* CL/VI */ |
| 633 | if (uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VI) | ||
| 634 | uapsd = true; | ||
| 825 | break; | 635 | break; |
| 826 | case 3: /* AC_VO */ | 636 | case 3: /* AC_VO */ |
| 827 | queue = 0; | 637 | queue = 0; |
| 828 | if (acm) | 638 | if (acm) |
| 829 | local->wmm_acm |= BIT(6) | BIT(7); /* VO/NC */ | 639 | local->wmm_acm |= BIT(6) | BIT(7); /* VO/NC */ |
| 640 | if (uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VO) | ||
| 641 | uapsd = true; | ||
| 830 | break; | 642 | break; |
| 831 | case 0: /* AC_BE */ | 643 | case 0: /* AC_BE */ |
| 832 | default: | 644 | default: |
| 833 | queue = 2; | 645 | queue = 2; |
| 834 | if (acm) | 646 | if (acm) |
| 835 | local->wmm_acm |= BIT(0) | BIT(3); /* BE/EE */ | 647 | local->wmm_acm |= BIT(0) | BIT(3); /* BE/EE */ |
| 648 | if (uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_BE) | ||
| 649 | uapsd = true; | ||
| 836 | break; | 650 | break; |
| 837 | } | 651 | } |
| 838 | 652 | ||
| @@ -840,11 +654,14 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local, | |||
| 840 | params.cw_max = ecw2cw((pos[1] & 0xf0) >> 4); | 654 | params.cw_max = ecw2cw((pos[1] & 0xf0) >> 4); |
| 841 | params.cw_min = ecw2cw(pos[1] & 0x0f); | 655 | params.cw_min = ecw2cw(pos[1] & 0x0f); |
| 842 | params.txop = get_unaligned_le16(pos + 2); | 656 | params.txop = get_unaligned_le16(pos + 2); |
| 657 | params.uapsd = uapsd; | ||
| 658 | |||
| 843 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | 659 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG |
| 844 | printk(KERN_DEBUG "%s: WMM queue=%d aci=%d acm=%d aifs=%d " | 660 | printk(KERN_DEBUG "%s: WMM queue=%d aci=%d acm=%d aifs=%d " |
| 845 | "cWmin=%d cWmax=%d txop=%d\n", | 661 | "cWmin=%d cWmax=%d txop=%d uapsd=%d\n", |
| 846 | wiphy_name(local->hw.wiphy), queue, aci, acm, | 662 | wiphy_name(local->hw.wiphy), queue, aci, acm, |
| 847 | params.aifs, params.cw_min, params.cw_max, params.txop); | 663 | params.aifs, params.cw_min, params.cw_max, params.txop, |
| 664 | params.uapsd); | ||
| 848 | #endif | 665 | #endif |
| 849 | if (drv_conf_tx(local, queue, ¶ms) && local->ops->conf_tx) | 666 | if (drv_conf_tx(local, queue, ¶ms) && local->ops->conf_tx) |
| 850 | printk(KERN_DEBUG "%s: failed to set TX queue " | 667 | printk(KERN_DEBUG "%s: failed to set TX queue " |
| @@ -871,6 +688,8 @@ static u32 ieee80211_handle_bss_capability(struct ieee80211_sub_if_data *sdata, | |||
| 871 | } | 688 | } |
| 872 | 689 | ||
| 873 | use_short_slot = !!(capab & WLAN_CAPABILITY_SHORT_SLOT_TIME); | 690 | use_short_slot = !!(capab & WLAN_CAPABILITY_SHORT_SLOT_TIME); |
| 691 | if (sdata->local->hw.conf.channel->band == IEEE80211_BAND_5GHZ) | ||
| 692 | use_short_slot = true; | ||
| 874 | 693 | ||
| 875 | if (use_protection != bss_conf->use_cts_prot) { | 694 | if (use_protection != bss_conf->use_cts_prot) { |
| 876 | bss_conf->use_cts_prot = use_protection; | 695 | bss_conf->use_cts_prot = use_protection; |
| @@ -891,25 +710,23 @@ static u32 ieee80211_handle_bss_capability(struct ieee80211_sub_if_data *sdata, | |||
| 891 | } | 710 | } |
| 892 | 711 | ||
| 893 | static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, | 712 | static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, |
| 894 | struct ieee80211_mgd_work *wk, | 713 | struct cfg80211_bss *cbss, |
| 895 | u32 bss_info_changed) | 714 | u32 bss_info_changed) |
| 896 | { | 715 | { |
| 716 | struct ieee80211_bss *bss = (void *)cbss->priv; | ||
| 897 | struct ieee80211_local *local = sdata->local; | 717 | struct ieee80211_local *local = sdata->local; |
| 898 | struct ieee80211_bss *bss = wk->bss; | ||
| 899 | 718 | ||
| 900 | bss_info_changed |= BSS_CHANGED_ASSOC; | 719 | bss_info_changed |= BSS_CHANGED_ASSOC; |
| 901 | /* set timing information */ | 720 | /* set timing information */ |
| 902 | sdata->vif.bss_conf.beacon_int = bss->cbss.beacon_interval; | 721 | sdata->vif.bss_conf.beacon_int = cbss->beacon_interval; |
| 903 | sdata->vif.bss_conf.timestamp = bss->cbss.tsf; | 722 | sdata->vif.bss_conf.timestamp = cbss->tsf; |
| 904 | sdata->vif.bss_conf.dtim_period = bss->dtim_period; | ||
| 905 | 723 | ||
| 906 | bss_info_changed |= BSS_CHANGED_BEACON_INT; | 724 | bss_info_changed |= BSS_CHANGED_BEACON_INT; |
| 907 | bss_info_changed |= ieee80211_handle_bss_capability(sdata, | 725 | bss_info_changed |= ieee80211_handle_bss_capability(sdata, |
| 908 | bss->cbss.capability, bss->has_erp_value, bss->erp_value); | 726 | cbss->capability, bss->has_erp_value, bss->erp_value); |
| 909 | 727 | ||
| 910 | sdata->u.mgd.associated = bss; | 728 | sdata->u.mgd.associated = cbss; |
| 911 | sdata->u.mgd.old_associate_work = wk; | 729 | memcpy(sdata->u.mgd.bssid, cbss->bssid, ETH_ALEN); |
| 912 | memcpy(sdata->u.mgd.bssid, bss->cbss.bssid, ETH_ALEN); | ||
| 913 | 730 | ||
| 914 | /* just to be sure */ | 731 | /* just to be sure */ |
| 915 | sdata->u.mgd.flags &= ~(IEEE80211_STA_CONNECTION_POLL | | 732 | sdata->u.mgd.flags &= ~(IEEE80211_STA_CONNECTION_POLL | |
| @@ -940,99 +757,14 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, | |||
| 940 | 757 | ||
| 941 | mutex_lock(&local->iflist_mtx); | 758 | mutex_lock(&local->iflist_mtx); |
| 942 | ieee80211_recalc_ps(local, -1); | 759 | ieee80211_recalc_ps(local, -1); |
| 760 | ieee80211_recalc_smps(local, sdata); | ||
| 943 | mutex_unlock(&local->iflist_mtx); | 761 | mutex_unlock(&local->iflist_mtx); |
| 944 | 762 | ||
| 945 | netif_tx_start_all_queues(sdata->dev); | 763 | netif_tx_start_all_queues(sdata->dev); |
| 946 | netif_carrier_on(sdata->dev); | 764 | netif_carrier_on(sdata->dev); |
| 947 | } | 765 | } |
| 948 | 766 | ||
| 949 | static enum rx_mgmt_action __must_check | 767 | static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata) |
| 950 | ieee80211_direct_probe(struct ieee80211_sub_if_data *sdata, | ||
| 951 | struct ieee80211_mgd_work *wk) | ||
| 952 | { | ||
| 953 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
| 954 | struct ieee80211_local *local = sdata->local; | ||
| 955 | |||
| 956 | wk->tries++; | ||
| 957 | if (wk->tries > IEEE80211_AUTH_MAX_TRIES) { | ||
| 958 | printk(KERN_DEBUG "%s: direct probe to AP %pM timed out\n", | ||
| 959 | sdata->dev->name, wk->bss->cbss.bssid); | ||
| 960 | |||
| 961 | /* | ||
| 962 | * Most likely AP is not in the range so remove the | ||
| 963 | * bss struct for that AP. | ||
| 964 | */ | ||
| 965 | cfg80211_unlink_bss(local->hw.wiphy, &wk->bss->cbss); | ||
| 966 | |||
| 967 | /* | ||
| 968 | * We might have a pending scan which had no chance to run yet | ||
| 969 | * due to work needing to be done. Hence, queue the STAs work | ||
| 970 | * again for that. | ||
| 971 | */ | ||
| 972 | ieee80211_queue_work(&local->hw, &ifmgd->work); | ||
| 973 | return RX_MGMT_CFG80211_AUTH_TO; | ||
| 974 | } | ||
| 975 | |||
| 976 | printk(KERN_DEBUG "%s: direct probe to AP %pM (try %d)\n", | ||
| 977 | sdata->dev->name, wk->bss->cbss.bssid, | ||
| 978 | wk->tries); | ||
| 979 | |||
| 980 | /* | ||
| 981 | * Direct probe is sent to broadcast address as some APs | ||
| 982 | * will not answer to direct packet in unassociated state. | ||
| 983 | */ | ||
| 984 | ieee80211_send_probe_req(sdata, NULL, wk->ssid, wk->ssid_len, NULL, 0); | ||
| 985 | |||
| 986 | wk->timeout = jiffies + IEEE80211_AUTH_TIMEOUT; | ||
| 987 | run_again(ifmgd, wk->timeout); | ||
| 988 | |||
| 989 | return RX_MGMT_NONE; | ||
| 990 | } | ||
| 991 | |||
| 992 | |||
| 993 | static enum rx_mgmt_action __must_check | ||
| 994 | ieee80211_authenticate(struct ieee80211_sub_if_data *sdata, | ||
| 995 | struct ieee80211_mgd_work *wk) | ||
| 996 | { | ||
| 997 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
| 998 | struct ieee80211_local *local = sdata->local; | ||
| 999 | |||
| 1000 | wk->tries++; | ||
| 1001 | if (wk->tries > IEEE80211_AUTH_MAX_TRIES) { | ||
| 1002 | printk(KERN_DEBUG "%s: authentication with AP %pM" | ||
| 1003 | " timed out\n", | ||
| 1004 | sdata->dev->name, wk->bss->cbss.bssid); | ||
| 1005 | |||
| 1006 | /* | ||
| 1007 | * Most likely AP is not in the range so remove the | ||
| 1008 | * bss struct for that AP. | ||
| 1009 | */ | ||
| 1010 | cfg80211_unlink_bss(local->hw.wiphy, &wk->bss->cbss); | ||
| 1011 | |||
| 1012 | /* | ||
| 1013 | * We might have a pending scan which had no chance to run yet | ||
| 1014 | * due to work needing to be done. Hence, queue the STAs work | ||
| 1015 | * again for that. | ||
| 1016 | */ | ||
| 1017 | ieee80211_queue_work(&local->hw, &ifmgd->work); | ||
| 1018 | return RX_MGMT_CFG80211_AUTH_TO; | ||
| 1019 | } | ||
| 1020 | |||
| 1021 | printk(KERN_DEBUG "%s: authenticate with AP %pM (try %d)\n", | ||
| 1022 | sdata->dev->name, wk->bss->cbss.bssid, wk->tries); | ||
| 1023 | |||
| 1024 | ieee80211_send_auth(sdata, 1, wk->auth_alg, wk->ie, wk->ie_len, | ||
| 1025 | wk->bss->cbss.bssid, NULL, 0, 0); | ||
| 1026 | wk->auth_transaction = 2; | ||
| 1027 | |||
| 1028 | wk->timeout = jiffies + IEEE80211_AUTH_TIMEOUT; | ||
| 1029 | run_again(ifmgd, wk->timeout); | ||
| 1030 | |||
| 1031 | return RX_MGMT_NONE; | ||
| 1032 | } | ||
| 1033 | |||
| 1034 | static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, | ||
| 1035 | bool deauth) | ||
| 1036 | { | 768 | { |
| 1037 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 769 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
| 1038 | struct ieee80211_local *local = sdata->local; | 770 | struct ieee80211_local *local = sdata->local; |
| @@ -1045,21 +777,11 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, | |||
| 1045 | if (WARN_ON(!ifmgd->associated)) | 777 | if (WARN_ON(!ifmgd->associated)) |
| 1046 | return; | 778 | return; |
| 1047 | 779 | ||
| 1048 | memcpy(bssid, ifmgd->associated->cbss.bssid, ETH_ALEN); | 780 | memcpy(bssid, ifmgd->associated->bssid, ETH_ALEN); |
| 1049 | 781 | ||
| 1050 | ifmgd->associated = NULL; | 782 | ifmgd->associated = NULL; |
| 1051 | memset(ifmgd->bssid, 0, ETH_ALEN); | 783 | memset(ifmgd->bssid, 0, ETH_ALEN); |
| 1052 | 784 | ||
| 1053 | if (deauth) { | ||
| 1054 | kfree(ifmgd->old_associate_work); | ||
| 1055 | ifmgd->old_associate_work = NULL; | ||
| 1056 | } else { | ||
| 1057 | struct ieee80211_mgd_work *wk = ifmgd->old_associate_work; | ||
| 1058 | |||
| 1059 | wk->state = IEEE80211_MGD_STATE_IDLE; | ||
| 1060 | list_add(&wk->list, &ifmgd->work_list); | ||
| 1061 | } | ||
| 1062 | |||
| 1063 | /* | 785 | /* |
| 1064 | * we need to commit the associated = NULL change because the | 786 | * we need to commit the associated = NULL change because the |
| 1065 | * scan code uses that to determine whether this iface should | 787 | * scan code uses that to determine whether this iface should |
| @@ -1078,9 +800,11 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, | |||
| 1078 | netif_carrier_off(sdata->dev); | 800 | netif_carrier_off(sdata->dev); |
| 1079 | 801 | ||
| 1080 | rcu_read_lock(); | 802 | rcu_read_lock(); |
| 1081 | sta = sta_info_get(local, bssid); | 803 | sta = sta_info_get(sdata, bssid); |
| 1082 | if (sta) | 804 | if (sta) { |
| 805 | set_sta_flags(sta, WLAN_STA_DISASSOC); | ||
| 1083 | ieee80211_sta_tear_down_BA_sessions(sta); | 806 | ieee80211_sta_tear_down_BA_sessions(sta); |
| 807 | } | ||
| 1084 | rcu_read_unlock(); | 808 | rcu_read_unlock(); |
| 1085 | 809 | ||
| 1086 | changed |= ieee80211_reset_erp_info(sdata); | 810 | changed |= ieee80211_reset_erp_info(sdata); |
| @@ -1113,57 +837,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, | |||
| 1113 | changed |= BSS_CHANGED_BSSID; | 837 | changed |= BSS_CHANGED_BSSID; |
| 1114 | ieee80211_bss_info_change_notify(sdata, changed); | 838 | ieee80211_bss_info_change_notify(sdata, changed); |
| 1115 | 839 | ||
| 1116 | rcu_read_lock(); | 840 | sta_info_destroy_addr(sdata, bssid); |
| 1117 | |||
| 1118 | sta = sta_info_get(local, bssid); | ||
| 1119 | if (!sta) { | ||
| 1120 | rcu_read_unlock(); | ||
| 1121 | return; | ||
| 1122 | } | ||
| 1123 | |||
| 1124 | sta_info_unlink(&sta); | ||
| 1125 | |||
| 1126 | rcu_read_unlock(); | ||
| 1127 | |||
| 1128 | sta_info_destroy(sta); | ||
| 1129 | } | ||
| 1130 | |||
| 1131 | static enum rx_mgmt_action __must_check | ||
| 1132 | ieee80211_associate(struct ieee80211_sub_if_data *sdata, | ||
| 1133 | struct ieee80211_mgd_work *wk) | ||
| 1134 | { | ||
| 1135 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
| 1136 | struct ieee80211_local *local = sdata->local; | ||
| 1137 | |||
| 1138 | wk->tries++; | ||
| 1139 | if (wk->tries > IEEE80211_ASSOC_MAX_TRIES) { | ||
| 1140 | printk(KERN_DEBUG "%s: association with AP %pM" | ||
| 1141 | " timed out\n", | ||
| 1142 | sdata->dev->name, wk->bss->cbss.bssid); | ||
| 1143 | |||
| 1144 | /* | ||
| 1145 | * Most likely AP is not in the range so remove the | ||
| 1146 | * bss struct for that AP. | ||
| 1147 | */ | ||
| 1148 | cfg80211_unlink_bss(local->hw.wiphy, &wk->bss->cbss); | ||
| 1149 | |||
| 1150 | /* | ||
| 1151 | * We might have a pending scan which had no chance to run yet | ||
| 1152 | * due to work needing to be done. Hence, queue the STAs work | ||
| 1153 | * again for that. | ||
| 1154 | */ | ||
| 1155 | ieee80211_queue_work(&local->hw, &ifmgd->work); | ||
| 1156 | return RX_MGMT_CFG80211_ASSOC_TO; | ||
| 1157 | } | ||
| 1158 | |||
| 1159 | printk(KERN_DEBUG "%s: associate with AP %pM (try %d)\n", | ||
| 1160 | sdata->dev->name, wk->bss->cbss.bssid, wk->tries); | ||
| 1161 | ieee80211_send_assoc(sdata, wk); | ||
| 1162 | |||
| 1163 | wk->timeout = jiffies + IEEE80211_ASSOC_TIMEOUT; | ||
| 1164 | run_again(ifmgd, wk->timeout); | ||
| 1165 | |||
| 1166 | return RX_MGMT_NONE; | ||
| 1167 | } | 841 | } |
| 1168 | 842 | ||
| 1169 | void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata, | 843 | void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata, |
| @@ -1189,8 +863,8 @@ static void ieee80211_mgd_probe_ap_send(struct ieee80211_sub_if_data *sdata) | |||
| 1189 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 863 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
| 1190 | const u8 *ssid; | 864 | const u8 *ssid; |
| 1191 | 865 | ||
| 1192 | ssid = ieee80211_bss_get_ie(&ifmgd->associated->cbss, WLAN_EID_SSID); | 866 | ssid = ieee80211_bss_get_ie(ifmgd->associated, WLAN_EID_SSID); |
| 1193 | ieee80211_send_probe_req(sdata, ifmgd->associated->cbss.bssid, | 867 | ieee80211_send_probe_req(sdata, ifmgd->associated->bssid, |
| 1194 | ssid + 2, ssid[1], NULL, 0); | 868 | ssid + 2, ssid[1], NULL, 0); |
| 1195 | 869 | ||
| 1196 | ifmgd->probe_send_count++; | 870 | ifmgd->probe_send_count++; |
| @@ -1204,12 +878,15 @@ static void ieee80211_mgd_probe_ap(struct ieee80211_sub_if_data *sdata, | |||
| 1204 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 878 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
| 1205 | bool already = false; | 879 | bool already = false; |
| 1206 | 880 | ||
| 1207 | if (!netif_running(sdata->dev)) | 881 | if (!ieee80211_sdata_running(sdata)) |
| 1208 | return; | 882 | return; |
| 1209 | 883 | ||
| 1210 | if (sdata->local->scanning) | 884 | if (sdata->local->scanning) |
| 1211 | return; | 885 | return; |
| 1212 | 886 | ||
| 887 | if (sdata->local->tmp_channel) | ||
| 888 | return; | ||
| 889 | |||
| 1213 | mutex_lock(&ifmgd->mtx); | 890 | mutex_lock(&ifmgd->mtx); |
| 1214 | 891 | ||
| 1215 | if (!ifmgd->associated) | 892 | if (!ifmgd->associated) |
| @@ -1218,7 +895,7 @@ static void ieee80211_mgd_probe_ap(struct ieee80211_sub_if_data *sdata, | |||
| 1218 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | 895 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG |
| 1219 | if (beacon && net_ratelimit()) | 896 | if (beacon && net_ratelimit()) |
| 1220 | printk(KERN_DEBUG "%s: detected beacon loss from AP " | 897 | printk(KERN_DEBUG "%s: detected beacon loss from AP " |
| 1221 | "- sending probe request\n", sdata->dev->name); | 898 | "- sending probe request\n", sdata->name); |
| 1222 | #endif | 899 | #endif |
| 1223 | 900 | ||
| 1224 | /* | 901 | /* |
| @@ -1271,88 +948,8 @@ void ieee80211_beacon_loss(struct ieee80211_vif *vif) | |||
| 1271 | } | 948 | } |
| 1272 | EXPORT_SYMBOL(ieee80211_beacon_loss); | 949 | EXPORT_SYMBOL(ieee80211_beacon_loss); |
| 1273 | 950 | ||
| 1274 | static void ieee80211_auth_completed(struct ieee80211_sub_if_data *sdata, | ||
| 1275 | struct ieee80211_mgd_work *wk) | ||
| 1276 | { | ||
| 1277 | wk->state = IEEE80211_MGD_STATE_IDLE; | ||
| 1278 | printk(KERN_DEBUG "%s: authenticated\n", sdata->dev->name); | ||
| 1279 | } | ||
| 1280 | |||
| 1281 | |||
| 1282 | static void ieee80211_auth_challenge(struct ieee80211_sub_if_data *sdata, | ||
| 1283 | struct ieee80211_mgd_work *wk, | ||
| 1284 | struct ieee80211_mgmt *mgmt, | ||
| 1285 | size_t len) | ||
| 1286 | { | ||
| 1287 | u8 *pos; | ||
| 1288 | struct ieee802_11_elems elems; | ||
| 1289 | |||
| 1290 | pos = mgmt->u.auth.variable; | ||
| 1291 | ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems); | ||
| 1292 | if (!elems.challenge) | ||
| 1293 | return; | ||
| 1294 | ieee80211_send_auth(sdata, 3, wk->auth_alg, | ||
| 1295 | elems.challenge - 2, elems.challenge_len + 2, | ||
| 1296 | wk->bss->cbss.bssid, | ||
| 1297 | wk->key, wk->key_len, wk->key_idx); | ||
| 1298 | wk->auth_transaction = 4; | ||
| 1299 | } | ||
| 1300 | |||
| 1301 | static enum rx_mgmt_action __must_check | ||
| 1302 | ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata, | ||
| 1303 | struct ieee80211_mgd_work *wk, | ||
| 1304 | struct ieee80211_mgmt *mgmt, size_t len) | ||
| 1305 | { | ||
| 1306 | u16 auth_alg, auth_transaction, status_code; | ||
| 1307 | |||
| 1308 | if (wk->state != IEEE80211_MGD_STATE_AUTH) | ||
| 1309 | return RX_MGMT_NONE; | ||
| 1310 | |||
| 1311 | if (len < 24 + 6) | ||
| 1312 | return RX_MGMT_NONE; | ||
| 1313 | |||
| 1314 | if (memcmp(wk->bss->cbss.bssid, mgmt->sa, ETH_ALEN) != 0) | ||
| 1315 | return RX_MGMT_NONE; | ||
| 1316 | |||
| 1317 | if (memcmp(wk->bss->cbss.bssid, mgmt->bssid, ETH_ALEN) != 0) | ||
| 1318 | return RX_MGMT_NONE; | ||
| 1319 | |||
| 1320 | auth_alg = le16_to_cpu(mgmt->u.auth.auth_alg); | ||
| 1321 | auth_transaction = le16_to_cpu(mgmt->u.auth.auth_transaction); | ||
| 1322 | status_code = le16_to_cpu(mgmt->u.auth.status_code); | ||
| 1323 | |||
| 1324 | if (auth_alg != wk->auth_alg || | ||
| 1325 | auth_transaction != wk->auth_transaction) | ||
| 1326 | return RX_MGMT_NONE; | ||
| 1327 | |||
| 1328 | if (status_code != WLAN_STATUS_SUCCESS) { | ||
| 1329 | list_del(&wk->list); | ||
| 1330 | kfree(wk); | ||
| 1331 | return RX_MGMT_CFG80211_AUTH; | ||
| 1332 | } | ||
| 1333 | |||
| 1334 | switch (wk->auth_alg) { | ||
| 1335 | case WLAN_AUTH_OPEN: | ||
| 1336 | case WLAN_AUTH_LEAP: | ||
| 1337 | case WLAN_AUTH_FT: | ||
| 1338 | ieee80211_auth_completed(sdata, wk); | ||
| 1339 | return RX_MGMT_CFG80211_AUTH; | ||
| 1340 | case WLAN_AUTH_SHARED_KEY: | ||
| 1341 | if (wk->auth_transaction == 4) { | ||
| 1342 | ieee80211_auth_completed(sdata, wk); | ||
| 1343 | return RX_MGMT_CFG80211_AUTH; | ||
| 1344 | } else | ||
| 1345 | ieee80211_auth_challenge(sdata, wk, mgmt, len); | ||
| 1346 | break; | ||
| 1347 | } | ||
| 1348 | |||
| 1349 | return RX_MGMT_NONE; | ||
| 1350 | } | ||
| 1351 | |||
| 1352 | |||
| 1353 | static enum rx_mgmt_action __must_check | 951 | static enum rx_mgmt_action __must_check |
| 1354 | ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata, | 952 | ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata, |
| 1355 | struct ieee80211_mgd_work *wk, | ||
| 1356 | struct ieee80211_mgmt *mgmt, size_t len) | 953 | struct ieee80211_mgmt *mgmt, size_t len) |
| 1357 | { | 954 | { |
| 1358 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 955 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
| @@ -1364,23 +961,15 @@ ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata, | |||
| 1364 | 961 | ||
| 1365 | ASSERT_MGD_MTX(ifmgd); | 962 | ASSERT_MGD_MTX(ifmgd); |
| 1366 | 963 | ||
| 1367 | if (wk) | 964 | bssid = ifmgd->associated->bssid; |
| 1368 | bssid = wk->bss->cbss.bssid; | ||
| 1369 | else | ||
| 1370 | bssid = ifmgd->associated->cbss.bssid; | ||
| 1371 | 965 | ||
| 1372 | reason_code = le16_to_cpu(mgmt->u.deauth.reason_code); | 966 | reason_code = le16_to_cpu(mgmt->u.deauth.reason_code); |
| 1373 | 967 | ||
| 1374 | printk(KERN_DEBUG "%s: deauthenticated from %pM (Reason: %u)\n", | 968 | printk(KERN_DEBUG "%s: deauthenticated from %pM (Reason: %u)\n", |
| 1375 | sdata->dev->name, bssid, reason_code); | 969 | sdata->name, bssid, reason_code); |
| 1376 | 970 | ||
| 1377 | if (!wk) { | 971 | ieee80211_set_disassoc(sdata); |
| 1378 | ieee80211_set_disassoc(sdata, true); | 972 | ieee80211_recalc_idle(sdata->local); |
| 1379 | ieee80211_recalc_idle(sdata->local); | ||
| 1380 | } else { | ||
| 1381 | list_del(&wk->list); | ||
| 1382 | kfree(wk); | ||
| 1383 | } | ||
| 1384 | 973 | ||
| 1385 | return RX_MGMT_CFG80211_DEAUTH; | 974 | return RX_MGMT_CFG80211_DEAUTH; |
| 1386 | } | 975 | } |
| @@ -1401,123 +990,72 @@ ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata, | |||
| 1401 | if (WARN_ON(!ifmgd->associated)) | 990 | if (WARN_ON(!ifmgd->associated)) |
| 1402 | return RX_MGMT_NONE; | 991 | return RX_MGMT_NONE; |
| 1403 | 992 | ||
| 1404 | if (WARN_ON(memcmp(ifmgd->associated->cbss.bssid, mgmt->sa, ETH_ALEN))) | 993 | if (WARN_ON(memcmp(ifmgd->associated->bssid, mgmt->sa, ETH_ALEN))) |
| 1405 | return RX_MGMT_NONE; | 994 | return RX_MGMT_NONE; |
| 1406 | 995 | ||
| 1407 | reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code); | 996 | reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code); |
| 1408 | 997 | ||
| 1409 | printk(KERN_DEBUG "%s: disassociated from %pM (Reason: %u)\n", | 998 | printk(KERN_DEBUG "%s: disassociated from %pM (Reason: %u)\n", |
| 1410 | sdata->dev->name, mgmt->sa, reason_code); | 999 | sdata->name, mgmt->sa, reason_code); |
| 1411 | 1000 | ||
| 1412 | ieee80211_set_disassoc(sdata, false); | 1001 | ieee80211_set_disassoc(sdata); |
| 1413 | ieee80211_recalc_idle(sdata->local); | 1002 | ieee80211_recalc_idle(sdata->local); |
| 1414 | return RX_MGMT_CFG80211_DISASSOC; | 1003 | return RX_MGMT_CFG80211_DISASSOC; |
| 1415 | } | 1004 | } |
| 1416 | 1005 | ||
| 1417 | 1006 | ||
| 1418 | static enum rx_mgmt_action __must_check | 1007 | static bool ieee80211_assoc_success(struct ieee80211_work *wk, |
| 1419 | ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, | 1008 | struct ieee80211_mgmt *mgmt, size_t len) |
| 1420 | struct ieee80211_mgd_work *wk, | ||
| 1421 | struct ieee80211_mgmt *mgmt, size_t len, | ||
| 1422 | bool reassoc) | ||
| 1423 | { | 1009 | { |
| 1010 | struct ieee80211_sub_if_data *sdata = wk->sdata; | ||
| 1424 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 1011 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
| 1425 | struct ieee80211_local *local = sdata->local; | 1012 | struct ieee80211_local *local = sdata->local; |
| 1426 | struct ieee80211_supported_band *sband; | 1013 | struct ieee80211_supported_band *sband; |
| 1427 | struct sta_info *sta; | 1014 | struct sta_info *sta; |
| 1015 | struct cfg80211_bss *cbss = wk->assoc.bss; | ||
| 1016 | u8 *pos; | ||
| 1428 | u32 rates, basic_rates; | 1017 | u32 rates, basic_rates; |
| 1429 | u16 capab_info, status_code, aid; | 1018 | u16 capab_info, aid; |
| 1430 | struct ieee802_11_elems elems; | 1019 | struct ieee802_11_elems elems; |
| 1431 | struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf; | 1020 | struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf; |
| 1432 | u8 *pos; | ||
| 1433 | u32 changed = 0; | 1021 | u32 changed = 0; |
| 1434 | int i, j; | 1022 | int i, j, err; |
| 1435 | bool have_higher_than_11mbit = false, newsta = false; | 1023 | bool have_higher_than_11mbit = false; |
| 1436 | u16 ap_ht_cap_flags; | 1024 | u16 ap_ht_cap_flags; |
| 1437 | 1025 | ||
| 1438 | /* | 1026 | /* AssocResp and ReassocResp have identical structure */ |
| 1439 | * AssocResp and ReassocResp have identical structure, so process both | ||
| 1440 | * of them in this function. | ||
| 1441 | */ | ||
| 1442 | |||
| 1443 | if (len < 24 + 6) | ||
| 1444 | return RX_MGMT_NONE; | ||
| 1445 | 1027 | ||
| 1446 | if (memcmp(wk->bss->cbss.bssid, mgmt->sa, ETH_ALEN) != 0) | ||
| 1447 | return RX_MGMT_NONE; | ||
| 1448 | |||
| 1449 | capab_info = le16_to_cpu(mgmt->u.assoc_resp.capab_info); | ||
| 1450 | status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code); | ||
| 1451 | aid = le16_to_cpu(mgmt->u.assoc_resp.aid); | 1028 | aid = le16_to_cpu(mgmt->u.assoc_resp.aid); |
| 1452 | 1029 | capab_info = le16_to_cpu(mgmt->u.assoc_resp.capab_info); | |
| 1453 | printk(KERN_DEBUG "%s: RX %sssocResp from %pM (capab=0x%x " | ||
| 1454 | "status=%d aid=%d)\n", | ||
| 1455 | sdata->dev->name, reassoc ? "Rea" : "A", mgmt->sa, | ||
| 1456 | capab_info, status_code, (u16)(aid & ~(BIT(15) | BIT(14)))); | ||
| 1457 | |||
| 1458 | pos = mgmt->u.assoc_resp.variable; | ||
| 1459 | ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems); | ||
| 1460 | |||
| 1461 | if (status_code == WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY && | ||
| 1462 | elems.timeout_int && elems.timeout_int_len == 5 && | ||
| 1463 | elems.timeout_int[0] == WLAN_TIMEOUT_ASSOC_COMEBACK) { | ||
| 1464 | u32 tu, ms; | ||
| 1465 | tu = get_unaligned_le32(elems.timeout_int + 1); | ||
| 1466 | ms = tu * 1024 / 1000; | ||
| 1467 | printk(KERN_DEBUG "%s: AP rejected association temporarily; " | ||
| 1468 | "comeback duration %u TU (%u ms)\n", | ||
| 1469 | sdata->dev->name, tu, ms); | ||
| 1470 | wk->timeout = jiffies + msecs_to_jiffies(ms); | ||
| 1471 | if (ms > IEEE80211_ASSOC_TIMEOUT) | ||
| 1472 | run_again(ifmgd, jiffies + msecs_to_jiffies(ms)); | ||
| 1473 | return RX_MGMT_NONE; | ||
| 1474 | } | ||
| 1475 | |||
| 1476 | if (status_code != WLAN_STATUS_SUCCESS) { | ||
| 1477 | printk(KERN_DEBUG "%s: AP denied association (code=%d)\n", | ||
| 1478 | sdata->dev->name, status_code); | ||
| 1479 | wk->state = IEEE80211_MGD_STATE_IDLE; | ||
| 1480 | return RX_MGMT_CFG80211_ASSOC; | ||
| 1481 | } | ||
| 1482 | 1030 | ||
| 1483 | if ((aid & (BIT(15) | BIT(14))) != (BIT(15) | BIT(14))) | 1031 | if ((aid & (BIT(15) | BIT(14))) != (BIT(15) | BIT(14))) |
| 1484 | printk(KERN_DEBUG "%s: invalid aid value %d; bits 15:14 not " | 1032 | printk(KERN_DEBUG "%s: invalid aid value %d; bits 15:14 not " |
| 1485 | "set\n", sdata->dev->name, aid); | 1033 | "set\n", sdata->name, aid); |
| 1486 | aid &= ~(BIT(15) | BIT(14)); | 1034 | aid &= ~(BIT(15) | BIT(14)); |
| 1487 | 1035 | ||
| 1036 | pos = mgmt->u.assoc_resp.variable; | ||
| 1037 | ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems); | ||
| 1038 | |||
| 1488 | if (!elems.supp_rates) { | 1039 | if (!elems.supp_rates) { |
| 1489 | printk(KERN_DEBUG "%s: no SuppRates element in AssocResp\n", | 1040 | printk(KERN_DEBUG "%s: no SuppRates element in AssocResp\n", |
| 1490 | sdata->dev->name); | 1041 | sdata->name); |
| 1491 | return RX_MGMT_NONE; | 1042 | return false; |
| 1492 | } | 1043 | } |
| 1493 | 1044 | ||
| 1494 | printk(KERN_DEBUG "%s: associated\n", sdata->dev->name); | ||
| 1495 | ifmgd->aid = aid; | 1045 | ifmgd->aid = aid; |
| 1496 | 1046 | ||
| 1497 | rcu_read_lock(); | 1047 | sta = sta_info_alloc(sdata, cbss->bssid, GFP_KERNEL); |
| 1498 | |||
| 1499 | /* Add STA entry for the AP */ | ||
| 1500 | sta = sta_info_get(local, wk->bss->cbss.bssid); | ||
| 1501 | if (!sta) { | 1048 | if (!sta) { |
| 1502 | newsta = true; | 1049 | printk(KERN_DEBUG "%s: failed to alloc STA entry for" |
| 1503 | 1050 | " the AP\n", sdata->name); | |
| 1504 | rcu_read_unlock(); | 1051 | return false; |
| 1505 | |||
| 1506 | sta = sta_info_alloc(sdata, wk->bss->cbss.bssid, GFP_KERNEL); | ||
| 1507 | if (!sta) { | ||
| 1508 | printk(KERN_DEBUG "%s: failed to alloc STA entry for" | ||
| 1509 | " the AP\n", sdata->dev->name); | ||
| 1510 | return RX_MGMT_NONE; | ||
| 1511 | } | ||
| 1512 | |||
| 1513 | set_sta_flags(sta, WLAN_STA_AUTH | WLAN_STA_ASSOC | | ||
| 1514 | WLAN_STA_ASSOC_AP); | ||
| 1515 | if (!(ifmgd->flags & IEEE80211_STA_CONTROL_PORT)) | ||
| 1516 | set_sta_flags(sta, WLAN_STA_AUTHORIZED); | ||
| 1517 | |||
| 1518 | rcu_read_lock(); | ||
| 1519 | } | 1052 | } |
| 1520 | 1053 | ||
| 1054 | set_sta_flags(sta, WLAN_STA_AUTH | WLAN_STA_ASSOC | | ||
| 1055 | WLAN_STA_ASSOC_AP); | ||
| 1056 | if (!(ifmgd->flags & IEEE80211_STA_CONTROL_PORT)) | ||
| 1057 | set_sta_flags(sta, WLAN_STA_AUTHORIZED); | ||
| 1058 | |||
| 1521 | rates = 0; | 1059 | rates = 0; |
| 1522 | basic_rates = 0; | 1060 | basic_rates = 0; |
| 1523 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | 1061 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; |
| @@ -1580,40 +1118,40 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, | |||
| 1580 | if (elems.wmm_param) | 1118 | if (elems.wmm_param) |
| 1581 | set_sta_flags(sta, WLAN_STA_WME); | 1119 | set_sta_flags(sta, WLAN_STA_WME); |
| 1582 | 1120 | ||
| 1583 | if (newsta) { | 1121 | err = sta_info_insert(sta); |
| 1584 | int err = sta_info_insert(sta); | 1122 | sta = NULL; |
| 1585 | if (err) { | 1123 | if (err) { |
| 1586 | printk(KERN_DEBUG "%s: failed to insert STA entry for" | 1124 | printk(KERN_DEBUG "%s: failed to insert STA entry for" |
| 1587 | " the AP (error %d)\n", sdata->dev->name, err); | 1125 | " the AP (error %d)\n", sdata->name, err); |
| 1588 | rcu_read_unlock(); | 1126 | return false; |
| 1589 | return RX_MGMT_NONE; | ||
| 1590 | } | ||
| 1591 | } | 1127 | } |
| 1592 | 1128 | ||
| 1593 | rcu_read_unlock(); | ||
| 1594 | |||
| 1595 | if (elems.wmm_param) | 1129 | if (elems.wmm_param) |
| 1596 | ieee80211_sta_wmm_params(local, ifmgd, elems.wmm_param, | 1130 | ieee80211_sta_wmm_params(local, ifmgd, elems.wmm_param, |
| 1597 | elems.wmm_param_len); | 1131 | elems.wmm_param_len); |
| 1598 | else | 1132 | else |
| 1599 | ieee80211_set_wmm_default(sdata); | 1133 | ieee80211_set_wmm_default(sdata); |
| 1600 | 1134 | ||
| 1135 | local->oper_channel = wk->chan; | ||
| 1136 | |||
| 1601 | if (elems.ht_info_elem && elems.wmm_param && | 1137 | if (elems.ht_info_elem && elems.wmm_param && |
| 1602 | (ifmgd->flags & IEEE80211_STA_WMM_ENABLED) && | 1138 | (sdata->local->hw.queues >= 4) && |
| 1603 | !(ifmgd->flags & IEEE80211_STA_DISABLE_11N)) | 1139 | !(ifmgd->flags & IEEE80211_STA_DISABLE_11N)) |
| 1604 | changed |= ieee80211_enable_ht(sdata, elems.ht_info_elem, | 1140 | changed |= ieee80211_enable_ht(sdata, elems.ht_info_elem, |
| 1605 | wk->bss->cbss.bssid, | 1141 | cbss->bssid, ap_ht_cap_flags); |
| 1606 | ap_ht_cap_flags); | ||
| 1607 | |||
| 1608 | /* delete work item -- must be before set_associated for PS */ | ||
| 1609 | list_del(&wk->list); | ||
| 1610 | 1142 | ||
| 1611 | /* set AID and assoc capability, | 1143 | /* set AID and assoc capability, |
| 1612 | * ieee80211_set_associated() will tell the driver */ | 1144 | * ieee80211_set_associated() will tell the driver */ |
| 1613 | bss_conf->aid = aid; | 1145 | bss_conf->aid = aid; |
| 1614 | bss_conf->assoc_capability = capab_info; | 1146 | bss_conf->assoc_capability = capab_info; |
| 1615 | /* this will take ownership of wk */ | 1147 | ieee80211_set_associated(sdata, cbss, changed); |
| 1616 | ieee80211_set_associated(sdata, wk, changed); | 1148 | |
| 1149 | /* | ||
| 1150 | * If we're using 4-addr mode, let the AP know that we're | ||
| 1151 | * doing so, so that it can create the STA VLAN on its side | ||
| 1152 | */ | ||
| 1153 | if (ifmgd->use_4addr) | ||
| 1154 | ieee80211_send_4addr_nullfunc(local, sdata); | ||
| 1617 | 1155 | ||
| 1618 | /* | 1156 | /* |
| 1619 | * Start timer to probe the connection to the AP now. | 1157 | * Start timer to probe the connection to the AP now. |
| @@ -1622,7 +1160,7 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, | |||
| 1622 | ieee80211_sta_rx_notify(sdata, (struct ieee80211_hdr *)mgmt); | 1160 | ieee80211_sta_rx_notify(sdata, (struct ieee80211_hdr *)mgmt); |
| 1623 | mod_beacon_timer(sdata); | 1161 | mod_beacon_timer(sdata); |
| 1624 | 1162 | ||
| 1625 | return RX_MGMT_CFG80211_ASSOC; | 1163 | return true; |
| 1626 | } | 1164 | } |
| 1627 | 1165 | ||
| 1628 | 1166 | ||
| @@ -1637,6 +1175,13 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | |||
| 1637 | int freq; | 1175 | int freq; |
| 1638 | struct ieee80211_bss *bss; | 1176 | struct ieee80211_bss *bss; |
| 1639 | struct ieee80211_channel *channel; | 1177 | struct ieee80211_channel *channel; |
| 1178 | bool need_ps = false; | ||
| 1179 | |||
| 1180 | if (sdata->u.mgd.associated) { | ||
| 1181 | bss = (void *)sdata->u.mgd.associated->priv; | ||
| 1182 | /* not previously set so we may need to recalc */ | ||
| 1183 | need_ps = !bss->dtim_period; | ||
| 1184 | } | ||
| 1640 | 1185 | ||
| 1641 | if (elems->ds_params && elems->ds_params_len == 1) | 1186 | if (elems->ds_params && elems->ds_params_len == 1) |
| 1642 | freq = ieee80211_channel_to_frequency(elems->ds_params[0]); | 1187 | freq = ieee80211_channel_to_frequency(elems->ds_params[0]); |
| @@ -1656,8 +1201,14 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | |||
| 1656 | if (!sdata->u.mgd.associated) | 1201 | if (!sdata->u.mgd.associated) |
| 1657 | return; | 1202 | return; |
| 1658 | 1203 | ||
| 1204 | if (need_ps) { | ||
| 1205 | mutex_lock(&local->iflist_mtx); | ||
| 1206 | ieee80211_recalc_ps(local, -1); | ||
| 1207 | mutex_unlock(&local->iflist_mtx); | ||
| 1208 | } | ||
| 1209 | |||
| 1659 | if (elems->ch_switch_elem && (elems->ch_switch_elem_len == 3) && | 1210 | if (elems->ch_switch_elem && (elems->ch_switch_elem_len == 3) && |
| 1660 | (memcmp(mgmt->bssid, sdata->u.mgd.associated->cbss.bssid, | 1211 | (memcmp(mgmt->bssid, sdata->u.mgd.associated->bssid, |
| 1661 | ETH_ALEN) == 0)) { | 1212 | ETH_ALEN) == 0)) { |
| 1662 | struct ieee80211_channel_sw_ie *sw_elem = | 1213 | struct ieee80211_channel_sw_ie *sw_elem = |
| 1663 | (struct ieee80211_channel_sw_ie *)elems->ch_switch_elem; | 1214 | (struct ieee80211_channel_sw_ie *)elems->ch_switch_elem; |
| @@ -1667,19 +1218,19 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | |||
| 1667 | 1218 | ||
| 1668 | 1219 | ||
| 1669 | static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata, | 1220 | static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata, |
| 1670 | struct ieee80211_mgd_work *wk, | 1221 | struct sk_buff *skb) |
| 1671 | struct ieee80211_mgmt *mgmt, size_t len, | ||
| 1672 | struct ieee80211_rx_status *rx_status) | ||
| 1673 | { | 1222 | { |
| 1223 | struct ieee80211_mgmt *mgmt = (void *)skb->data; | ||
| 1674 | struct ieee80211_if_managed *ifmgd; | 1224 | struct ieee80211_if_managed *ifmgd; |
| 1675 | size_t baselen; | 1225 | struct ieee80211_rx_status *rx_status = (void *) skb->cb; |
| 1226 | size_t baselen, len = skb->len; | ||
| 1676 | struct ieee802_11_elems elems; | 1227 | struct ieee802_11_elems elems; |
| 1677 | 1228 | ||
| 1678 | ifmgd = &sdata->u.mgd; | 1229 | ifmgd = &sdata->u.mgd; |
| 1679 | 1230 | ||
| 1680 | ASSERT_MGD_MTX(ifmgd); | 1231 | ASSERT_MGD_MTX(ifmgd); |
| 1681 | 1232 | ||
| 1682 | if (memcmp(mgmt->da, sdata->dev->dev_addr, ETH_ALEN)) | 1233 | if (memcmp(mgmt->da, sdata->vif.addr, ETH_ALEN)) |
| 1683 | return; /* ignore ProbeResp to foreign address */ | 1234 | return; /* ignore ProbeResp to foreign address */ |
| 1684 | 1235 | ||
| 1685 | baselen = (u8 *) mgmt->u.probe_resp.variable - (u8 *) mgmt; | 1236 | baselen = (u8 *) mgmt->u.probe_resp.variable - (u8 *) mgmt; |
| @@ -1691,17 +1242,8 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata, | |||
| 1691 | 1242 | ||
| 1692 | ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems, false); | 1243 | ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems, false); |
| 1693 | 1244 | ||
| 1694 | /* direct probe may be part of the association flow */ | ||
| 1695 | if (wk && wk->state == IEEE80211_MGD_STATE_PROBE) { | ||
| 1696 | printk(KERN_DEBUG "%s: direct probe responded\n", | ||
| 1697 | sdata->dev->name); | ||
| 1698 | wk->tries = 0; | ||
| 1699 | wk->state = IEEE80211_MGD_STATE_AUTH; | ||
| 1700 | WARN_ON(ieee80211_authenticate(sdata, wk) != RX_MGMT_NONE); | ||
| 1701 | } | ||
| 1702 | |||
| 1703 | if (ifmgd->associated && | 1245 | if (ifmgd->associated && |
| 1704 | memcmp(mgmt->bssid, ifmgd->associated->cbss.bssid, ETH_ALEN) == 0 && | 1246 | memcmp(mgmt->bssid, ifmgd->associated->bssid, ETH_ALEN) == 0 && |
| 1705 | ifmgd->flags & (IEEE80211_STA_BEACON_POLL | | 1247 | ifmgd->flags & (IEEE80211_STA_BEACON_POLL | |
| 1706 | IEEE80211_STA_CONNECTION_POLL)) { | 1248 | IEEE80211_STA_CONNECTION_POLL)) { |
| 1707 | ifmgd->flags &= ~(IEEE80211_STA_CONNECTION_POLL | | 1249 | ifmgd->flags &= ~(IEEE80211_STA_CONNECTION_POLL | |
| @@ -1774,7 +1316,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
| 1774 | if (!ifmgd->associated) | 1316 | if (!ifmgd->associated) |
| 1775 | return; | 1317 | return; |
| 1776 | 1318 | ||
| 1777 | bssid = ifmgd->associated->cbss.bssid; | 1319 | bssid = ifmgd->associated->bssid; |
| 1778 | 1320 | ||
| 1779 | /* | 1321 | /* |
| 1780 | * And in theory even frames from a different AP we were just | 1322 | * And in theory even frames from a different AP we were just |
| @@ -1787,7 +1329,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
| 1787 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | 1329 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG |
| 1788 | if (net_ratelimit()) { | 1330 | if (net_ratelimit()) { |
| 1789 | printk(KERN_DEBUG "%s: cancelling probereq poll due " | 1331 | printk(KERN_DEBUG "%s: cancelling probereq poll due " |
| 1790 | "to a received beacon\n", sdata->dev->name); | 1332 | "to a received beacon\n", sdata->name); |
| 1791 | } | 1333 | } |
| 1792 | #endif | 1334 | #endif |
| 1793 | ifmgd->flags &= ~IEEE80211_STA_BEACON_POLL; | 1335 | ifmgd->flags &= ~IEEE80211_STA_BEACON_POLL; |
| @@ -1865,7 +1407,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
| 1865 | 1407 | ||
| 1866 | rcu_read_lock(); | 1408 | rcu_read_lock(); |
| 1867 | 1409 | ||
| 1868 | sta = sta_info_get(local, bssid); | 1410 | sta = sta_info_get(sdata, bssid); |
| 1869 | if (WARN_ON(!sta)) { | 1411 | if (WARN_ON(!sta)) { |
| 1870 | rcu_read_unlock(); | 1412 | rcu_read_unlock(); |
| 1871 | return; | 1413 | return; |
| @@ -1913,9 +1455,6 @@ ieee80211_rx_result ieee80211_sta_rx_mgmt(struct ieee80211_sub_if_data *sdata, | |||
| 1913 | switch (fc & IEEE80211_FCTL_STYPE) { | 1455 | switch (fc & IEEE80211_FCTL_STYPE) { |
| 1914 | case IEEE80211_STYPE_PROBE_RESP: | 1456 | case IEEE80211_STYPE_PROBE_RESP: |
| 1915 | case IEEE80211_STYPE_BEACON: | 1457 | case IEEE80211_STYPE_BEACON: |
| 1916 | case IEEE80211_STYPE_AUTH: | ||
| 1917 | case IEEE80211_STYPE_ASSOC_RESP: | ||
| 1918 | case IEEE80211_STYPE_REASSOC_RESP: | ||
| 1919 | case IEEE80211_STYPE_DEAUTH: | 1458 | case IEEE80211_STYPE_DEAUTH: |
| 1920 | case IEEE80211_STYPE_DISASSOC: | 1459 | case IEEE80211_STYPE_DISASSOC: |
| 1921 | case IEEE80211_STYPE_ACTION: | 1460 | case IEEE80211_STYPE_ACTION: |
| @@ -1933,7 +1472,6 @@ static void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, | |||
| 1933 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 1472 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
| 1934 | struct ieee80211_rx_status *rx_status; | 1473 | struct ieee80211_rx_status *rx_status; |
| 1935 | struct ieee80211_mgmt *mgmt; | 1474 | struct ieee80211_mgmt *mgmt; |
| 1936 | struct ieee80211_mgd_work *wk; | ||
| 1937 | enum rx_mgmt_action rma = RX_MGMT_NONE; | 1475 | enum rx_mgmt_action rma = RX_MGMT_NONE; |
| 1938 | u16 fc; | 1476 | u16 fc; |
| 1939 | 1477 | ||
| @@ -1944,20 +1482,17 @@ static void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, | |||
| 1944 | mutex_lock(&ifmgd->mtx); | 1482 | mutex_lock(&ifmgd->mtx); |
| 1945 | 1483 | ||
| 1946 | if (ifmgd->associated && | 1484 | if (ifmgd->associated && |
| 1947 | memcmp(ifmgd->associated->cbss.bssid, mgmt->bssid, | 1485 | memcmp(ifmgd->associated->bssid, mgmt->bssid, ETH_ALEN) == 0) { |
| 1948 | ETH_ALEN) == 0) { | ||
| 1949 | switch (fc & IEEE80211_FCTL_STYPE) { | 1486 | switch (fc & IEEE80211_FCTL_STYPE) { |
| 1950 | case IEEE80211_STYPE_BEACON: | 1487 | case IEEE80211_STYPE_BEACON: |
| 1951 | ieee80211_rx_mgmt_beacon(sdata, mgmt, skb->len, | 1488 | ieee80211_rx_mgmt_beacon(sdata, mgmt, skb->len, |
| 1952 | rx_status); | 1489 | rx_status); |
| 1953 | break; | 1490 | break; |
| 1954 | case IEEE80211_STYPE_PROBE_RESP: | 1491 | case IEEE80211_STYPE_PROBE_RESP: |
| 1955 | ieee80211_rx_mgmt_probe_resp(sdata, NULL, mgmt, | 1492 | ieee80211_rx_mgmt_probe_resp(sdata, skb); |
| 1956 | skb->len, rx_status); | ||
| 1957 | break; | 1493 | break; |
| 1958 | case IEEE80211_STYPE_DEAUTH: | 1494 | case IEEE80211_STYPE_DEAUTH: |
| 1959 | rma = ieee80211_rx_mgmt_deauth(sdata, NULL, | 1495 | rma = ieee80211_rx_mgmt_deauth(sdata, mgmt, skb->len); |
| 1960 | mgmt, skb->len); | ||
| 1961 | break; | 1496 | break; |
| 1962 | case IEEE80211_STYPE_DISASSOC: | 1497 | case IEEE80211_STYPE_DISASSOC: |
| 1963 | rma = ieee80211_rx_mgmt_disassoc(sdata, mgmt, skb->len); | 1498 | rma = ieee80211_rx_mgmt_disassoc(sdata, mgmt, skb->len); |
| @@ -1968,7 +1503,7 @@ static void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, | |||
| 1968 | 1503 | ||
| 1969 | ieee80211_sta_process_chanswitch(sdata, | 1504 | ieee80211_sta_process_chanswitch(sdata, |
| 1970 | &mgmt->u.action.u.chan_switch.sw_elem, | 1505 | &mgmt->u.action.u.chan_switch.sw_elem, |
| 1971 | ifmgd->associated); | 1506 | (void *)ifmgd->associated->priv); |
| 1972 | break; | 1507 | break; |
| 1973 | } | 1508 | } |
| 1974 | mutex_unlock(&ifmgd->mtx); | 1509 | mutex_unlock(&ifmgd->mtx); |
| @@ -1989,58 +1524,11 @@ static void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, | |||
| 1989 | goto out; | 1524 | goto out; |
| 1990 | } | 1525 | } |
| 1991 | 1526 | ||
| 1992 | list_for_each_entry(wk, &ifmgd->work_list, list) { | ||
| 1993 | if (memcmp(wk->bss->cbss.bssid, mgmt->bssid, ETH_ALEN) != 0) | ||
| 1994 | continue; | ||
| 1995 | |||
| 1996 | switch (fc & IEEE80211_FCTL_STYPE) { | ||
| 1997 | case IEEE80211_STYPE_PROBE_RESP: | ||
| 1998 | ieee80211_rx_mgmt_probe_resp(sdata, wk, mgmt, skb->len, | ||
| 1999 | rx_status); | ||
| 2000 | break; | ||
| 2001 | case IEEE80211_STYPE_AUTH: | ||
| 2002 | rma = ieee80211_rx_mgmt_auth(sdata, wk, mgmt, skb->len); | ||
| 2003 | break; | ||
| 2004 | case IEEE80211_STYPE_ASSOC_RESP: | ||
| 2005 | rma = ieee80211_rx_mgmt_assoc_resp(sdata, wk, mgmt, | ||
| 2006 | skb->len, false); | ||
| 2007 | break; | ||
| 2008 | case IEEE80211_STYPE_REASSOC_RESP: | ||
| 2009 | rma = ieee80211_rx_mgmt_assoc_resp(sdata, wk, mgmt, | ||
| 2010 | skb->len, true); | ||
| 2011 | break; | ||
| 2012 | case IEEE80211_STYPE_DEAUTH: | ||
| 2013 | rma = ieee80211_rx_mgmt_deauth(sdata, wk, mgmt, | ||
| 2014 | skb->len); | ||
| 2015 | break; | ||
| 2016 | } | ||
| 2017 | /* | ||
| 2018 | * We've processed this frame for that work, so it can't | ||
| 2019 | * belong to another work struct. | ||
| 2020 | * NB: this is also required for correctness because the | ||
| 2021 | * called functions can free 'wk', and for 'rma'! | ||
| 2022 | */ | ||
| 2023 | break; | ||
| 2024 | } | ||
| 2025 | |||
| 2026 | mutex_unlock(&ifmgd->mtx); | 1527 | mutex_unlock(&ifmgd->mtx); |
| 2027 | 1528 | ||
| 2028 | switch (rma) { | 1529 | if (skb->len >= 24 + 2 /* mgmt + deauth reason */ && |
| 2029 | case RX_MGMT_NONE: | 1530 | (fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_DEAUTH) |
| 2030 | /* no action */ | ||
| 2031 | break; | ||
| 2032 | case RX_MGMT_CFG80211_AUTH: | ||
| 2033 | cfg80211_send_rx_auth(sdata->dev, (u8 *) mgmt, skb->len); | ||
| 2034 | break; | ||
| 2035 | case RX_MGMT_CFG80211_ASSOC: | ||
| 2036 | cfg80211_send_rx_assoc(sdata->dev, (u8 *) mgmt, skb->len); | ||
| 2037 | break; | ||
| 2038 | case RX_MGMT_CFG80211_DEAUTH: | ||
| 2039 | cfg80211_send_deauth(sdata->dev, (u8 *)mgmt, skb->len); | 1531 | cfg80211_send_deauth(sdata->dev, (u8 *)mgmt, skb->len); |
| 2040 | break; | ||
| 2041 | default: | ||
| 2042 | WARN(1, "unexpected: %d", rma); | ||
| 2043 | } | ||
| 2044 | 1532 | ||
| 2045 | out: | 1533 | out: |
| 2046 | kfree_skb(skb); | 1534 | kfree_skb(skb); |
| @@ -2068,12 +1556,8 @@ static void ieee80211_sta_work(struct work_struct *work) | |||
| 2068 | struct ieee80211_local *local = sdata->local; | 1556 | struct ieee80211_local *local = sdata->local; |
| 2069 | struct ieee80211_if_managed *ifmgd; | 1557 | struct ieee80211_if_managed *ifmgd; |
| 2070 | struct sk_buff *skb; | 1558 | struct sk_buff *skb; |
| 2071 | struct ieee80211_mgd_work *wk, *tmp; | ||
| 2072 | LIST_HEAD(free_work); | ||
| 2073 | enum rx_mgmt_action rma; | ||
| 2074 | bool anybusy = false; | ||
| 2075 | 1559 | ||
| 2076 | if (!netif_running(sdata->dev)) | 1560 | if (!ieee80211_sdata_running(sdata)) |
| 2077 | return; | 1561 | return; |
| 2078 | 1562 | ||
| 2079 | if (local->scanning) | 1563 | if (local->scanning) |
| @@ -2104,7 +1588,7 @@ static void ieee80211_sta_work(struct work_struct *work) | |||
| 2104 | ifmgd->associated) { | 1588 | ifmgd->associated) { |
| 2105 | u8 bssid[ETH_ALEN]; | 1589 | u8 bssid[ETH_ALEN]; |
| 2106 | 1590 | ||
| 2107 | memcpy(bssid, ifmgd->associated->cbss.bssid, ETH_ALEN); | 1591 | memcpy(bssid, ifmgd->associated->bssid, ETH_ALEN); |
| 2108 | if (time_is_after_jiffies(ifmgd->probe_timeout)) | 1592 | if (time_is_after_jiffies(ifmgd->probe_timeout)) |
| 2109 | run_again(ifmgd, ifmgd->probe_timeout); | 1593 | run_again(ifmgd, ifmgd->probe_timeout); |
| 2110 | 1594 | ||
| @@ -2126,7 +1610,7 @@ static void ieee80211_sta_work(struct work_struct *work) | |||
| 2126 | printk(KERN_DEBUG "No probe response from AP %pM" | 1610 | printk(KERN_DEBUG "No probe response from AP %pM" |
| 2127 | " after %dms, disconnecting.\n", | 1611 | " after %dms, disconnecting.\n", |
| 2128 | bssid, (1000 * IEEE80211_PROBE_WAIT)/HZ); | 1612 | bssid, (1000 * IEEE80211_PROBE_WAIT)/HZ); |
| 2129 | ieee80211_set_disassoc(sdata, true); | 1613 | ieee80211_set_disassoc(sdata); |
| 2130 | ieee80211_recalc_idle(local); | 1614 | ieee80211_recalc_idle(local); |
| 2131 | mutex_unlock(&ifmgd->mtx); | 1615 | mutex_unlock(&ifmgd->mtx); |
| 2132 | /* | 1616 | /* |
| @@ -2141,87 +1625,7 @@ static void ieee80211_sta_work(struct work_struct *work) | |||
| 2141 | } | 1625 | } |
| 2142 | } | 1626 | } |
| 2143 | 1627 | ||
| 2144 | |||
| 2145 | ieee80211_recalc_idle(local); | ||
| 2146 | |||
| 2147 | list_for_each_entry_safe(wk, tmp, &ifmgd->work_list, list) { | ||
| 2148 | if (time_is_after_jiffies(wk->timeout)) { | ||
| 2149 | /* | ||
| 2150 | * This work item isn't supposed to be worked on | ||
| 2151 | * right now, but take care to adjust the timer | ||
| 2152 | * properly. | ||
| 2153 | */ | ||
| 2154 | run_again(ifmgd, wk->timeout); | ||
| 2155 | continue; | ||
| 2156 | } | ||
| 2157 | |||
| 2158 | switch (wk->state) { | ||
| 2159 | default: | ||
| 2160 | WARN_ON(1); | ||
| 2161 | /* fall through */ | ||
| 2162 | case IEEE80211_MGD_STATE_IDLE: | ||
| 2163 | /* nothing */ | ||
| 2164 | rma = RX_MGMT_NONE; | ||
| 2165 | break; | ||
| 2166 | case IEEE80211_MGD_STATE_PROBE: | ||
| 2167 | rma = ieee80211_direct_probe(sdata, wk); | ||
| 2168 | break; | ||
| 2169 | case IEEE80211_MGD_STATE_AUTH: | ||
| 2170 | rma = ieee80211_authenticate(sdata, wk); | ||
| 2171 | break; | ||
| 2172 | case IEEE80211_MGD_STATE_ASSOC: | ||
| 2173 | rma = ieee80211_associate(sdata, wk); | ||
| 2174 | break; | ||
| 2175 | } | ||
| 2176 | |||
| 2177 | switch (rma) { | ||
| 2178 | case RX_MGMT_NONE: | ||
| 2179 | /* no action required */ | ||
| 2180 | break; | ||
| 2181 | case RX_MGMT_CFG80211_AUTH_TO: | ||
| 2182 | case RX_MGMT_CFG80211_ASSOC_TO: | ||
| 2183 | list_del(&wk->list); | ||
| 2184 | list_add(&wk->list, &free_work); | ||
| 2185 | wk->tries = rma; /* small abuse but only local */ | ||
| 2186 | break; | ||
| 2187 | default: | ||
| 2188 | WARN(1, "unexpected: %d", rma); | ||
| 2189 | } | ||
| 2190 | } | ||
| 2191 | |||
| 2192 | list_for_each_entry(wk, &ifmgd->work_list, list) { | ||
| 2193 | if (wk->state != IEEE80211_MGD_STATE_IDLE) { | ||
| 2194 | anybusy = true; | ||
| 2195 | break; | ||
| 2196 | } | ||
| 2197 | } | ||
| 2198 | if (!anybusy && | ||
| 2199 | test_and_clear_bit(IEEE80211_STA_REQ_SCAN, &ifmgd->request)) | ||
| 2200 | ieee80211_queue_delayed_work(&local->hw, | ||
| 2201 | &local->scan_work, | ||
| 2202 | round_jiffies_relative(0)); | ||
| 2203 | |||
| 2204 | mutex_unlock(&ifmgd->mtx); | 1628 | mutex_unlock(&ifmgd->mtx); |
| 2205 | |||
| 2206 | list_for_each_entry_safe(wk, tmp, &free_work, list) { | ||
| 2207 | switch (wk->tries) { | ||
| 2208 | case RX_MGMT_CFG80211_AUTH_TO: | ||
| 2209 | cfg80211_send_auth_timeout(sdata->dev, | ||
| 2210 | wk->bss->cbss.bssid); | ||
| 2211 | break; | ||
| 2212 | case RX_MGMT_CFG80211_ASSOC_TO: | ||
| 2213 | cfg80211_send_assoc_timeout(sdata->dev, | ||
| 2214 | wk->bss->cbss.bssid); | ||
| 2215 | break; | ||
| 2216 | default: | ||
| 2217 | WARN(1, "unexpected: %d", wk->tries); | ||
| 2218 | } | ||
| 2219 | |||
| 2220 | list_del(&wk->list); | ||
| 2221 | kfree(wk); | ||
| 2222 | } | ||
| 2223 | |||
| 2224 | ieee80211_recalc_idle(local); | ||
| 2225 | } | 1629 | } |
| 2226 | 1630 | ||
| 2227 | static void ieee80211_sta_bcn_mon_timer(unsigned long data) | 1631 | static void ieee80211_sta_bcn_mon_timer(unsigned long data) |
| @@ -2330,14 +1734,14 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata) | |||
| 2330 | (unsigned long) sdata); | 1734 | (unsigned long) sdata); |
| 2331 | skb_queue_head_init(&ifmgd->skb_queue); | 1735 | skb_queue_head_init(&ifmgd->skb_queue); |
| 2332 | 1736 | ||
| 2333 | INIT_LIST_HEAD(&ifmgd->work_list); | ||
| 2334 | |||
| 2335 | ifmgd->capab = WLAN_CAPABILITY_ESS; | ||
| 2336 | ifmgd->flags = 0; | 1737 | ifmgd->flags = 0; |
| 2337 | if (sdata->local->hw.queues >= 4) | ||
| 2338 | ifmgd->flags |= IEEE80211_STA_WMM_ENABLED; | ||
| 2339 | 1738 | ||
| 2340 | mutex_init(&ifmgd->mtx); | 1739 | mutex_init(&ifmgd->mtx); |
| 1740 | |||
| 1741 | if (sdata->local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS) | ||
| 1742 | ifmgd->req_smps = IEEE80211_SMPS_AUTOMATIC; | ||
| 1743 | else | ||
| 1744 | ifmgd->req_smps = IEEE80211_SMPS_OFF; | ||
| 2341 | } | 1745 | } |
| 2342 | 1746 | ||
| 2343 | /* scan finished notification */ | 1747 | /* scan finished notification */ |
| @@ -2368,12 +1772,34 @@ int ieee80211_max_network_latency(struct notifier_block *nb, | |||
| 2368 | } | 1772 | } |
| 2369 | 1773 | ||
| 2370 | /* config hooks */ | 1774 | /* config hooks */ |
| 1775 | static enum work_done_result | ||
| 1776 | ieee80211_probe_auth_done(struct ieee80211_work *wk, | ||
| 1777 | struct sk_buff *skb) | ||
| 1778 | { | ||
| 1779 | if (!skb) { | ||
| 1780 | cfg80211_send_auth_timeout(wk->sdata->dev, wk->filter_ta); | ||
| 1781 | return WORK_DONE_DESTROY; | ||
| 1782 | } | ||
| 1783 | |||
| 1784 | if (wk->type == IEEE80211_WORK_AUTH) { | ||
| 1785 | cfg80211_send_rx_auth(wk->sdata->dev, skb->data, skb->len); | ||
| 1786 | return WORK_DONE_DESTROY; | ||
| 1787 | } | ||
| 1788 | |||
| 1789 | mutex_lock(&wk->sdata->u.mgd.mtx); | ||
| 1790 | ieee80211_rx_mgmt_probe_resp(wk->sdata, skb); | ||
| 1791 | mutex_unlock(&wk->sdata->u.mgd.mtx); | ||
| 1792 | |||
| 1793 | wk->type = IEEE80211_WORK_AUTH; | ||
| 1794 | wk->probe_auth.tries = 0; | ||
| 1795 | return WORK_DONE_REQUEUE; | ||
| 1796 | } | ||
| 1797 | |||
| 2371 | int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, | 1798 | int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, |
| 2372 | struct cfg80211_auth_request *req) | 1799 | struct cfg80211_auth_request *req) |
| 2373 | { | 1800 | { |
| 2374 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
| 2375 | const u8 *ssid; | 1801 | const u8 *ssid; |
| 2376 | struct ieee80211_mgd_work *wk; | 1802 | struct ieee80211_work *wk; |
| 2377 | u16 auth_alg; | 1803 | u16 auth_alg; |
| 2378 | 1804 | ||
| 2379 | switch (req->auth_type) { | 1805 | switch (req->auth_type) { |
| @@ -2397,7 +1823,7 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, | |||
| 2397 | if (!wk) | 1823 | if (!wk) |
| 2398 | return -ENOMEM; | 1824 | return -ENOMEM; |
| 2399 | 1825 | ||
| 2400 | wk->bss = (void *)req->bss; | 1826 | memcpy(wk->filter_ta, req->bss->bssid, ETH_ALEN); |
| 2401 | 1827 | ||
| 2402 | if (req->ie && req->ie_len) { | 1828 | if (req->ie && req->ie_len) { |
| 2403 | memcpy(wk->ie, req->ie, req->ie_len); | 1829 | memcpy(wk->ie, req->ie, req->ie_len); |
| @@ -2405,68 +1831,95 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, | |||
| 2405 | } | 1831 | } |
| 2406 | 1832 | ||
| 2407 | if (req->key && req->key_len) { | 1833 | if (req->key && req->key_len) { |
| 2408 | wk->key_len = req->key_len; | 1834 | wk->probe_auth.key_len = req->key_len; |
| 2409 | wk->key_idx = req->key_idx; | 1835 | wk->probe_auth.key_idx = req->key_idx; |
| 2410 | memcpy(wk->key, req->key, req->key_len); | 1836 | memcpy(wk->probe_auth.key, req->key, req->key_len); |
| 2411 | } | 1837 | } |
| 2412 | 1838 | ||
| 2413 | ssid = ieee80211_bss_get_ie(req->bss, WLAN_EID_SSID); | 1839 | ssid = ieee80211_bss_get_ie(req->bss, WLAN_EID_SSID); |
| 2414 | memcpy(wk->ssid, ssid + 2, ssid[1]); | 1840 | memcpy(wk->probe_auth.ssid, ssid + 2, ssid[1]); |
| 2415 | wk->ssid_len = ssid[1]; | 1841 | wk->probe_auth.ssid_len = ssid[1]; |
| 2416 | 1842 | ||
| 2417 | wk->state = IEEE80211_MGD_STATE_PROBE; | 1843 | wk->probe_auth.algorithm = auth_alg; |
| 2418 | wk->auth_alg = auth_alg; | 1844 | wk->probe_auth.privacy = req->bss->capability & WLAN_CAPABILITY_PRIVACY; |
| 2419 | wk->timeout = jiffies; /* run right away */ | ||
| 2420 | 1845 | ||
| 2421 | /* | 1846 | /* if we already have a probe, don't probe again */ |
| 2422 | * XXX: if still associated need to tell AP that we're going | 1847 | if (req->bss->proberesp_ies) |
| 2423 | * to sleep and then change channel etc. | 1848 | wk->type = IEEE80211_WORK_AUTH; |
| 2424 | */ | 1849 | else |
| 2425 | sdata->local->oper_channel = req->bss->channel; | 1850 | wk->type = IEEE80211_WORK_DIRECT_PROBE; |
| 2426 | ieee80211_hw_config(sdata->local, 0); | 1851 | wk->chan = req->bss->channel; |
| 2427 | 1852 | wk->sdata = sdata; | |
| 2428 | mutex_lock(&ifmgd->mtx); | 1853 | wk->done = ieee80211_probe_auth_done; |
| 2429 | list_add(&wk->list, &sdata->u.mgd.work_list); | ||
| 2430 | mutex_unlock(&ifmgd->mtx); | ||
| 2431 | 1854 | ||
| 2432 | ieee80211_queue_work(&sdata->local->hw, &sdata->u.mgd.work); | 1855 | ieee80211_add_work(wk); |
| 2433 | return 0; | 1856 | return 0; |
| 2434 | } | 1857 | } |
| 2435 | 1858 | ||
| 2436 | int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, | 1859 | static enum work_done_result ieee80211_assoc_done(struct ieee80211_work *wk, |
| 2437 | struct cfg80211_assoc_request *req) | 1860 | struct sk_buff *skb) |
| 2438 | { | 1861 | { |
| 2439 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 1862 | struct ieee80211_mgmt *mgmt; |
| 2440 | struct ieee80211_mgd_work *wk, *found = NULL; | 1863 | u16 status; |
| 2441 | int i, err; | ||
| 2442 | 1864 | ||
| 2443 | mutex_lock(&ifmgd->mtx); | 1865 | if (!skb) { |
| 1866 | cfg80211_send_assoc_timeout(wk->sdata->dev, wk->filter_ta); | ||
| 1867 | return WORK_DONE_DESTROY; | ||
| 1868 | } | ||
| 2444 | 1869 | ||
| 2445 | list_for_each_entry(wk, &ifmgd->work_list, list) { | 1870 | mgmt = (void *)skb->data; |
| 2446 | if (&wk->bss->cbss == req->bss && | 1871 | status = le16_to_cpu(mgmt->u.assoc_resp.status_code); |
| 2447 | wk->state == IEEE80211_MGD_STATE_IDLE) { | 1872 | |
| 2448 | found = wk; | 1873 | if (status == WLAN_STATUS_SUCCESS) { |
| 2449 | break; | 1874 | mutex_lock(&wk->sdata->u.mgd.mtx); |
| 1875 | if (!ieee80211_assoc_success(wk, mgmt, skb->len)) { | ||
| 1876 | mutex_unlock(&wk->sdata->u.mgd.mtx); | ||
| 1877 | /* oops -- internal error -- send timeout for now */ | ||
| 1878 | cfg80211_send_assoc_timeout(wk->sdata->dev, | ||
| 1879 | wk->filter_ta); | ||
| 1880 | return WORK_DONE_DESTROY; | ||
| 2450 | } | 1881 | } |
| 1882 | mutex_unlock(&wk->sdata->u.mgd.mtx); | ||
| 2451 | } | 1883 | } |
| 2452 | 1884 | ||
| 2453 | if (!found) { | 1885 | cfg80211_send_rx_assoc(wk->sdata->dev, skb->data, skb->len); |
| 2454 | err = -ENOLINK; | 1886 | return WORK_DONE_DESTROY; |
| 2455 | goto out; | 1887 | } |
| 2456 | } | ||
| 2457 | 1888 | ||
| 2458 | list_del(&found->list); | 1889 | int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, |
| 1890 | struct cfg80211_assoc_request *req) | ||
| 1891 | { | ||
| 1892 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
| 1893 | struct ieee80211_bss *bss = (void *)req->bss->priv; | ||
| 1894 | struct ieee80211_work *wk; | ||
| 1895 | const u8 *ssid; | ||
| 1896 | int i; | ||
| 2459 | 1897 | ||
| 2460 | wk = krealloc(found, sizeof(*wk) + req->ie_len, GFP_KERNEL); | 1898 | mutex_lock(&ifmgd->mtx); |
| 2461 | if (!wk) { | 1899 | if (ifmgd->associated) { |
| 2462 | list_add(&found->list, &ifmgd->work_list); | 1900 | if (!req->prev_bssid || |
| 2463 | err = -ENOMEM; | 1901 | memcmp(req->prev_bssid, ifmgd->associated->bssid, |
| 2464 | goto out; | 1902 | ETH_ALEN)) { |
| 1903 | /* | ||
| 1904 | * We are already associated and the request was not a | ||
| 1905 | * reassociation request from the current BSS, so | ||
| 1906 | * reject it. | ||
| 1907 | */ | ||
| 1908 | mutex_unlock(&ifmgd->mtx); | ||
| 1909 | return -EALREADY; | ||
| 1910 | } | ||
| 1911 | |||
| 1912 | /* Trying to reassociate - clear previous association state */ | ||
| 1913 | ieee80211_set_disassoc(sdata); | ||
| 2465 | } | 1914 | } |
| 1915 | mutex_unlock(&ifmgd->mtx); | ||
| 2466 | 1916 | ||
| 2467 | list_add(&wk->list, &ifmgd->work_list); | 1917 | wk = kzalloc(sizeof(*wk) + req->ie_len, GFP_KERNEL); |
| 1918 | if (!wk) | ||
| 1919 | return -ENOMEM; | ||
| 2468 | 1920 | ||
| 2469 | ifmgd->flags &= ~IEEE80211_STA_DISABLE_11N; | 1921 | ifmgd->flags &= ~IEEE80211_STA_DISABLE_11N; |
| 1922 | ifmgd->flags &= ~IEEE80211_STA_NULLFUNC_ACKED; | ||
| 2470 | 1923 | ||
| 2471 | for (i = 0; i < req->crypto.n_ciphers_pairwise; i++) | 1924 | for (i = 0; i < req->crypto.n_ciphers_pairwise; i++) |
| 2472 | if (req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP40 || | 1925 | if (req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP40 || |
| @@ -2474,8 +1927,6 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, | |||
| 2474 | req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP104) | 1927 | req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP104) |
| 2475 | ifmgd->flags |= IEEE80211_STA_DISABLE_11N; | 1928 | ifmgd->flags |= IEEE80211_STA_DISABLE_11N; |
| 2476 | 1929 | ||
| 2477 | sdata->local->oper_channel = req->bss->channel; | ||
| 2478 | ieee80211_hw_config(sdata->local, 0); | ||
| 2479 | 1930 | ||
| 2480 | if (req->ie && req->ie_len) { | 1931 | if (req->ie && req->ie_len) { |
| 2481 | memcpy(wk->ie, req->ie, req->ie_len); | 1932 | memcpy(wk->ie, req->ie, req->ie_len); |
| @@ -2483,12 +1934,55 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, | |||
| 2483 | } else | 1934 | } else |
| 2484 | wk->ie_len = 0; | 1935 | wk->ie_len = 0; |
| 2485 | 1936 | ||
| 1937 | wk->assoc.bss = req->bss; | ||
| 1938 | |||
| 1939 | memcpy(wk->filter_ta, req->bss->bssid, ETH_ALEN); | ||
| 1940 | |||
| 1941 | /* new association always uses requested smps mode */ | ||
| 1942 | if (ifmgd->req_smps == IEEE80211_SMPS_AUTOMATIC) { | ||
| 1943 | if (ifmgd->powersave) | ||
| 1944 | ifmgd->ap_smps = IEEE80211_SMPS_DYNAMIC; | ||
| 1945 | else | ||
| 1946 | ifmgd->ap_smps = IEEE80211_SMPS_OFF; | ||
| 1947 | } else | ||
| 1948 | ifmgd->ap_smps = ifmgd->req_smps; | ||
| 1949 | |||
| 1950 | wk->assoc.smps = ifmgd->ap_smps; | ||
| 1951 | /* | ||
| 1952 | * IEEE802.11n does not allow TKIP/WEP as pairwise ciphers in HT mode. | ||
| 1953 | * We still associate in non-HT mode (11a/b/g) if any one of these | ||
| 1954 | * ciphers is configured as pairwise. | ||
| 1955 | * We can set this to true for non-11n hardware, that'll be checked | ||
| 1956 | * separately along with the peer capabilities. | ||
| 1957 | */ | ||
| 1958 | wk->assoc.use_11n = !(ifmgd->flags & IEEE80211_STA_DISABLE_11N); | ||
| 1959 | wk->assoc.capability = req->bss->capability; | ||
| 1960 | wk->assoc.wmm_used = bss->wmm_used; | ||
| 1961 | wk->assoc.supp_rates = bss->supp_rates; | ||
| 1962 | wk->assoc.supp_rates_len = bss->supp_rates_len; | ||
| 1963 | wk->assoc.ht_information_ie = | ||
| 1964 | ieee80211_bss_get_ie(req->bss, WLAN_EID_HT_INFORMATION); | ||
| 1965 | |||
| 1966 | if (bss->wmm_used && bss->uapsd_supported && | ||
| 1967 | (sdata->local->hw.flags & IEEE80211_HW_SUPPORTS_UAPSD)) { | ||
| 1968 | wk->assoc.uapsd_used = true; | ||
| 1969 | ifmgd->flags |= IEEE80211_STA_UAPSD_ENABLED; | ||
| 1970 | } else { | ||
| 1971 | wk->assoc.uapsd_used = false; | ||
| 1972 | ifmgd->flags &= ~IEEE80211_STA_UAPSD_ENABLED; | ||
| 1973 | } | ||
| 1974 | |||
| 1975 | ssid = ieee80211_bss_get_ie(req->bss, WLAN_EID_SSID); | ||
| 1976 | memcpy(wk->assoc.ssid, ssid + 2, ssid[1]); | ||
| 1977 | wk->assoc.ssid_len = ssid[1]; | ||
| 1978 | |||
| 2486 | if (req->prev_bssid) | 1979 | if (req->prev_bssid) |
| 2487 | memcpy(wk->prev_bssid, req->prev_bssid, ETH_ALEN); | 1980 | memcpy(wk->assoc.prev_bssid, req->prev_bssid, ETH_ALEN); |
| 2488 | 1981 | ||
| 2489 | wk->state = IEEE80211_MGD_STATE_ASSOC; | 1982 | wk->type = IEEE80211_WORK_ASSOC; |
| 2490 | wk->tries = 0; | 1983 | wk->chan = req->bss->channel; |
| 2491 | wk->timeout = jiffies; /* run right away */ | 1984 | wk->sdata = sdata; |
| 1985 | wk->done = ieee80211_assoc_done; | ||
| 2492 | 1986 | ||
| 2493 | if (req->use_mfp) { | 1987 | if (req->use_mfp) { |
| 2494 | ifmgd->mfp = IEEE80211_MFP_REQUIRED; | 1988 | ifmgd->mfp = IEEE80211_MFP_REQUIRED; |
| @@ -2503,69 +1997,65 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, | |||
| 2503 | else | 1997 | else |
| 2504 | ifmgd->flags &= ~IEEE80211_STA_CONTROL_PORT; | 1998 | ifmgd->flags &= ~IEEE80211_STA_CONTROL_PORT; |
| 2505 | 1999 | ||
| 2506 | ieee80211_queue_work(&sdata->local->hw, &sdata->u.mgd.work); | 2000 | ieee80211_add_work(wk); |
| 2507 | 2001 | return 0; | |
| 2508 | err = 0; | ||
| 2509 | |||
| 2510 | out: | ||
| 2511 | mutex_unlock(&ifmgd->mtx); | ||
| 2512 | return err; | ||
| 2513 | } | 2002 | } |
| 2514 | 2003 | ||
| 2515 | int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, | 2004 | int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, |
| 2516 | struct cfg80211_deauth_request *req, | 2005 | struct cfg80211_deauth_request *req, |
| 2517 | void *cookie) | 2006 | void *cookie) |
| 2518 | { | 2007 | { |
| 2008 | struct ieee80211_local *local = sdata->local; | ||
| 2519 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 2009 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
| 2520 | struct ieee80211_mgd_work *wk; | 2010 | struct ieee80211_work *wk; |
| 2521 | const u8 *bssid = NULL; | 2011 | const u8 *bssid = req->bss->bssid; |
| 2522 | bool not_auth_yet = false; | ||
| 2523 | 2012 | ||
| 2524 | mutex_lock(&ifmgd->mtx); | 2013 | mutex_lock(&ifmgd->mtx); |
| 2525 | 2014 | ||
| 2526 | if (ifmgd->associated && &ifmgd->associated->cbss == req->bss) { | 2015 | if (ifmgd->associated == req->bss) { |
| 2527 | bssid = req->bss->bssid; | 2016 | bssid = req->bss->bssid; |
| 2528 | ieee80211_set_disassoc(sdata, true); | 2017 | ieee80211_set_disassoc(sdata); |
| 2529 | } else list_for_each_entry(wk, &ifmgd->work_list, list) { | ||
| 2530 | if (&wk->bss->cbss == req->bss) { | ||
| 2531 | bssid = req->bss->bssid; | ||
| 2532 | if (wk->state == IEEE80211_MGD_STATE_PROBE) | ||
| 2533 | not_auth_yet = true; | ||
| 2534 | list_del(&wk->list); | ||
| 2535 | kfree(wk); | ||
| 2536 | break; | ||
| 2537 | } | ||
| 2538 | } | ||
| 2539 | |||
| 2540 | /* | ||
| 2541 | * If somebody requests authentication and we haven't | ||
| 2542 | * sent out an auth frame yet there's no need to send | ||
| 2543 | * out a deauth frame either. If the state was PROBE, | ||
| 2544 | * then this is the case. If it's AUTH we have sent a | ||
| 2545 | * frame, and if it's IDLE we have completed the auth | ||
| 2546 | * process already. | ||
| 2547 | */ | ||
| 2548 | if (not_auth_yet) { | ||
| 2549 | mutex_unlock(&ifmgd->mtx); | 2018 | mutex_unlock(&ifmgd->mtx); |
| 2550 | __cfg80211_auth_canceled(sdata->dev, bssid); | 2019 | } else { |
| 2551 | return 0; | 2020 | bool not_auth_yet = false; |
| 2552 | } | ||
| 2553 | 2021 | ||
| 2554 | /* | ||
| 2555 | * cfg80211 should catch this ... but it's racy since | ||
| 2556 | * we can receive a deauth frame, process it, hand it | ||
| 2557 | * to cfg80211 while that's in a locked section already | ||
| 2558 | * trying to tell us that the user wants to disconnect. | ||
| 2559 | */ | ||
| 2560 | if (!bssid) { | ||
| 2561 | mutex_unlock(&ifmgd->mtx); | 2022 | mutex_unlock(&ifmgd->mtx); |
| 2562 | return -ENOLINK; | ||
| 2563 | } | ||
| 2564 | 2023 | ||
| 2565 | mutex_unlock(&ifmgd->mtx); | 2024 | mutex_lock(&local->work_mtx); |
| 2025 | list_for_each_entry(wk, &local->work_list, list) { | ||
| 2026 | if (wk->sdata != sdata) | ||
| 2027 | continue; | ||
| 2028 | |||
| 2029 | if (wk->type != IEEE80211_WORK_DIRECT_PROBE && | ||
| 2030 | wk->type != IEEE80211_WORK_AUTH) | ||
| 2031 | continue; | ||
| 2032 | |||
| 2033 | if (memcmp(req->bss->bssid, wk->filter_ta, ETH_ALEN)) | ||
| 2034 | continue; | ||
| 2035 | |||
| 2036 | not_auth_yet = wk->type == IEEE80211_WORK_DIRECT_PROBE; | ||
| 2037 | list_del_rcu(&wk->list); | ||
| 2038 | free_work(wk); | ||
| 2039 | break; | ||
| 2040 | } | ||
| 2041 | mutex_unlock(&local->work_mtx); | ||
| 2042 | |||
| 2043 | /* | ||
| 2044 | * If somebody requests authentication and we haven't | ||
| 2045 | * sent out an auth frame yet there's no need to send | ||
| 2046 | * out a deauth frame either. If the state was PROBE, | ||
| 2047 | * then this is the case. If it's AUTH we have sent a | ||
| 2048 | * frame, and if it's IDLE we have completed the auth | ||
| 2049 | * process already. | ||
| 2050 | */ | ||
| 2051 | if (not_auth_yet) { | ||
| 2052 | __cfg80211_auth_canceled(sdata->dev, bssid); | ||
| 2053 | return 0; | ||
| 2054 | } | ||
| 2055 | } | ||
| 2566 | 2056 | ||
| 2567 | printk(KERN_DEBUG "%s: deauthenticating from %pM by local choice (reason=%d)\n", | 2057 | printk(KERN_DEBUG "%s: deauthenticating from %pM by local choice (reason=%d)\n", |
| 2568 | sdata->dev->name, bssid, req->reason_code); | 2058 | sdata->name, bssid, req->reason_code); |
| 2569 | 2059 | ||
| 2570 | ieee80211_send_deauth_disassoc(sdata, bssid, | 2060 | ieee80211_send_deauth_disassoc(sdata, bssid, |
| 2571 | IEEE80211_STYPE_DEAUTH, req->reason_code, | 2061 | IEEE80211_STYPE_DEAUTH, req->reason_code, |
| @@ -2590,15 +2080,15 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata, | |||
| 2590 | * to cfg80211 while that's in a locked section already | 2080 | * to cfg80211 while that's in a locked section already |
| 2591 | * trying to tell us that the user wants to disconnect. | 2081 | * trying to tell us that the user wants to disconnect. |
| 2592 | */ | 2082 | */ |
| 2593 | if (&ifmgd->associated->cbss != req->bss) { | 2083 | if (ifmgd->associated != req->bss) { |
| 2594 | mutex_unlock(&ifmgd->mtx); | 2084 | mutex_unlock(&ifmgd->mtx); |
| 2595 | return -ENOLINK; | 2085 | return -ENOLINK; |
| 2596 | } | 2086 | } |
| 2597 | 2087 | ||
| 2598 | printk(KERN_DEBUG "%s: disassociating from %pM by local choice (reason=%d)\n", | 2088 | printk(KERN_DEBUG "%s: disassociating from %pM by local choice (reason=%d)\n", |
| 2599 | sdata->dev->name, req->bss->bssid, req->reason_code); | 2089 | sdata->name, req->bss->bssid, req->reason_code); |
| 2600 | 2090 | ||
| 2601 | ieee80211_set_disassoc(sdata, false); | 2091 | ieee80211_set_disassoc(sdata); |
| 2602 | 2092 | ||
| 2603 | mutex_unlock(&ifmgd->mtx); | 2093 | mutex_unlock(&ifmgd->mtx); |
| 2604 | 2094 | ||
| @@ -2610,3 +2100,38 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata, | |||
| 2610 | 2100 | ||
| 2611 | return 0; | 2101 | return 0; |
| 2612 | } | 2102 | } |
| 2103 | |||
| 2104 | int ieee80211_mgd_action(struct ieee80211_sub_if_data *sdata, | ||
| 2105 | struct ieee80211_channel *chan, | ||
| 2106 | enum nl80211_channel_type channel_type, | ||
| 2107 | const u8 *buf, size_t len, u64 *cookie) | ||
| 2108 | { | ||
| 2109 | struct ieee80211_local *local = sdata->local; | ||
| 2110 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
| 2111 | struct sk_buff *skb; | ||
| 2112 | |||
| 2113 | /* Check that we are on the requested channel for transmission */ | ||
| 2114 | if ((chan != local->tmp_channel || | ||
| 2115 | channel_type != local->tmp_channel_type) && | ||
| 2116 | (chan != local->oper_channel || | ||
| 2117 | channel_type != local->oper_channel_type)) | ||
| 2118 | return -EBUSY; | ||
| 2119 | |||
| 2120 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + len); | ||
| 2121 | if (!skb) | ||
| 2122 | return -ENOMEM; | ||
| 2123 | skb_reserve(skb, local->hw.extra_tx_headroom); | ||
| 2124 | |||
| 2125 | memcpy(skb_put(skb, len), buf, len); | ||
| 2126 | |||
| 2127 | if (!(ifmgd->flags & IEEE80211_STA_MFP_ENABLED)) | ||
| 2128 | IEEE80211_SKB_CB(skb)->flags |= | ||
| 2129 | IEEE80211_TX_INTFL_DONT_ENCRYPT; | ||
| 2130 | IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_NL80211_FRAME_TX | | ||
| 2131 | IEEE80211_TX_CTL_REQ_TX_STATUS; | ||
| 2132 | skb->dev = sdata->dev; | ||
| 2133 | ieee80211_tx_skb(sdata, skb); | ||
| 2134 | |||
| 2135 | *cookie = (unsigned long) skb; | ||
| 2136 | return 0; | ||
| 2137 | } | ||
diff --git a/net/mac80211/offchannel.c b/net/mac80211/offchannel.c new file mode 100644 index 000000000000..c36b1911987a --- /dev/null +++ b/net/mac80211/offchannel.c | |||
| @@ -0,0 +1,170 @@ | |||
| 1 | /* | ||
| 2 | * Off-channel operation helpers | ||
| 3 | * | ||
| 4 | * Copyright 2003, Jouni Malinen <jkmaline@cc.hut.fi> | ||
| 5 | * Copyright 2004, Instant802 Networks, Inc. | ||
| 6 | * Copyright 2005, Devicescape Software, Inc. | ||
| 7 | * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz> | ||
| 8 | * Copyright 2007, Michael Wu <flamingice@sourmilk.net> | ||
| 9 | * Copyright 2009 Johannes Berg <johannes@sipsolutions.net> | ||
| 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 | #include <net/mac80211.h> | ||
| 16 | #include "ieee80211_i.h" | ||
| 17 | |||
| 18 | /* | ||
| 19 | * inform AP that we will go to sleep so that it will buffer the frames | ||
| 20 | * while we scan | ||
| 21 | */ | ||
| 22 | static void ieee80211_offchannel_ps_enable(struct ieee80211_sub_if_data *sdata) | ||
| 23 | { | ||
| 24 | struct ieee80211_local *local = sdata->local; | ||
| 25 | |||
| 26 | local->offchannel_ps_enabled = false; | ||
| 27 | |||
| 28 | /* FIXME: what to do when local->pspolling is true? */ | ||
| 29 | |||
| 30 | del_timer_sync(&local->dynamic_ps_timer); | ||
| 31 | cancel_work_sync(&local->dynamic_ps_enable_work); | ||
| 32 | |||
| 33 | if (local->hw.conf.flags & IEEE80211_CONF_PS) { | ||
| 34 | local->offchannel_ps_enabled = true; | ||
| 35 | local->hw.conf.flags &= ~IEEE80211_CONF_PS; | ||
| 36 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); | ||
| 37 | } | ||
| 38 | |||
| 39 | if (!(local->offchannel_ps_enabled) || | ||
| 40 | !(local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK)) | ||
| 41 | /* | ||
| 42 | * If power save was enabled, no need to send a nullfunc | ||
| 43 | * frame because AP knows that we are sleeping. But if the | ||
| 44 | * hardware is creating the nullfunc frame for power save | ||
| 45 | * status (ie. IEEE80211_HW_PS_NULLFUNC_STACK is not | ||
| 46 | * enabled) and power save was enabled, the firmware just | ||
| 47 | * sent a null frame with power save disabled. So we need | ||
| 48 | * to send a new nullfunc frame to inform the AP that we | ||
| 49 | * are again sleeping. | ||
| 50 | */ | ||
| 51 | ieee80211_send_nullfunc(local, sdata, 1); | ||
| 52 | } | ||
| 53 | |||
| 54 | /* inform AP that we are awake again, unless power save is enabled */ | ||
| 55 | static void ieee80211_offchannel_ps_disable(struct ieee80211_sub_if_data *sdata) | ||
| 56 | { | ||
| 57 | struct ieee80211_local *local = sdata->local; | ||
| 58 | |||
| 59 | if (!local->ps_sdata) | ||
| 60 | ieee80211_send_nullfunc(local, sdata, 0); | ||
| 61 | else if (local->offchannel_ps_enabled) { | ||
| 62 | /* | ||
| 63 | * In !IEEE80211_HW_PS_NULLFUNC_STACK case the hardware | ||
| 64 | * will send a nullfunc frame with the powersave bit set | ||
| 65 | * even though the AP already knows that we are sleeping. | ||
| 66 | * This could be avoided by sending a null frame with power | ||
| 67 | * save bit disabled before enabling the power save, but | ||
| 68 | * this doesn't gain anything. | ||
| 69 | * | ||
| 70 | * When IEEE80211_HW_PS_NULLFUNC_STACK is enabled, no need | ||
| 71 | * to send a nullfunc frame because AP already knows that | ||
| 72 | * we are sleeping, let's just enable power save mode in | ||
| 73 | * hardware. | ||
| 74 | */ | ||
| 75 | local->hw.conf.flags |= IEEE80211_CONF_PS; | ||
| 76 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); | ||
| 77 | } else if (local->hw.conf.dynamic_ps_timeout > 0) { | ||
| 78 | /* | ||
| 79 | * If IEEE80211_CONF_PS was not set and the dynamic_ps_timer | ||
| 80 | * had been running before leaving the operating channel, | ||
| 81 | * restart the timer now and send a nullfunc frame to inform | ||
| 82 | * the AP that we are awake. | ||
| 83 | */ | ||
| 84 | ieee80211_send_nullfunc(local, sdata, 0); | ||
| 85 | mod_timer(&local->dynamic_ps_timer, jiffies + | ||
| 86 | msecs_to_jiffies(local->hw.conf.dynamic_ps_timeout)); | ||
| 87 | } | ||
| 88 | } | ||
| 89 | |||
| 90 | void ieee80211_offchannel_stop_beaconing(struct ieee80211_local *local) | ||
| 91 | { | ||
| 92 | struct ieee80211_sub_if_data *sdata; | ||
| 93 | |||
| 94 | mutex_lock(&local->iflist_mtx); | ||
| 95 | list_for_each_entry(sdata, &local->interfaces, list) { | ||
| 96 | if (!ieee80211_sdata_running(sdata)) | ||
| 97 | continue; | ||
| 98 | |||
| 99 | /* disable beaconing */ | ||
| 100 | if (sdata->vif.type == NL80211_IFTYPE_AP || | ||
| 101 | sdata->vif.type == NL80211_IFTYPE_ADHOC || | ||
| 102 | sdata->vif.type == NL80211_IFTYPE_MESH_POINT) | ||
| 103 | ieee80211_bss_info_change_notify( | ||
| 104 | sdata, BSS_CHANGED_BEACON_ENABLED); | ||
| 105 | |||
| 106 | /* | ||
| 107 | * only handle non-STA interfaces here, STA interfaces | ||
| 108 | * are handled in ieee80211_offchannel_stop_station(), | ||
| 109 | * e.g., from the background scan state machine. | ||
| 110 | * | ||
| 111 | * In addition, do not stop monitor interface to allow it to be | ||
| 112 | * used from user space controlled off-channel operations. | ||
| 113 | */ | ||
| 114 | if (sdata->vif.type != NL80211_IFTYPE_STATION && | ||
| 115 | sdata->vif.type != NL80211_IFTYPE_MONITOR) | ||
| 116 | netif_tx_stop_all_queues(sdata->dev); | ||
| 117 | } | ||
| 118 | mutex_unlock(&local->iflist_mtx); | ||
| 119 | } | ||
| 120 | |||
| 121 | void ieee80211_offchannel_stop_station(struct ieee80211_local *local) | ||
| 122 | { | ||
| 123 | struct ieee80211_sub_if_data *sdata; | ||
| 124 | |||
| 125 | /* | ||
| 126 | * notify the AP about us leaving the channel and stop all STA interfaces | ||
| 127 | */ | ||
| 128 | mutex_lock(&local->iflist_mtx); | ||
| 129 | list_for_each_entry(sdata, &local->interfaces, list) { | ||
| 130 | if (!ieee80211_sdata_running(sdata)) | ||
| 131 | continue; | ||
| 132 | |||
| 133 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { | ||
| 134 | netif_tx_stop_all_queues(sdata->dev); | ||
| 135 | if (sdata->u.mgd.associated) | ||
| 136 | ieee80211_offchannel_ps_enable(sdata); | ||
| 137 | } | ||
| 138 | } | ||
| 139 | mutex_unlock(&local->iflist_mtx); | ||
| 140 | } | ||
| 141 | |||
| 142 | void ieee80211_offchannel_return(struct ieee80211_local *local, | ||
| 143 | bool enable_beaconing) | ||
| 144 | { | ||
| 145 | struct ieee80211_sub_if_data *sdata; | ||
| 146 | |||
| 147 | mutex_lock(&local->iflist_mtx); | ||
| 148 | list_for_each_entry(sdata, &local->interfaces, list) { | ||
| 149 | if (!ieee80211_sdata_running(sdata)) | ||
| 150 | continue; | ||
| 151 | |||
| 152 | /* Tell AP we're back */ | ||
| 153 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { | ||
| 154 | if (sdata->u.mgd.associated) | ||
| 155 | ieee80211_offchannel_ps_disable(sdata); | ||
| 156 | } | ||
| 157 | |||
| 158 | if (sdata->vif.type != NL80211_IFTYPE_MONITOR) | ||
| 159 | netif_tx_wake_all_queues(sdata->dev); | ||
| 160 | |||
| 161 | /* re-enable beaconing */ | ||
| 162 | if (enable_beaconing && | ||
| 163 | (sdata->vif.type == NL80211_IFTYPE_AP || | ||
| 164 | sdata->vif.type == NL80211_IFTYPE_ADHOC || | ||
| 165 | sdata->vif.type == NL80211_IFTYPE_MESH_POINT)) | ||
| 166 | ieee80211_bss_info_change_notify( | ||
| 167 | sdata, BSS_CHANGED_BEACON_ENABLED); | ||
| 168 | } | ||
| 169 | mutex_unlock(&local->iflist_mtx); | ||
| 170 | } | ||
diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c index e535f1c988fe..0e64484e861c 100644 --- a/net/mac80211/pm.c +++ b/net/mac80211/pm.c | |||
| @@ -10,9 +10,7 @@ int __ieee80211_suspend(struct ieee80211_hw *hw) | |||
| 10 | { | 10 | { |
| 11 | struct ieee80211_local *local = hw_to_local(hw); | 11 | struct ieee80211_local *local = hw_to_local(hw); |
| 12 | struct ieee80211_sub_if_data *sdata; | 12 | struct ieee80211_sub_if_data *sdata; |
| 13 | struct ieee80211_if_init_conf conf; | ||
| 14 | struct sta_info *sta; | 13 | struct sta_info *sta; |
| 15 | unsigned long flags; | ||
| 16 | 14 | ||
| 17 | ieee80211_scan_cancel(local); | 15 | ieee80211_scan_cancel(local); |
| 18 | 16 | ||
| @@ -56,22 +54,21 @@ int __ieee80211_suspend(struct ieee80211_hw *hw) | |||
| 56 | rcu_read_unlock(); | 54 | rcu_read_unlock(); |
| 57 | 55 | ||
| 58 | /* remove STAs */ | 56 | /* remove STAs */ |
| 59 | spin_lock_irqsave(&local->sta_lock, flags); | 57 | mutex_lock(&local->sta_mtx); |
| 60 | list_for_each_entry(sta, &local->sta_list, list) { | 58 | list_for_each_entry(sta, &local->sta_list, list) { |
| 61 | if (local->ops->sta_notify) { | 59 | if (sta->uploaded) { |
| 62 | sdata = sta->sdata; | 60 | sdata = sta->sdata; |
| 63 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | 61 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) |
| 64 | sdata = container_of(sdata->bss, | 62 | sdata = container_of(sdata->bss, |
| 65 | struct ieee80211_sub_if_data, | 63 | struct ieee80211_sub_if_data, |
| 66 | u.ap); | 64 | u.ap); |
| 67 | 65 | ||
| 68 | drv_sta_notify(local, &sdata->vif, STA_NOTIFY_REMOVE, | 66 | drv_sta_remove(local, sdata, &sta->sta); |
| 69 | &sta->sta); | ||
| 70 | } | 67 | } |
| 71 | 68 | ||
| 72 | mesh_plink_quiesce(sta); | 69 | mesh_plink_quiesce(sta); |
| 73 | } | 70 | } |
| 74 | spin_unlock_irqrestore(&local->sta_lock, flags); | 71 | mutex_unlock(&local->sta_mtx); |
| 75 | 72 | ||
| 76 | /* remove all interfaces */ | 73 | /* remove all interfaces */ |
| 77 | list_for_each_entry(sdata, &local->interfaces, list) { | 74 | list_for_each_entry(sdata, &local->interfaces, list) { |
| @@ -93,17 +90,14 @@ int __ieee80211_suspend(struct ieee80211_hw *hw) | |||
| 93 | break; | 90 | break; |
| 94 | } | 91 | } |
| 95 | 92 | ||
| 96 | if (!netif_running(sdata->dev)) | 93 | if (!ieee80211_sdata_running(sdata)) |
| 97 | continue; | 94 | continue; |
| 98 | 95 | ||
| 99 | /* disable beaconing */ | 96 | /* disable beaconing */ |
| 100 | ieee80211_bss_info_change_notify(sdata, | 97 | ieee80211_bss_info_change_notify(sdata, |
| 101 | BSS_CHANGED_BEACON_ENABLED); | 98 | BSS_CHANGED_BEACON_ENABLED); |
| 102 | 99 | ||
| 103 | conf.vif = &sdata->vif; | 100 | drv_remove_interface(local, &sdata->vif); |
| 104 | conf.type = sdata->vif.type; | ||
| 105 | conf.mac_addr = sdata->dev->dev_addr; | ||
| 106 | drv_remove_interface(local, &conf); | ||
| 107 | } | 101 | } |
| 108 | 102 | ||
| 109 | /* stop hardware - this must stop RX */ | 103 | /* stop hardware - this must stop RX */ |
diff --git a/net/mac80211/rate.c b/net/mac80211/rate.c index 12a2bff7dcdb..0b299d236fa1 100644 --- a/net/mac80211/rate.c +++ b/net/mac80211/rate.c | |||
| @@ -145,7 +145,7 @@ static const struct file_operations rcname_ops = { | |||
| 145 | }; | 145 | }; |
| 146 | #endif | 146 | #endif |
| 147 | 147 | ||
| 148 | struct rate_control_ref *rate_control_alloc(const char *name, | 148 | static struct rate_control_ref *rate_control_alloc(const char *name, |
| 149 | struct ieee80211_local *local) | 149 | struct ieee80211_local *local) |
| 150 | { | 150 | { |
| 151 | struct dentry *debugfsdir = NULL; | 151 | struct dentry *debugfsdir = NULL; |
| @@ -207,6 +207,27 @@ static bool rc_no_data_or_no_ack(struct ieee80211_tx_rate_control *txrc) | |||
| 207 | return ((info->flags & IEEE80211_TX_CTL_NO_ACK) || !ieee80211_is_data(fc)); | 207 | return ((info->flags & IEEE80211_TX_CTL_NO_ACK) || !ieee80211_is_data(fc)); |
| 208 | } | 208 | } |
| 209 | 209 | ||
| 210 | static void rc_send_low_broadcast(s8 *idx, u32 basic_rates, u8 max_rate_idx) | ||
| 211 | { | ||
| 212 | u8 i; | ||
| 213 | |||
| 214 | if (basic_rates == 0) | ||
| 215 | return; /* assume basic rates unknown and accept rate */ | ||
| 216 | if (*idx < 0) | ||
| 217 | return; | ||
| 218 | if (basic_rates & (1 << *idx)) | ||
| 219 | return; /* selected rate is a basic rate */ | ||
| 220 | |||
| 221 | for (i = *idx + 1; i <= max_rate_idx; i++) { | ||
| 222 | if (basic_rates & (1 << i)) { | ||
| 223 | *idx = i; | ||
| 224 | return; | ||
| 225 | } | ||
| 226 | } | ||
| 227 | |||
| 228 | /* could not find a basic rate; use original selection */ | ||
| 229 | } | ||
| 230 | |||
| 210 | bool rate_control_send_low(struct ieee80211_sta *sta, | 231 | bool rate_control_send_low(struct ieee80211_sta *sta, |
| 211 | void *priv_sta, | 232 | void *priv_sta, |
| 212 | struct ieee80211_tx_rate_control *txrc) | 233 | struct ieee80211_tx_rate_control *txrc) |
| @@ -218,12 +239,48 @@ bool rate_control_send_low(struct ieee80211_sta *sta, | |||
| 218 | info->control.rates[0].count = | 239 | info->control.rates[0].count = |
| 219 | (info->flags & IEEE80211_TX_CTL_NO_ACK) ? | 240 | (info->flags & IEEE80211_TX_CTL_NO_ACK) ? |
| 220 | 1 : txrc->hw->max_rate_tries; | 241 | 1 : txrc->hw->max_rate_tries; |
| 242 | if (!sta && txrc->ap) | ||
| 243 | rc_send_low_broadcast(&info->control.rates[0].idx, | ||
| 244 | txrc->bss_conf->basic_rates, | ||
| 245 | txrc->sband->n_bitrates); | ||
| 221 | return true; | 246 | return true; |
| 222 | } | 247 | } |
| 223 | return false; | 248 | return false; |
| 224 | } | 249 | } |
| 225 | EXPORT_SYMBOL(rate_control_send_low); | 250 | EXPORT_SYMBOL(rate_control_send_low); |
| 226 | 251 | ||
| 252 | static void rate_idx_match_mask(struct ieee80211_tx_rate *rate, | ||
| 253 | int n_bitrates, u32 mask) | ||
| 254 | { | ||
| 255 | int j; | ||
| 256 | |||
| 257 | /* See whether the selected rate or anything below it is allowed. */ | ||
| 258 | for (j = rate->idx; j >= 0; j--) { | ||
| 259 | if (mask & (1 << j)) { | ||
| 260 | /* Okay, found a suitable rate. Use it. */ | ||
| 261 | rate->idx = j; | ||
| 262 | return; | ||
| 263 | } | ||
| 264 | } | ||
| 265 | |||
| 266 | /* Try to find a higher rate that would be allowed */ | ||
| 267 | for (j = rate->idx + 1; j < n_bitrates; j++) { | ||
| 268 | if (mask & (1 << j)) { | ||
| 269 | /* Okay, found a suitable rate. Use it. */ | ||
| 270 | rate->idx = j; | ||
| 271 | return; | ||
| 272 | } | ||
| 273 | } | ||
| 274 | |||
| 275 | /* | ||
| 276 | * Uh.. No suitable rate exists. This should not really happen with | ||
| 277 | * sane TX rate mask configurations. However, should someone manage to | ||
| 278 | * configure supported rates and TX rate mask in incompatible way, | ||
| 279 | * allow the frame to be transmitted with whatever the rate control | ||
| 280 | * selected. | ||
| 281 | */ | ||
| 282 | } | ||
| 283 | |||
| 227 | void rate_control_get_rate(struct ieee80211_sub_if_data *sdata, | 284 | void rate_control_get_rate(struct ieee80211_sub_if_data *sdata, |
| 228 | struct sta_info *sta, | 285 | struct sta_info *sta, |
| 229 | struct ieee80211_tx_rate_control *txrc) | 286 | struct ieee80211_tx_rate_control *txrc) |
| @@ -233,6 +290,7 @@ void rate_control_get_rate(struct ieee80211_sub_if_data *sdata, | |||
| 233 | struct ieee80211_sta *ista = NULL; | 290 | struct ieee80211_sta *ista = NULL; |
| 234 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(txrc->skb); | 291 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(txrc->skb); |
| 235 | int i; | 292 | int i; |
| 293 | u32 mask; | ||
| 236 | 294 | ||
| 237 | if (sta) { | 295 | if (sta) { |
| 238 | ista = &sta->sta; | 296 | ista = &sta->sta; |
| @@ -248,23 +306,31 @@ void rate_control_get_rate(struct ieee80211_sub_if_data *sdata, | |||
| 248 | if (sdata->local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL) | 306 | if (sdata->local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL) |
| 249 | return; | 307 | return; |
| 250 | 308 | ||
| 251 | if (sta && sdata->force_unicast_rateidx > -1) { | 309 | ref->ops->get_rate(ref->priv, ista, priv_sta, txrc); |
| 252 | info->control.rates[0].idx = sdata->force_unicast_rateidx; | ||
| 253 | } else { | ||
| 254 | ref->ops->get_rate(ref->priv, ista, priv_sta, txrc); | ||
| 255 | info->flags |= IEEE80211_TX_INTFL_RCALGO; | ||
| 256 | } | ||
| 257 | 310 | ||
| 258 | /* | 311 | /* |
| 259 | * try to enforce the maximum rate the user wanted | 312 | * Try to enforce the rateidx mask the user wanted. skip this if the |
| 313 | * default mask (allow all rates) is used to save some processing for | ||
| 314 | * the common case. | ||
| 260 | */ | 315 | */ |
| 261 | if (sdata->max_ratectrl_rateidx > -1) | 316 | mask = sdata->rc_rateidx_mask[info->band]; |
| 317 | if (mask != (1 << txrc->sband->n_bitrates) - 1) { | ||
| 318 | if (sta) { | ||
| 319 | /* Filter out rates that the STA does not support */ | ||
| 320 | mask &= sta->sta.supp_rates[info->band]; | ||
| 321 | } | ||
| 322 | /* | ||
| 323 | * Make sure the rate index selected for each TX rate is | ||
| 324 | * included in the configured mask and change the rate indexes | ||
| 325 | * if needed. | ||
| 326 | */ | ||
| 262 | for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) { | 327 | for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) { |
| 328 | /* Rate masking supports only legacy rates for now */ | ||
| 263 | if (info->control.rates[i].flags & IEEE80211_TX_RC_MCS) | 329 | if (info->control.rates[i].flags & IEEE80211_TX_RC_MCS) |
| 264 | continue; | 330 | continue; |
| 265 | info->control.rates[i].idx = | 331 | rate_idx_match_mask(&info->control.rates[i], |
| 266 | min_t(s8, info->control.rates[i].idx, | 332 | txrc->sband->n_bitrates, mask); |
| 267 | sdata->max_ratectrl_rateidx); | 333 | } |
| 268 | } | 334 | } |
| 269 | 335 | ||
| 270 | BUG_ON(info->control.rates[0].idx < 0); | 336 | BUG_ON(info->control.rates[0].idx < 0); |
diff --git a/net/mac80211/rate.h b/net/mac80211/rate.h index cb9bd1f65e27..065a96190e32 100644 --- a/net/mac80211/rate.h +++ b/net/mac80211/rate.h | |||
| @@ -26,10 +26,6 @@ struct rate_control_ref { | |||
| 26 | struct kref kref; | 26 | struct kref kref; |
| 27 | }; | 27 | }; |
| 28 | 28 | ||
| 29 | /* Get a reference to the rate control algorithm. If `name' is NULL, get the | ||
| 30 | * first available algorithm. */ | ||
| 31 | struct rate_control_ref *rate_control_alloc(const char *name, | ||
| 32 | struct ieee80211_local *local); | ||
| 33 | void rate_control_get_rate(struct ieee80211_sub_if_data *sdata, | 29 | void rate_control_get_rate(struct ieee80211_sub_if_data *sdata, |
| 34 | struct sta_info *sta, | 30 | struct sta_info *sta, |
| 35 | struct ieee80211_tx_rate_control *txrc); | 31 | struct ieee80211_tx_rate_control *txrc); |
| @@ -44,10 +40,11 @@ static inline void rate_control_tx_status(struct ieee80211_local *local, | |||
| 44 | struct rate_control_ref *ref = local->rate_ctrl; | 40 | struct rate_control_ref *ref = local->rate_ctrl; |
| 45 | struct ieee80211_sta *ista = &sta->sta; | 41 | struct ieee80211_sta *ista = &sta->sta; |
| 46 | void *priv_sta = sta->rate_ctrl_priv; | 42 | void *priv_sta = sta->rate_ctrl_priv; |
| 47 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | ||
| 48 | 43 | ||
| 49 | if (likely(info->flags & IEEE80211_TX_INTFL_RCALGO)) | 44 | if (!ref) |
| 50 | ref->ops->tx_status(ref->priv, sband, ista, priv_sta, skb); | 45 | return; |
| 46 | |||
| 47 | ref->ops->tx_status(ref->priv, sband, ista, priv_sta, skb); | ||
| 51 | } | 48 | } |
| 52 | 49 | ||
| 53 | 50 | ||
| @@ -69,7 +66,8 @@ static inline void rate_control_rate_init(struct sta_info *sta) | |||
| 69 | 66 | ||
| 70 | static inline void rate_control_rate_update(struct ieee80211_local *local, | 67 | static inline void rate_control_rate_update(struct ieee80211_local *local, |
| 71 | struct ieee80211_supported_band *sband, | 68 | struct ieee80211_supported_band *sband, |
| 72 | struct sta_info *sta, u32 changed) | 69 | struct sta_info *sta, u32 changed, |
| 70 | enum nl80211_channel_type oper_chan_type) | ||
| 73 | { | 71 | { |
| 74 | struct rate_control_ref *ref = local->rate_ctrl; | 72 | struct rate_control_ref *ref = local->rate_ctrl; |
| 75 | struct ieee80211_sta *ista = &sta->sta; | 73 | struct ieee80211_sta *ista = &sta->sta; |
| @@ -77,7 +75,7 @@ static inline void rate_control_rate_update(struct ieee80211_local *local, | |||
| 77 | 75 | ||
| 78 | if (ref && ref->ops->rate_update) | 76 | if (ref && ref->ops->rate_update) |
| 79 | ref->ops->rate_update(ref->priv, sband, ista, | 77 | ref->ops->rate_update(ref->priv, sband, ista, |
| 80 | priv_sta, changed); | 78 | priv_sta, changed, oper_chan_type); |
| 81 | } | 79 | } |
| 82 | 80 | ||
| 83 | static inline void *rate_control_alloc_sta(struct rate_control_ref *ref, | 81 | static inline void *rate_control_alloc_sta(struct rate_control_ref *ref, |
| @@ -115,7 +113,8 @@ static inline void rate_control_remove_sta_debugfs(struct sta_info *sta) | |||
| 115 | #endif | 113 | #endif |
| 116 | } | 114 | } |
| 117 | 115 | ||
| 118 | /* functions for rate control related to a device */ | 116 | /* Get a reference to the rate control algorithm. If `name' is NULL, get the |
| 117 | * first available algorithm. */ | ||
| 119 | int ieee80211_init_rate_ctrl_alg(struct ieee80211_local *local, | 118 | int ieee80211_init_rate_ctrl_alg(struct ieee80211_local *local, |
| 120 | const char *name); | 119 | const char *name); |
| 121 | void rate_control_deinitialize(struct ieee80211_local *local); | 120 | void rate_control_deinitialize(struct ieee80211_local *local); |
diff --git a/net/mac80211/rc80211_pid_algo.c b/net/mac80211/rc80211_pid_algo.c index 29bc4c516238..2652a374974e 100644 --- a/net/mac80211/rc80211_pid_algo.c +++ b/net/mac80211/rc80211_pid_algo.c | |||
| @@ -157,9 +157,7 @@ static void rate_control_pid_sample(struct rc_pid_info *pinfo, | |||
| 157 | 157 | ||
| 158 | /* In case nothing happened during the previous control interval, turn | 158 | /* In case nothing happened during the previous control interval, turn |
| 159 | * the sharpening factor on. */ | 159 | * the sharpening factor on. */ |
| 160 | period = (HZ * pinfo->sampling_period + 500) / 1000; | 160 | period = msecs_to_jiffies(pinfo->sampling_period); |
| 161 | if (!period) | ||
| 162 | period = 1; | ||
| 163 | if (jiffies - spinfo->last_sample > 2 * period) | 161 | if (jiffies - spinfo->last_sample > 2 * period) |
| 164 | spinfo->sharp_cnt = pinfo->sharpen_duration; | 162 | spinfo->sharp_cnt = pinfo->sharpen_duration; |
| 165 | 163 | ||
| @@ -252,9 +250,7 @@ static void rate_control_pid_tx_status(void *priv, struct ieee80211_supported_ba | |||
| 252 | } | 250 | } |
| 253 | 251 | ||
| 254 | /* Update PID controller state. */ | 252 | /* Update PID controller state. */ |
| 255 | period = (HZ * pinfo->sampling_period + 500) / 1000; | 253 | period = msecs_to_jiffies(pinfo->sampling_period); |
| 256 | if (!period) | ||
| 257 | period = 1; | ||
| 258 | if (time_after(jiffies, spinfo->last_sample + period)) | 254 | if (time_after(jiffies, spinfo->last_sample + period)) |
| 259 | rate_control_pid_sample(pinfo, sband, sta, spinfo); | 255 | rate_control_pid_sample(pinfo, sband, sta, spinfo); |
| 260 | } | 256 | } |
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 82a30c1bf3ab..b5c48de81d8b 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
| @@ -2,7 +2,7 @@ | |||
| 2 | * Copyright 2002-2005, Instant802 Networks, Inc. | 2 | * Copyright 2002-2005, Instant802 Networks, Inc. |
| 3 | * Copyright 2005-2006, Devicescape Software, Inc. | 3 | * Copyright 2005-2006, Devicescape Software, Inc. |
| 4 | * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz> | 4 | * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz> |
| 5 | * Copyright 2007 Johannes Berg <johannes@sipsolutions.net> | 5 | * Copyright 2007-2010 Johannes Berg <johannes@sipsolutions.net> |
| 6 | * | 6 | * |
| 7 | * This program is free software; you can redistribute it and/or modify | 7 | * This program is free software; you can redistribute it and/or modify |
| 8 | * it under the terms of the GNU General Public License version 2 as | 8 | * it under the terms of the GNU General Public License version 2 as |
| @@ -283,15 +283,15 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb, | |||
| 283 | skb->protocol = htons(ETH_P_802_2); | 283 | skb->protocol = htons(ETH_P_802_2); |
| 284 | 284 | ||
| 285 | list_for_each_entry_rcu(sdata, &local->interfaces, list) { | 285 | list_for_each_entry_rcu(sdata, &local->interfaces, list) { |
| 286 | if (!netif_running(sdata->dev)) | ||
| 287 | continue; | ||
| 288 | |||
| 289 | if (sdata->vif.type != NL80211_IFTYPE_MONITOR) | 286 | if (sdata->vif.type != NL80211_IFTYPE_MONITOR) |
| 290 | continue; | 287 | continue; |
| 291 | 288 | ||
| 292 | if (sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES) | 289 | if (sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES) |
| 293 | continue; | 290 | continue; |
| 294 | 291 | ||
| 292 | if (!ieee80211_sdata_running(sdata)) | ||
| 293 | continue; | ||
| 294 | |||
| 295 | if (prev_dev) { | 295 | if (prev_dev) { |
| 296 | skb2 = skb_clone(skb, GFP_ATOMIC); | 296 | skb2 = skb_clone(skb, GFP_ATOMIC); |
| 297 | if (skb2) { | 297 | if (skb2) { |
| @@ -361,7 +361,9 @@ static void ieee80211_parse_qos(struct ieee80211_rx_data *rx) | |||
| 361 | * boundary. In the case of regular frames, this simply means aligning the | 361 | * boundary. In the case of regular frames, this simply means aligning the |
| 362 | * payload to a four-byte boundary (because either the IP header is directly | 362 | * payload to a four-byte boundary (because either the IP header is directly |
| 363 | * contained, or IV/RFC1042 headers that have a length divisible by four are | 363 | * contained, or IV/RFC1042 headers that have a length divisible by four are |
| 364 | * in front of it). | 364 | * in front of it). If the payload data is not properly aligned and the |
| 365 | * architecture doesn't support efficient unaligned operations, mac80211 | ||
| 366 | * will align the data. | ||
| 365 | * | 367 | * |
| 366 | * With A-MSDU frames, however, the payload data address must yield two modulo | 368 | * With A-MSDU frames, however, the payload data address must yield two modulo |
| 367 | * four because there are 14-byte 802.3 headers within the A-MSDU frames that | 369 | * four because there are 14-byte 802.3 headers within the A-MSDU frames that |
| @@ -375,25 +377,10 @@ static void ieee80211_parse_qos(struct ieee80211_rx_data *rx) | |||
| 375 | */ | 377 | */ |
| 376 | static void ieee80211_verify_alignment(struct ieee80211_rx_data *rx) | 378 | static void ieee80211_verify_alignment(struct ieee80211_rx_data *rx) |
| 377 | { | 379 | { |
| 378 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; | 380 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG |
| 379 | int hdrlen; | 381 | WARN_ONCE((unsigned long)rx->skb->data & 1, |
| 380 | 382 | "unaligned packet at 0x%p\n", rx->skb->data); | |
| 381 | #ifndef CONFIG_MAC80211_DEBUG_PACKET_ALIGNMENT | ||
| 382 | return; | ||
| 383 | #endif | 383 | #endif |
| 384 | |||
| 385 | if (WARN_ONCE((unsigned long)rx->skb->data & 1, | ||
| 386 | "unaligned packet at 0x%p\n", rx->skb->data)) | ||
| 387 | return; | ||
| 388 | |||
| 389 | if (!ieee80211_is_data_present(hdr->frame_control)) | ||
| 390 | return; | ||
| 391 | |||
| 392 | hdrlen = ieee80211_hdrlen(hdr->frame_control); | ||
| 393 | if (rx->flags & IEEE80211_RX_AMSDU) | ||
| 394 | hdrlen += ETH_HLEN; | ||
| 395 | WARN_ONCE(((unsigned long)(rx->skb->data + hdrlen)) & 3, | ||
| 396 | "unaligned IP payload at 0x%p\n", rx->skb->data + hdrlen); | ||
| 397 | } | 384 | } |
| 398 | 385 | ||
| 399 | 386 | ||
| @@ -476,7 +463,7 @@ ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx) | |||
| 476 | { | 463 | { |
| 477 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; | 464 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; |
| 478 | unsigned int hdrlen = ieee80211_hdrlen(hdr->frame_control); | 465 | unsigned int hdrlen = ieee80211_hdrlen(hdr->frame_control); |
| 479 | char *dev_addr = rx->sdata->dev->dev_addr; | 466 | char *dev_addr = rx->sdata->vif.addr; |
| 480 | 467 | ||
| 481 | if (ieee80211_is_data(hdr->frame_control)) { | 468 | if (ieee80211_is_data(hdr->frame_control)) { |
| 482 | if (is_multicast_ether_addr(hdr->addr1)) { | 469 | if (is_multicast_ether_addr(hdr->addr1)) { |
| @@ -1021,10 +1008,10 @@ static void ap_sta_ps_start(struct sta_info *sta) | |||
| 1021 | 1008 | ||
| 1022 | atomic_inc(&sdata->bss->num_sta_ps); | 1009 | atomic_inc(&sdata->bss->num_sta_ps); |
| 1023 | set_sta_flags(sta, WLAN_STA_PS_STA); | 1010 | set_sta_flags(sta, WLAN_STA_PS_STA); |
| 1024 | drv_sta_notify(local, &sdata->vif, STA_NOTIFY_SLEEP, &sta->sta); | 1011 | drv_sta_notify(local, sdata, STA_NOTIFY_SLEEP, &sta->sta); |
| 1025 | #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG | 1012 | #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG |
| 1026 | printk(KERN_DEBUG "%s: STA %pM aid %d enters power save mode\n", | 1013 | printk(KERN_DEBUG "%s: STA %pM aid %d enters power save mode\n", |
| 1027 | sdata->dev->name, sta->sta.addr, sta->sta.aid); | 1014 | sdata->name, sta->sta.addr, sta->sta.aid); |
| 1028 | #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ | 1015 | #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ |
| 1029 | } | 1016 | } |
| 1030 | 1017 | ||
| @@ -1038,13 +1025,13 @@ static void ap_sta_ps_end(struct sta_info *sta) | |||
| 1038 | 1025 | ||
| 1039 | #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG | 1026 | #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG |
| 1040 | printk(KERN_DEBUG "%s: STA %pM aid %d exits power save mode\n", | 1027 | printk(KERN_DEBUG "%s: STA %pM aid %d exits power save mode\n", |
| 1041 | sdata->dev->name, sta->sta.addr, sta->sta.aid); | 1028 | sdata->name, sta->sta.addr, sta->sta.aid); |
| 1042 | #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ | 1029 | #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ |
| 1043 | 1030 | ||
| 1044 | if (test_sta_flags(sta, WLAN_STA_PS_DRIVER)) { | 1031 | if (test_sta_flags(sta, WLAN_STA_PS_DRIVER)) { |
| 1045 | #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG | 1032 | #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG |
| 1046 | printk(KERN_DEBUG "%s: STA %pM aid %d driver-ps-blocked\n", | 1033 | printk(KERN_DEBUG "%s: STA %pM aid %d driver-ps-blocked\n", |
| 1047 | sdata->dev->name, sta->sta.addr, sta->sta.aid); | 1034 | sdata->name, sta->sta.addr, sta->sta.aid); |
| 1048 | #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ | 1035 | #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ |
| 1049 | return; | 1036 | return; |
| 1050 | } | 1037 | } |
| @@ -1124,6 +1111,18 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx) | |||
| 1124 | if (ieee80211_is_nullfunc(hdr->frame_control) || | 1111 | if (ieee80211_is_nullfunc(hdr->frame_control) || |
| 1125 | ieee80211_is_qos_nullfunc(hdr->frame_control)) { | 1112 | ieee80211_is_qos_nullfunc(hdr->frame_control)) { |
| 1126 | I802_DEBUG_INC(rx->local->rx_handlers_drop_nullfunc); | 1113 | I802_DEBUG_INC(rx->local->rx_handlers_drop_nullfunc); |
| 1114 | |||
| 1115 | /* | ||
| 1116 | * If we receive a 4-addr nullfunc frame from a STA | ||
| 1117 | * that was not moved to a 4-addr STA vlan yet, drop | ||
| 1118 | * the frame to the monitor interface, to make sure | ||
| 1119 | * that hostapd sees it | ||
| 1120 | */ | ||
| 1121 | if (ieee80211_has_a4(hdr->frame_control) && | ||
| 1122 | (rx->sdata->vif.type == NL80211_IFTYPE_AP || | ||
| 1123 | (rx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN && | ||
| 1124 | !rx->sdata->u.vlan.sta))) | ||
| 1125 | return RX_DROP_MONITOR; | ||
| 1127 | /* | 1126 | /* |
| 1128 | * Update counter and free packet here to avoid | 1127 | * Update counter and free packet here to avoid |
| 1129 | * counting this as a dropped packed. | 1128 | * counting this as a dropped packed. |
| @@ -1156,7 +1155,7 @@ ieee80211_reassemble_add(struct ieee80211_sub_if_data *sdata, | |||
| 1156 | printk(KERN_DEBUG "%s: RX reassembly removed oldest " | 1155 | printk(KERN_DEBUG "%s: RX reassembly removed oldest " |
| 1157 | "fragment entry (idx=%d age=%lu seq=%d last_frag=%d " | 1156 | "fragment entry (idx=%d age=%lu seq=%d last_frag=%d " |
| 1158 | "addr1=%pM addr2=%pM\n", | 1157 | "addr1=%pM addr2=%pM\n", |
| 1159 | sdata->dev->name, idx, | 1158 | sdata->name, idx, |
| 1160 | jiffies - entry->first_frag_time, entry->seq, | 1159 | jiffies - entry->first_frag_time, entry->seq, |
| 1161 | entry->last_frag, hdr->addr1, hdr->addr2); | 1160 | entry->last_frag, hdr->addr1, hdr->addr2); |
| 1162 | #endif | 1161 | #endif |
| @@ -1398,6 +1397,21 @@ ieee80211_drop_unencrypted(struct ieee80211_rx_data *rx, __le16 fc) | |||
| 1398 | ieee80211_is_data(fc) && | 1397 | ieee80211_is_data(fc) && |
| 1399 | (rx->key || rx->sdata->drop_unencrypted))) | 1398 | (rx->key || rx->sdata->drop_unencrypted))) |
| 1400 | return -EACCES; | 1399 | return -EACCES; |
| 1400 | |||
| 1401 | return 0; | ||
| 1402 | } | ||
| 1403 | |||
| 1404 | static int | ||
| 1405 | ieee80211_drop_unencrypted_mgmt(struct ieee80211_rx_data *rx) | ||
| 1406 | { | ||
| 1407 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; | ||
| 1408 | __le16 fc = hdr->frame_control; | ||
| 1409 | int res; | ||
| 1410 | |||
| 1411 | res = ieee80211_drop_unencrypted(rx, fc); | ||
| 1412 | if (unlikely(res)) | ||
| 1413 | return res; | ||
| 1414 | |||
| 1401 | if (rx->sta && test_sta_flags(rx->sta, WLAN_STA_MFP)) { | 1415 | if (rx->sta && test_sta_flags(rx->sta, WLAN_STA_MFP)) { |
| 1402 | if (unlikely(ieee80211_is_unicast_robust_mgmt_frame(rx->skb) && | 1416 | if (unlikely(ieee80211_is_unicast_robust_mgmt_frame(rx->skb) && |
| 1403 | rx->key)) | 1417 | rx->key)) |
| @@ -1424,7 +1438,6 @@ static int | |||
| 1424 | __ieee80211_data_to_8023(struct ieee80211_rx_data *rx) | 1438 | __ieee80211_data_to_8023(struct ieee80211_rx_data *rx) |
| 1425 | { | 1439 | { |
| 1426 | struct ieee80211_sub_if_data *sdata = rx->sdata; | 1440 | struct ieee80211_sub_if_data *sdata = rx->sdata; |
| 1427 | struct net_device *dev = sdata->dev; | ||
| 1428 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; | 1441 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; |
| 1429 | 1442 | ||
| 1430 | if (ieee80211_has_a4(hdr->frame_control) && | 1443 | if (ieee80211_has_a4(hdr->frame_control) && |
| @@ -1436,7 +1449,7 @@ __ieee80211_data_to_8023(struct ieee80211_rx_data *rx) | |||
| 1436 | (sdata->vif.type == NL80211_IFTYPE_STATION && sdata->u.mgd.use_4addr))) | 1449 | (sdata->vif.type == NL80211_IFTYPE_STATION && sdata->u.mgd.use_4addr))) |
| 1437 | return -1; | 1450 | return -1; |
| 1438 | 1451 | ||
| 1439 | return ieee80211_data_to_8023(rx->skb, dev->dev_addr, sdata->vif.type); | 1452 | return ieee80211_data_to_8023(rx->skb, sdata->vif.addr, sdata->vif.type); |
| 1440 | } | 1453 | } |
| 1441 | 1454 | ||
| 1442 | /* | 1455 | /* |
| @@ -1453,7 +1466,7 @@ static bool ieee80211_frame_allowed(struct ieee80211_rx_data *rx, __le16 fc) | |||
| 1453 | * of whether the frame was encrypted or not. | 1466 | * of whether the frame was encrypted or not. |
| 1454 | */ | 1467 | */ |
| 1455 | if (ehdr->h_proto == htons(ETH_P_PAE) && | 1468 | if (ehdr->h_proto == htons(ETH_P_PAE) && |
| 1456 | (compare_ether_addr(ehdr->h_dest, rx->sdata->dev->dev_addr) == 0 || | 1469 | (compare_ether_addr(ehdr->h_dest, rx->sdata->vif.addr) == 0 || |
| 1457 | compare_ether_addr(ehdr->h_dest, pae_group_addr) == 0)) | 1470 | compare_ether_addr(ehdr->h_dest, pae_group_addr) == 0)) |
| 1458 | return true; | 1471 | return true; |
| 1459 | 1472 | ||
| @@ -1472,7 +1485,6 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx) | |||
| 1472 | { | 1485 | { |
| 1473 | struct ieee80211_sub_if_data *sdata = rx->sdata; | 1486 | struct ieee80211_sub_if_data *sdata = rx->sdata; |
| 1474 | struct net_device *dev = sdata->dev; | 1487 | struct net_device *dev = sdata->dev; |
| 1475 | struct ieee80211_local *local = rx->local; | ||
| 1476 | struct sk_buff *skb, *xmit_skb; | 1488 | struct sk_buff *skb, *xmit_skb; |
| 1477 | struct ethhdr *ehdr = (struct ethhdr *) rx->skb->data; | 1489 | struct ethhdr *ehdr = (struct ethhdr *) rx->skb->data; |
| 1478 | struct sta_info *dsta; | 1490 | struct sta_info *dsta; |
| @@ -1495,8 +1507,8 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx) | |||
| 1495 | printk(KERN_DEBUG "%s: failed to clone " | 1507 | printk(KERN_DEBUG "%s: failed to clone " |
| 1496 | "multicast frame\n", dev->name); | 1508 | "multicast frame\n", dev->name); |
| 1497 | } else { | 1509 | } else { |
| 1498 | dsta = sta_info_get(local, skb->data); | 1510 | dsta = sta_info_get(sdata, skb->data); |
| 1499 | if (dsta && dsta->sdata->dev == dev) { | 1511 | if (dsta) { |
| 1500 | /* | 1512 | /* |
| 1501 | * The destination station is associated to | 1513 | * The destination station is associated to |
| 1502 | * this AP (in this VLAN), so send the frame | 1514 | * this AP (in this VLAN), so send the frame |
| @@ -1512,7 +1524,7 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx) | |||
| 1512 | if (skb) { | 1524 | if (skb) { |
| 1513 | int align __maybe_unused; | 1525 | int align __maybe_unused; |
| 1514 | 1526 | ||
| 1515 | #if defined(CONFIG_MAC80211_DEBUG_PACKET_ALIGNMENT) || !defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) | 1527 | #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS |
| 1516 | /* | 1528 | /* |
| 1517 | * 'align' will only take the values 0 or 2 here | 1529 | * 'align' will only take the values 0 or 2 here |
| 1518 | * since all frames are required to be aligned | 1530 | * since all frames are required to be aligned |
| @@ -1556,16 +1568,10 @@ static ieee80211_rx_result debug_noinline | |||
| 1556 | ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx) | 1568 | ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx) |
| 1557 | { | 1569 | { |
| 1558 | struct net_device *dev = rx->sdata->dev; | 1570 | struct net_device *dev = rx->sdata->dev; |
| 1559 | struct ieee80211_local *local = rx->local; | 1571 | struct sk_buff *skb = rx->skb; |
| 1560 | u16 ethertype; | ||
| 1561 | u8 *payload; | ||
| 1562 | struct sk_buff *skb = rx->skb, *frame = NULL; | ||
| 1563 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; | 1572 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; |
| 1564 | __le16 fc = hdr->frame_control; | 1573 | __le16 fc = hdr->frame_control; |
| 1565 | const struct ethhdr *eth; | 1574 | struct sk_buff_head frame_list; |
| 1566 | int remaining, err; | ||
| 1567 | u8 dst[ETH_ALEN]; | ||
| 1568 | u8 src[ETH_ALEN]; | ||
| 1569 | 1575 | ||
| 1570 | if (unlikely(!ieee80211_is_data(fc))) | 1576 | if (unlikely(!ieee80211_is_data(fc))) |
| 1571 | return RX_CONTINUE; | 1577 | return RX_CONTINUE; |
| @@ -1576,94 +1582,34 @@ ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx) | |||
| 1576 | if (!(rx->flags & IEEE80211_RX_AMSDU)) | 1582 | if (!(rx->flags & IEEE80211_RX_AMSDU)) |
| 1577 | return RX_CONTINUE; | 1583 | return RX_CONTINUE; |
| 1578 | 1584 | ||
| 1579 | err = __ieee80211_data_to_8023(rx); | 1585 | if (ieee80211_has_a4(hdr->frame_control) && |
| 1580 | if (unlikely(err)) | 1586 | rx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN && |
| 1587 | !rx->sdata->u.vlan.sta) | ||
| 1581 | return RX_DROP_UNUSABLE; | 1588 | return RX_DROP_UNUSABLE; |
| 1582 | 1589 | ||
| 1583 | skb->dev = dev; | 1590 | if (is_multicast_ether_addr(hdr->addr1) && |
| 1584 | 1591 | ((rx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN && | |
| 1585 | dev->stats.rx_packets++; | 1592 | rx->sdata->u.vlan.sta) || |
| 1586 | dev->stats.rx_bytes += skb->len; | 1593 | (rx->sdata->vif.type == NL80211_IFTYPE_STATION && |
| 1587 | 1594 | rx->sdata->u.mgd.use_4addr))) | |
| 1588 | /* skip the wrapping header */ | ||
| 1589 | eth = (struct ethhdr *) skb_pull(skb, sizeof(struct ethhdr)); | ||
| 1590 | if (!eth) | ||
| 1591 | return RX_DROP_UNUSABLE; | 1595 | return RX_DROP_UNUSABLE; |
| 1592 | 1596 | ||
| 1593 | while (skb != frame) { | 1597 | skb->dev = dev; |
| 1594 | u8 padding; | 1598 | __skb_queue_head_init(&frame_list); |
| 1595 | __be16 len = eth->h_proto; | ||
| 1596 | unsigned int subframe_len = sizeof(struct ethhdr) + ntohs(len); | ||
| 1597 | |||
| 1598 | remaining = skb->len; | ||
| 1599 | memcpy(dst, eth->h_dest, ETH_ALEN); | ||
| 1600 | memcpy(src, eth->h_source, ETH_ALEN); | ||
| 1601 | |||
| 1602 | padding = ((4 - subframe_len) & 0x3); | ||
| 1603 | /* the last MSDU has no padding */ | ||
| 1604 | if (subframe_len > remaining) | ||
| 1605 | return RX_DROP_UNUSABLE; | ||
| 1606 | 1599 | ||
| 1607 | skb_pull(skb, sizeof(struct ethhdr)); | 1600 | ieee80211_amsdu_to_8023s(skb, &frame_list, dev->dev_addr, |
| 1608 | /* if last subframe reuse skb */ | 1601 | rx->sdata->vif.type, |
| 1609 | if (remaining <= subframe_len + padding) | 1602 | rx->local->hw.extra_tx_headroom); |
| 1610 | frame = skb; | ||
| 1611 | else { | ||
| 1612 | /* | ||
| 1613 | * Allocate and reserve two bytes more for payload | ||
| 1614 | * alignment since sizeof(struct ethhdr) is 14. | ||
| 1615 | */ | ||
| 1616 | frame = dev_alloc_skb( | ||
| 1617 | ALIGN(local->hw.extra_tx_headroom, 4) + | ||
| 1618 | subframe_len + 2); | ||
| 1619 | |||
| 1620 | if (frame == NULL) | ||
| 1621 | return RX_DROP_UNUSABLE; | ||
| 1622 | |||
| 1623 | skb_reserve(frame, | ||
| 1624 | ALIGN(local->hw.extra_tx_headroom, 4) + | ||
| 1625 | sizeof(struct ethhdr) + 2); | ||
| 1626 | memcpy(skb_put(frame, ntohs(len)), skb->data, | ||
| 1627 | ntohs(len)); | ||
| 1628 | |||
| 1629 | eth = (struct ethhdr *) skb_pull(skb, ntohs(len) + | ||
| 1630 | padding); | ||
| 1631 | if (!eth) { | ||
| 1632 | dev_kfree_skb(frame); | ||
| 1633 | return RX_DROP_UNUSABLE; | ||
| 1634 | } | ||
| 1635 | } | ||
| 1636 | 1603 | ||
| 1637 | skb_reset_network_header(frame); | 1604 | while (!skb_queue_empty(&frame_list)) { |
| 1638 | frame->dev = dev; | 1605 | rx->skb = __skb_dequeue(&frame_list); |
| 1639 | frame->priority = skb->priority; | ||
| 1640 | rx->skb = frame; | ||
| 1641 | |||
| 1642 | payload = frame->data; | ||
| 1643 | ethertype = (payload[6] << 8) | payload[7]; | ||
| 1644 | |||
| 1645 | if (likely((compare_ether_addr(payload, rfc1042_header) == 0 && | ||
| 1646 | ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) || | ||
| 1647 | compare_ether_addr(payload, | ||
| 1648 | bridge_tunnel_header) == 0)) { | ||
| 1649 | /* remove RFC1042 or Bridge-Tunnel | ||
| 1650 | * encapsulation and replace EtherType */ | ||
| 1651 | skb_pull(frame, 6); | ||
| 1652 | memcpy(skb_push(frame, ETH_ALEN), src, ETH_ALEN); | ||
| 1653 | memcpy(skb_push(frame, ETH_ALEN), dst, ETH_ALEN); | ||
| 1654 | } else { | ||
| 1655 | memcpy(skb_push(frame, sizeof(__be16)), | ||
| 1656 | &len, sizeof(__be16)); | ||
| 1657 | memcpy(skb_push(frame, ETH_ALEN), src, ETH_ALEN); | ||
| 1658 | memcpy(skb_push(frame, ETH_ALEN), dst, ETH_ALEN); | ||
| 1659 | } | ||
| 1660 | 1606 | ||
| 1661 | if (!ieee80211_frame_allowed(rx, fc)) { | 1607 | if (!ieee80211_frame_allowed(rx, fc)) { |
| 1662 | if (skb == frame) /* last frame */ | 1608 | dev_kfree_skb(rx->skb); |
| 1663 | return RX_DROP_UNUSABLE; | ||
| 1664 | dev_kfree_skb(frame); | ||
| 1665 | continue; | 1609 | continue; |
| 1666 | } | 1610 | } |
| 1611 | dev->stats.rx_packets++; | ||
| 1612 | dev->stats.rx_bytes += rx->skb->len; | ||
| 1667 | 1613 | ||
| 1668 | ieee80211_deliver_skb(rx); | 1614 | ieee80211_deliver_skb(rx); |
| 1669 | } | 1615 | } |
| @@ -1721,7 +1667,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx) | |||
| 1721 | 1667 | ||
| 1722 | /* Frame has reached destination. Don't forward */ | 1668 | /* Frame has reached destination. Don't forward */ |
| 1723 | if (!is_multicast_ether_addr(hdr->addr1) && | 1669 | if (!is_multicast_ether_addr(hdr->addr1) && |
| 1724 | compare_ether_addr(sdata->dev->dev_addr, hdr->addr3) == 0) | 1670 | compare_ether_addr(sdata->vif.addr, hdr->addr3) == 0) |
| 1725 | return RX_CONTINUE; | 1671 | return RX_CONTINUE; |
| 1726 | 1672 | ||
| 1727 | mesh_hdr->ttl--; | 1673 | mesh_hdr->ttl--; |
| @@ -1738,10 +1684,10 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx) | |||
| 1738 | 1684 | ||
| 1739 | if (!fwd_skb && net_ratelimit()) | 1685 | if (!fwd_skb && net_ratelimit()) |
| 1740 | printk(KERN_DEBUG "%s: failed to clone mesh frame\n", | 1686 | printk(KERN_DEBUG "%s: failed to clone mesh frame\n", |
| 1741 | sdata->dev->name); | 1687 | sdata->name); |
| 1742 | 1688 | ||
| 1743 | fwd_hdr = (struct ieee80211_hdr *) fwd_skb->data; | 1689 | fwd_hdr = (struct ieee80211_hdr *) fwd_skb->data; |
| 1744 | memcpy(fwd_hdr->addr2, sdata->dev->dev_addr, ETH_ALEN); | 1690 | memcpy(fwd_hdr->addr2, sdata->vif.addr, ETH_ALEN); |
| 1745 | info = IEEE80211_SKB_CB(fwd_skb); | 1691 | info = IEEE80211_SKB_CB(fwd_skb); |
| 1746 | memset(info, 0, sizeof(*info)); | 1692 | memset(info, 0, sizeof(*info)); |
| 1747 | info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING; | 1693 | info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING; |
| @@ -1788,6 +1734,7 @@ static ieee80211_rx_result debug_noinline | |||
| 1788 | ieee80211_rx_h_data(struct ieee80211_rx_data *rx) | 1734 | ieee80211_rx_h_data(struct ieee80211_rx_data *rx) |
| 1789 | { | 1735 | { |
| 1790 | struct ieee80211_sub_if_data *sdata = rx->sdata; | 1736 | struct ieee80211_sub_if_data *sdata = rx->sdata; |
| 1737 | struct ieee80211_local *local = rx->local; | ||
| 1791 | struct net_device *dev = sdata->dev; | 1738 | struct net_device *dev = sdata->dev; |
| 1792 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; | 1739 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; |
| 1793 | __le16 fc = hdr->frame_control; | 1740 | __le16 fc = hdr->frame_control; |
| @@ -1819,6 +1766,13 @@ ieee80211_rx_h_data(struct ieee80211_rx_data *rx) | |||
| 1819 | dev->stats.rx_packets++; | 1766 | dev->stats.rx_packets++; |
| 1820 | dev->stats.rx_bytes += rx->skb->len; | 1767 | dev->stats.rx_bytes += rx->skb->len; |
| 1821 | 1768 | ||
| 1769 | if (ieee80211_is_data(hdr->frame_control) && | ||
| 1770 | !is_multicast_ether_addr(hdr->addr1) && | ||
| 1771 | local->hw.conf.dynamic_ps_timeout > 0 && local->ps_sdata) { | ||
| 1772 | mod_timer(&local->dynamic_ps_timer, jiffies + | ||
| 1773 | msecs_to_jiffies(local->hw.conf.dynamic_ps_timeout)); | ||
| 1774 | } | ||
| 1775 | |||
| 1822 | ieee80211_deliver_skb(rx); | 1776 | ieee80211_deliver_skb(rx); |
| 1823 | 1777 | ||
| 1824 | return RX_QUEUED; | 1778 | return RX_QUEUED; |
| @@ -1872,7 +1826,7 @@ static void ieee80211_process_sa_query_req(struct ieee80211_sub_if_data *sdata, | |||
| 1872 | struct sk_buff *skb; | 1826 | struct sk_buff *skb; |
| 1873 | struct ieee80211_mgmt *resp; | 1827 | struct ieee80211_mgmt *resp; |
| 1874 | 1828 | ||
| 1875 | if (compare_ether_addr(mgmt->da, sdata->dev->dev_addr) != 0) { | 1829 | if (compare_ether_addr(mgmt->da, sdata->vif.addr) != 0) { |
| 1876 | /* Not to own unicast address */ | 1830 | /* Not to own unicast address */ |
| 1877 | return; | 1831 | return; |
| 1878 | } | 1832 | } |
| @@ -1896,7 +1850,7 @@ static void ieee80211_process_sa_query_req(struct ieee80211_sub_if_data *sdata, | |||
| 1896 | resp = (struct ieee80211_mgmt *) skb_put(skb, 24); | 1850 | resp = (struct ieee80211_mgmt *) skb_put(skb, 24); |
| 1897 | memset(resp, 0, 24); | 1851 | memset(resp, 0, 24); |
| 1898 | memcpy(resp->da, mgmt->sa, ETH_ALEN); | 1852 | memcpy(resp->da, mgmt->sa, ETH_ALEN); |
| 1899 | memcpy(resp->sa, sdata->dev->dev_addr, ETH_ALEN); | 1853 | memcpy(resp->sa, sdata->vif.addr, ETH_ALEN); |
| 1900 | memcpy(resp->bssid, sdata->u.mgd.bssid, ETH_ALEN); | 1854 | memcpy(resp->bssid, sdata->u.mgd.bssid, ETH_ALEN); |
| 1901 | resp->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | 1855 | resp->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | |
| 1902 | IEEE80211_STYPE_ACTION); | 1856 | IEEE80211_STYPE_ACTION); |
| @@ -1916,23 +1870,25 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) | |||
| 1916 | struct ieee80211_local *local = rx->local; | 1870 | struct ieee80211_local *local = rx->local; |
| 1917 | struct ieee80211_sub_if_data *sdata = rx->sdata; | 1871 | struct ieee80211_sub_if_data *sdata = rx->sdata; |
| 1918 | struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) rx->skb->data; | 1872 | struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) rx->skb->data; |
| 1873 | struct sk_buff *nskb; | ||
| 1874 | struct ieee80211_rx_status *status; | ||
| 1919 | int len = rx->skb->len; | 1875 | int len = rx->skb->len; |
| 1920 | 1876 | ||
| 1921 | if (!ieee80211_is_action(mgmt->frame_control)) | 1877 | if (!ieee80211_is_action(mgmt->frame_control)) |
| 1922 | return RX_CONTINUE; | 1878 | return RX_CONTINUE; |
| 1923 | 1879 | ||
| 1924 | if (!rx->sta) | 1880 | /* drop too small frames */ |
| 1925 | return RX_DROP_MONITOR; | 1881 | if (len < IEEE80211_MIN_ACTION_SIZE) |
| 1882 | return RX_DROP_UNUSABLE; | ||
| 1926 | 1883 | ||
| 1927 | if (!(rx->flags & IEEE80211_RX_RA_MATCH)) | 1884 | if (!rx->sta && mgmt->u.action.category != WLAN_CATEGORY_PUBLIC) |
| 1928 | return RX_DROP_MONITOR; | 1885 | return RX_DROP_UNUSABLE; |
| 1929 | 1886 | ||
| 1930 | if (ieee80211_drop_unencrypted(rx, mgmt->frame_control)) | 1887 | if (!(rx->flags & IEEE80211_RX_RA_MATCH)) |
| 1931 | return RX_DROP_MONITOR; | 1888 | return RX_DROP_UNUSABLE; |
| 1932 | 1889 | ||
| 1933 | /* all categories we currently handle have action_code */ | 1890 | if (ieee80211_drop_unencrypted_mgmt(rx)) |
| 1934 | if (len < IEEE80211_MIN_ACTION_SIZE + 1) | 1891 | return RX_DROP_UNUSABLE; |
| 1935 | return RX_DROP_MONITOR; | ||
| 1936 | 1892 | ||
| 1937 | switch (mgmt->u.action.category) { | 1893 | switch (mgmt->u.action.category) { |
| 1938 | case WLAN_CATEGORY_BACK: | 1894 | case WLAN_CATEGORY_BACK: |
| @@ -1945,7 +1901,11 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) | |||
| 1945 | if (sdata->vif.type != NL80211_IFTYPE_STATION && | 1901 | if (sdata->vif.type != NL80211_IFTYPE_STATION && |
| 1946 | sdata->vif.type != NL80211_IFTYPE_AP_VLAN && | 1902 | sdata->vif.type != NL80211_IFTYPE_AP_VLAN && |
| 1947 | sdata->vif.type != NL80211_IFTYPE_AP) | 1903 | sdata->vif.type != NL80211_IFTYPE_AP) |
| 1948 | return RX_DROP_MONITOR; | 1904 | break; |
| 1905 | |||
| 1906 | /* verify action_code is present */ | ||
| 1907 | if (len < IEEE80211_MIN_ACTION_SIZE + 1) | ||
| 1908 | break; | ||
| 1949 | 1909 | ||
| 1950 | switch (mgmt->u.action.u.addba_req.action_code) { | 1910 | switch (mgmt->u.action.u.addba_req.action_code) { |
| 1951 | case WLAN_ACTION_ADDBA_REQ: | 1911 | case WLAN_ACTION_ADDBA_REQ: |
| @@ -1953,45 +1913,49 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) | |||
| 1953 | sizeof(mgmt->u.action.u.addba_req))) | 1913 | sizeof(mgmt->u.action.u.addba_req))) |
| 1954 | return RX_DROP_MONITOR; | 1914 | return RX_DROP_MONITOR; |
| 1955 | ieee80211_process_addba_request(local, rx->sta, mgmt, len); | 1915 | ieee80211_process_addba_request(local, rx->sta, mgmt, len); |
| 1956 | break; | 1916 | goto handled; |
| 1957 | case WLAN_ACTION_ADDBA_RESP: | 1917 | case WLAN_ACTION_ADDBA_RESP: |
| 1958 | if (len < (IEEE80211_MIN_ACTION_SIZE + | 1918 | if (len < (IEEE80211_MIN_ACTION_SIZE + |
| 1959 | sizeof(mgmt->u.action.u.addba_resp))) | 1919 | sizeof(mgmt->u.action.u.addba_resp))) |
| 1960 | return RX_DROP_MONITOR; | 1920 | break; |
| 1961 | ieee80211_process_addba_resp(local, rx->sta, mgmt, len); | 1921 | ieee80211_process_addba_resp(local, rx->sta, mgmt, len); |
| 1962 | break; | 1922 | goto handled; |
| 1963 | case WLAN_ACTION_DELBA: | 1923 | case WLAN_ACTION_DELBA: |
| 1964 | if (len < (IEEE80211_MIN_ACTION_SIZE + | 1924 | if (len < (IEEE80211_MIN_ACTION_SIZE + |
| 1965 | sizeof(mgmt->u.action.u.delba))) | 1925 | sizeof(mgmt->u.action.u.delba))) |
| 1966 | return RX_DROP_MONITOR; | 1926 | break; |
| 1967 | ieee80211_process_delba(sdata, rx->sta, mgmt, len); | 1927 | ieee80211_process_delba(sdata, rx->sta, mgmt, len); |
| 1968 | break; | 1928 | goto handled; |
| 1969 | } | 1929 | } |
| 1970 | break; | 1930 | break; |
| 1971 | case WLAN_CATEGORY_SPECTRUM_MGMT: | 1931 | case WLAN_CATEGORY_SPECTRUM_MGMT: |
| 1972 | if (local->hw.conf.channel->band != IEEE80211_BAND_5GHZ) | 1932 | if (local->hw.conf.channel->band != IEEE80211_BAND_5GHZ) |
| 1973 | return RX_DROP_MONITOR; | 1933 | break; |
| 1974 | 1934 | ||
| 1975 | if (sdata->vif.type != NL80211_IFTYPE_STATION) | 1935 | if (sdata->vif.type != NL80211_IFTYPE_STATION) |
| 1976 | return RX_DROP_MONITOR; | 1936 | break; |
| 1937 | |||
| 1938 | /* verify action_code is present */ | ||
| 1939 | if (len < IEEE80211_MIN_ACTION_SIZE + 1) | ||
| 1940 | break; | ||
| 1977 | 1941 | ||
| 1978 | switch (mgmt->u.action.u.measurement.action_code) { | 1942 | switch (mgmt->u.action.u.measurement.action_code) { |
| 1979 | case WLAN_ACTION_SPCT_MSR_REQ: | 1943 | case WLAN_ACTION_SPCT_MSR_REQ: |
| 1980 | if (len < (IEEE80211_MIN_ACTION_SIZE + | 1944 | if (len < (IEEE80211_MIN_ACTION_SIZE + |
| 1981 | sizeof(mgmt->u.action.u.measurement))) | 1945 | sizeof(mgmt->u.action.u.measurement))) |
| 1982 | return RX_DROP_MONITOR; | 1946 | break; |
| 1983 | ieee80211_process_measurement_req(sdata, mgmt, len); | 1947 | ieee80211_process_measurement_req(sdata, mgmt, len); |
| 1984 | break; | 1948 | goto handled; |
| 1985 | case WLAN_ACTION_SPCT_CHL_SWITCH: | 1949 | case WLAN_ACTION_SPCT_CHL_SWITCH: |
| 1986 | if (len < (IEEE80211_MIN_ACTION_SIZE + | 1950 | if (len < (IEEE80211_MIN_ACTION_SIZE + |
| 1987 | sizeof(mgmt->u.action.u.chan_switch))) | 1951 | sizeof(mgmt->u.action.u.chan_switch))) |
| 1988 | return RX_DROP_MONITOR; | 1952 | break; |
| 1989 | 1953 | ||
| 1990 | if (sdata->vif.type != NL80211_IFTYPE_STATION) | 1954 | if (sdata->vif.type != NL80211_IFTYPE_STATION) |
| 1991 | return RX_DROP_MONITOR; | 1955 | break; |
| 1992 | 1956 | ||
| 1993 | if (memcmp(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN)) | 1957 | if (memcmp(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN)) |
| 1994 | return RX_DROP_MONITOR; | 1958 | break; |
| 1995 | 1959 | ||
| 1996 | return ieee80211_sta_rx_mgmt(sdata, rx->skb); | 1960 | return ieee80211_sta_rx_mgmt(sdata, rx->skb); |
| 1997 | } | 1961 | } |
| @@ -1999,30 +1963,64 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) | |||
| 1999 | case WLAN_CATEGORY_SA_QUERY: | 1963 | case WLAN_CATEGORY_SA_QUERY: |
| 2000 | if (len < (IEEE80211_MIN_ACTION_SIZE + | 1964 | if (len < (IEEE80211_MIN_ACTION_SIZE + |
| 2001 | sizeof(mgmt->u.action.u.sa_query))) | 1965 | sizeof(mgmt->u.action.u.sa_query))) |
| 2002 | return RX_DROP_MONITOR; | 1966 | break; |
| 1967 | |||
| 2003 | switch (mgmt->u.action.u.sa_query.action) { | 1968 | switch (mgmt->u.action.u.sa_query.action) { |
| 2004 | case WLAN_ACTION_SA_QUERY_REQUEST: | 1969 | case WLAN_ACTION_SA_QUERY_REQUEST: |
| 2005 | if (sdata->vif.type != NL80211_IFTYPE_STATION) | 1970 | if (sdata->vif.type != NL80211_IFTYPE_STATION) |
| 2006 | return RX_DROP_MONITOR; | 1971 | break; |
| 2007 | ieee80211_process_sa_query_req(sdata, mgmt, len); | 1972 | ieee80211_process_sa_query_req(sdata, mgmt, len); |
| 2008 | break; | 1973 | goto handled; |
| 2009 | case WLAN_ACTION_SA_QUERY_RESPONSE: | ||
| 2010 | /* | ||
| 2011 | * SA Query response is currently only used in AP mode | ||
| 2012 | * and it is processed in user space. | ||
| 2013 | */ | ||
| 2014 | return RX_CONTINUE; | ||
| 2015 | } | 1974 | } |
| 2016 | break; | 1975 | break; |
| 2017 | default: | 1976 | } |
| 2018 | /* do not process rejected action frames */ | ||
| 2019 | if (mgmt->u.action.category & 0x80) | ||
| 2020 | return RX_DROP_MONITOR; | ||
| 2021 | 1977 | ||
| 2022 | return RX_CONTINUE; | 1978 | /* |
| 1979 | * For AP mode, hostapd is responsible for handling any action | ||
| 1980 | * frames that we didn't handle, including returning unknown | ||
| 1981 | * ones. For all other modes we will return them to the sender, | ||
| 1982 | * setting the 0x80 bit in the action category, as required by | ||
| 1983 | * 802.11-2007 7.3.1.11. | ||
| 1984 | */ | ||
| 1985 | if (sdata->vif.type == NL80211_IFTYPE_AP || | ||
| 1986 | sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | ||
| 1987 | return RX_DROP_MONITOR; | ||
| 1988 | |||
| 1989 | /* | ||
| 1990 | * Getting here means the kernel doesn't know how to handle | ||
| 1991 | * it, but maybe userspace does ... include returned frames | ||
| 1992 | * so userspace can register for those to know whether ones | ||
| 1993 | * it transmitted were processed or returned. | ||
| 1994 | */ | ||
| 1995 | status = IEEE80211_SKB_RXCB(rx->skb); | ||
| 1996 | |||
| 1997 | if (sdata->vif.type == NL80211_IFTYPE_STATION && | ||
| 1998 | cfg80211_rx_action(rx->sdata->dev, status->freq, | ||
| 1999 | rx->skb->data, rx->skb->len, | ||
| 2000 | GFP_ATOMIC)) | ||
| 2001 | goto handled; | ||
| 2002 | |||
| 2003 | /* do not return rejected action frames */ | ||
| 2004 | if (mgmt->u.action.category & 0x80) | ||
| 2005 | return RX_DROP_UNUSABLE; | ||
| 2006 | |||
| 2007 | nskb = skb_copy_expand(rx->skb, local->hw.extra_tx_headroom, 0, | ||
| 2008 | GFP_ATOMIC); | ||
| 2009 | if (nskb) { | ||
| 2010 | struct ieee80211_mgmt *mgmt = (void *)nskb->data; | ||
| 2011 | |||
| 2012 | mgmt->u.action.category |= 0x80; | ||
| 2013 | memcpy(mgmt->da, mgmt->sa, ETH_ALEN); | ||
| 2014 | memcpy(mgmt->sa, rx->sdata->vif.addr, ETH_ALEN); | ||
| 2015 | |||
| 2016 | memset(nskb->cb, 0, sizeof(nskb->cb)); | ||
| 2017 | |||
| 2018 | ieee80211_tx_skb(rx->sdata, nskb); | ||
| 2023 | } | 2019 | } |
| 2024 | 2020 | ||
| 2025 | rx->sta->rx_packets++; | 2021 | handled: |
| 2022 | if (rx->sta) | ||
| 2023 | rx->sta->rx_packets++; | ||
| 2026 | dev_kfree_skb(rx->skb); | 2024 | dev_kfree_skb(rx->skb); |
| 2027 | return RX_QUEUED; | 2025 | return RX_QUEUED; |
| 2028 | } | 2026 | } |
| @@ -2031,13 +2029,17 @@ static ieee80211_rx_result debug_noinline | |||
| 2031 | ieee80211_rx_h_mgmt(struct ieee80211_rx_data *rx) | 2029 | ieee80211_rx_h_mgmt(struct ieee80211_rx_data *rx) |
| 2032 | { | 2030 | { |
| 2033 | struct ieee80211_sub_if_data *sdata = rx->sdata; | 2031 | struct ieee80211_sub_if_data *sdata = rx->sdata; |
| 2034 | struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) rx->skb->data; | 2032 | ieee80211_rx_result rxs; |
| 2035 | 2033 | ||
| 2036 | if (!(rx->flags & IEEE80211_RX_RA_MATCH)) | 2034 | if (!(rx->flags & IEEE80211_RX_RA_MATCH)) |
| 2037 | return RX_DROP_MONITOR; | 2035 | return RX_DROP_MONITOR; |
| 2038 | 2036 | ||
| 2039 | if (ieee80211_drop_unencrypted(rx, mgmt->frame_control)) | 2037 | if (ieee80211_drop_unencrypted_mgmt(rx)) |
| 2040 | return RX_DROP_MONITOR; | 2038 | return RX_DROP_UNUSABLE; |
| 2039 | |||
| 2040 | rxs = ieee80211_work_rx_mgmt(rx->sdata, rx->skb); | ||
| 2041 | if (rxs != RX_CONTINUE) | ||
| 2042 | return rxs; | ||
| 2041 | 2043 | ||
| 2042 | if (ieee80211_vif_is_mesh(&sdata->vif)) | 2044 | if (ieee80211_vif_is_mesh(&sdata->vif)) |
| 2043 | return ieee80211_mesh_rx_mgmt(sdata, rx->skb); | 2045 | return ieee80211_mesh_rx_mgmt(sdata, rx->skb); |
| @@ -2143,7 +2145,7 @@ static void ieee80211_rx_cooked_monitor(struct ieee80211_rx_data *rx, | |||
| 2143 | skb->protocol = htons(ETH_P_802_2); | 2145 | skb->protocol = htons(ETH_P_802_2); |
| 2144 | 2146 | ||
| 2145 | list_for_each_entry_rcu(sdata, &local->interfaces, list) { | 2147 | list_for_each_entry_rcu(sdata, &local->interfaces, list) { |
| 2146 | if (!netif_running(sdata->dev)) | 2148 | if (!ieee80211_sdata_running(sdata)) |
| 2147 | continue; | 2149 | continue; |
| 2148 | 2150 | ||
| 2149 | if (sdata->vif.type != NL80211_IFTYPE_MONITOR || | 2151 | if (sdata->vif.type != NL80211_IFTYPE_MONITOR || |
| @@ -2280,7 +2282,7 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata, | |||
| 2280 | if (!bssid && !sdata->u.mgd.use_4addr) | 2282 | if (!bssid && !sdata->u.mgd.use_4addr) |
| 2281 | return 0; | 2283 | return 0; |
| 2282 | if (!multicast && | 2284 | if (!multicast && |
| 2283 | compare_ether_addr(sdata->dev->dev_addr, hdr->addr1) != 0) { | 2285 | compare_ether_addr(sdata->vif.addr, hdr->addr1) != 0) { |
| 2284 | if (!(sdata->dev->flags & IFF_PROMISC)) | 2286 | if (!(sdata->dev->flags & IFF_PROMISC)) |
| 2285 | return 0; | 2287 | return 0; |
| 2286 | rx->flags &= ~IEEE80211_RX_RA_MATCH; | 2288 | rx->flags &= ~IEEE80211_RX_RA_MATCH; |
| @@ -2297,7 +2299,7 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata, | |||
| 2297 | return 0; | 2299 | return 0; |
| 2298 | rx->flags &= ~IEEE80211_RX_RA_MATCH; | 2300 | rx->flags &= ~IEEE80211_RX_RA_MATCH; |
| 2299 | } else if (!multicast && | 2301 | } else if (!multicast && |
| 2300 | compare_ether_addr(sdata->dev->dev_addr, | 2302 | compare_ether_addr(sdata->vif.addr, |
| 2301 | hdr->addr1) != 0) { | 2303 | hdr->addr1) != 0) { |
| 2302 | if (!(sdata->dev->flags & IFF_PROMISC)) | 2304 | if (!(sdata->dev->flags & IFF_PROMISC)) |
| 2303 | return 0; | 2305 | return 0; |
| @@ -2308,13 +2310,13 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata, | |||
| 2308 | rate_idx = 0; /* TODO: HT rates */ | 2310 | rate_idx = 0; /* TODO: HT rates */ |
| 2309 | else | 2311 | else |
| 2310 | rate_idx = status->rate_idx; | 2312 | rate_idx = status->rate_idx; |
| 2311 | rx->sta = ieee80211_ibss_add_sta(sdata, bssid, hdr->addr2, | 2313 | rx->sta = ieee80211_ibss_add_sta(sdata, bssid, |
| 2312 | BIT(rate_idx)); | 2314 | hdr->addr2, BIT(rate_idx), GFP_ATOMIC); |
| 2313 | } | 2315 | } |
| 2314 | break; | 2316 | break; |
| 2315 | case NL80211_IFTYPE_MESH_POINT: | 2317 | case NL80211_IFTYPE_MESH_POINT: |
| 2316 | if (!multicast && | 2318 | if (!multicast && |
| 2317 | compare_ether_addr(sdata->dev->dev_addr, | 2319 | compare_ether_addr(sdata->vif.addr, |
| 2318 | hdr->addr1) != 0) { | 2320 | hdr->addr1) != 0) { |
| 2319 | if (!(sdata->dev->flags & IFF_PROMISC)) | 2321 | if (!(sdata->dev->flags & IFF_PROMISC)) |
| 2320 | return 0; | 2322 | return 0; |
| @@ -2325,11 +2327,11 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata, | |||
| 2325 | case NL80211_IFTYPE_AP_VLAN: | 2327 | case NL80211_IFTYPE_AP_VLAN: |
| 2326 | case NL80211_IFTYPE_AP: | 2328 | case NL80211_IFTYPE_AP: |
| 2327 | if (!bssid) { | 2329 | if (!bssid) { |
| 2328 | if (compare_ether_addr(sdata->dev->dev_addr, | 2330 | if (compare_ether_addr(sdata->vif.addr, |
| 2329 | hdr->addr1)) | 2331 | hdr->addr1)) |
| 2330 | return 0; | 2332 | return 0; |
| 2331 | } else if (!ieee80211_bssid_match(bssid, | 2333 | } else if (!ieee80211_bssid_match(bssid, |
| 2332 | sdata->dev->dev_addr)) { | 2334 | sdata->vif.addr)) { |
| 2333 | if (!(rx->flags & IEEE80211_RX_IN_SCAN)) | 2335 | if (!(rx->flags & IEEE80211_RX_IN_SCAN)) |
| 2334 | return 0; | 2336 | return 0; |
| 2335 | rx->flags &= ~IEEE80211_RX_RA_MATCH; | 2337 | rx->flags &= ~IEEE80211_RX_RA_MATCH; |
| @@ -2368,6 +2370,8 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, | |||
| 2368 | int prepares; | 2370 | int prepares; |
| 2369 | struct ieee80211_sub_if_data *prev = NULL; | 2371 | struct ieee80211_sub_if_data *prev = NULL; |
| 2370 | struct sk_buff *skb_new; | 2372 | struct sk_buff *skb_new; |
| 2373 | struct sta_info *sta, *tmp; | ||
| 2374 | bool found_sta = false; | ||
| 2371 | 2375 | ||
| 2372 | hdr = (struct ieee80211_hdr *)skb->data; | 2376 | hdr = (struct ieee80211_hdr *)skb->data; |
| 2373 | memset(&rx, 0, sizeof(rx)); | 2377 | memset(&rx, 0, sizeof(rx)); |
| @@ -2384,68 +2388,87 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, | |||
| 2384 | ieee80211_parse_qos(&rx); | 2388 | ieee80211_parse_qos(&rx); |
| 2385 | ieee80211_verify_alignment(&rx); | 2389 | ieee80211_verify_alignment(&rx); |
| 2386 | 2390 | ||
| 2387 | rx.sta = sta_info_get(local, hdr->addr2); | 2391 | if (ieee80211_is_data(hdr->frame_control)) { |
| 2388 | if (rx.sta) | 2392 | for_each_sta_info(local, hdr->addr2, sta, tmp) { |
| 2389 | rx.sdata = rx.sta->sdata; | 2393 | rx.sta = sta; |
| 2390 | 2394 | found_sta = true; | |
| 2391 | if (rx.sdata && ieee80211_is_data(hdr->frame_control)) { | 2395 | rx.sdata = sta->sdata; |
| 2392 | rx.flags |= IEEE80211_RX_RA_MATCH; | 2396 | |
| 2393 | prepares = prepare_for_handlers(rx.sdata, &rx, hdr); | 2397 | rx.flags |= IEEE80211_RX_RA_MATCH; |
| 2394 | if (prepares) { | 2398 | prepares = prepare_for_handlers(rx.sdata, &rx, hdr); |
| 2395 | if (status->flag & RX_FLAG_MMIC_ERROR) { | 2399 | if (prepares) { |
| 2396 | if (rx.flags & IEEE80211_RX_RA_MATCH) | 2400 | if (status->flag & RX_FLAG_MMIC_ERROR) { |
| 2397 | ieee80211_rx_michael_mic_report(hdr, &rx); | 2401 | if (rx.flags & IEEE80211_RX_RA_MATCH) |
| 2398 | } else | 2402 | ieee80211_rx_michael_mic_report(hdr, &rx); |
| 2399 | prev = rx.sdata; | 2403 | } else |
| 2404 | prev = rx.sdata; | ||
| 2405 | } | ||
| 2400 | } | 2406 | } |
| 2401 | } else list_for_each_entry_rcu(sdata, &local->interfaces, list) { | 2407 | } |
| 2402 | if (!netif_running(sdata->dev)) | 2408 | if (!found_sta) { |
| 2403 | continue; | 2409 | list_for_each_entry_rcu(sdata, &local->interfaces, list) { |
| 2410 | if (!ieee80211_sdata_running(sdata)) | ||
| 2411 | continue; | ||
| 2404 | 2412 | ||
| 2405 | if (sdata->vif.type == NL80211_IFTYPE_MONITOR || | 2413 | if (sdata->vif.type == NL80211_IFTYPE_MONITOR || |
| 2406 | sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | 2414 | sdata->vif.type == NL80211_IFTYPE_AP_VLAN) |
| 2407 | continue; | 2415 | continue; |
| 2408 | 2416 | ||
| 2409 | rx.flags |= IEEE80211_RX_RA_MATCH; | 2417 | /* |
| 2410 | prepares = prepare_for_handlers(sdata, &rx, hdr); | 2418 | * frame is destined for this interface, but if it's |
| 2419 | * not also for the previous one we handle that after | ||
| 2420 | * the loop to avoid copying the SKB once too much | ||
| 2421 | */ | ||
| 2411 | 2422 | ||
| 2412 | if (!prepares) | 2423 | if (!prev) { |
| 2413 | continue; | 2424 | prev = sdata; |
| 2425 | continue; | ||
| 2426 | } | ||
| 2414 | 2427 | ||
| 2415 | if (status->flag & RX_FLAG_MMIC_ERROR) { | 2428 | rx.sta = sta_info_get_bss(prev, hdr->addr2); |
| 2416 | rx.sdata = sdata; | ||
| 2417 | if (rx.flags & IEEE80211_RX_RA_MATCH) | ||
| 2418 | ieee80211_rx_michael_mic_report(hdr, &rx); | ||
| 2419 | continue; | ||
| 2420 | } | ||
| 2421 | 2429 | ||
| 2422 | /* | 2430 | rx.flags |= IEEE80211_RX_RA_MATCH; |
| 2423 | * frame is destined for this interface, but if it's not | 2431 | prepares = prepare_for_handlers(prev, &rx, hdr); |
| 2424 | * also for the previous one we handle that after the | 2432 | |
| 2425 | * loop to avoid copying the SKB once too much | 2433 | if (!prepares) |
| 2426 | */ | 2434 | goto next; |
| 2427 | 2435 | ||
| 2428 | if (!prev) { | 2436 | if (status->flag & RX_FLAG_MMIC_ERROR) { |
| 2437 | rx.sdata = prev; | ||
| 2438 | if (rx.flags & IEEE80211_RX_RA_MATCH) | ||
| 2439 | ieee80211_rx_michael_mic_report(hdr, | ||
| 2440 | &rx); | ||
| 2441 | goto next; | ||
| 2442 | } | ||
| 2443 | |||
| 2444 | /* | ||
| 2445 | * frame was destined for the previous interface | ||
| 2446 | * so invoke RX handlers for it | ||
| 2447 | */ | ||
| 2448 | |||
| 2449 | skb_new = skb_copy(skb, GFP_ATOMIC); | ||
| 2450 | if (!skb_new) { | ||
| 2451 | if (net_ratelimit()) | ||
| 2452 | printk(KERN_DEBUG "%s: failed to copy " | ||
| 2453 | "multicast frame for %s\n", | ||
| 2454 | wiphy_name(local->hw.wiphy), | ||
| 2455 | prev->name); | ||
| 2456 | goto next; | ||
| 2457 | } | ||
| 2458 | ieee80211_invoke_rx_handlers(prev, &rx, skb_new, rate); | ||
| 2459 | next: | ||
| 2429 | prev = sdata; | 2460 | prev = sdata; |
| 2430 | continue; | ||
| 2431 | } | 2461 | } |
| 2432 | 2462 | ||
| 2433 | /* | 2463 | if (prev) { |
| 2434 | * frame was destined for the previous interface | 2464 | rx.sta = sta_info_get_bss(prev, hdr->addr2); |
| 2435 | * so invoke RX handlers for it | ||
| 2436 | */ | ||
| 2437 | 2465 | ||
| 2438 | skb_new = skb_copy(skb, GFP_ATOMIC); | 2466 | rx.flags |= IEEE80211_RX_RA_MATCH; |
| 2439 | if (!skb_new) { | 2467 | prepares = prepare_for_handlers(prev, &rx, hdr); |
| 2440 | if (net_ratelimit()) | 2468 | |
| 2441 | printk(KERN_DEBUG "%s: failed to copy " | 2469 | if (!prepares) |
| 2442 | "multicast frame for %s\n", | 2470 | prev = NULL; |
| 2443 | wiphy_name(local->hw.wiphy), | ||
| 2444 | prev->dev->name); | ||
| 2445 | continue; | ||
| 2446 | } | 2471 | } |
| 2447 | ieee80211_invoke_rx_handlers(prev, &rx, skb_new, rate); | ||
| 2448 | prev = sdata; | ||
| 2449 | } | 2472 | } |
| 2450 | if (prev) | 2473 | if (prev) |
| 2451 | ieee80211_invoke_rx_handlers(prev, &rx, skb, rate); | 2474 | ieee80211_invoke_rx_handlers(prev, &rx, skb, rate); |
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index bc17cf7d68db..b822dce97867 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c | |||
| @@ -12,7 +12,6 @@ | |||
| 12 | * published by the Free Software Foundation. | 12 | * published by the Free Software Foundation. |
| 13 | */ | 13 | */ |
| 14 | 14 | ||
| 15 | #include <linux/wireless.h> | ||
| 16 | #include <linux/if_arp.h> | 15 | #include <linux/if_arp.h> |
| 17 | #include <linux/rtnetlink.h> | 16 | #include <linux/rtnetlink.h> |
| 18 | #include <net/mac80211.h> | 17 | #include <net/mac80211.h> |
| @@ -29,16 +28,19 @@ struct ieee80211_bss * | |||
| 29 | ieee80211_rx_bss_get(struct ieee80211_local *local, u8 *bssid, int freq, | 28 | ieee80211_rx_bss_get(struct ieee80211_local *local, u8 *bssid, int freq, |
| 30 | u8 *ssid, u8 ssid_len) | 29 | u8 *ssid, u8 ssid_len) |
| 31 | { | 30 | { |
| 32 | return (void *)cfg80211_get_bss(local->hw.wiphy, | 31 | struct cfg80211_bss *cbss; |
| 33 | ieee80211_get_channel(local->hw.wiphy, | 32 | |
| 34 | freq), | 33 | cbss = cfg80211_get_bss(local->hw.wiphy, |
| 35 | bssid, ssid, ssid_len, | 34 | ieee80211_get_channel(local->hw.wiphy, freq), |
| 36 | 0, 0); | 35 | bssid, ssid, ssid_len, 0, 0); |
| 36 | if (!cbss) | ||
| 37 | return NULL; | ||
| 38 | return (void *)cbss->priv; | ||
| 37 | } | 39 | } |
| 38 | 40 | ||
| 39 | static void ieee80211_rx_bss_free(struct cfg80211_bss *cbss) | 41 | static void ieee80211_rx_bss_free(struct cfg80211_bss *cbss) |
| 40 | { | 42 | { |
| 41 | struct ieee80211_bss *bss = (void *)cbss; | 43 | struct ieee80211_bss *bss = (void *)cbss->priv; |
| 42 | 44 | ||
| 43 | kfree(bss_mesh_id(bss)); | 45 | kfree(bss_mesh_id(bss)); |
| 44 | kfree(bss_mesh_cfg(bss)); | 46 | kfree(bss_mesh_cfg(bss)); |
| @@ -47,7 +49,26 @@ static void ieee80211_rx_bss_free(struct cfg80211_bss *cbss) | |||
| 47 | void ieee80211_rx_bss_put(struct ieee80211_local *local, | 49 | void ieee80211_rx_bss_put(struct ieee80211_local *local, |
| 48 | struct ieee80211_bss *bss) | 50 | struct ieee80211_bss *bss) |
| 49 | { | 51 | { |
| 50 | cfg80211_put_bss((struct cfg80211_bss *)bss); | 52 | if (!bss) |
| 53 | return; | ||
| 54 | cfg80211_put_bss(container_of((void *)bss, struct cfg80211_bss, priv)); | ||
| 55 | } | ||
| 56 | |||
| 57 | static bool is_uapsd_supported(struct ieee802_11_elems *elems) | ||
| 58 | { | ||
| 59 | u8 qos_info; | ||
| 60 | |||
| 61 | if (elems->wmm_info && elems->wmm_info_len == 7 | ||
| 62 | && elems->wmm_info[5] == 1) | ||
| 63 | qos_info = elems->wmm_info[6]; | ||
| 64 | else if (elems->wmm_param && elems->wmm_param_len == 24 | ||
| 65 | && elems->wmm_param[5] == 1) | ||
| 66 | qos_info = elems->wmm_param[6]; | ||
| 67 | else | ||
| 68 | /* no valid wmm information or parameter element found */ | ||
| 69 | return false; | ||
| 70 | |||
| 71 | return qos_info & IEEE80211_WMM_IE_AP_QOSINFO_UAPSD; | ||
| 51 | } | 72 | } |
| 52 | 73 | ||
| 53 | struct ieee80211_bss * | 74 | struct ieee80211_bss * |
| @@ -59,6 +80,7 @@ ieee80211_bss_info_update(struct ieee80211_local *local, | |||
| 59 | struct ieee80211_channel *channel, | 80 | struct ieee80211_channel *channel, |
| 60 | bool beacon) | 81 | bool beacon) |
| 61 | { | 82 | { |
| 83 | struct cfg80211_bss *cbss; | ||
| 62 | struct ieee80211_bss *bss; | 84 | struct ieee80211_bss *bss; |
| 63 | int clen; | 85 | int clen; |
| 64 | s32 signal = 0; | 86 | s32 signal = 0; |
| @@ -68,13 +90,14 @@ ieee80211_bss_info_update(struct ieee80211_local *local, | |||
| 68 | else if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC) | 90 | else if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC) |
| 69 | signal = (rx_status->signal * 100) / local->hw.max_signal; | 91 | signal = (rx_status->signal * 100) / local->hw.max_signal; |
| 70 | 92 | ||
| 71 | bss = (void *)cfg80211_inform_bss_frame(local->hw.wiphy, channel, | 93 | cbss = cfg80211_inform_bss_frame(local->hw.wiphy, channel, |
| 72 | mgmt, len, signal, GFP_ATOMIC); | 94 | mgmt, len, signal, GFP_ATOMIC); |
| 73 | 95 | ||
| 74 | if (!bss) | 96 | if (!cbss) |
| 75 | return NULL; | 97 | return NULL; |
| 76 | 98 | ||
| 77 | bss->cbss.free_priv = ieee80211_rx_bss_free; | 99 | cbss->free_priv = ieee80211_rx_bss_free; |
| 100 | bss = (void *)cbss->priv; | ||
| 78 | 101 | ||
| 79 | /* save the ERP value so that it is available at association time */ | 102 | /* save the ERP value so that it is available at association time */ |
| 80 | if (elems->erp_info && elems->erp_info_len >= 1) { | 103 | if (elems->erp_info && elems->erp_info_len >= 1) { |
| @@ -88,10 +111,6 @@ ieee80211_bss_info_update(struct ieee80211_local *local, | |||
| 88 | bss->dtim_period = tim_ie->dtim_period; | 111 | bss->dtim_period = tim_ie->dtim_period; |
| 89 | } | 112 | } |
| 90 | 113 | ||
| 91 | /* set default value for buggy AP/no TIM element */ | ||
| 92 | if (bss->dtim_period == 0) | ||
| 93 | bss->dtim_period = 1; | ||
| 94 | |||
| 95 | bss->supp_rates_len = 0; | 114 | bss->supp_rates_len = 0; |
| 96 | if (elems->supp_rates) { | 115 | if (elems->supp_rates) { |
| 97 | clen = IEEE80211_MAX_SUPP_RATES - bss->supp_rates_len; | 116 | clen = IEEE80211_MAX_SUPP_RATES - bss->supp_rates_len; |
| @@ -111,6 +130,7 @@ ieee80211_bss_info_update(struct ieee80211_local *local, | |||
| 111 | } | 130 | } |
| 112 | 131 | ||
| 113 | bss->wmm_used = elems->wmm_param || elems->wmm_info; | 132 | bss->wmm_used = elems->wmm_param || elems->wmm_info; |
| 133 | bss->uapsd_supported = is_uapsd_supported(elems); | ||
| 114 | 134 | ||
| 115 | if (!beacon) | 135 | if (!beacon) |
| 116 | bss->last_probe_resp = jiffies; | 136 | bss->last_probe_resp = jiffies; |
| @@ -147,7 +167,7 @@ ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) | |||
| 147 | presp = ieee80211_is_probe_resp(fc); | 167 | presp = ieee80211_is_probe_resp(fc); |
| 148 | if (presp) { | 168 | if (presp) { |
| 149 | /* ignore ProbeResp to foreign address */ | 169 | /* ignore ProbeResp to foreign address */ |
| 150 | if (memcmp(mgmt->da, sdata->dev->dev_addr, ETH_ALEN)) | 170 | if (memcmp(mgmt->da, sdata->vif.addr, ETH_ALEN)) |
| 151 | return RX_DROP_MONITOR; | 171 | return RX_DROP_MONITOR; |
| 152 | 172 | ||
| 153 | presp = true; | 173 | presp = true; |
| @@ -220,82 +240,9 @@ static bool ieee80211_prep_hw_scan(struct ieee80211_local *local) | |||
| 220 | return true; | 240 | return true; |
| 221 | } | 241 | } |
| 222 | 242 | ||
| 223 | /* | ||
| 224 | * inform AP that we will go to sleep so that it will buffer the frames | ||
| 225 | * while we scan | ||
| 226 | */ | ||
| 227 | static void ieee80211_scan_ps_enable(struct ieee80211_sub_if_data *sdata) | ||
| 228 | { | ||
| 229 | struct ieee80211_local *local = sdata->local; | ||
| 230 | |||
| 231 | local->scan_ps_enabled = false; | ||
| 232 | |||
| 233 | /* FIXME: what to do when local->pspolling is true? */ | ||
| 234 | |||
| 235 | del_timer_sync(&local->dynamic_ps_timer); | ||
| 236 | cancel_work_sync(&local->dynamic_ps_enable_work); | ||
| 237 | |||
| 238 | if (local->hw.conf.flags & IEEE80211_CONF_PS) { | ||
| 239 | local->scan_ps_enabled = true; | ||
| 240 | local->hw.conf.flags &= ~IEEE80211_CONF_PS; | ||
| 241 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); | ||
| 242 | } | ||
| 243 | |||
| 244 | if (!(local->scan_ps_enabled) || | ||
| 245 | !(local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK)) | ||
| 246 | /* | ||
| 247 | * If power save was enabled, no need to send a nullfunc | ||
| 248 | * frame because AP knows that we are sleeping. But if the | ||
| 249 | * hardware is creating the nullfunc frame for power save | ||
| 250 | * status (ie. IEEE80211_HW_PS_NULLFUNC_STACK is not | ||
| 251 | * enabled) and power save was enabled, the firmware just | ||
| 252 | * sent a null frame with power save disabled. So we need | ||
| 253 | * to send a new nullfunc frame to inform the AP that we | ||
| 254 | * are again sleeping. | ||
| 255 | */ | ||
| 256 | ieee80211_send_nullfunc(local, sdata, 1); | ||
| 257 | } | ||
| 258 | |||
| 259 | /* inform AP that we are awake again, unless power save is enabled */ | ||
| 260 | static void ieee80211_scan_ps_disable(struct ieee80211_sub_if_data *sdata) | ||
| 261 | { | ||
| 262 | struct ieee80211_local *local = sdata->local; | ||
| 263 | |||
| 264 | if (!local->ps_sdata) | ||
| 265 | ieee80211_send_nullfunc(local, sdata, 0); | ||
| 266 | else if (local->scan_ps_enabled) { | ||
| 267 | /* | ||
| 268 | * In !IEEE80211_HW_PS_NULLFUNC_STACK case the hardware | ||
| 269 | * will send a nullfunc frame with the powersave bit set | ||
| 270 | * even though the AP already knows that we are sleeping. | ||
| 271 | * This could be avoided by sending a null frame with power | ||
| 272 | * save bit disabled before enabling the power save, but | ||
| 273 | * this doesn't gain anything. | ||
| 274 | * | ||
| 275 | * When IEEE80211_HW_PS_NULLFUNC_STACK is enabled, no need | ||
| 276 | * to send a nullfunc frame because AP already knows that | ||
| 277 | * we are sleeping, let's just enable power save mode in | ||
| 278 | * hardware. | ||
| 279 | */ | ||
| 280 | local->hw.conf.flags |= IEEE80211_CONF_PS; | ||
| 281 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); | ||
| 282 | } else if (local->hw.conf.dynamic_ps_timeout > 0) { | ||
| 283 | /* | ||
| 284 | * If IEEE80211_CONF_PS was not set and the dynamic_ps_timer | ||
| 285 | * had been running before leaving the operating channel, | ||
| 286 | * restart the timer now and send a nullfunc frame to inform | ||
| 287 | * the AP that we are awake. | ||
| 288 | */ | ||
| 289 | ieee80211_send_nullfunc(local, sdata, 0); | ||
| 290 | mod_timer(&local->dynamic_ps_timer, jiffies + | ||
| 291 | msecs_to_jiffies(local->hw.conf.dynamic_ps_timeout)); | ||
| 292 | } | ||
| 293 | } | ||
| 294 | |||
| 295 | void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) | 243 | void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) |
| 296 | { | 244 | { |
| 297 | struct ieee80211_local *local = hw_to_local(hw); | 245 | struct ieee80211_local *local = hw_to_local(hw); |
| 298 | struct ieee80211_sub_if_data *sdata; | ||
| 299 | bool was_hw_scan; | 246 | bool was_hw_scan; |
| 300 | 247 | ||
| 301 | mutex_lock(&local->scan_mtx); | 248 | mutex_lock(&local->scan_mtx); |
| @@ -344,41 +291,19 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) | |||
| 344 | 291 | ||
| 345 | drv_sw_scan_complete(local); | 292 | drv_sw_scan_complete(local); |
| 346 | 293 | ||
| 347 | mutex_lock(&local->iflist_mtx); | 294 | ieee80211_offchannel_return(local, true); |
| 348 | list_for_each_entry(sdata, &local->interfaces, list) { | ||
| 349 | if (!netif_running(sdata->dev)) | ||
| 350 | continue; | ||
| 351 | |||
| 352 | /* Tell AP we're back */ | ||
| 353 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { | ||
| 354 | if (sdata->u.mgd.associated) { | ||
| 355 | ieee80211_scan_ps_disable(sdata); | ||
| 356 | netif_tx_wake_all_queues(sdata->dev); | ||
| 357 | } | ||
| 358 | } else | ||
| 359 | netif_tx_wake_all_queues(sdata->dev); | ||
| 360 | |||
| 361 | /* re-enable beaconing */ | ||
| 362 | if (sdata->vif.type == NL80211_IFTYPE_AP || | ||
| 363 | sdata->vif.type == NL80211_IFTYPE_ADHOC || | ||
| 364 | sdata->vif.type == NL80211_IFTYPE_MESH_POINT) | ||
| 365 | ieee80211_bss_info_change_notify( | ||
| 366 | sdata, BSS_CHANGED_BEACON_ENABLED); | ||
| 367 | } | ||
| 368 | mutex_unlock(&local->iflist_mtx); | ||
| 369 | 295 | ||
| 370 | done: | 296 | done: |
| 371 | ieee80211_recalc_idle(local); | 297 | ieee80211_recalc_idle(local); |
| 372 | ieee80211_mlme_notify_scan_completed(local); | 298 | ieee80211_mlme_notify_scan_completed(local); |
| 373 | ieee80211_ibss_notify_scan_completed(local); | 299 | ieee80211_ibss_notify_scan_completed(local); |
| 374 | ieee80211_mesh_notify_scan_completed(local); | 300 | ieee80211_mesh_notify_scan_completed(local); |
| 301 | ieee80211_queue_work(&local->hw, &local->work_work); | ||
| 375 | } | 302 | } |
| 376 | EXPORT_SYMBOL(ieee80211_scan_completed); | 303 | EXPORT_SYMBOL(ieee80211_scan_completed); |
| 377 | 304 | ||
| 378 | static int ieee80211_start_sw_scan(struct ieee80211_local *local) | 305 | static int ieee80211_start_sw_scan(struct ieee80211_local *local) |
| 379 | { | 306 | { |
| 380 | struct ieee80211_sub_if_data *sdata; | ||
| 381 | |||
| 382 | /* | 307 | /* |
| 383 | * Hardware/driver doesn't support hw_scan, so use software | 308 | * Hardware/driver doesn't support hw_scan, so use software |
| 384 | * scanning instead. First send a nullfunc frame with power save | 309 | * scanning instead. First send a nullfunc frame with power save |
| @@ -394,33 +319,15 @@ static int ieee80211_start_sw_scan(struct ieee80211_local *local) | |||
| 394 | */ | 319 | */ |
| 395 | drv_sw_scan_start(local); | 320 | drv_sw_scan_start(local); |
| 396 | 321 | ||
| 397 | mutex_lock(&local->iflist_mtx); | 322 | ieee80211_offchannel_stop_beaconing(local); |
| 398 | list_for_each_entry(sdata, &local->interfaces, list) { | ||
| 399 | if (!netif_running(sdata->dev)) | ||
| 400 | continue; | ||
| 401 | |||
| 402 | /* disable beaconing */ | ||
| 403 | if (sdata->vif.type == NL80211_IFTYPE_AP || | ||
| 404 | sdata->vif.type == NL80211_IFTYPE_ADHOC || | ||
| 405 | sdata->vif.type == NL80211_IFTYPE_MESH_POINT) | ||
| 406 | ieee80211_bss_info_change_notify( | ||
| 407 | sdata, BSS_CHANGED_BEACON_ENABLED); | ||
| 408 | |||
| 409 | /* | ||
| 410 | * only handle non-STA interfaces here, STA interfaces | ||
| 411 | * are handled in the scan state machine | ||
| 412 | */ | ||
| 413 | if (sdata->vif.type != NL80211_IFTYPE_STATION) | ||
| 414 | netif_tx_stop_all_queues(sdata->dev); | ||
| 415 | } | ||
| 416 | mutex_unlock(&local->iflist_mtx); | ||
| 417 | 323 | ||
| 418 | local->next_scan_state = SCAN_DECISION; | 324 | local->next_scan_state = SCAN_DECISION; |
| 419 | local->scan_channel_idx = 0; | 325 | local->scan_channel_idx = 0; |
| 420 | 326 | ||
| 327 | drv_flush(local, false); | ||
| 328 | |||
| 421 | ieee80211_configure_filter(local); | 329 | ieee80211_configure_filter(local); |
| 422 | 330 | ||
| 423 | /* TODO: start scan as soon as all nullfunc frames are ACKed */ | ||
| 424 | ieee80211_queue_delayed_work(&local->hw, | 331 | ieee80211_queue_delayed_work(&local->hw, |
| 425 | &local->scan_work, | 332 | &local->scan_work, |
| 426 | IEEE80211_CHANNEL_TIME); | 333 | IEEE80211_CHANNEL_TIME); |
| @@ -433,17 +340,13 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, | |||
| 433 | struct cfg80211_scan_request *req) | 340 | struct cfg80211_scan_request *req) |
| 434 | { | 341 | { |
| 435 | struct ieee80211_local *local = sdata->local; | 342 | struct ieee80211_local *local = sdata->local; |
| 436 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
| 437 | int rc; | 343 | int rc; |
| 438 | 344 | ||
| 439 | if (local->scan_req) | 345 | if (local->scan_req) |
| 440 | return -EBUSY; | 346 | return -EBUSY; |
| 441 | 347 | ||
| 442 | if (req != local->int_scan_req && | 348 | if (!list_empty(&local->work_list)) { |
| 443 | sdata->vif.type == NL80211_IFTYPE_STATION && | 349 | /* wait for the work to finish/time out */ |
| 444 | !list_empty(&ifmgd->work_list)) { | ||
| 445 | /* actually wait for the work it's doing to finish/time out */ | ||
| 446 | set_bit(IEEE80211_STA_REQ_SCAN, &ifmgd->request); | ||
| 447 | local->scan_req = req; | 350 | local->scan_req = req; |
| 448 | local->scan_sdata = sdata; | 351 | local->scan_sdata = sdata; |
| 449 | return 0; | 352 | return 0; |
| @@ -468,6 +371,14 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, | |||
| 468 | local->hw_scan_req->ie = ies; | 371 | local->hw_scan_req->ie = ies; |
| 469 | 372 | ||
| 470 | local->hw_scan_band = 0; | 373 | local->hw_scan_band = 0; |
| 374 | |||
| 375 | /* | ||
| 376 | * After allocating local->hw_scan_req, we must | ||
| 377 | * go through until ieee80211_prep_hw_scan(), so | ||
| 378 | * anything that might be changed here and leave | ||
| 379 | * this function early must not go after this | ||
| 380 | * allocation. | ||
| 381 | */ | ||
| 471 | } | 382 | } |
| 472 | 383 | ||
| 473 | local->scan_req = req; | 384 | local->scan_req = req; |
| @@ -477,15 +388,16 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, | |||
| 477 | __set_bit(SCAN_HW_SCANNING, &local->scanning); | 388 | __set_bit(SCAN_HW_SCANNING, &local->scanning); |
| 478 | else | 389 | else |
| 479 | __set_bit(SCAN_SW_SCANNING, &local->scanning); | 390 | __set_bit(SCAN_SW_SCANNING, &local->scanning); |
| 391 | |||
| 480 | /* | 392 | /* |
| 481 | * Kicking off the scan need not be protected, | 393 | * Kicking off the scan need not be protected, |
| 482 | * only the scan variable stuff, since now | 394 | * only the scan variable stuff, since now |
| 483 | * local->scan_req is assigned and other callers | 395 | * local->scan_req is assigned and other callers |
| 484 | * will abort their scan attempts. | 396 | * will abort their scan attempts. |
| 485 | * | 397 | * |
| 486 | * This avoids getting a scan_mtx -> iflist_mtx | 398 | * This avoids too many locking dependencies |
| 487 | * dependency, so that the scan completed calls | 399 | * so that the scan completed calls have more |
| 488 | * have more locking freedom. | 400 | * locking freedom. |
| 489 | */ | 401 | */ |
| 490 | 402 | ||
| 491 | ieee80211_recalc_idle(local); | 403 | ieee80211_recalc_idle(local); |
| @@ -528,7 +440,7 @@ static int ieee80211_scan_state_decision(struct ieee80211_local *local, | |||
| 528 | /* check if at least one STA interface is associated */ | 440 | /* check if at least one STA interface is associated */ |
| 529 | mutex_lock(&local->iflist_mtx); | 441 | mutex_lock(&local->iflist_mtx); |
| 530 | list_for_each_entry(sdata, &local->interfaces, list) { | 442 | list_for_each_entry(sdata, &local->interfaces, list) { |
| 531 | if (!netif_running(sdata->dev)) | 443 | if (!ieee80211_sdata_running(sdata)) |
| 532 | continue; | 444 | continue; |
| 533 | 445 | ||
| 534 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { | 446 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { |
| @@ -566,56 +478,35 @@ static int ieee80211_scan_state_decision(struct ieee80211_local *local, | |||
| 566 | static void ieee80211_scan_state_leave_oper_channel(struct ieee80211_local *local, | 478 | static void ieee80211_scan_state_leave_oper_channel(struct ieee80211_local *local, |
| 567 | unsigned long *next_delay) | 479 | unsigned long *next_delay) |
| 568 | { | 480 | { |
| 569 | struct ieee80211_sub_if_data *sdata; | 481 | ieee80211_offchannel_stop_station(local); |
| 482 | |||
| 483 | __set_bit(SCAN_OFF_CHANNEL, &local->scanning); | ||
| 570 | 484 | ||
| 571 | /* | 485 | /* |
| 572 | * notify the AP about us leaving the channel and stop all STA interfaces | 486 | * What if the nullfunc frames didn't arrive? |
| 573 | */ | 487 | */ |
| 574 | mutex_lock(&local->iflist_mtx); | 488 | drv_flush(local, false); |
| 575 | list_for_each_entry(sdata, &local->interfaces, list) { | 489 | if (local->ops->flush) |
| 576 | if (!netif_running(sdata->dev)) | 490 | *next_delay = 0; |
| 577 | continue; | 491 | else |
| 578 | 492 | *next_delay = HZ / 10; | |
| 579 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { | ||
| 580 | netif_tx_stop_all_queues(sdata->dev); | ||
| 581 | if (sdata->u.mgd.associated) | ||
| 582 | ieee80211_scan_ps_enable(sdata); | ||
| 583 | } | ||
| 584 | } | ||
| 585 | mutex_unlock(&local->iflist_mtx); | ||
| 586 | |||
| 587 | __set_bit(SCAN_OFF_CHANNEL, &local->scanning); | ||
| 588 | 493 | ||
| 589 | /* advance to the next channel to be scanned */ | 494 | /* advance to the next channel to be scanned */ |
| 590 | *next_delay = HZ / 10; | ||
| 591 | local->next_scan_state = SCAN_SET_CHANNEL; | 495 | local->next_scan_state = SCAN_SET_CHANNEL; |
| 592 | } | 496 | } |
| 593 | 497 | ||
| 594 | static void ieee80211_scan_state_enter_oper_channel(struct ieee80211_local *local, | 498 | static void ieee80211_scan_state_enter_oper_channel(struct ieee80211_local *local, |
| 595 | unsigned long *next_delay) | 499 | unsigned long *next_delay) |
| 596 | { | 500 | { |
| 597 | struct ieee80211_sub_if_data *sdata = local->scan_sdata; | ||
| 598 | |||
| 599 | /* switch back to the operating channel */ | 501 | /* switch back to the operating channel */ |
| 600 | local->scan_channel = NULL; | 502 | local->scan_channel = NULL; |
| 601 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); | 503 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); |
| 602 | 504 | ||
| 603 | /* | 505 | /* |
| 604 | * notify the AP about us being back and restart all STA interfaces | 506 | * Only re-enable station mode interface now; beaconing will be |
| 507 | * re-enabled once the full scan has been completed. | ||
| 605 | */ | 508 | */ |
| 606 | mutex_lock(&local->iflist_mtx); | 509 | ieee80211_offchannel_return(local, false); |
| 607 | list_for_each_entry(sdata, &local->interfaces, list) { | ||
| 608 | if (!netif_running(sdata->dev)) | ||
| 609 | continue; | ||
| 610 | |||
| 611 | /* Tell AP we're back */ | ||
| 612 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { | ||
| 613 | if (sdata->u.mgd.associated) | ||
| 614 | ieee80211_scan_ps_disable(sdata); | ||
| 615 | netif_tx_wake_all_queues(sdata->dev); | ||
| 616 | } | ||
| 617 | } | ||
| 618 | mutex_unlock(&local->iflist_mtx); | ||
| 619 | 510 | ||
| 620 | __clear_bit(SCAN_OFF_CHANNEL, &local->scanning); | 511 | __clear_bit(SCAN_OFF_CHANNEL, &local->scanning); |
| 621 | 512 | ||
| @@ -729,7 +620,7 @@ void ieee80211_scan_work(struct work_struct *work) | |||
| 729 | /* | 620 | /* |
| 730 | * Avoid re-scheduling when the sdata is going away. | 621 | * Avoid re-scheduling when the sdata is going away. |
| 731 | */ | 622 | */ |
| 732 | if (!netif_running(sdata->dev)) { | 623 | if (!ieee80211_sdata_running(sdata)) { |
| 733 | ieee80211_scan_completed(&local->hw, true); | 624 | ieee80211_scan_completed(&local->hw, true); |
| 734 | return; | 625 | return; |
| 735 | } | 626 | } |
diff --git a/net/mac80211/spectmgmt.c b/net/mac80211/spectmgmt.c index aa743a895cf9..7733f66ee2c4 100644 --- a/net/mac80211/spectmgmt.c +++ b/net/mac80211/spectmgmt.c | |||
| @@ -35,7 +35,7 @@ static void ieee80211_send_refuse_measurement_request(struct ieee80211_sub_if_da | |||
| 35 | 35 | ||
| 36 | if (!skb) { | 36 | if (!skb) { |
| 37 | printk(KERN_ERR "%s: failed to allocate buffer for " | 37 | printk(KERN_ERR "%s: failed to allocate buffer for " |
| 38 | "measurement report frame\n", sdata->dev->name); | 38 | "measurement report frame\n", sdata->name); |
| 39 | return; | 39 | return; |
| 40 | } | 40 | } |
| 41 | 41 | ||
| @@ -43,7 +43,7 @@ static void ieee80211_send_refuse_measurement_request(struct ieee80211_sub_if_da | |||
| 43 | msr_report = (struct ieee80211_mgmt *)skb_put(skb, 24); | 43 | msr_report = (struct ieee80211_mgmt *)skb_put(skb, 24); |
| 44 | memset(msr_report, 0, 24); | 44 | memset(msr_report, 0, 24); |
| 45 | memcpy(msr_report->da, da, ETH_ALEN); | 45 | memcpy(msr_report->da, da, ETH_ALEN); |
| 46 | memcpy(msr_report->sa, sdata->dev->dev_addr, ETH_ALEN); | 46 | memcpy(msr_report->sa, sdata->vif.addr, ETH_ALEN); |
| 47 | memcpy(msr_report->bssid, bssid, ETH_ALEN); | 47 | memcpy(msr_report->bssid, bssid, ETH_ALEN); |
| 48 | msr_report->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | 48 | msr_report->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | |
| 49 | IEEE80211_STYPE_ACTION); | 49 | IEEE80211_STYPE_ACTION); |
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 71f370dd24bc..56422d894351 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c | |||
| @@ -32,49 +32,33 @@ | |||
| 32 | * for faster lookup and a list for iteration. They are managed using | 32 | * for faster lookup and a list for iteration. They are managed using |
| 33 | * RCU, i.e. access to the list and hash table is protected by RCU. | 33 | * RCU, i.e. access to the list and hash table is protected by RCU. |
| 34 | * | 34 | * |
| 35 | * Upon allocating a STA info structure with sta_info_alloc(), the caller owns | 35 | * Upon allocating a STA info structure with sta_info_alloc(), the caller |
| 36 | * that structure. It must then either destroy it using sta_info_destroy() | 36 | * owns that structure. It must then insert it into the hash table using |
| 37 | * (which is pretty useless) or insert it into the hash table using | 37 | * either sta_info_insert() or sta_info_insert_rcu(); only in the latter |
| 38 | * sta_info_insert() which demotes the reference from ownership to a regular | 38 | * case (which acquires an rcu read section but must not be called from |
| 39 | * RCU-protected reference; if the function is called without protection by an | 39 | * within one) will the pointer still be valid after the call. Note that |
| 40 | * RCU critical section the reference is instantly invalidated. Note that the | 40 | * the caller may not do much with the STA info before inserting it, in |
| 41 | * caller may not do much with the STA info before inserting it, in particular, | 41 | * particular, it may not start any mesh peer link management or add |
| 42 | * it may not start any mesh peer link management or add encryption keys. | 42 | * encryption keys. |
| 43 | * | 43 | * |
| 44 | * When the insertion fails (sta_info_insert()) returns non-zero), the | 44 | * When the insertion fails (sta_info_insert()) returns non-zero), the |
| 45 | * structure will have been freed by sta_info_insert()! | 45 | * structure will have been freed by sta_info_insert()! |
| 46 | * | 46 | * |
| 47 | * sta entries are added by mac80211 when you establish a link with a | 47 | * Station entries are added by mac80211 when you establish a link with a |
| 48 | * peer. This means different things for the different type of interfaces | 48 | * peer. This means different things for the different type of interfaces |
| 49 | * we support. For a regular station this mean we add the AP sta when we | 49 | * we support. For a regular station this mean we add the AP sta when we |
| 50 | * receive an assocation response from the AP. For IBSS this occurs when | 50 | * receive an assocation response from the AP. For IBSS this occurs when |
| 51 | * we receive a probe response or a beacon from target IBSS network. For | 51 | * get to know about a peer on the same IBSS. For WDS we add the sta for |
| 52 | * WDS we add the sta for the peer imediately upon device open. When using | 52 | * the peer imediately upon device open. When using AP mode we add stations |
| 53 | * AP mode we add stations for each respective station upon request from | 53 | * for each respective station upon request from userspace through nl80211. |
| 54 | * userspace through nl80211. | ||
| 55 | * | 54 | * |
| 56 | * Because there are debugfs entries for each station, and adding those | 55 | * In order to remove a STA info structure, various sta_info_destroy_*() |
| 57 | * must be able to sleep, it is also possible to "pin" a station entry, | 56 | * calls are available. |
| 58 | * that means it can be removed from the hash table but not be freed. | ||
| 59 | * See the comment in __sta_info_unlink() for more information, this is | ||
| 60 | * an internal capability only. | ||
| 61 | * | 57 | * |
| 62 | * In order to remove a STA info structure, the caller needs to first | 58 | * There is no concept of ownership on a STA entry, each structure is |
| 63 | * unlink it (sta_info_unlink()) from the list and hash tables and | 59 | * owned by the global hash table/list until it is removed. All users of |
| 64 | * then destroy it; sta_info_destroy() will wait for an RCU grace period | 60 | * the structure need to be RCU protected so that the structure won't be |
| 65 | * to elapse before actually freeing it. Due to the pinning and the | 61 | * freed before they are done using it. |
| 66 | * possibility of multiple callers trying to remove the same STA info at | ||
| 67 | * the same time, sta_info_unlink() can clear the STA info pointer it is | ||
| 68 | * passed to indicate that the STA info is owned by somebody else now. | ||
| 69 | * | ||
| 70 | * If sta_info_unlink() did not clear the pointer then the caller owns | ||
| 71 | * the STA info structure now and is responsible of destroying it with | ||
| 72 | * a call to sta_info_destroy(). | ||
| 73 | * | ||
| 74 | * In all other cases, there is no concept of ownership on a STA entry, | ||
| 75 | * each structure is owned by the global hash table/list until it is | ||
| 76 | * removed. All users of the structure need to be RCU protected so that | ||
| 77 | * the structure won't be freed before they are done using it. | ||
| 78 | */ | 62 | */ |
| 79 | 63 | ||
| 80 | /* Caller must hold local->sta_lock */ | 64 | /* Caller must hold local->sta_lock */ |
| @@ -103,13 +87,37 @@ static int sta_info_hash_del(struct ieee80211_local *local, | |||
| 103 | } | 87 | } |
| 104 | 88 | ||
| 105 | /* protected by RCU */ | 89 | /* protected by RCU */ |
| 106 | struct sta_info *sta_info_get(struct ieee80211_local *local, const u8 *addr) | 90 | struct sta_info *sta_info_get(struct ieee80211_sub_if_data *sdata, |
| 91 | const u8 *addr) | ||
| 107 | { | 92 | { |
| 93 | struct ieee80211_local *local = sdata->local; | ||
| 108 | struct sta_info *sta; | 94 | struct sta_info *sta; |
| 109 | 95 | ||
| 110 | sta = rcu_dereference(local->sta_hash[STA_HASH(addr)]); | 96 | sta = rcu_dereference(local->sta_hash[STA_HASH(addr)]); |
| 111 | while (sta) { | 97 | while (sta) { |
| 112 | if (memcmp(sta->sta.addr, addr, ETH_ALEN) == 0) | 98 | if (sta->sdata == sdata && |
| 99 | memcmp(sta->sta.addr, addr, ETH_ALEN) == 0) | ||
| 100 | break; | ||
| 101 | sta = rcu_dereference(sta->hnext); | ||
| 102 | } | ||
| 103 | return sta; | ||
| 104 | } | ||
| 105 | |||
| 106 | /* | ||
| 107 | * Get sta info either from the specified interface | ||
| 108 | * or from one of its vlans | ||
| 109 | */ | ||
| 110 | struct sta_info *sta_info_get_bss(struct ieee80211_sub_if_data *sdata, | ||
| 111 | const u8 *addr) | ||
| 112 | { | ||
| 113 | struct ieee80211_local *local = sdata->local; | ||
| 114 | struct sta_info *sta; | ||
| 115 | |||
| 116 | sta = rcu_dereference(local->sta_hash[STA_HASH(addr)]); | ||
| 117 | while (sta) { | ||
| 118 | if ((sta->sdata == sdata || | ||
| 119 | sta->sdata->bss == sdata->bss) && | ||
| 120 | memcmp(sta->sta.addr, addr, ETH_ALEN) == 0) | ||
| 113 | break; | 121 | break; |
| 114 | sta = rcu_dereference(sta->hnext); | 122 | sta = rcu_dereference(sta->hnext); |
| 115 | } | 123 | } |
| @@ -161,101 +169,6 @@ static void __sta_info_free(struct ieee80211_local *local, | |||
| 161 | kfree(sta); | 169 | kfree(sta); |
| 162 | } | 170 | } |
| 163 | 171 | ||
| 164 | void sta_info_destroy(struct sta_info *sta) | ||
| 165 | { | ||
| 166 | struct ieee80211_local *local; | ||
| 167 | struct sk_buff *skb; | ||
| 168 | int i; | ||
| 169 | |||
| 170 | might_sleep(); | ||
| 171 | |||
| 172 | if (!sta) | ||
| 173 | return; | ||
| 174 | |||
| 175 | local = sta->local; | ||
| 176 | |||
| 177 | cancel_work_sync(&sta->drv_unblock_wk); | ||
| 178 | |||
| 179 | rate_control_remove_sta_debugfs(sta); | ||
| 180 | ieee80211_sta_debugfs_remove(sta); | ||
| 181 | |||
| 182 | #ifdef CONFIG_MAC80211_MESH | ||
| 183 | if (ieee80211_vif_is_mesh(&sta->sdata->vif)) | ||
| 184 | mesh_plink_deactivate(sta); | ||
| 185 | #endif | ||
| 186 | |||
| 187 | /* | ||
| 188 | * We have only unlinked the key, and actually destroying it | ||
| 189 | * may mean it is removed from hardware which requires that | ||
| 190 | * the key->sta pointer is still valid, so flush the key todo | ||
| 191 | * list here. | ||
| 192 | * | ||
| 193 | * ieee80211_key_todo() will synchronize_rcu() so after this | ||
| 194 | * nothing can reference this sta struct any more. | ||
| 195 | */ | ||
| 196 | ieee80211_key_todo(); | ||
| 197 | |||
| 198 | #ifdef CONFIG_MAC80211_MESH | ||
| 199 | if (ieee80211_vif_is_mesh(&sta->sdata->vif)) | ||
| 200 | del_timer_sync(&sta->plink_timer); | ||
| 201 | #endif | ||
| 202 | |||
| 203 | while ((skb = skb_dequeue(&sta->ps_tx_buf)) != NULL) { | ||
| 204 | local->total_ps_buffered--; | ||
| 205 | dev_kfree_skb_any(skb); | ||
| 206 | } | ||
| 207 | |||
| 208 | while ((skb = skb_dequeue(&sta->tx_filtered)) != NULL) | ||
| 209 | dev_kfree_skb_any(skb); | ||
| 210 | |||
| 211 | for (i = 0; i < STA_TID_NUM; i++) { | ||
| 212 | struct tid_ampdu_rx *tid_rx; | ||
| 213 | struct tid_ampdu_tx *tid_tx; | ||
| 214 | |||
| 215 | spin_lock_bh(&sta->lock); | ||
| 216 | tid_rx = sta->ampdu_mlme.tid_rx[i]; | ||
| 217 | /* Make sure timer won't free the tid_rx struct, see below */ | ||
| 218 | if (tid_rx) | ||
| 219 | tid_rx->shutdown = true; | ||
| 220 | |||
| 221 | spin_unlock_bh(&sta->lock); | ||
| 222 | |||
| 223 | /* | ||
| 224 | * Outside spinlock - shutdown is true now so that the timer | ||
| 225 | * won't free tid_rx, we have to do that now. Can't let the | ||
| 226 | * timer do it because we have to sync the timer outside the | ||
| 227 | * lock that it takes itself. | ||
| 228 | */ | ||
| 229 | if (tid_rx) { | ||
| 230 | del_timer_sync(&tid_rx->session_timer); | ||
| 231 | kfree(tid_rx); | ||
| 232 | } | ||
| 233 | |||
| 234 | /* | ||
| 235 | * No need to do such complications for TX agg sessions, the | ||
| 236 | * path leading to freeing the tid_tx struct goes via a call | ||
| 237 | * from the driver, and thus needs to look up the sta struct | ||
| 238 | * again, which cannot be found when we get here. Hence, we | ||
| 239 | * just need to delete the timer and free the aggregation | ||
| 240 | * info; we won't be telling the peer about it then but that | ||
| 241 | * doesn't matter if we're not talking to it again anyway. | ||
| 242 | */ | ||
| 243 | tid_tx = sta->ampdu_mlme.tid_tx[i]; | ||
| 244 | if (tid_tx) { | ||
| 245 | del_timer_sync(&tid_tx->addba_resp_timer); | ||
| 246 | /* | ||
| 247 | * STA removed while aggregation session being | ||
| 248 | * started? Bit odd, but purge frames anyway. | ||
| 249 | */ | ||
| 250 | skb_queue_purge(&tid_tx->pending); | ||
| 251 | kfree(tid_tx); | ||
| 252 | } | ||
| 253 | } | ||
| 254 | |||
| 255 | __sta_info_free(local, sta); | ||
| 256 | } | ||
| 257 | |||
| 258 | |||
| 259 | /* Caller must hold local->sta_lock */ | 172 | /* Caller must hold local->sta_lock */ |
| 260 | static void sta_info_hash_add(struct ieee80211_local *local, | 173 | static void sta_info_hash_add(struct ieee80211_local *local, |
| 261 | struct sta_info *sta) | 174 | struct sta_info *sta) |
| @@ -352,7 +265,93 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, | |||
| 352 | return sta; | 265 | return sta; |
| 353 | } | 266 | } |
| 354 | 267 | ||
| 355 | int sta_info_insert(struct sta_info *sta) | 268 | static int sta_info_finish_insert(struct sta_info *sta, bool async) |
| 269 | { | ||
| 270 | struct ieee80211_local *local = sta->local; | ||
| 271 | struct ieee80211_sub_if_data *sdata = sta->sdata; | ||
| 272 | struct station_info sinfo; | ||
| 273 | unsigned long flags; | ||
| 274 | int err = 0; | ||
| 275 | |||
| 276 | WARN_ON(!mutex_is_locked(&local->sta_mtx)); | ||
| 277 | |||
| 278 | /* notify driver */ | ||
| 279 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | ||
| 280 | sdata = container_of(sdata->bss, | ||
| 281 | struct ieee80211_sub_if_data, | ||
| 282 | u.ap); | ||
| 283 | err = drv_sta_add(local, sdata, &sta->sta); | ||
| 284 | if (err) { | ||
| 285 | if (!async) | ||
| 286 | return err; | ||
| 287 | printk(KERN_DEBUG "%s: failed to add IBSS STA %pM to driver (%d)" | ||
| 288 | " - keeping it anyway.\n", | ||
| 289 | sdata->name, sta->sta.addr, err); | ||
| 290 | } else { | ||
| 291 | sta->uploaded = true; | ||
| 292 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | ||
| 293 | if (async) | ||
| 294 | printk(KERN_DEBUG "%s: Finished adding IBSS STA %pM\n", | ||
| 295 | wiphy_name(local->hw.wiphy), sta->sta.addr); | ||
| 296 | #endif | ||
| 297 | } | ||
| 298 | |||
| 299 | sdata = sta->sdata; | ||
| 300 | |||
| 301 | if (!async) { | ||
| 302 | local->num_sta++; | ||
| 303 | local->sta_generation++; | ||
| 304 | smp_mb(); | ||
| 305 | |||
| 306 | /* make the station visible */ | ||
| 307 | spin_lock_irqsave(&local->sta_lock, flags); | ||
| 308 | sta_info_hash_add(local, sta); | ||
| 309 | spin_unlock_irqrestore(&local->sta_lock, flags); | ||
| 310 | } | ||
| 311 | |||
| 312 | list_add(&sta->list, &local->sta_list); | ||
| 313 | |||
| 314 | ieee80211_sta_debugfs_add(sta); | ||
| 315 | rate_control_add_sta_debugfs(sta); | ||
| 316 | |||
| 317 | sinfo.filled = 0; | ||
| 318 | sinfo.generation = local->sta_generation; | ||
| 319 | cfg80211_new_sta(sdata->dev, sta->sta.addr, &sinfo, GFP_KERNEL); | ||
| 320 | |||
| 321 | |||
| 322 | return 0; | ||
| 323 | } | ||
| 324 | |||
| 325 | static void sta_info_finish_pending(struct ieee80211_local *local) | ||
| 326 | { | ||
| 327 | struct sta_info *sta; | ||
| 328 | unsigned long flags; | ||
| 329 | |||
| 330 | spin_lock_irqsave(&local->sta_lock, flags); | ||
| 331 | while (!list_empty(&local->sta_pending_list)) { | ||
| 332 | sta = list_first_entry(&local->sta_pending_list, | ||
| 333 | struct sta_info, list); | ||
| 334 | list_del(&sta->list); | ||
| 335 | spin_unlock_irqrestore(&local->sta_lock, flags); | ||
| 336 | |||
| 337 | sta_info_finish_insert(sta, true); | ||
| 338 | |||
| 339 | spin_lock_irqsave(&local->sta_lock, flags); | ||
| 340 | } | ||
| 341 | spin_unlock_irqrestore(&local->sta_lock, flags); | ||
| 342 | } | ||
| 343 | |||
| 344 | static void sta_info_finish_work(struct work_struct *work) | ||
| 345 | { | ||
| 346 | struct ieee80211_local *local = | ||
| 347 | container_of(work, struct ieee80211_local, sta_finish_work); | ||
| 348 | |||
| 349 | mutex_lock(&local->sta_mtx); | ||
| 350 | sta_info_finish_pending(local); | ||
| 351 | mutex_unlock(&local->sta_mtx); | ||
| 352 | } | ||
| 353 | |||
| 354 | int sta_info_insert_rcu(struct sta_info *sta) __acquires(RCU) | ||
| 356 | { | 355 | { |
| 357 | struct ieee80211_local *local = sta->local; | 356 | struct ieee80211_local *local = sta->local; |
| 358 | struct ieee80211_sub_if_data *sdata = sta->sdata; | 357 | struct ieee80211_sub_if_data *sdata = sta->sdata; |
| @@ -364,38 +363,90 @@ int sta_info_insert(struct sta_info *sta) | |||
| 364 | * something inserts a STA (on one CPU) without holding the RTNL | 363 | * something inserts a STA (on one CPU) without holding the RTNL |
| 365 | * and another CPU turns off the net device. | 364 | * and another CPU turns off the net device. |
| 366 | */ | 365 | */ |
| 367 | if (unlikely(!netif_running(sdata->dev))) { | 366 | if (unlikely(!ieee80211_sdata_running(sdata))) { |
| 368 | err = -ENETDOWN; | 367 | err = -ENETDOWN; |
| 368 | rcu_read_lock(); | ||
| 369 | goto out_free; | 369 | goto out_free; |
| 370 | } | 370 | } |
| 371 | 371 | ||
| 372 | if (WARN_ON(compare_ether_addr(sta->sta.addr, sdata->dev->dev_addr) == 0 || | 372 | if (WARN_ON(compare_ether_addr(sta->sta.addr, sdata->vif.addr) == 0 || |
| 373 | is_multicast_ether_addr(sta->sta.addr))) { | 373 | is_multicast_ether_addr(sta->sta.addr))) { |
| 374 | err = -EINVAL; | 374 | err = -EINVAL; |
| 375 | rcu_read_lock(); | ||
| 375 | goto out_free; | 376 | goto out_free; |
| 376 | } | 377 | } |
| 377 | 378 | ||
| 379 | /* | ||
| 380 | * In ad-hoc mode, we sometimes need to insert stations | ||
| 381 | * from tasklet context from the RX path. To avoid races, | ||
| 382 | * always do so in that case -- see the comment below. | ||
| 383 | */ | ||
| 384 | if (sdata->vif.type == NL80211_IFTYPE_ADHOC) { | ||
| 385 | spin_lock_irqsave(&local->sta_lock, flags); | ||
| 386 | /* check if STA exists already */ | ||
| 387 | if (sta_info_get_bss(sdata, sta->sta.addr)) { | ||
| 388 | spin_unlock_irqrestore(&local->sta_lock, flags); | ||
| 389 | rcu_read_lock(); | ||
| 390 | err = -EEXIST; | ||
| 391 | goto out_free; | ||
| 392 | } | ||
| 393 | |||
| 394 | local->num_sta++; | ||
| 395 | local->sta_generation++; | ||
| 396 | smp_mb(); | ||
| 397 | sta_info_hash_add(local, sta); | ||
| 398 | |||
| 399 | list_add_tail(&sta->list, &local->sta_pending_list); | ||
| 400 | |||
| 401 | rcu_read_lock(); | ||
| 402 | spin_unlock_irqrestore(&local->sta_lock, flags); | ||
| 403 | |||
| 404 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | ||
| 405 | printk(KERN_DEBUG "%s: Added IBSS STA %pM\n", | ||
| 406 | wiphy_name(local->hw.wiphy), sta->sta.addr); | ||
| 407 | #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ | ||
| 408 | |||
| 409 | ieee80211_queue_work(&local->hw, &local->sta_finish_work); | ||
| 410 | |||
| 411 | return 0; | ||
| 412 | } | ||
| 413 | |||
| 414 | /* | ||
| 415 | * On first glance, this will look racy, because the code | ||
| 416 | * below this point, which inserts a station with sleeping, | ||
| 417 | * unlocks the sta_lock between checking existence in the | ||
| 418 | * hash table and inserting into it. | ||
| 419 | * | ||
| 420 | * However, it is not racy against itself because it keeps | ||
| 421 | * the mutex locked. It still seems to race against the | ||
| 422 | * above code that atomically inserts the station... That, | ||
| 423 | * however, is not true because the above code can only | ||
| 424 | * be invoked for IBSS interfaces, and the below code will | ||
| 425 | * not be -- and the two do not race against each other as | ||
| 426 | * the hash table also keys off the interface. | ||
| 427 | */ | ||
| 428 | |||
| 429 | might_sleep(); | ||
| 430 | |||
| 431 | mutex_lock(&local->sta_mtx); | ||
| 432 | |||
| 378 | spin_lock_irqsave(&local->sta_lock, flags); | 433 | spin_lock_irqsave(&local->sta_lock, flags); |
| 379 | /* check if STA exists already */ | 434 | /* check if STA exists already */ |
| 380 | if (sta_info_get(local, sta->sta.addr)) { | 435 | if (sta_info_get_bss(sdata, sta->sta.addr)) { |
| 381 | spin_unlock_irqrestore(&local->sta_lock, flags); | 436 | spin_unlock_irqrestore(&local->sta_lock, flags); |
| 437 | mutex_unlock(&local->sta_mtx); | ||
| 438 | rcu_read_lock(); | ||
| 382 | err = -EEXIST; | 439 | err = -EEXIST; |
| 383 | goto out_free; | 440 | goto out_free; |
| 384 | } | 441 | } |
| 385 | list_add(&sta->list, &local->sta_list); | ||
| 386 | local->sta_generation++; | ||
| 387 | local->num_sta++; | ||
| 388 | sta_info_hash_add(local, sta); | ||
| 389 | 442 | ||
| 390 | /* notify driver */ | 443 | spin_unlock_irqrestore(&local->sta_lock, flags); |
| 391 | if (local->ops->sta_notify) { | ||
| 392 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | ||
| 393 | sdata = container_of(sdata->bss, | ||
| 394 | struct ieee80211_sub_if_data, | ||
| 395 | u.ap); | ||
| 396 | 444 | ||
| 397 | drv_sta_notify(local, &sdata->vif, STA_NOTIFY_ADD, &sta->sta); | 445 | err = sta_info_finish_insert(sta, false); |
| 398 | sdata = sta->sdata; | 446 | if (err) { |
| 447 | mutex_unlock(&local->sta_mtx); | ||
| 448 | rcu_read_lock(); | ||
| 449 | goto out_free; | ||
| 399 | } | 450 | } |
| 400 | 451 | ||
| 401 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | 452 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG |
| @@ -403,18 +454,9 @@ int sta_info_insert(struct sta_info *sta) | |||
| 403 | wiphy_name(local->hw.wiphy), sta->sta.addr); | 454 | wiphy_name(local->hw.wiphy), sta->sta.addr); |
| 404 | #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ | 455 | #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ |
| 405 | 456 | ||
| 406 | spin_unlock_irqrestore(&local->sta_lock, flags); | 457 | /* move reference to rcu-protected */ |
| 407 | 458 | rcu_read_lock(); | |
| 408 | #ifdef CONFIG_MAC80211_DEBUGFS | 459 | mutex_unlock(&local->sta_mtx); |
| 409 | /* | ||
| 410 | * Debugfs entry adding might sleep, so schedule process | ||
| 411 | * context task for adding entry for STAs that do not yet | ||
| 412 | * have one. | ||
| 413 | * NOTE: due to auto-freeing semantics this may only be done | ||
| 414 | * if the insertion is successful! | ||
| 415 | */ | ||
| 416 | schedule_work(&local->sta_debugfs_add); | ||
| 417 | #endif | ||
| 418 | 460 | ||
| 419 | if (ieee80211_vif_is_mesh(&sdata->vif)) | 461 | if (ieee80211_vif_is_mesh(&sdata->vif)) |
| 420 | mesh_accept_plinks_update(sdata); | 462 | mesh_accept_plinks_update(sdata); |
| @@ -426,6 +468,15 @@ int sta_info_insert(struct sta_info *sta) | |||
| 426 | return err; | 468 | return err; |
| 427 | } | 469 | } |
| 428 | 470 | ||
| 471 | int sta_info_insert(struct sta_info *sta) | ||
| 472 | { | ||
| 473 | int err = sta_info_insert_rcu(sta); | ||
| 474 | |||
| 475 | rcu_read_unlock(); | ||
| 476 | |||
| 477 | return err; | ||
| 478 | } | ||
| 479 | |||
| 429 | static inline void __bss_tim_set(struct ieee80211_if_ap *bss, u16 aid) | 480 | static inline void __bss_tim_set(struct ieee80211_if_ap *bss, u16 aid) |
| 430 | { | 481 | { |
| 431 | /* | 482 | /* |
| @@ -494,108 +545,6 @@ void sta_info_clear_tim_bit(struct sta_info *sta) | |||
| 494 | spin_unlock_irqrestore(&sta->local->sta_lock, flags); | 545 | spin_unlock_irqrestore(&sta->local->sta_lock, flags); |
| 495 | } | 546 | } |
| 496 | 547 | ||
| 497 | static void __sta_info_unlink(struct sta_info **sta) | ||
| 498 | { | ||
| 499 | struct ieee80211_local *local = (*sta)->local; | ||
| 500 | struct ieee80211_sub_if_data *sdata = (*sta)->sdata; | ||
| 501 | /* | ||
| 502 | * pull caller's reference if we're already gone. | ||
| 503 | */ | ||
| 504 | if (sta_info_hash_del(local, *sta)) { | ||
| 505 | *sta = NULL; | ||
| 506 | return; | ||
| 507 | } | ||
| 508 | |||
| 509 | if ((*sta)->key) { | ||
| 510 | ieee80211_key_free((*sta)->key); | ||
| 511 | WARN_ON((*sta)->key); | ||
| 512 | } | ||
| 513 | |||
| 514 | list_del(&(*sta)->list); | ||
| 515 | (*sta)->dead = true; | ||
| 516 | |||
| 517 | if (test_and_clear_sta_flags(*sta, | ||
| 518 | WLAN_STA_PS_STA | WLAN_STA_PS_DRIVER)) { | ||
| 519 | BUG_ON(!sdata->bss); | ||
| 520 | |||
| 521 | atomic_dec(&sdata->bss->num_sta_ps); | ||
| 522 | __sta_info_clear_tim_bit(sdata->bss, *sta); | ||
| 523 | } | ||
| 524 | |||
| 525 | local->num_sta--; | ||
| 526 | local->sta_generation++; | ||
| 527 | |||
| 528 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | ||
| 529 | rcu_assign_pointer(sdata->u.vlan.sta, NULL); | ||
| 530 | |||
| 531 | if (local->ops->sta_notify) { | ||
| 532 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | ||
| 533 | sdata = container_of(sdata->bss, | ||
| 534 | struct ieee80211_sub_if_data, | ||
| 535 | u.ap); | ||
| 536 | |||
| 537 | drv_sta_notify(local, &sdata->vif, STA_NOTIFY_REMOVE, | ||
| 538 | &(*sta)->sta); | ||
| 539 | sdata = (*sta)->sdata; | ||
| 540 | } | ||
| 541 | |||
| 542 | if (ieee80211_vif_is_mesh(&sdata->vif)) { | ||
| 543 | mesh_accept_plinks_update(sdata); | ||
| 544 | #ifdef CONFIG_MAC80211_MESH | ||
| 545 | del_timer(&(*sta)->plink_timer); | ||
| 546 | #endif | ||
| 547 | } | ||
| 548 | |||
| 549 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | ||
| 550 | printk(KERN_DEBUG "%s: Removed STA %pM\n", | ||
| 551 | wiphy_name(local->hw.wiphy), (*sta)->sta.addr); | ||
| 552 | #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ | ||
| 553 | |||
| 554 | /* | ||
| 555 | * Finally, pull caller's reference if the STA is pinned by the | ||
| 556 | * task that is adding the debugfs entries. In that case, we | ||
| 557 | * leave the STA "to be freed". | ||
| 558 | * | ||
| 559 | * The rules are not trivial, but not too complex either: | ||
| 560 | * (1) pin_status is only modified under the sta_lock | ||
| 561 | * (2) STAs may only be pinned under the RTNL so that | ||
| 562 | * sta_info_flush() is guaranteed to actually destroy | ||
| 563 | * all STAs that are active for a given interface, this | ||
| 564 | * is required for correctness because otherwise we | ||
| 565 | * could notify a driver that an interface is going | ||
| 566 | * away and only after that (!) notify it about a STA | ||
| 567 | * on that interface going away. | ||
| 568 | * (3) sta_info_debugfs_add_work() will set the status | ||
| 569 | * to PINNED when it found an item that needs a new | ||
| 570 | * debugfs directory created. In that case, that item | ||
| 571 | * must not be freed although all *RCU* users are done | ||
| 572 | * with it. Hence, we tell the caller of _unlink() | ||
| 573 | * that the item is already gone (as can happen when | ||
| 574 | * two tasks try to unlink/destroy at the same time) | ||
| 575 | * (4) We set the pin_status to DESTROY here when we | ||
| 576 | * find such an item. | ||
| 577 | * (5) sta_info_debugfs_add_work() will reset the pin_status | ||
| 578 | * from PINNED to NORMAL when it is done with the item, | ||
| 579 | * but will check for DESTROY before resetting it in | ||
| 580 | * which case it will free the item. | ||
| 581 | */ | ||
| 582 | if ((*sta)->pin_status == STA_INFO_PIN_STAT_PINNED) { | ||
| 583 | (*sta)->pin_status = STA_INFO_PIN_STAT_DESTROY; | ||
| 584 | *sta = NULL; | ||
| 585 | return; | ||
| 586 | } | ||
| 587 | } | ||
| 588 | |||
| 589 | void sta_info_unlink(struct sta_info **sta) | ||
| 590 | { | ||
| 591 | struct ieee80211_local *local = (*sta)->local; | ||
| 592 | unsigned long flags; | ||
| 593 | |||
| 594 | spin_lock_irqsave(&local->sta_lock, flags); | ||
| 595 | __sta_info_unlink(sta); | ||
| 596 | spin_unlock_irqrestore(&local->sta_lock, flags); | ||
| 597 | } | ||
| 598 | |||
| 599 | static int sta_info_buffer_expired(struct sta_info *sta, | 548 | static int sta_info_buffer_expired(struct sta_info *sta, |
| 600 | struct sk_buff *skb) | 549 | struct sk_buff *skb) |
| 601 | { | 550 | { |
| @@ -652,109 +601,209 @@ static void sta_info_cleanup_expire_buffered(struct ieee80211_local *local, | |||
| 652 | } | 601 | } |
| 653 | } | 602 | } |
| 654 | 603 | ||
| 655 | 604 | static int __must_check __sta_info_destroy(struct sta_info *sta) | |
| 656 | static void sta_info_cleanup(unsigned long data) | ||
| 657 | { | 605 | { |
| 658 | struct ieee80211_local *local = (struct ieee80211_local *) data; | 606 | struct ieee80211_local *local; |
| 659 | struct sta_info *sta; | 607 | struct ieee80211_sub_if_data *sdata; |
| 608 | struct sk_buff *skb; | ||
| 609 | unsigned long flags; | ||
| 610 | int ret, i; | ||
| 660 | 611 | ||
| 661 | rcu_read_lock(); | 612 | might_sleep(); |
| 662 | list_for_each_entry_rcu(sta, &local->sta_list, list) | ||
| 663 | sta_info_cleanup_expire_buffered(local, sta); | ||
| 664 | rcu_read_unlock(); | ||
| 665 | 613 | ||
| 666 | if (local->quiescing) | 614 | if (!sta) |
| 667 | return; | 615 | return -ENOENT; |
| 668 | 616 | ||
| 669 | local->sta_cleanup.expires = | 617 | local = sta->local; |
| 670 | round_jiffies(jiffies + STA_INFO_CLEANUP_INTERVAL); | 618 | sdata = sta->sdata; |
| 671 | add_timer(&local->sta_cleanup); | ||
| 672 | } | ||
| 673 | 619 | ||
| 674 | #ifdef CONFIG_MAC80211_DEBUGFS | 620 | spin_lock_irqsave(&local->sta_lock, flags); |
| 675 | /* | 621 | ret = sta_info_hash_del(local, sta); |
| 676 | * See comment in __sta_info_unlink, | 622 | /* this might still be the pending list ... which is fine */ |
| 677 | * caller must hold local->sta_lock. | 623 | if (!ret) |
| 678 | */ | 624 | list_del(&sta->list); |
| 679 | static void __sta_info_pin(struct sta_info *sta) | 625 | spin_unlock_irqrestore(&local->sta_lock, flags); |
| 680 | { | 626 | if (ret) |
| 681 | WARN_ON(sta->pin_status != STA_INFO_PIN_STAT_NORMAL); | 627 | return ret; |
| 682 | sta->pin_status = STA_INFO_PIN_STAT_PINNED; | 628 | |
| 629 | if (sta->key) { | ||
| 630 | ieee80211_key_free(sta->key); | ||
| 631 | /* | ||
| 632 | * We have only unlinked the key, and actually destroying it | ||
| 633 | * may mean it is removed from hardware which requires that | ||
| 634 | * the key->sta pointer is still valid, so flush the key todo | ||
| 635 | * list here. | ||
| 636 | * | ||
| 637 | * ieee80211_key_todo() will synchronize_rcu() so after this | ||
| 638 | * nothing can reference this sta struct any more. | ||
| 639 | */ | ||
| 640 | ieee80211_key_todo(); | ||
| 641 | |||
| 642 | WARN_ON(sta->key); | ||
| 643 | } | ||
| 644 | |||
| 645 | sta->dead = true; | ||
| 646 | |||
| 647 | if (test_and_clear_sta_flags(sta, | ||
| 648 | WLAN_STA_PS_STA | WLAN_STA_PS_DRIVER)) { | ||
| 649 | BUG_ON(!sdata->bss); | ||
| 650 | |||
| 651 | atomic_dec(&sdata->bss->num_sta_ps); | ||
| 652 | __sta_info_clear_tim_bit(sdata->bss, sta); | ||
| 653 | } | ||
| 654 | |||
| 655 | local->num_sta--; | ||
| 656 | local->sta_generation++; | ||
| 657 | |||
| 658 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | ||
| 659 | rcu_assign_pointer(sdata->u.vlan.sta, NULL); | ||
| 660 | |||
| 661 | if (sta->uploaded) { | ||
| 662 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | ||
| 663 | sdata = container_of(sdata->bss, | ||
| 664 | struct ieee80211_sub_if_data, | ||
| 665 | u.ap); | ||
| 666 | drv_sta_remove(local, sdata, &sta->sta); | ||
| 667 | sdata = sta->sdata; | ||
| 668 | } | ||
| 669 | |||
| 670 | #ifdef CONFIG_MAC80211_MESH | ||
| 671 | if (ieee80211_vif_is_mesh(&sdata->vif)) { | ||
| 672 | mesh_accept_plinks_update(sdata); | ||
| 673 | del_timer(&sta->plink_timer); | ||
| 674 | } | ||
| 675 | #endif | ||
| 676 | |||
| 677 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | ||
| 678 | printk(KERN_DEBUG "%s: Removed STA %pM\n", | ||
| 679 | wiphy_name(local->hw.wiphy), sta->sta.addr); | ||
| 680 | #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ | ||
| 681 | cancel_work_sync(&sta->drv_unblock_wk); | ||
| 682 | |||
| 683 | rate_control_remove_sta_debugfs(sta); | ||
| 684 | ieee80211_sta_debugfs_remove(sta); | ||
| 685 | |||
| 686 | #ifdef CONFIG_MAC80211_MESH | ||
| 687 | if (ieee80211_vif_is_mesh(&sta->sdata->vif)) { | ||
| 688 | mesh_plink_deactivate(sta); | ||
| 689 | del_timer_sync(&sta->plink_timer); | ||
| 690 | } | ||
| 691 | #endif | ||
| 692 | |||
| 693 | while ((skb = skb_dequeue(&sta->ps_tx_buf)) != NULL) { | ||
| 694 | local->total_ps_buffered--; | ||
| 695 | dev_kfree_skb_any(skb); | ||
| 696 | } | ||
| 697 | |||
| 698 | while ((skb = skb_dequeue(&sta->tx_filtered)) != NULL) | ||
| 699 | dev_kfree_skb_any(skb); | ||
| 700 | |||
| 701 | for (i = 0; i < STA_TID_NUM; i++) { | ||
| 702 | struct tid_ampdu_rx *tid_rx; | ||
| 703 | struct tid_ampdu_tx *tid_tx; | ||
| 704 | |||
| 705 | spin_lock_bh(&sta->lock); | ||
| 706 | tid_rx = sta->ampdu_mlme.tid_rx[i]; | ||
| 707 | /* Make sure timer won't free the tid_rx struct, see below */ | ||
| 708 | if (tid_rx) | ||
| 709 | tid_rx->shutdown = true; | ||
| 710 | |||
| 711 | spin_unlock_bh(&sta->lock); | ||
| 712 | |||
| 713 | /* | ||
| 714 | * Outside spinlock - shutdown is true now so that the timer | ||
| 715 | * won't free tid_rx, we have to do that now. Can't let the | ||
| 716 | * timer do it because we have to sync the timer outside the | ||
| 717 | * lock that it takes itself. | ||
| 718 | */ | ||
| 719 | if (tid_rx) { | ||
| 720 | del_timer_sync(&tid_rx->session_timer); | ||
| 721 | kfree(tid_rx); | ||
| 722 | } | ||
| 723 | |||
| 724 | /* | ||
| 725 | * No need to do such complications for TX agg sessions, the | ||
| 726 | * path leading to freeing the tid_tx struct goes via a call | ||
| 727 | * from the driver, and thus needs to look up the sta struct | ||
| 728 | * again, which cannot be found when we get here. Hence, we | ||
| 729 | * just need to delete the timer and free the aggregation | ||
| 730 | * info; we won't be telling the peer about it then but that | ||
| 731 | * doesn't matter if we're not talking to it again anyway. | ||
| 732 | */ | ||
| 733 | tid_tx = sta->ampdu_mlme.tid_tx[i]; | ||
| 734 | if (tid_tx) { | ||
| 735 | del_timer_sync(&tid_tx->addba_resp_timer); | ||
| 736 | /* | ||
| 737 | * STA removed while aggregation session being | ||
| 738 | * started? Bit odd, but purge frames anyway. | ||
| 739 | */ | ||
| 740 | skb_queue_purge(&tid_tx->pending); | ||
| 741 | kfree(tid_tx); | ||
| 742 | } | ||
| 743 | } | ||
| 744 | |||
| 745 | __sta_info_free(local, sta); | ||
| 746 | |||
| 747 | return 0; | ||
| 683 | } | 748 | } |
| 684 | 749 | ||
| 685 | /* | 750 | int sta_info_destroy_addr(struct ieee80211_sub_if_data *sdata, const u8 *addr) |
| 686 | * See comment in __sta_info_unlink, returns sta if it | ||
| 687 | * needs to be destroyed. | ||
| 688 | */ | ||
| 689 | static struct sta_info *__sta_info_unpin(struct sta_info *sta) | ||
| 690 | { | 751 | { |
| 691 | struct sta_info *ret = NULL; | 752 | struct sta_info *sta; |
| 692 | unsigned long flags; | 753 | int ret; |
| 693 | 754 | ||
| 694 | spin_lock_irqsave(&sta->local->sta_lock, flags); | 755 | mutex_lock(&sdata->local->sta_mtx); |
| 695 | WARN_ON(sta->pin_status != STA_INFO_PIN_STAT_DESTROY && | 756 | sta = sta_info_get(sdata, addr); |
| 696 | sta->pin_status != STA_INFO_PIN_STAT_PINNED); | 757 | ret = __sta_info_destroy(sta); |
| 697 | if (sta->pin_status == STA_INFO_PIN_STAT_DESTROY) | 758 | mutex_unlock(&sdata->local->sta_mtx); |
| 698 | ret = sta; | ||
| 699 | sta->pin_status = STA_INFO_PIN_STAT_NORMAL; | ||
| 700 | spin_unlock_irqrestore(&sta->local->sta_lock, flags); | ||
| 701 | 759 | ||
| 702 | return ret; | 760 | return ret; |
| 703 | } | 761 | } |
| 704 | 762 | ||
| 705 | static void sta_info_debugfs_add_work(struct work_struct *work) | 763 | int sta_info_destroy_addr_bss(struct ieee80211_sub_if_data *sdata, |
| 764 | const u8 *addr) | ||
| 706 | { | 765 | { |
| 707 | struct ieee80211_local *local = | 766 | struct sta_info *sta; |
| 708 | container_of(work, struct ieee80211_local, sta_debugfs_add); | 767 | int ret; |
| 709 | struct sta_info *sta, *tmp; | ||
| 710 | unsigned long flags; | ||
| 711 | 768 | ||
| 712 | /* We need to keep the RTNL across the whole pinned status. */ | 769 | mutex_lock(&sdata->local->sta_mtx); |
| 713 | rtnl_lock(); | 770 | sta = sta_info_get_bss(sdata, addr); |
| 714 | while (1) { | 771 | ret = __sta_info_destroy(sta); |
| 715 | sta = NULL; | 772 | mutex_unlock(&sdata->local->sta_mtx); |
| 716 | 773 | ||
| 717 | spin_lock_irqsave(&local->sta_lock, flags); | 774 | return ret; |
| 718 | list_for_each_entry(tmp, &local->sta_list, list) { | 775 | } |
| 719 | /* | ||
| 720 | * debugfs.add_has_run will be set by | ||
| 721 | * ieee80211_sta_debugfs_add regardless | ||
| 722 | * of what else it does. | ||
| 723 | */ | ||
| 724 | if (!tmp->debugfs.add_has_run) { | ||
| 725 | sta = tmp; | ||
| 726 | __sta_info_pin(sta); | ||
| 727 | break; | ||
| 728 | } | ||
| 729 | } | ||
| 730 | spin_unlock_irqrestore(&local->sta_lock, flags); | ||
| 731 | 776 | ||
| 732 | if (!sta) | 777 | static void sta_info_cleanup(unsigned long data) |
| 733 | break; | 778 | { |
| 779 | struct ieee80211_local *local = (struct ieee80211_local *) data; | ||
| 780 | struct sta_info *sta; | ||
| 734 | 781 | ||
| 735 | ieee80211_sta_debugfs_add(sta); | 782 | rcu_read_lock(); |
| 736 | rate_control_add_sta_debugfs(sta); | 783 | list_for_each_entry_rcu(sta, &local->sta_list, list) |
| 784 | sta_info_cleanup_expire_buffered(local, sta); | ||
| 785 | rcu_read_unlock(); | ||
| 737 | 786 | ||
| 738 | sta = __sta_info_unpin(sta); | 787 | if (local->quiescing) |
| 739 | sta_info_destroy(sta); | 788 | return; |
| 740 | } | 789 | |
| 741 | rtnl_unlock(); | 790 | local->sta_cleanup.expires = |
| 791 | round_jiffies(jiffies + STA_INFO_CLEANUP_INTERVAL); | ||
| 792 | add_timer(&local->sta_cleanup); | ||
| 742 | } | 793 | } |
| 743 | #endif | ||
| 744 | 794 | ||
| 745 | void sta_info_init(struct ieee80211_local *local) | 795 | void sta_info_init(struct ieee80211_local *local) |
| 746 | { | 796 | { |
| 747 | spin_lock_init(&local->sta_lock); | 797 | spin_lock_init(&local->sta_lock); |
| 798 | mutex_init(&local->sta_mtx); | ||
| 748 | INIT_LIST_HEAD(&local->sta_list); | 799 | INIT_LIST_HEAD(&local->sta_list); |
| 800 | INIT_LIST_HEAD(&local->sta_pending_list); | ||
| 801 | INIT_WORK(&local->sta_finish_work, sta_info_finish_work); | ||
| 749 | 802 | ||
| 750 | setup_timer(&local->sta_cleanup, sta_info_cleanup, | 803 | setup_timer(&local->sta_cleanup, sta_info_cleanup, |
| 751 | (unsigned long)local); | 804 | (unsigned long)local); |
| 752 | local->sta_cleanup.expires = | 805 | local->sta_cleanup.expires = |
| 753 | round_jiffies(jiffies + STA_INFO_CLEANUP_INTERVAL); | 806 | round_jiffies(jiffies + STA_INFO_CLEANUP_INTERVAL); |
| 754 | |||
| 755 | #ifdef CONFIG_MAC80211_DEBUGFS | ||
| 756 | INIT_WORK(&local->sta_debugfs_add, sta_info_debugfs_add_work); | ||
| 757 | #endif | ||
| 758 | } | 807 | } |
| 759 | 808 | ||
| 760 | int sta_info_start(struct ieee80211_local *local) | 809 | int sta_info_start(struct ieee80211_local *local) |
| @@ -766,16 +815,6 @@ int sta_info_start(struct ieee80211_local *local) | |||
| 766 | void sta_info_stop(struct ieee80211_local *local) | 815 | void sta_info_stop(struct ieee80211_local *local) |
| 767 | { | 816 | { |
| 768 | del_timer(&local->sta_cleanup); | 817 | del_timer(&local->sta_cleanup); |
| 769 | #ifdef CONFIG_MAC80211_DEBUGFS | ||
| 770 | /* | ||
| 771 | * Make sure the debugfs adding work isn't pending after this | ||
| 772 | * because we're about to be destroyed. It doesn't matter | ||
| 773 | * whether it ran or not since we're going to flush all STAs | ||
| 774 | * anyway. | ||
| 775 | */ | ||
| 776 | cancel_work_sync(&local->sta_debugfs_add); | ||
| 777 | #endif | ||
| 778 | |||
| 779 | sta_info_flush(local, NULL); | 818 | sta_info_flush(local, NULL); |
| 780 | } | 819 | } |
| 781 | 820 | ||
| @@ -791,26 +830,19 @@ int sta_info_flush(struct ieee80211_local *local, | |||
| 791 | struct ieee80211_sub_if_data *sdata) | 830 | struct ieee80211_sub_if_data *sdata) |
| 792 | { | 831 | { |
| 793 | struct sta_info *sta, *tmp; | 832 | struct sta_info *sta, *tmp; |
| 794 | LIST_HEAD(tmp_list); | ||
| 795 | int ret = 0; | 833 | int ret = 0; |
| 796 | unsigned long flags; | ||
| 797 | 834 | ||
| 798 | might_sleep(); | 835 | might_sleep(); |
| 799 | 836 | ||
| 800 | spin_lock_irqsave(&local->sta_lock, flags); | 837 | mutex_lock(&local->sta_mtx); |
| 838 | |||
| 839 | sta_info_finish_pending(local); | ||
| 840 | |||
| 801 | list_for_each_entry_safe(sta, tmp, &local->sta_list, list) { | 841 | list_for_each_entry_safe(sta, tmp, &local->sta_list, list) { |
| 802 | if (!sdata || sdata == sta->sdata) { | 842 | if (!sdata || sdata == sta->sdata) |
| 803 | __sta_info_unlink(&sta); | 843 | WARN_ON(__sta_info_destroy(sta)); |
| 804 | if (sta) { | ||
| 805 | list_add_tail(&sta->list, &tmp_list); | ||
| 806 | ret++; | ||
| 807 | } | ||
| 808 | } | ||
| 809 | } | 844 | } |
| 810 | spin_unlock_irqrestore(&local->sta_lock, flags); | 845 | mutex_unlock(&local->sta_mtx); |
| 811 | |||
| 812 | list_for_each_entry_safe(sta, tmp, &tmp_list, list) | ||
| 813 | sta_info_destroy(sta); | ||
| 814 | 846 | ||
| 815 | return ret; | 847 | return ret; |
| 816 | } | 848 | } |
| @@ -820,34 +852,28 @@ void ieee80211_sta_expire(struct ieee80211_sub_if_data *sdata, | |||
| 820 | { | 852 | { |
| 821 | struct ieee80211_local *local = sdata->local; | 853 | struct ieee80211_local *local = sdata->local; |
| 822 | struct sta_info *sta, *tmp; | 854 | struct sta_info *sta, *tmp; |
| 823 | LIST_HEAD(tmp_list); | ||
| 824 | unsigned long flags; | ||
| 825 | 855 | ||
| 826 | spin_lock_irqsave(&local->sta_lock, flags); | 856 | mutex_lock(&local->sta_mtx); |
| 827 | list_for_each_entry_safe(sta, tmp, &local->sta_list, list) | 857 | list_for_each_entry_safe(sta, tmp, &local->sta_list, list) |
| 828 | if (time_after(jiffies, sta->last_rx + exp_time)) { | 858 | if (time_after(jiffies, sta->last_rx + exp_time)) { |
| 829 | #ifdef CONFIG_MAC80211_IBSS_DEBUG | 859 | #ifdef CONFIG_MAC80211_IBSS_DEBUG |
| 830 | printk(KERN_DEBUG "%s: expiring inactive STA %pM\n", | 860 | printk(KERN_DEBUG "%s: expiring inactive STA %pM\n", |
| 831 | sdata->dev->name, sta->sta.addr); | 861 | sdata->name, sta->sta.addr); |
| 832 | #endif | 862 | #endif |
| 833 | __sta_info_unlink(&sta); | 863 | WARN_ON(__sta_info_destroy(sta)); |
| 834 | if (sta) | ||
| 835 | list_add(&sta->list, &tmp_list); | ||
| 836 | } | 864 | } |
| 837 | spin_unlock_irqrestore(&local->sta_lock, flags); | 865 | mutex_unlock(&local->sta_mtx); |
| 838 | |||
| 839 | list_for_each_entry_safe(sta, tmp, &tmp_list, list) | ||
| 840 | sta_info_destroy(sta); | ||
| 841 | } | 866 | } |
| 842 | 867 | ||
| 843 | struct ieee80211_sta *ieee80211_find_sta_by_hw(struct ieee80211_hw *hw, | 868 | struct ieee80211_sta *ieee80211_find_sta_by_hw(struct ieee80211_hw *hw, |
| 844 | const u8 *addr) | 869 | const u8 *addr) |
| 845 | { | 870 | { |
| 846 | struct sta_info *sta = sta_info_get(hw_to_local(hw), addr); | 871 | struct sta_info *sta, *nxt; |
| 847 | 872 | ||
| 848 | if (!sta) | 873 | /* Just return a random station ... first in list ... */ |
| 849 | return NULL; | 874 | for_each_sta_info(hw_to_local(hw), addr, sta, nxt) |
| 850 | return &sta->sta; | 875 | return &sta->sta; |
| 876 | return NULL; | ||
| 851 | } | 877 | } |
| 852 | EXPORT_SYMBOL_GPL(ieee80211_find_sta_by_hw); | 878 | EXPORT_SYMBOL_GPL(ieee80211_find_sta_by_hw); |
| 853 | 879 | ||
| @@ -872,7 +898,7 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta) | |||
| 872 | struct ieee80211_local *local = sdata->local; | 898 | struct ieee80211_local *local = sdata->local; |
| 873 | int sent, buffered; | 899 | int sent, buffered; |
| 874 | 900 | ||
| 875 | drv_sta_notify(local, &sdata->vif, STA_NOTIFY_AWAKE, &sta->sta); | 901 | drv_sta_notify(local, sdata, STA_NOTIFY_AWAKE, &sta->sta); |
| 876 | 902 | ||
| 877 | if (!skb_queue_empty(&sta->ps_tx_buf)) | 903 | if (!skb_queue_empty(&sta->ps_tx_buf)) |
| 878 | sta_info_clear_tim_bit(sta); | 904 | sta_info_clear_tim_bit(sta); |
| @@ -885,7 +911,7 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta) | |||
| 885 | 911 | ||
| 886 | #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG | 912 | #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG |
| 887 | printk(KERN_DEBUG "%s: STA %pM aid %d sending %d filtered/%d PS frames " | 913 | printk(KERN_DEBUG "%s: STA %pM aid %d sending %d filtered/%d PS frames " |
| 888 | "since STA not sleeping anymore\n", sdata->dev->name, | 914 | "since STA not sleeping anymore\n", sdata->name, |
| 889 | sta->sta.addr, sta->sta.aid, sent - buffered, buffered); | 915 | sta->sta.addr, sta->sta.aid, sent - buffered, buffered); |
| 890 | #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ | 916 | #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ |
| 891 | } | 917 | } |
| @@ -944,7 +970,7 @@ void ieee80211_sta_ps_deliver_poll_response(struct sta_info *sta) | |||
| 944 | */ | 970 | */ |
| 945 | printk(KERN_DEBUG "%s: STA %pM sent PS Poll even " | 971 | printk(KERN_DEBUG "%s: STA %pM sent PS Poll even " |
| 946 | "though there are no buffered frames for it\n", | 972 | "though there are no buffered frames for it\n", |
| 947 | sdata->dev->name, sta->sta.addr); | 973 | sdata->name, sta->sta.addr); |
| 948 | #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ | 974 | #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ |
| 949 | } | 975 | } |
| 950 | } | 976 | } |
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index b4810f6aa94f..822d84522937 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h | |||
| @@ -42,6 +42,9 @@ | |||
| 42 | * be in the queues | 42 | * be in the queues |
| 43 | * @WLAN_STA_PSPOLL: Station sent PS-poll while driver was keeping | 43 | * @WLAN_STA_PSPOLL: Station sent PS-poll while driver was keeping |
| 44 | * station in power-save mode, reply when the driver unblocks. | 44 | * station in power-save mode, reply when the driver unblocks. |
| 45 | * @WLAN_STA_DISASSOC: Disassociation in progress. | ||
| 46 | * This is used to reject TX BA session requests when disassociation | ||
| 47 | * is in progress. | ||
| 45 | */ | 48 | */ |
| 46 | enum ieee80211_sta_info_flags { | 49 | enum ieee80211_sta_info_flags { |
| 47 | WLAN_STA_AUTH = 1<<0, | 50 | WLAN_STA_AUTH = 1<<0, |
| @@ -57,6 +60,7 @@ enum ieee80211_sta_info_flags { | |||
| 57 | WLAN_STA_SUSPEND = 1<<11, | 60 | WLAN_STA_SUSPEND = 1<<11, |
| 58 | WLAN_STA_PS_DRIVER = 1<<12, | 61 | WLAN_STA_PS_DRIVER = 1<<12, |
| 59 | WLAN_STA_PSPOLL = 1<<13, | 62 | WLAN_STA_PSPOLL = 1<<13, |
| 63 | WLAN_STA_DISASSOC = 1<<14, | ||
| 60 | }; | 64 | }; |
| 61 | 65 | ||
| 62 | #define STA_TID_NUM 16 | 66 | #define STA_TID_NUM 16 |
| @@ -162,11 +166,6 @@ struct sta_ampdu_mlme { | |||
| 162 | }; | 166 | }; |
| 163 | 167 | ||
| 164 | 168 | ||
| 165 | /* see __sta_info_unlink */ | ||
| 166 | #define STA_INFO_PIN_STAT_NORMAL 0 | ||
| 167 | #define STA_INFO_PIN_STAT_PINNED 1 | ||
| 168 | #define STA_INFO_PIN_STAT_DESTROY 2 | ||
| 169 | |||
| 170 | /** | 169 | /** |
| 171 | * struct sta_info - STA information | 170 | * struct sta_info - STA information |
| 172 | * | 171 | * |
| @@ -187,7 +186,6 @@ struct sta_ampdu_mlme { | |||
| 187 | * @flaglock: spinlock for flags accesses | 186 | * @flaglock: spinlock for flags accesses |
| 188 | * @drv_unblock_wk: used for driver PS unblocking | 187 | * @drv_unblock_wk: used for driver PS unblocking |
| 189 | * @listen_interval: listen interval of this station, when we're acting as AP | 188 | * @listen_interval: listen interval of this station, when we're acting as AP |
| 190 | * @pin_status: used internally for pinning a STA struct into memory | ||
| 191 | * @flags: STA flags, see &enum ieee80211_sta_info_flags | 189 | * @flags: STA flags, see &enum ieee80211_sta_info_flags |
| 192 | * @ps_tx_buf: buffer of frames to transmit to this station | 190 | * @ps_tx_buf: buffer of frames to transmit to this station |
| 193 | * when it leaves power saving state | 191 | * when it leaves power saving state |
| @@ -226,6 +224,7 @@ struct sta_ampdu_mlme { | |||
| 226 | * @debugfs: debug filesystem info | 224 | * @debugfs: debug filesystem info |
| 227 | * @sta: station information we share with the driver | 225 | * @sta: station information we share with the driver |
| 228 | * @dead: set to true when sta is unlinked | 226 | * @dead: set to true when sta is unlinked |
| 227 | * @uploaded: set to true when sta is uploaded to the driver | ||
| 229 | */ | 228 | */ |
| 230 | struct sta_info { | 229 | struct sta_info { |
| 231 | /* General information, mostly static */ | 230 | /* General information, mostly static */ |
| @@ -245,11 +244,7 @@ struct sta_info { | |||
| 245 | 244 | ||
| 246 | bool dead; | 245 | bool dead; |
| 247 | 246 | ||
| 248 | /* | 247 | bool uploaded; |
| 249 | * for use by the internal lifetime management, | ||
| 250 | * see __sta_info_unlink | ||
| 251 | */ | ||
| 252 | u8 pin_status; | ||
| 253 | 248 | ||
| 254 | /* | 249 | /* |
| 255 | * frequently updated, locked with own spinlock (flaglock), | 250 | * frequently updated, locked with own spinlock (flaglock), |
| @@ -403,9 +398,37 @@ static inline u32 get_sta_flags(struct sta_info *sta) | |||
| 403 | #define STA_INFO_CLEANUP_INTERVAL (10 * HZ) | 398 | #define STA_INFO_CLEANUP_INTERVAL (10 * HZ) |
| 404 | 399 | ||
| 405 | /* | 400 | /* |
| 406 | * Get a STA info, must have be under RCU read lock. | 401 | * Get a STA info, must be under RCU read lock. |
| 407 | */ | 402 | */ |
| 408 | struct sta_info *sta_info_get(struct ieee80211_local *local, const u8 *addr); | 403 | struct sta_info *sta_info_get(struct ieee80211_sub_if_data *sdata, |
| 404 | const u8 *addr); | ||
| 405 | |||
| 406 | struct sta_info *sta_info_get_bss(struct ieee80211_sub_if_data *sdata, | ||
| 407 | const u8 *addr); | ||
| 408 | |||
| 409 | static inline | ||
| 410 | void for_each_sta_info_type_check(struct ieee80211_local *local, | ||
| 411 | const u8 *addr, | ||
| 412 | struct sta_info *sta, | ||
| 413 | struct sta_info *nxt) | ||
| 414 | { | ||
| 415 | } | ||
| 416 | |||
| 417 | #define for_each_sta_info(local, _addr, sta, nxt) \ | ||
| 418 | for ( /* initialise loop */ \ | ||
| 419 | sta = rcu_dereference(local->sta_hash[STA_HASH(_addr)]),\ | ||
| 420 | nxt = sta ? rcu_dereference(sta->hnext) : NULL; \ | ||
| 421 | /* typecheck */ \ | ||
| 422 | for_each_sta_info_type_check(local, (_addr), sta, nxt), \ | ||
| 423 | /* continue condition */ \ | ||
| 424 | sta; \ | ||
| 425 | /* advance loop */ \ | ||
| 426 | sta = nxt, \ | ||
| 427 | nxt = sta ? rcu_dereference(sta->hnext) : NULL \ | ||
| 428 | ) \ | ||
| 429 | /* compare address and run code only if it matches */ \ | ||
| 430 | if (memcmp(sta->sta.addr, (_addr), ETH_ALEN) == 0) | ||
| 431 | |||
| 409 | /* | 432 | /* |
| 410 | * Get STA info by index, BROKEN! | 433 | * Get STA info by index, BROKEN! |
| 411 | */ | 434 | */ |
| @@ -421,18 +444,19 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, | |||
| 421 | * Insert STA info into hash table/list, returns zero or a | 444 | * Insert STA info into hash table/list, returns zero or a |
| 422 | * -EEXIST if (if the same MAC address is already present). | 445 | * -EEXIST if (if the same MAC address is already present). |
| 423 | * | 446 | * |
| 424 | * Calling this without RCU protection makes the caller | 447 | * Calling the non-rcu version makes the caller relinquish, |
| 425 | * relinquish its reference to @sta. | 448 | * the _rcu version calls read_lock_rcu() and must be called |
| 449 | * without it held. | ||
| 426 | */ | 450 | */ |
| 427 | int sta_info_insert(struct sta_info *sta); | 451 | int sta_info_insert(struct sta_info *sta); |
| 428 | /* | 452 | int sta_info_insert_rcu(struct sta_info *sta) __acquires(RCU); |
| 429 | * Unlink a STA info from the hash table/list. | 453 | int sta_info_insert_atomic(struct sta_info *sta); |
| 430 | * This can NULL the STA pointer if somebody else | 454 | |
| 431 | * has already unlinked it. | 455 | int sta_info_destroy_addr(struct ieee80211_sub_if_data *sdata, |
| 432 | */ | 456 | const u8 *addr); |
| 433 | void sta_info_unlink(struct sta_info **sta); | 457 | int sta_info_destroy_addr_bss(struct ieee80211_sub_if_data *sdata, |
| 458 | const u8 *addr); | ||
| 434 | 459 | ||
| 435 | void sta_info_destroy(struct sta_info *sta); | ||
| 436 | void sta_info_set_tim_bit(struct sta_info *sta); | 460 | void sta_info_set_tim_bit(struct sta_info *sta); |
| 437 | void sta_info_clear_tim_bit(struct sta_info *sta); | 461 | void sta_info_clear_tim_bit(struct sta_info *sta); |
| 438 | 462 | ||
diff --git a/net/mac80211/status.c b/net/mac80211/status.c index d78f36c64c7b..56d5b9a6ec5b 100644 --- a/net/mac80211/status.c +++ b/net/mac80211/status.c | |||
| @@ -2,7 +2,7 @@ | |||
| 2 | * Copyright 2002-2005, Instant802 Networks, Inc. | 2 | * Copyright 2002-2005, Instant802 Networks, Inc. |
| 3 | * Copyright 2005-2006, Devicescape Software, Inc. | 3 | * Copyright 2005-2006, Devicescape Software, Inc. |
| 4 | * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz> | 4 | * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz> |
| 5 | * Copyright 2008-2009 Johannes Berg <johannes@sipsolutions.net> | 5 | * Copyright 2008-2010 Johannes Berg <johannes@sipsolutions.net> |
| 6 | * | 6 | * |
| 7 | * This program is free software; you can redistribute it and/or modify | 7 | * This program is free software; you can redistribute it and/or modify |
| 8 | * it under the terms of the GNU General Public License version 2 as | 8 | * it under the terms of the GNU General Public License version 2 as |
| @@ -45,29 +45,19 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local, | |||
| 45 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | 45 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
| 46 | 46 | ||
| 47 | /* | 47 | /* |
| 48 | * XXX: This is temporary! | 48 | * This skb 'survived' a round-trip through the driver, and |
| 49 | * | 49 | * hopefully the driver didn't mangle it too badly. However, |
| 50 | * The problem here is that when we get here, the driver will | 50 | * we can definitely not rely on the the control information |
| 51 | * quite likely have pretty much overwritten info->control by | 51 | * being correct. Clear it so we don't get junk there, and |
| 52 | * using info->driver_data or info->rate_driver_data. Thus, | 52 | * indicate that it needs new processing, but must not be |
| 53 | * when passing out the frame to the driver again, we would be | 53 | * modified/encrypted again. |
| 54 | * passing completely bogus data since the driver would then | ||
| 55 | * expect a properly filled info->control. In mac80211 itself | ||
| 56 | * the same problem occurs, since we need info->control.vif | ||
| 57 | * internally. | ||
| 58 | * | ||
| 59 | * To fix this, we should send the frame through TX processing | ||
| 60 | * again. However, it's not that simple, since the frame will | ||
| 61 | * have been software-encrypted (if applicable) already, and | ||
| 62 | * encrypting it again doesn't do much good. So to properly do | ||
| 63 | * that, we not only have to skip the actual 'raw' encryption | ||
| 64 | * (key selection etc. still has to be done!) but also the | ||
| 65 | * sequence number assignment since that impacts the crypto | ||
| 66 | * encapsulation, of course. | ||
| 67 | * | ||
| 68 | * Hence, for now, fix the bug by just dropping the frame. | ||
| 69 | */ | 54 | */ |
| 70 | goto drop; | 55 | memset(&info->control, 0, sizeof(info->control)); |
| 56 | |||
| 57 | info->control.jiffies = jiffies; | ||
| 58 | info->control.vif = &sta->sdata->vif; | ||
| 59 | info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING | | ||
| 60 | IEEE80211_TX_INTFL_RETRANSMISSION; | ||
| 71 | 61 | ||
| 72 | sta->tx_filtered_count++; | 62 | sta->tx_filtered_count++; |
| 73 | 63 | ||
| @@ -122,7 +112,6 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local, | |||
| 122 | return; | 112 | return; |
| 123 | } | 113 | } |
| 124 | 114 | ||
| 125 | drop: | ||
| 126 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | 115 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG |
| 127 | if (net_ratelimit()) | 116 | if (net_ratelimit()) |
| 128 | printk(KERN_DEBUG "%s: dropped TX filtered frame, " | 117 | printk(KERN_DEBUG "%s: dropped TX filtered frame, " |
| @@ -134,6 +123,40 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local, | |||
| 134 | dev_kfree_skb(skb); | 123 | dev_kfree_skb(skb); |
| 135 | } | 124 | } |
| 136 | 125 | ||
| 126 | static void ieee80211_frame_acked(struct sta_info *sta, struct sk_buff *skb) | ||
| 127 | { | ||
| 128 | struct ieee80211_mgmt *mgmt = (void *) skb->data; | ||
| 129 | struct ieee80211_local *local = sta->local; | ||
| 130 | struct ieee80211_sub_if_data *sdata = sta->sdata; | ||
| 131 | |||
| 132 | if (ieee80211_is_action(mgmt->frame_control) && | ||
| 133 | sdata->vif.type == NL80211_IFTYPE_STATION && | ||
| 134 | mgmt->u.action.category == WLAN_CATEGORY_HT && | ||
| 135 | mgmt->u.action.u.ht_smps.action == WLAN_HT_ACTION_SMPS) { | ||
| 136 | /* | ||
| 137 | * This update looks racy, but isn't -- if we come | ||
| 138 | * here we've definitely got a station that we're | ||
| 139 | * talking to, and on a managed interface that can | ||
| 140 | * only be the AP. And the only other place updating | ||
| 141 | * this variable is before we're associated. | ||
| 142 | */ | ||
| 143 | switch (mgmt->u.action.u.ht_smps.smps_control) { | ||
| 144 | case WLAN_HT_SMPS_CONTROL_DYNAMIC: | ||
| 145 | sta->sdata->u.mgd.ap_smps = IEEE80211_SMPS_DYNAMIC; | ||
| 146 | break; | ||
| 147 | case WLAN_HT_SMPS_CONTROL_STATIC: | ||
| 148 | sta->sdata->u.mgd.ap_smps = IEEE80211_SMPS_STATIC; | ||
| 149 | break; | ||
| 150 | case WLAN_HT_SMPS_CONTROL_DISABLED: | ||
| 151 | default: /* shouldn't happen since we don't send that */ | ||
| 152 | sta->sdata->u.mgd.ap_smps = IEEE80211_SMPS_OFF; | ||
| 153 | break; | ||
| 154 | } | ||
| 155 | |||
| 156 | ieee80211_queue_work(&local->hw, &local->recalc_smps); | ||
| 157 | } | ||
| 158 | } | ||
| 159 | |||
| 137 | void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) | 160 | void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) |
| 138 | { | 161 | { |
| 139 | struct sk_buff *skb2; | 162 | struct sk_buff *skb2; |
| @@ -146,7 +169,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
| 146 | struct ieee80211_tx_status_rtap_hdr *rthdr; | 169 | struct ieee80211_tx_status_rtap_hdr *rthdr; |
| 147 | struct ieee80211_sub_if_data *sdata; | 170 | struct ieee80211_sub_if_data *sdata; |
| 148 | struct net_device *prev_dev = NULL; | 171 | struct net_device *prev_dev = NULL; |
| 149 | struct sta_info *sta; | 172 | struct sta_info *sta, *tmp; |
| 150 | int retry_count = -1, i; | 173 | int retry_count = -1, i; |
| 151 | bool injected; | 174 | bool injected; |
| 152 | 175 | ||
| @@ -165,10 +188,13 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
| 165 | rcu_read_lock(); | 188 | rcu_read_lock(); |
| 166 | 189 | ||
| 167 | sband = local->hw.wiphy->bands[info->band]; | 190 | sband = local->hw.wiphy->bands[info->band]; |
| 191 | fc = hdr->frame_control; | ||
| 168 | 192 | ||
| 169 | sta = sta_info_get(local, hdr->addr1); | 193 | for_each_sta_info(local, hdr->addr1, sta, tmp) { |
| 194 | /* skip wrong virtual interface */ | ||
| 195 | if (memcmp(hdr->addr2, sta->sdata->vif.addr, ETH_ALEN)) | ||
| 196 | continue; | ||
| 170 | 197 | ||
| 171 | if (sta) { | ||
| 172 | if (!(info->flags & IEEE80211_TX_STAT_ACK) && | 198 | if (!(info->flags & IEEE80211_TX_STAT_ACK) && |
| 173 | test_sta_flags(sta, WLAN_STA_PS_STA)) { | 199 | test_sta_flags(sta, WLAN_STA_PS_STA)) { |
| 174 | /* | 200 | /* |
| @@ -180,8 +206,6 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
| 180 | return; | 206 | return; |
| 181 | } | 207 | } |
| 182 | 208 | ||
| 183 | fc = hdr->frame_control; | ||
| 184 | |||
| 185 | if ((info->flags & IEEE80211_TX_STAT_AMPDU_NO_BACK) && | 209 | if ((info->flags & IEEE80211_TX_STAT_AMPDU_NO_BACK) && |
| 186 | (ieee80211_is_data_qos(fc))) { | 210 | (ieee80211_is_data_qos(fc))) { |
| 187 | u16 tid, ssn; | 211 | u16 tid, ssn; |
| @@ -208,6 +232,10 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
| 208 | rate_control_tx_status(local, sband, sta, skb); | 232 | rate_control_tx_status(local, sband, sta, skb); |
| 209 | if (ieee80211_vif_is_mesh(&sta->sdata->vif)) | 233 | if (ieee80211_vif_is_mesh(&sta->sdata->vif)) |
| 210 | ieee80211s_update_metric(local, sta, skb); | 234 | ieee80211s_update_metric(local, sta, skb); |
| 235 | |||
| 236 | if (!(info->flags & IEEE80211_TX_CTL_INJECTED) && | ||
| 237 | (info->flags & IEEE80211_TX_STAT_ACK)) | ||
| 238 | ieee80211_frame_acked(sta, skb); | ||
| 211 | } | 239 | } |
| 212 | 240 | ||
| 213 | rcu_read_unlock(); | 241 | rcu_read_unlock(); |
| @@ -246,6 +274,25 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
| 246 | local->dot11FailedCount++; | 274 | local->dot11FailedCount++; |
| 247 | } | 275 | } |
| 248 | 276 | ||
| 277 | if (ieee80211_is_nullfunc(fc) && ieee80211_has_pm(fc) && | ||
| 278 | (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) && | ||
| 279 | !(info->flags & IEEE80211_TX_CTL_INJECTED) && | ||
| 280 | local->ps_sdata && !(local->scanning)) { | ||
| 281 | if (info->flags & IEEE80211_TX_STAT_ACK) { | ||
| 282 | local->ps_sdata->u.mgd.flags |= | ||
| 283 | IEEE80211_STA_NULLFUNC_ACKED; | ||
| 284 | ieee80211_queue_work(&local->hw, | ||
| 285 | &local->dynamic_ps_enable_work); | ||
| 286 | } else | ||
| 287 | mod_timer(&local->dynamic_ps_timer, jiffies + | ||
| 288 | msecs_to_jiffies(10)); | ||
| 289 | } | ||
| 290 | |||
| 291 | if (info->flags & IEEE80211_TX_INTFL_NL80211_FRAME_TX) | ||
| 292 | cfg80211_action_tx_status( | ||
| 293 | skb->dev, (unsigned long) skb, skb->data, skb->len, | ||
| 294 | !!(info->flags & IEEE80211_TX_STAT_ACK), GFP_ATOMIC); | ||
| 295 | |||
| 249 | /* this was a transmitted frame, but now we want to reuse it */ | 296 | /* this was a transmitted frame, but now we want to reuse it */ |
| 250 | skb_orphan(skb); | 297 | skb_orphan(skb); |
| 251 | 298 | ||
| @@ -311,7 +358,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
| 311 | rcu_read_lock(); | 358 | rcu_read_lock(); |
| 312 | list_for_each_entry_rcu(sdata, &local->interfaces, list) { | 359 | list_for_each_entry_rcu(sdata, &local->interfaces, list) { |
| 313 | if (sdata->vif.type == NL80211_IFTYPE_MONITOR) { | 360 | if (sdata->vif.type == NL80211_IFTYPE_MONITOR) { |
| 314 | if (!netif_running(sdata->dev)) | 361 | if (!ieee80211_sdata_running(sdata)) |
| 315 | continue; | 362 | continue; |
| 316 | 363 | ||
| 317 | if ((sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES) && | 364 | if ((sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES) && |
diff --git a/net/mac80211/tkip.c b/net/mac80211/tkip.c index 4921d724b6c7..7ef491e9d66d 100644 --- a/net/mac80211/tkip.c +++ b/net/mac80211/tkip.c | |||
| @@ -100,7 +100,7 @@ static void tkip_mixing_phase1(const u8 *tk, struct tkip_ctx *ctx, | |||
| 100 | p1k[3] += tkipS(p1k[2] ^ get_unaligned_le16(tk + 12 + j)); | 100 | p1k[3] += tkipS(p1k[2] ^ get_unaligned_le16(tk + 12 + j)); |
| 101 | p1k[4] += tkipS(p1k[3] ^ get_unaligned_le16(tk + 0 + j)) + i; | 101 | p1k[4] += tkipS(p1k[3] ^ get_unaligned_le16(tk + 0 + j)) + i; |
| 102 | } | 102 | } |
| 103 | ctx->initialized = 1; | 103 | ctx->state = TKIP_STATE_PHASE1_DONE; |
| 104 | } | 104 | } |
| 105 | 105 | ||
| 106 | static void tkip_mixing_phase2(const u8 *tk, struct tkip_ctx *ctx, | 106 | static void tkip_mixing_phase2(const u8 *tk, struct tkip_ctx *ctx, |
| @@ -183,7 +183,7 @@ void ieee80211_get_tkip_key(struct ieee80211_key_conf *keyconf, | |||
| 183 | /* Update the p1k only when the iv16 in the packet wraps around, this | 183 | /* Update the p1k only when the iv16 in the packet wraps around, this |
| 184 | * might occur after the wrap around of iv16 in the key in case of | 184 | * might occur after the wrap around of iv16 in the key in case of |
| 185 | * fragmented packets. */ | 185 | * fragmented packets. */ |
| 186 | if (iv16 == 0 || !ctx->initialized) | 186 | if (iv16 == 0 || ctx->state == TKIP_STATE_NOT_INIT) |
| 187 | tkip_mixing_phase1(tk, ctx, hdr->addr2, iv32); | 187 | tkip_mixing_phase1(tk, ctx, hdr->addr2, iv32); |
| 188 | 188 | ||
| 189 | if (type == IEEE80211_TKIP_P1_KEY) { | 189 | if (type == IEEE80211_TKIP_P1_KEY) { |
| @@ -195,11 +195,13 @@ void ieee80211_get_tkip_key(struct ieee80211_key_conf *keyconf, | |||
| 195 | } | 195 | } |
| 196 | EXPORT_SYMBOL(ieee80211_get_tkip_key); | 196 | EXPORT_SYMBOL(ieee80211_get_tkip_key); |
| 197 | 197 | ||
| 198 | /* Encrypt packet payload with TKIP using @key. @pos is a pointer to the | 198 | /* |
| 199 | * Encrypt packet payload with TKIP using @key. @pos is a pointer to the | ||
| 199 | * beginning of the buffer containing payload. This payload must include | 200 | * beginning of the buffer containing payload. This payload must include |
| 200 | * headroom of eight octets for IV and Ext. IV and taildroom of four octets | 201 | * the IV/Ext.IV and space for (taildroom) four octets for ICV. |
| 201 | * for ICV. @payload_len is the length of payload (_not_ including extra | 202 | * @payload_len is the length of payload (_not_ including IV/ICV length). |
| 202 | * headroom and tailroom). @ta is the transmitter addresses. */ | 203 | * @ta is the transmitter addresses. |
| 204 | */ | ||
| 203 | void ieee80211_tkip_encrypt_data(struct crypto_blkcipher *tfm, | 205 | void ieee80211_tkip_encrypt_data(struct crypto_blkcipher *tfm, |
| 204 | struct ieee80211_key *key, | 206 | struct ieee80211_key *key, |
| 205 | u8 *pos, size_t payload_len, u8 *ta) | 207 | u8 *pos, size_t payload_len, u8 *ta) |
| @@ -209,12 +211,11 @@ void ieee80211_tkip_encrypt_data(struct crypto_blkcipher *tfm, | |||
| 209 | const u8 *tk = &key->conf.key[NL80211_TKIP_DATA_OFFSET_ENCR_KEY]; | 211 | const u8 *tk = &key->conf.key[NL80211_TKIP_DATA_OFFSET_ENCR_KEY]; |
| 210 | 212 | ||
| 211 | /* Calculate per-packet key */ | 213 | /* Calculate per-packet key */ |
| 212 | if (ctx->iv16 == 0 || !ctx->initialized) | 214 | if (ctx->iv16 == 0 || ctx->state == TKIP_STATE_NOT_INIT) |
| 213 | tkip_mixing_phase1(tk, ctx, ta, ctx->iv32); | 215 | tkip_mixing_phase1(tk, ctx, ta, ctx->iv32); |
| 214 | 216 | ||
| 215 | tkip_mixing_phase2(tk, ctx, ctx->iv16, rc4key); | 217 | tkip_mixing_phase2(tk, ctx, ctx->iv16, rc4key); |
| 216 | 218 | ||
| 217 | pos = ieee80211_tkip_add_iv(pos, key, key->u.tkip.tx.iv16); | ||
| 218 | ieee80211_wep_encrypt_data(tfm, rc4key, 16, pos, payload_len); | 219 | ieee80211_wep_encrypt_data(tfm, rc4key, 16, pos, payload_len); |
| 219 | } | 220 | } |
| 220 | 221 | ||
| @@ -259,7 +260,7 @@ int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm, | |||
| 259 | if ((keyid >> 6) != key->conf.keyidx) | 260 | if ((keyid >> 6) != key->conf.keyidx) |
| 260 | return TKIP_DECRYPT_INVALID_KEYIDX; | 261 | return TKIP_DECRYPT_INVALID_KEYIDX; |
| 261 | 262 | ||
| 262 | if (key->u.tkip.rx[queue].initialized && | 263 | if (key->u.tkip.rx[queue].state != TKIP_STATE_NOT_INIT && |
| 263 | (iv32 < key->u.tkip.rx[queue].iv32 || | 264 | (iv32 < key->u.tkip.rx[queue].iv32 || |
| 264 | (iv32 == key->u.tkip.rx[queue].iv32 && | 265 | (iv32 == key->u.tkip.rx[queue].iv32 && |
| 265 | iv16 <= key->u.tkip.rx[queue].iv16))) { | 266 | iv16 <= key->u.tkip.rx[queue].iv16))) { |
| @@ -275,11 +276,11 @@ int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm, | |||
| 275 | 276 | ||
| 276 | if (only_iv) { | 277 | if (only_iv) { |
| 277 | res = TKIP_DECRYPT_OK; | 278 | res = TKIP_DECRYPT_OK; |
| 278 | key->u.tkip.rx[queue].initialized = 1; | 279 | key->u.tkip.rx[queue].state = TKIP_STATE_PHASE1_HW_UPLOADED; |
| 279 | goto done; | 280 | goto done; |
| 280 | } | 281 | } |
| 281 | 282 | ||
| 282 | if (!key->u.tkip.rx[queue].initialized || | 283 | if (key->u.tkip.rx[queue].state == TKIP_STATE_NOT_INIT || |
| 283 | key->u.tkip.rx[queue].iv32 != iv32) { | 284 | key->u.tkip.rx[queue].iv32 != iv32) { |
| 284 | /* IV16 wrapped around - perform TKIP phase 1 */ | 285 | /* IV16 wrapped around - perform TKIP phase 1 */ |
| 285 | tkip_mixing_phase1(tk, &key->u.tkip.rx[queue], ta, iv32); | 286 | tkip_mixing_phase1(tk, &key->u.tkip.rx[queue], ta, iv32); |
| @@ -299,18 +300,18 @@ int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm, | |||
| 299 | printk("\n"); | 300 | printk("\n"); |
| 300 | } | 301 | } |
| 301 | #endif | 302 | #endif |
| 302 | if (key->local->ops->update_tkip_key && | 303 | } |
| 303 | key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) { | 304 | if (key->local->ops->update_tkip_key && |
| 304 | static const u8 bcast[ETH_ALEN] = | 305 | key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE && |
| 305 | {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; | 306 | key->u.tkip.rx[queue].state != TKIP_STATE_PHASE1_HW_UPLOADED) { |
| 306 | const u8 *sta_addr = key->sta->sta.addr; | 307 | struct ieee80211_sub_if_data *sdata = key->sdata; |
| 307 | 308 | ||
| 308 | if (is_multicast_ether_addr(ra)) | 309 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) |
| 309 | sta_addr = bcast; | 310 | sdata = container_of(key->sdata->bss, |
| 310 | 311 | struct ieee80211_sub_if_data, u.ap); | |
| 311 | drv_update_tkip_key(key->local, &key->conf, sta_addr, | 312 | drv_update_tkip_key(key->local, sdata, &key->conf, key->sta, |
| 312 | iv32, key->u.tkip.rx[queue].p1k); | 313 | iv32, key->u.tkip.rx[queue].p1k); |
| 313 | } | 314 | key->u.tkip.rx[queue].state = TKIP_STATE_PHASE1_HW_UPLOADED; |
| 314 | } | 315 | } |
| 315 | 316 | ||
| 316 | tkip_mixing_phase2(tk, &key->u.tkip.rx[queue], iv16, rc4key); | 317 | tkip_mixing_phase2(tk, &key->u.tkip.rx[queue], iv16, rc4key); |
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index ac210b586702..cbe53ed4fb0b 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c | |||
| @@ -180,6 +180,71 @@ static int inline is_ieee80211_device(struct ieee80211_local *local, | |||
| 180 | } | 180 | } |
| 181 | 181 | ||
| 182 | /* tx handlers */ | 182 | /* tx handlers */ |
| 183 | static ieee80211_tx_result debug_noinline | ||
| 184 | ieee80211_tx_h_dynamic_ps(struct ieee80211_tx_data *tx) | ||
| 185 | { | ||
| 186 | struct ieee80211_local *local = tx->local; | ||
| 187 | struct ieee80211_if_managed *ifmgd; | ||
| 188 | |||
| 189 | /* driver doesn't support power save */ | ||
| 190 | if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_PS)) | ||
| 191 | return TX_CONTINUE; | ||
| 192 | |||
| 193 | /* hardware does dynamic power save */ | ||
| 194 | if (local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS) | ||
| 195 | return TX_CONTINUE; | ||
| 196 | |||
| 197 | /* dynamic power save disabled */ | ||
| 198 | if (local->hw.conf.dynamic_ps_timeout <= 0) | ||
| 199 | return TX_CONTINUE; | ||
| 200 | |||
| 201 | /* we are scanning, don't enable power save */ | ||
| 202 | if (local->scanning) | ||
| 203 | return TX_CONTINUE; | ||
| 204 | |||
| 205 | if (!local->ps_sdata) | ||
| 206 | return TX_CONTINUE; | ||
| 207 | |||
| 208 | /* No point if we're going to suspend */ | ||
| 209 | if (local->quiescing) | ||
| 210 | return TX_CONTINUE; | ||
| 211 | |||
| 212 | /* dynamic ps is supported only in managed mode */ | ||
| 213 | if (tx->sdata->vif.type != NL80211_IFTYPE_STATION) | ||
| 214 | return TX_CONTINUE; | ||
| 215 | |||
| 216 | ifmgd = &tx->sdata->u.mgd; | ||
| 217 | |||
| 218 | /* | ||
| 219 | * Don't wakeup from power save if u-apsd is enabled, voip ac has | ||
| 220 | * u-apsd enabled and the frame is in voip class. This effectively | ||
| 221 | * means that even if all access categories have u-apsd enabled, in | ||
| 222 | * practise u-apsd is only used with the voip ac. This is a | ||
| 223 | * workaround for the case when received voip class packets do not | ||
| 224 | * have correct qos tag for some reason, due the network or the | ||
| 225 | * peer application. | ||
| 226 | * | ||
| 227 | * Note: local->uapsd_queues access is racy here. If the value is | ||
| 228 | * changed via debugfs, user needs to reassociate manually to have | ||
| 229 | * everything in sync. | ||
| 230 | */ | ||
| 231 | if ((ifmgd->flags & IEEE80211_STA_UAPSD_ENABLED) | ||
| 232 | && (local->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VO) | ||
| 233 | && skb_get_queue_mapping(tx->skb) == 0) | ||
| 234 | return TX_CONTINUE; | ||
| 235 | |||
| 236 | if (local->hw.conf.flags & IEEE80211_CONF_PS) { | ||
| 237 | ieee80211_stop_queues_by_reason(&local->hw, | ||
| 238 | IEEE80211_QUEUE_STOP_REASON_PS); | ||
| 239 | ieee80211_queue_work(&local->hw, | ||
| 240 | &local->dynamic_ps_disable_work); | ||
| 241 | } | ||
| 242 | |||
| 243 | mod_timer(&local->dynamic_ps_timer, jiffies + | ||
| 244 | msecs_to_jiffies(local->hw.conf.dynamic_ps_timeout)); | ||
| 245 | |||
| 246 | return TX_CONTINUE; | ||
| 247 | } | ||
| 183 | 248 | ||
| 184 | static ieee80211_tx_result debug_noinline | 249 | static ieee80211_tx_result debug_noinline |
| 185 | ieee80211_tx_h_check_assoc(struct ieee80211_tx_data *tx) | 250 | ieee80211_tx_h_check_assoc(struct ieee80211_tx_data *tx) |
| @@ -223,7 +288,7 @@ ieee80211_tx_h_check_assoc(struct ieee80211_tx_data *tx) | |||
| 223 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | 288 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG |
| 224 | printk(KERN_DEBUG "%s: dropped data frame to not " | 289 | printk(KERN_DEBUG "%s: dropped data frame to not " |
| 225 | "associated station %pM\n", | 290 | "associated station %pM\n", |
| 226 | tx->dev->name, hdr->addr1); | 291 | tx->sdata->name, hdr->addr1); |
| 227 | #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ | 292 | #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ |
| 228 | I802_DEBUG_INC(tx->local->tx_handlers_drop_not_assoc); | 293 | I802_DEBUG_INC(tx->local->tx_handlers_drop_not_assoc); |
| 229 | return TX_DROP; | 294 | return TX_DROP; |
| @@ -331,7 +396,7 @@ ieee80211_tx_h_multicast_ps_buf(struct ieee80211_tx_data *tx) | |||
| 331 | #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG | 396 | #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG |
| 332 | if (net_ratelimit()) | 397 | if (net_ratelimit()) |
| 333 | printk(KERN_DEBUG "%s: BC TX buffer full - dropping the oldest frame\n", | 398 | printk(KERN_DEBUG "%s: BC TX buffer full - dropping the oldest frame\n", |
| 334 | tx->dev->name); | 399 | tx->sdata->name); |
| 335 | #endif | 400 | #endif |
| 336 | dev_kfree_skb(skb_dequeue(&tx->sdata->bss->ps_bc_buf)); | 401 | dev_kfree_skb(skb_dequeue(&tx->sdata->bss->ps_bc_buf)); |
| 337 | } else | 402 | } else |
| @@ -391,7 +456,7 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx) | |||
| 391 | if (net_ratelimit()) { | 456 | if (net_ratelimit()) { |
| 392 | printk(KERN_DEBUG "%s: STA %pM TX " | 457 | printk(KERN_DEBUG "%s: STA %pM TX " |
| 393 | "buffer full - dropping oldest frame\n", | 458 | "buffer full - dropping oldest frame\n", |
| 394 | tx->dev->name, sta->sta.addr); | 459 | tx->sdata->name, sta->sta.addr); |
| 395 | } | 460 | } |
| 396 | #endif | 461 | #endif |
| 397 | dev_kfree_skb(old); | 462 | dev_kfree_skb(old); |
| @@ -416,7 +481,7 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx) | |||
| 416 | #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG | 481 | #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG |
| 417 | else if (unlikely(staflags & WLAN_STA_PS_STA)) { | 482 | else if (unlikely(staflags & WLAN_STA_PS_STA)) { |
| 418 | printk(KERN_DEBUG "%s: STA %pM in PS mode, but pspoll " | 483 | printk(KERN_DEBUG "%s: STA %pM in PS mode, but pspoll " |
| 419 | "set -> send frame\n", tx->dev->name, | 484 | "set -> send frame\n", tx->sdata->name, |
| 420 | sta->sta.addr); | 485 | sta->sta.addr); |
| 421 | } | 486 | } |
| 422 | #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ | 487 | #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ |
| @@ -464,6 +529,8 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx) | |||
| 464 | tx->key = NULL; | 529 | tx->key = NULL; |
| 465 | 530 | ||
| 466 | if (tx->key) { | 531 | if (tx->key) { |
| 532 | bool skip_hw = false; | ||
| 533 | |||
| 467 | tx->key->tx_rx_count++; | 534 | tx->key->tx_rx_count++; |
| 468 | /* TODO: add threshold stuff again */ | 535 | /* TODO: add threshold stuff again */ |
| 469 | 536 | ||
| @@ -480,16 +547,32 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx) | |||
| 480 | !ieee80211_use_mfp(hdr->frame_control, tx->sta, | 547 | !ieee80211_use_mfp(hdr->frame_control, tx->sta, |
| 481 | tx->skb)) | 548 | tx->skb)) |
| 482 | tx->key = NULL; | 549 | tx->key = NULL; |
| 550 | else | ||
| 551 | skip_hw = (tx->key->conf.flags & | ||
| 552 | IEEE80211_KEY_FLAG_SW_MGMT) && | ||
| 553 | ieee80211_is_mgmt(hdr->frame_control); | ||
| 483 | break; | 554 | break; |
| 484 | case ALG_AES_CMAC: | 555 | case ALG_AES_CMAC: |
| 485 | if (!ieee80211_is_mgmt(hdr->frame_control)) | 556 | if (!ieee80211_is_mgmt(hdr->frame_control)) |
| 486 | tx->key = NULL; | 557 | tx->key = NULL; |
| 487 | break; | 558 | break; |
| 488 | } | 559 | } |
| 560 | |||
| 561 | if (!skip_hw && tx->key && | ||
| 562 | tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) | ||
| 563 | info->control.hw_key = &tx->key->conf; | ||
| 489 | } | 564 | } |
| 490 | 565 | ||
| 491 | if (!tx->key || !(tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) | 566 | return TX_CONTINUE; |
| 492 | info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; | 567 | } |
| 568 | |||
| 569 | static ieee80211_tx_result debug_noinline | ||
| 570 | ieee80211_tx_h_sta(struct ieee80211_tx_data *tx) | ||
| 571 | { | ||
| 572 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb); | ||
| 573 | |||
| 574 | if (tx->sta && tx->sta->uploaded) | ||
| 575 | info->control.sta = &tx->sta->sta; | ||
| 493 | 576 | ||
| 494 | return TX_CONTINUE; | 577 | return TX_CONTINUE; |
| 495 | } | 578 | } |
| @@ -519,7 +602,12 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx) | |||
| 519 | txrc.bss_conf = &tx->sdata->vif.bss_conf; | 602 | txrc.bss_conf = &tx->sdata->vif.bss_conf; |
| 520 | txrc.skb = tx->skb; | 603 | txrc.skb = tx->skb; |
| 521 | txrc.reported_rate.idx = -1; | 604 | txrc.reported_rate.idx = -1; |
| 522 | txrc.max_rate_idx = tx->sdata->max_ratectrl_rateidx; | 605 | txrc.rate_idx_mask = tx->sdata->rc_rateidx_mask[tx->channel->band]; |
| 606 | if (txrc.rate_idx_mask == (1 << sband->n_bitrates) - 1) | ||
| 607 | txrc.max_rate_idx = -1; | ||
| 608 | else | ||
| 609 | txrc.max_rate_idx = fls(txrc.rate_idx_mask) - 1; | ||
| 610 | txrc.ap = tx->sdata->vif.type == NL80211_IFTYPE_AP; | ||
| 523 | 611 | ||
| 524 | /* set up RTS protection if desired */ | 612 | /* set up RTS protection if desired */ |
| 525 | if (len > tx->local->hw.wiphy->rts_threshold) { | 613 | if (len > tx->local->hw.wiphy->rts_threshold) { |
| @@ -549,7 +637,7 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx) | |||
| 549 | "%s: Dropped data frame as no usable bitrate found while " | 637 | "%s: Dropped data frame as no usable bitrate found while " |
| 550 | "scanning and associated. Target station: " | 638 | "scanning and associated. Target station: " |
| 551 | "%pM on %d GHz band\n", | 639 | "%pM on %d GHz band\n", |
| 552 | tx->dev->name, hdr->addr1, | 640 | tx->sdata->name, hdr->addr1, |
| 553 | tx->channel->band ? 5 : 2)) | 641 | tx->channel->band ? 5 : 2)) |
| 554 | return TX_DROP; | 642 | return TX_DROP; |
| 555 | 643 | ||
| @@ -664,17 +752,6 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx) | |||
| 664 | } | 752 | } |
| 665 | 753 | ||
| 666 | static ieee80211_tx_result debug_noinline | 754 | static ieee80211_tx_result debug_noinline |
| 667 | ieee80211_tx_h_misc(struct ieee80211_tx_data *tx) | ||
| 668 | { | ||
| 669 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb); | ||
| 670 | |||
| 671 | if (tx->sta) | ||
| 672 | info->control.sta = &tx->sta->sta; | ||
| 673 | |||
| 674 | return TX_CONTINUE; | ||
| 675 | } | ||
| 676 | |||
| 677 | static ieee80211_tx_result debug_noinline | ||
| 678 | ieee80211_tx_h_sequence(struct ieee80211_tx_data *tx) | 755 | ieee80211_tx_h_sequence(struct ieee80211_tx_data *tx) |
| 679 | { | 756 | { |
| 680 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb); | 757 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb); |
| @@ -933,7 +1010,8 @@ static bool __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx, | |||
| 933 | (struct ieee80211_radiotap_header *) skb->data; | 1010 | (struct ieee80211_radiotap_header *) skb->data; |
| 934 | struct ieee80211_supported_band *sband; | 1011 | struct ieee80211_supported_band *sband; |
| 935 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | 1012 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
| 936 | int ret = ieee80211_radiotap_iterator_init(&iterator, rthdr, skb->len); | 1013 | int ret = ieee80211_radiotap_iterator_init(&iterator, rthdr, skb->len, |
| 1014 | NULL); | ||
| 937 | 1015 | ||
| 938 | sband = tx->local->hw.wiphy->bands[tx->channel->band]; | 1016 | sband = tx->local->hw.wiphy->bands[tx->channel->band]; |
| 939 | 1017 | ||
| @@ -969,7 +1047,7 @@ static bool __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx, | |||
| 969 | * because it will be recomputed and added | 1047 | * because it will be recomputed and added |
| 970 | * on transmission | 1048 | * on transmission |
| 971 | */ | 1049 | */ |
| 972 | if (skb->len < (iterator.max_length + FCS_LEN)) | 1050 | if (skb->len < (iterator._max_length + FCS_LEN)) |
| 973 | return false; | 1051 | return false; |
| 974 | 1052 | ||
| 975 | skb_trim(skb, skb->len - FCS_LEN); | 1053 | skb_trim(skb, skb->len - FCS_LEN); |
| @@ -996,10 +1074,10 @@ static bool __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx, | |||
| 996 | 1074 | ||
| 997 | /* | 1075 | /* |
| 998 | * remove the radiotap header | 1076 | * remove the radiotap header |
| 999 | * iterator->max_length was sanity-checked against | 1077 | * iterator->_max_length was sanity-checked against |
| 1000 | * skb->len by iterator init | 1078 | * skb->len by iterator init |
| 1001 | */ | 1079 | */ |
| 1002 | skb_pull(skb, iterator.max_length); | 1080 | skb_pull(skb, iterator._max_length); |
| 1003 | 1081 | ||
| 1004 | return true; | 1082 | return true; |
| 1005 | } | 1083 | } |
| @@ -1021,7 +1099,6 @@ ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata, | |||
| 1021 | 1099 | ||
| 1022 | memset(tx, 0, sizeof(*tx)); | 1100 | memset(tx, 0, sizeof(*tx)); |
| 1023 | tx->skb = skb; | 1101 | tx->skb = skb; |
| 1024 | tx->dev = sdata->dev; /* use original interface */ | ||
| 1025 | tx->local = local; | 1102 | tx->local = local; |
| 1026 | tx->sdata = sdata; | 1103 | tx->sdata = sdata; |
| 1027 | tx->channel = local->hw.conf.channel; | 1104 | tx->channel = local->hw.conf.channel; |
| @@ -1032,7 +1109,7 @@ ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata, | |||
| 1032 | tx->flags |= IEEE80211_TX_FRAGMENTED; | 1109 | tx->flags |= IEEE80211_TX_FRAGMENTED; |
| 1033 | 1110 | ||
| 1034 | /* process and remove the injection radiotap header */ | 1111 | /* process and remove the injection radiotap header */ |
| 1035 | if (unlikely(info->flags & IEEE80211_TX_CTL_INJECTED)) { | 1112 | if (unlikely(info->flags & IEEE80211_TX_INTFL_HAS_RADIOTAP)) { |
| 1036 | if (!__ieee80211_parse_tx_radiotap(tx, skb)) | 1113 | if (!__ieee80211_parse_tx_radiotap(tx, skb)) |
| 1037 | return TX_DROP; | 1114 | return TX_DROP; |
| 1038 | 1115 | ||
| @@ -1041,6 +1118,7 @@ ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata, | |||
| 1041 | * the radiotap header that was present and pre-filled | 1118 | * the radiotap header that was present and pre-filled |
| 1042 | * 'tx' with tx control information. | 1119 | * 'tx' with tx control information. |
| 1043 | */ | 1120 | */ |
| 1121 | info->flags &= ~IEEE80211_TX_INTFL_HAS_RADIOTAP; | ||
| 1044 | } | 1122 | } |
| 1045 | 1123 | ||
| 1046 | /* | 1124 | /* |
| @@ -1052,10 +1130,15 @@ ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata, | |||
| 1052 | 1130 | ||
| 1053 | hdr = (struct ieee80211_hdr *) skb->data; | 1131 | hdr = (struct ieee80211_hdr *) skb->data; |
| 1054 | 1132 | ||
| 1055 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | 1133 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) { |
| 1056 | tx->sta = rcu_dereference(sdata->u.vlan.sta); | 1134 | tx->sta = rcu_dereference(sdata->u.vlan.sta); |
| 1135 | if (!tx->sta && sdata->dev->ieee80211_ptr->use_4addr) | ||
| 1136 | return TX_DROP; | ||
| 1137 | } else if (info->flags & IEEE80211_TX_CTL_INJECTED) { | ||
| 1138 | tx->sta = sta_info_get_bss(sdata, hdr->addr1); | ||
| 1139 | } | ||
| 1057 | if (!tx->sta) | 1140 | if (!tx->sta) |
| 1058 | tx->sta = sta_info_get(local, hdr->addr1); | 1141 | tx->sta = sta_info_get(sdata, hdr->addr1); |
| 1059 | 1142 | ||
| 1060 | if (tx->sta && ieee80211_is_data_qos(hdr->frame_control) && | 1143 | if (tx->sta && ieee80211_is_data_qos(hdr->frame_control) && |
| 1061 | (local->hw.flags & IEEE80211_HW_AMPDU_AGGREGATION)) { | 1144 | (local->hw.flags & IEEE80211_HW_AMPDU_AGGREGATION)) { |
| @@ -1207,6 +1290,7 @@ static int __ieee80211_tx(struct ieee80211_local *local, | |||
| 1207 | static int invoke_tx_handlers(struct ieee80211_tx_data *tx) | 1290 | static int invoke_tx_handlers(struct ieee80211_tx_data *tx) |
| 1208 | { | 1291 | { |
| 1209 | struct sk_buff *skb = tx->skb; | 1292 | struct sk_buff *skb = tx->skb; |
| 1293 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | ||
| 1210 | ieee80211_tx_result res = TX_DROP; | 1294 | ieee80211_tx_result res = TX_DROP; |
| 1211 | 1295 | ||
| 1212 | #define CALL_TXH(txh) \ | 1296 | #define CALL_TXH(txh) \ |
| @@ -1216,13 +1300,18 @@ static int invoke_tx_handlers(struct ieee80211_tx_data *tx) | |||
| 1216 | goto txh_done; \ | 1300 | goto txh_done; \ |
| 1217 | } while (0) | 1301 | } while (0) |
| 1218 | 1302 | ||
| 1303 | CALL_TXH(ieee80211_tx_h_dynamic_ps); | ||
| 1219 | CALL_TXH(ieee80211_tx_h_check_assoc); | 1304 | CALL_TXH(ieee80211_tx_h_check_assoc); |
| 1220 | CALL_TXH(ieee80211_tx_h_ps_buf); | 1305 | CALL_TXH(ieee80211_tx_h_ps_buf); |
| 1221 | CALL_TXH(ieee80211_tx_h_select_key); | 1306 | CALL_TXH(ieee80211_tx_h_select_key); |
| 1222 | CALL_TXH(ieee80211_tx_h_michael_mic_add); | 1307 | CALL_TXH(ieee80211_tx_h_sta); |
| 1223 | if (!(tx->local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL)) | 1308 | if (!(tx->local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL)) |
| 1224 | CALL_TXH(ieee80211_tx_h_rate_ctrl); | 1309 | CALL_TXH(ieee80211_tx_h_rate_ctrl); |
| 1225 | CALL_TXH(ieee80211_tx_h_misc); | 1310 | |
| 1311 | if (unlikely(info->flags & IEEE80211_TX_INTFL_RETRANSMISSION)) | ||
| 1312 | goto txh_done; | ||
| 1313 | |||
| 1314 | CALL_TXH(ieee80211_tx_h_michael_mic_add); | ||
| 1226 | CALL_TXH(ieee80211_tx_h_sequence); | 1315 | CALL_TXH(ieee80211_tx_h_sequence); |
| 1227 | CALL_TXH(ieee80211_tx_h_fragment); | 1316 | CALL_TXH(ieee80211_tx_h_fragment); |
| 1228 | /* handlers after fragment must be aware of tx info fragmentation! */ | 1317 | /* handlers after fragment must be aware of tx info fragmentation! */ |
| @@ -1398,34 +1487,6 @@ static int ieee80211_skb_resize(struct ieee80211_local *local, | |||
| 1398 | return 0; | 1487 | return 0; |
| 1399 | } | 1488 | } |
| 1400 | 1489 | ||
| 1401 | static bool need_dynamic_ps(struct ieee80211_local *local) | ||
| 1402 | { | ||
| 1403 | /* driver doesn't support power save */ | ||
| 1404 | if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_PS)) | ||
| 1405 | return false; | ||
| 1406 | |||
| 1407 | /* hardware does dynamic power save */ | ||
| 1408 | if (local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS) | ||
| 1409 | return false; | ||
| 1410 | |||
| 1411 | /* dynamic power save disabled */ | ||
| 1412 | if (local->hw.conf.dynamic_ps_timeout <= 0) | ||
| 1413 | return false; | ||
| 1414 | |||
| 1415 | /* we are scanning, don't enable power save */ | ||
| 1416 | if (local->scanning) | ||
| 1417 | return false; | ||
| 1418 | |||
| 1419 | if (!local->ps_sdata) | ||
| 1420 | return false; | ||
| 1421 | |||
| 1422 | /* No point if we're going to suspend */ | ||
| 1423 | if (local->quiescing) | ||
| 1424 | return false; | ||
| 1425 | |||
| 1426 | return true; | ||
| 1427 | } | ||
| 1428 | |||
| 1429 | static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, | 1490 | static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, |
| 1430 | struct sk_buff *skb) | 1491 | struct sk_buff *skb) |
| 1431 | { | 1492 | { |
| @@ -1436,25 +1497,14 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, | |||
| 1436 | int headroom; | 1497 | int headroom; |
| 1437 | bool may_encrypt; | 1498 | bool may_encrypt; |
| 1438 | 1499 | ||
| 1439 | if (need_dynamic_ps(local)) { | ||
| 1440 | if (local->hw.conf.flags & IEEE80211_CONF_PS) { | ||
| 1441 | ieee80211_stop_queues_by_reason(&local->hw, | ||
| 1442 | IEEE80211_QUEUE_STOP_REASON_PS); | ||
| 1443 | ieee80211_queue_work(&local->hw, | ||
| 1444 | &local->dynamic_ps_disable_work); | ||
| 1445 | } | ||
| 1446 | |||
| 1447 | mod_timer(&local->dynamic_ps_timer, jiffies + | ||
| 1448 | msecs_to_jiffies(local->hw.conf.dynamic_ps_timeout)); | ||
| 1449 | } | ||
| 1450 | |||
| 1451 | rcu_read_lock(); | 1500 | rcu_read_lock(); |
| 1452 | 1501 | ||
| 1453 | if (unlikely(sdata->vif.type == NL80211_IFTYPE_MONITOR)) { | 1502 | if (unlikely(sdata->vif.type == NL80211_IFTYPE_MONITOR)) { |
| 1454 | int hdrlen; | 1503 | int hdrlen; |
| 1455 | u16 len_rthdr; | 1504 | u16 len_rthdr; |
| 1456 | 1505 | ||
| 1457 | info->flags |= IEEE80211_TX_CTL_INJECTED; | 1506 | info->flags |= IEEE80211_TX_CTL_INJECTED | |
| 1507 | IEEE80211_TX_INTFL_HAS_RADIOTAP; | ||
| 1458 | 1508 | ||
| 1459 | len_rthdr = ieee80211_get_radiotap_len(skb->data); | 1509 | len_rthdr = ieee80211_get_radiotap_len(skb->data); |
| 1460 | hdr = (struct ieee80211_hdr *)(skb->data + len_rthdr); | 1510 | hdr = (struct ieee80211_hdr *)(skb->data + len_rthdr); |
| @@ -1474,11 +1524,11 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, | |||
| 1474 | 1524 | ||
| 1475 | list_for_each_entry_rcu(tmp_sdata, &local->interfaces, | 1525 | list_for_each_entry_rcu(tmp_sdata, &local->interfaces, |
| 1476 | list) { | 1526 | list) { |
| 1477 | if (!netif_running(tmp_sdata->dev)) | 1527 | if (!ieee80211_sdata_running(tmp_sdata)) |
| 1478 | continue; | 1528 | continue; |
| 1479 | if (tmp_sdata->vif.type != NL80211_IFTYPE_AP) | 1529 | if (tmp_sdata->vif.type != NL80211_IFTYPE_AP) |
| 1480 | continue; | 1530 | continue; |
| 1481 | if (compare_ether_addr(tmp_sdata->dev->dev_addr, | 1531 | if (compare_ether_addr(tmp_sdata->vif.addr, |
| 1482 | hdr->addr2) == 0) { | 1532 | hdr->addr2) == 0) { |
| 1483 | sdata = tmp_sdata; | 1533 | sdata = tmp_sdata; |
| 1484 | break; | 1534 | break; |
| @@ -1642,7 +1692,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
| 1642 | fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS); | 1692 | fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS); |
| 1643 | /* RA TA DA SA */ | 1693 | /* RA TA DA SA */ |
| 1644 | memcpy(hdr.addr1, sta->sta.addr, ETH_ALEN); | 1694 | memcpy(hdr.addr1, sta->sta.addr, ETH_ALEN); |
| 1645 | memcpy(hdr.addr2, dev->dev_addr, ETH_ALEN); | 1695 | memcpy(hdr.addr2, sdata->vif.addr, ETH_ALEN); |
| 1646 | memcpy(hdr.addr3, skb->data, ETH_ALEN); | 1696 | memcpy(hdr.addr3, skb->data, ETH_ALEN); |
| 1647 | memcpy(hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN); | 1697 | memcpy(hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN); |
| 1648 | hdrlen = 30; | 1698 | hdrlen = 30; |
| @@ -1656,7 +1706,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
| 1656 | fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS); | 1706 | fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS); |
| 1657 | /* DA BSSID SA */ | 1707 | /* DA BSSID SA */ |
| 1658 | memcpy(hdr.addr1, skb->data, ETH_ALEN); | 1708 | memcpy(hdr.addr1, skb->data, ETH_ALEN); |
| 1659 | memcpy(hdr.addr2, dev->dev_addr, ETH_ALEN); | 1709 | memcpy(hdr.addr2, sdata->vif.addr, ETH_ALEN); |
| 1660 | memcpy(hdr.addr3, skb->data + ETH_ALEN, ETH_ALEN); | 1710 | memcpy(hdr.addr3, skb->data + ETH_ALEN, ETH_ALEN); |
| 1661 | hdrlen = 24; | 1711 | hdrlen = 24; |
| 1662 | break; | 1712 | break; |
| @@ -1664,7 +1714,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
| 1664 | fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS); | 1714 | fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS); |
| 1665 | /* RA TA DA SA */ | 1715 | /* RA TA DA SA */ |
| 1666 | memcpy(hdr.addr1, sdata->u.wds.remote_addr, ETH_ALEN); | 1716 | memcpy(hdr.addr1, sdata->u.wds.remote_addr, ETH_ALEN); |
| 1667 | memcpy(hdr.addr2, dev->dev_addr, ETH_ALEN); | 1717 | memcpy(hdr.addr2, sdata->vif.addr, ETH_ALEN); |
| 1668 | memcpy(hdr.addr3, skb->data, ETH_ALEN); | 1718 | memcpy(hdr.addr3, skb->data, ETH_ALEN); |
| 1669 | memcpy(hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN); | 1719 | memcpy(hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN); |
| 1670 | hdrlen = 30; | 1720 | hdrlen = 30; |
| @@ -1678,8 +1728,8 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
| 1678 | goto fail; | 1728 | goto fail; |
| 1679 | } | 1729 | } |
| 1680 | 1730 | ||
| 1681 | if (compare_ether_addr(dev->dev_addr, | 1731 | if (compare_ether_addr(sdata->vif.addr, |
| 1682 | skb->data + ETH_ALEN) == 0) { | 1732 | skb->data + ETH_ALEN) == 0) { |
| 1683 | hdrlen = ieee80211_fill_mesh_addresses(&hdr, &fc, | 1733 | hdrlen = ieee80211_fill_mesh_addresses(&hdr, &fc, |
| 1684 | skb->data, skb->data + ETH_ALEN); | 1734 | skb->data, skb->data + ETH_ALEN); |
| 1685 | meshhdrlen = ieee80211_new_mesh_header(&mesh_hdr, | 1735 | meshhdrlen = ieee80211_new_mesh_header(&mesh_hdr, |
| @@ -1709,7 +1759,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
| 1709 | } | 1759 | } |
| 1710 | } | 1760 | } |
| 1711 | hdrlen = ieee80211_fill_mesh_addresses(&hdr, &fc, | 1761 | hdrlen = ieee80211_fill_mesh_addresses(&hdr, &fc, |
| 1712 | mesh_da, dev->dev_addr); | 1762 | mesh_da, sdata->vif.addr); |
| 1713 | rcu_read_unlock(); | 1763 | rcu_read_unlock(); |
| 1714 | if (is_mesh_mcast) | 1764 | if (is_mesh_mcast) |
| 1715 | meshhdrlen = | 1765 | meshhdrlen = |
| @@ -1734,7 +1784,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
| 1734 | if (sdata->u.mgd.use_4addr && ethertype != ETH_P_PAE) { | 1784 | if (sdata->u.mgd.use_4addr && ethertype != ETH_P_PAE) { |
| 1735 | fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS); | 1785 | fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS); |
| 1736 | /* RA TA DA SA */ | 1786 | /* RA TA DA SA */ |
| 1737 | memcpy(hdr.addr2, dev->dev_addr, ETH_ALEN); | 1787 | memcpy(hdr.addr2, sdata->vif.addr, ETH_ALEN); |
| 1738 | memcpy(hdr.addr3, skb->data, ETH_ALEN); | 1788 | memcpy(hdr.addr3, skb->data, ETH_ALEN); |
| 1739 | memcpy(hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN); | 1789 | memcpy(hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN); |
| 1740 | hdrlen = 30; | 1790 | hdrlen = 30; |
| @@ -1765,9 +1815,8 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
| 1765 | */ | 1815 | */ |
| 1766 | if (!is_multicast_ether_addr(hdr.addr1)) { | 1816 | if (!is_multicast_ether_addr(hdr.addr1)) { |
| 1767 | rcu_read_lock(); | 1817 | rcu_read_lock(); |
| 1768 | sta = sta_info_get(local, hdr.addr1); | 1818 | sta = sta_info_get(sdata, hdr.addr1); |
| 1769 | /* XXX: in the future, use sdata to look up the sta */ | 1819 | if (sta) |
| 1770 | if (sta && sta->sdata == sdata) | ||
| 1771 | sta_flags = get_sta_flags(sta); | 1820 | sta_flags = get_sta_flags(sta); |
| 1772 | rcu_read_unlock(); | 1821 | rcu_read_unlock(); |
| 1773 | } | 1822 | } |
| @@ -1786,7 +1835,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
| 1786 | unlikely(!is_multicast_ether_addr(hdr.addr1) && | 1835 | unlikely(!is_multicast_ether_addr(hdr.addr1) && |
| 1787 | !(sta_flags & WLAN_STA_AUTHORIZED) && | 1836 | !(sta_flags & WLAN_STA_AUTHORIZED) && |
| 1788 | !(ethertype == ETH_P_PAE && | 1837 | !(ethertype == ETH_P_PAE && |
| 1789 | compare_ether_addr(dev->dev_addr, | 1838 | compare_ether_addr(sdata->vif.addr, |
| 1790 | skb->data + ETH_ALEN) == 0))) { | 1839 | skb->data + ETH_ALEN) == 0))) { |
| 1791 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | 1840 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG |
| 1792 | if (net_ratelimit()) | 1841 | if (net_ratelimit()) |
| @@ -1926,7 +1975,7 @@ static bool ieee80211_tx_pending_skb(struct ieee80211_local *local, | |||
| 1926 | ieee80211_tx(sdata, skb, true); | 1975 | ieee80211_tx(sdata, skb, true); |
| 1927 | } else { | 1976 | } else { |
| 1928 | hdr = (struct ieee80211_hdr *)skb->data; | 1977 | hdr = (struct ieee80211_hdr *)skb->data; |
| 1929 | sta = sta_info_get(local, hdr->addr1); | 1978 | sta = sta_info_get(sdata, hdr->addr1); |
| 1930 | 1979 | ||
| 1931 | ret = __ieee80211_tx(local, &skb, sta, true); | 1980 | ret = __ieee80211_tx(local, &skb, sta, true); |
| 1932 | if (ret != IEEE80211_TX_OK) | 1981 | if (ret != IEEE80211_TX_OK) |
| @@ -2062,6 +2111,7 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw, | |||
| 2062 | struct beacon_data *beacon; | 2111 | struct beacon_data *beacon; |
| 2063 | struct ieee80211_supported_band *sband; | 2112 | struct ieee80211_supported_band *sband; |
| 2064 | enum ieee80211_band band = local->hw.conf.channel->band; | 2113 | enum ieee80211_band band = local->hw.conf.channel->band; |
| 2114 | struct ieee80211_tx_rate_control txrc; | ||
| 2065 | 2115 | ||
| 2066 | sband = local->hw.wiphy->bands[band]; | 2116 | sband = local->hw.wiphy->bands[band]; |
| 2067 | 2117 | ||
| @@ -2150,8 +2200,8 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw, | |||
| 2150 | mgmt->frame_control = | 2200 | mgmt->frame_control = |
| 2151 | cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_BEACON); | 2201 | cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_BEACON); |
| 2152 | memset(mgmt->da, 0xff, ETH_ALEN); | 2202 | memset(mgmt->da, 0xff, ETH_ALEN); |
| 2153 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); | 2203 | memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); |
| 2154 | memcpy(mgmt->bssid, sdata->dev->dev_addr, ETH_ALEN); | 2204 | memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN); |
| 2155 | mgmt->u.beacon.beacon_int = | 2205 | mgmt->u.beacon.beacon_int = |
| 2156 | cpu_to_le16(sdata->vif.bss_conf.beacon_int); | 2206 | cpu_to_le16(sdata->vif.bss_conf.beacon_int); |
| 2157 | mgmt->u.beacon.capab_info = 0x0; /* 0x0 for MPs */ | 2207 | mgmt->u.beacon.capab_info = 0x0; /* 0x0 for MPs */ |
| @@ -2169,21 +2219,25 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw, | |||
| 2169 | info = IEEE80211_SKB_CB(skb); | 2219 | info = IEEE80211_SKB_CB(skb); |
| 2170 | 2220 | ||
| 2171 | info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; | 2221 | info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; |
| 2222 | info->flags |= IEEE80211_TX_CTL_NO_ACK; | ||
| 2172 | info->band = band; | 2223 | info->band = band; |
| 2173 | /* | 2224 | |
| 2174 | * XXX: For now, always use the lowest rate | 2225 | memset(&txrc, 0, sizeof(txrc)); |
| 2175 | */ | 2226 | txrc.hw = hw; |
| 2176 | info->control.rates[0].idx = 0; | 2227 | txrc.sband = sband; |
| 2177 | info->control.rates[0].count = 1; | 2228 | txrc.bss_conf = &sdata->vif.bss_conf; |
| 2178 | info->control.rates[1].idx = -1; | 2229 | txrc.skb = skb; |
| 2179 | info->control.rates[2].idx = -1; | 2230 | txrc.reported_rate.idx = -1; |
| 2180 | info->control.rates[3].idx = -1; | 2231 | txrc.rate_idx_mask = sdata->rc_rateidx_mask[band]; |
| 2181 | info->control.rates[4].idx = -1; | 2232 | if (txrc.rate_idx_mask == (1 << sband->n_bitrates) - 1) |
| 2182 | BUILD_BUG_ON(IEEE80211_TX_MAX_RATES != 5); | 2233 | txrc.max_rate_idx = -1; |
| 2234 | else | ||
| 2235 | txrc.max_rate_idx = fls(txrc.rate_idx_mask) - 1; | ||
| 2236 | txrc.ap = true; | ||
| 2237 | rate_control_get_rate(sdata, NULL, &txrc); | ||
| 2183 | 2238 | ||
| 2184 | info->control.vif = vif; | 2239 | info->control.vif = vif; |
| 2185 | 2240 | ||
| 2186 | info->flags |= IEEE80211_TX_CTL_NO_ACK; | ||
| 2187 | info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT; | 2241 | info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT; |
| 2188 | info->flags |= IEEE80211_TX_CTL_ASSIGN_SEQ; | 2242 | info->flags |= IEEE80211_TX_CTL_ASSIGN_SEQ; |
| 2189 | out: | 2243 | out: |
| @@ -2192,6 +2246,134 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw, | |||
| 2192 | } | 2246 | } |
| 2193 | EXPORT_SYMBOL(ieee80211_beacon_get_tim); | 2247 | EXPORT_SYMBOL(ieee80211_beacon_get_tim); |
| 2194 | 2248 | ||
| 2249 | struct sk_buff *ieee80211_pspoll_get(struct ieee80211_hw *hw, | ||
| 2250 | struct ieee80211_vif *vif) | ||
| 2251 | { | ||
| 2252 | struct ieee80211_sub_if_data *sdata; | ||
| 2253 | struct ieee80211_if_managed *ifmgd; | ||
| 2254 | struct ieee80211_pspoll *pspoll; | ||
| 2255 | struct ieee80211_local *local; | ||
| 2256 | struct sk_buff *skb; | ||
| 2257 | |||
| 2258 | if (WARN_ON(vif->type != NL80211_IFTYPE_STATION)) | ||
| 2259 | return NULL; | ||
| 2260 | |||
| 2261 | sdata = vif_to_sdata(vif); | ||
| 2262 | ifmgd = &sdata->u.mgd; | ||
| 2263 | local = sdata->local; | ||
| 2264 | |||
| 2265 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*pspoll)); | ||
| 2266 | if (!skb) { | ||
| 2267 | printk(KERN_DEBUG "%s: failed to allocate buffer for " | ||
| 2268 | "pspoll template\n", sdata->name); | ||
| 2269 | return NULL; | ||
| 2270 | } | ||
| 2271 | skb_reserve(skb, local->hw.extra_tx_headroom); | ||
| 2272 | |||
| 2273 | pspoll = (struct ieee80211_pspoll *) skb_put(skb, sizeof(*pspoll)); | ||
| 2274 | memset(pspoll, 0, sizeof(*pspoll)); | ||
| 2275 | pspoll->frame_control = cpu_to_le16(IEEE80211_FTYPE_CTL | | ||
| 2276 | IEEE80211_STYPE_PSPOLL); | ||
| 2277 | pspoll->aid = cpu_to_le16(ifmgd->aid); | ||
| 2278 | |||
| 2279 | /* aid in PS-Poll has its two MSBs each set to 1 */ | ||
| 2280 | pspoll->aid |= cpu_to_le16(1 << 15 | 1 << 14); | ||
| 2281 | |||
| 2282 | memcpy(pspoll->bssid, ifmgd->bssid, ETH_ALEN); | ||
| 2283 | memcpy(pspoll->ta, vif->addr, ETH_ALEN); | ||
| 2284 | |||
| 2285 | return skb; | ||
| 2286 | } | ||
| 2287 | EXPORT_SYMBOL(ieee80211_pspoll_get); | ||
| 2288 | |||
| 2289 | struct sk_buff *ieee80211_nullfunc_get(struct ieee80211_hw *hw, | ||
| 2290 | struct ieee80211_vif *vif) | ||
| 2291 | { | ||
| 2292 | struct ieee80211_hdr_3addr *nullfunc; | ||
| 2293 | struct ieee80211_sub_if_data *sdata; | ||
| 2294 | struct ieee80211_if_managed *ifmgd; | ||
| 2295 | struct ieee80211_local *local; | ||
| 2296 | struct sk_buff *skb; | ||
| 2297 | |||
| 2298 | if (WARN_ON(vif->type != NL80211_IFTYPE_STATION)) | ||
| 2299 | return NULL; | ||
| 2300 | |||
| 2301 | sdata = vif_to_sdata(vif); | ||
| 2302 | ifmgd = &sdata->u.mgd; | ||
| 2303 | local = sdata->local; | ||
| 2304 | |||
| 2305 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*nullfunc)); | ||
| 2306 | if (!skb) { | ||
| 2307 | printk(KERN_DEBUG "%s: failed to allocate buffer for nullfunc " | ||
| 2308 | "template\n", sdata->name); | ||
| 2309 | return NULL; | ||
| 2310 | } | ||
| 2311 | skb_reserve(skb, local->hw.extra_tx_headroom); | ||
| 2312 | |||
| 2313 | nullfunc = (struct ieee80211_hdr_3addr *) skb_put(skb, | ||
| 2314 | sizeof(*nullfunc)); | ||
| 2315 | memset(nullfunc, 0, sizeof(*nullfunc)); | ||
| 2316 | nullfunc->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA | | ||
| 2317 | IEEE80211_STYPE_NULLFUNC | | ||
| 2318 | IEEE80211_FCTL_TODS); | ||
| 2319 | memcpy(nullfunc->addr1, ifmgd->bssid, ETH_ALEN); | ||
| 2320 | memcpy(nullfunc->addr2, vif->addr, ETH_ALEN); | ||
| 2321 | memcpy(nullfunc->addr3, ifmgd->bssid, ETH_ALEN); | ||
| 2322 | |||
| 2323 | return skb; | ||
| 2324 | } | ||
| 2325 | EXPORT_SYMBOL(ieee80211_nullfunc_get); | ||
| 2326 | |||
| 2327 | struct sk_buff *ieee80211_probereq_get(struct ieee80211_hw *hw, | ||
| 2328 | struct ieee80211_vif *vif, | ||
| 2329 | const u8 *ssid, size_t ssid_len, | ||
| 2330 | const u8 *ie, size_t ie_len) | ||
| 2331 | { | ||
| 2332 | struct ieee80211_sub_if_data *sdata; | ||
| 2333 | struct ieee80211_local *local; | ||
| 2334 | struct ieee80211_hdr_3addr *hdr; | ||
| 2335 | struct sk_buff *skb; | ||
| 2336 | size_t ie_ssid_len; | ||
| 2337 | u8 *pos; | ||
| 2338 | |||
| 2339 | sdata = vif_to_sdata(vif); | ||
| 2340 | local = sdata->local; | ||
| 2341 | ie_ssid_len = 2 + ssid_len; | ||
| 2342 | |||
| 2343 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*hdr) + | ||
| 2344 | ie_ssid_len + ie_len); | ||
| 2345 | if (!skb) { | ||
| 2346 | printk(KERN_DEBUG "%s: failed to allocate buffer for probe " | ||
| 2347 | "request template\n", sdata->name); | ||
| 2348 | return NULL; | ||
| 2349 | } | ||
| 2350 | |||
| 2351 | skb_reserve(skb, local->hw.extra_tx_headroom); | ||
| 2352 | |||
| 2353 | hdr = (struct ieee80211_hdr_3addr *) skb_put(skb, sizeof(*hdr)); | ||
| 2354 | memset(hdr, 0, sizeof(*hdr)); | ||
| 2355 | hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | ||
| 2356 | IEEE80211_STYPE_PROBE_REQ); | ||
| 2357 | memset(hdr->addr1, 0xff, ETH_ALEN); | ||
| 2358 | memcpy(hdr->addr2, vif->addr, ETH_ALEN); | ||
| 2359 | memset(hdr->addr3, 0xff, ETH_ALEN); | ||
| 2360 | |||
| 2361 | pos = skb_put(skb, ie_ssid_len); | ||
| 2362 | *pos++ = WLAN_EID_SSID; | ||
| 2363 | *pos++ = ssid_len; | ||
| 2364 | if (ssid) | ||
| 2365 | memcpy(pos, ssid, ssid_len); | ||
| 2366 | pos += ssid_len; | ||
| 2367 | |||
| 2368 | if (ie) { | ||
| 2369 | pos = skb_put(skb, ie_len); | ||
| 2370 | memcpy(pos, ie, ie_len); | ||
| 2371 | } | ||
| 2372 | |||
| 2373 | return skb; | ||
| 2374 | } | ||
| 2375 | EXPORT_SYMBOL(ieee80211_probereq_get); | ||
| 2376 | |||
| 2195 | void ieee80211_rts_get(struct ieee80211_hw *hw, struct ieee80211_vif *vif, | 2377 | void ieee80211_rts_get(struct ieee80211_hw *hw, struct ieee80211_vif *vif, |
| 2196 | const void *frame, size_t frame_len, | 2378 | const void *frame, size_t frame_len, |
| 2197 | const struct ieee80211_tx_info *frame_txctl, | 2379 | const struct ieee80211_tx_info *frame_txctl, |
diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 3848140313f5..c453226f06b2 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c | |||
| @@ -18,7 +18,6 @@ | |||
| 18 | #include <linux/skbuff.h> | 18 | #include <linux/skbuff.h> |
| 19 | #include <linux/etherdevice.h> | 19 | #include <linux/etherdevice.h> |
| 20 | #include <linux/if_arp.h> | 20 | #include <linux/if_arp.h> |
| 21 | #include <linux/wireless.h> | ||
| 22 | #include <linux/bitmap.h> | 21 | #include <linux/bitmap.h> |
| 23 | #include <linux/crc32.h> | 22 | #include <linux/crc32.h> |
| 24 | #include <net/net_namespace.h> | 23 | #include <net/net_namespace.h> |
| @@ -480,8 +479,8 @@ void ieee80211_iterate_active_interfaces( | |||
| 480 | case NL80211_IFTYPE_MESH_POINT: | 479 | case NL80211_IFTYPE_MESH_POINT: |
| 481 | break; | 480 | break; |
| 482 | } | 481 | } |
| 483 | if (netif_running(sdata->dev)) | 482 | if (ieee80211_sdata_running(sdata)) |
| 484 | iterator(data, sdata->dev->dev_addr, | 483 | iterator(data, sdata->vif.addr, |
| 485 | &sdata->vif); | 484 | &sdata->vif); |
| 486 | } | 485 | } |
| 487 | 486 | ||
| @@ -514,8 +513,8 @@ void ieee80211_iterate_active_interfaces_atomic( | |||
| 514 | case NL80211_IFTYPE_MESH_POINT: | 513 | case NL80211_IFTYPE_MESH_POINT: |
| 515 | break; | 514 | break; |
| 516 | } | 515 | } |
| 517 | if (netif_running(sdata->dev)) | 516 | if (ieee80211_sdata_running(sdata)) |
| 518 | iterator(data, sdata->dev->dev_addr, | 517 | iterator(data, sdata->vif.addr, |
| 519 | &sdata->vif); | 518 | &sdata->vif); |
| 520 | } | 519 | } |
| 521 | 520 | ||
| @@ -793,6 +792,8 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata) | |||
| 793 | break; | 792 | break; |
| 794 | } | 793 | } |
| 795 | 794 | ||
| 795 | qparam.uapsd = false; | ||
| 796 | |||
| 796 | drv_conf_tx(local, queue, &qparam); | 797 | drv_conf_tx(local, queue, &qparam); |
| 797 | } | 798 | } |
| 798 | } | 799 | } |
| @@ -860,7 +861,7 @@ void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, | |||
| 860 | sizeof(*mgmt) + 6 + extra_len); | 861 | sizeof(*mgmt) + 6 + extra_len); |
| 861 | if (!skb) { | 862 | if (!skb) { |
| 862 | printk(KERN_DEBUG "%s: failed to allocate buffer for auth " | 863 | printk(KERN_DEBUG "%s: failed to allocate buffer for auth " |
| 863 | "frame\n", sdata->dev->name); | 864 | "frame\n", sdata->name); |
| 864 | return; | 865 | return; |
| 865 | } | 866 | } |
| 866 | skb_reserve(skb, local->hw.extra_tx_headroom); | 867 | skb_reserve(skb, local->hw.extra_tx_headroom); |
| @@ -870,7 +871,7 @@ void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, | |||
| 870 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | 871 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | |
| 871 | IEEE80211_STYPE_AUTH); | 872 | IEEE80211_STYPE_AUTH); |
| 872 | memcpy(mgmt->da, bssid, ETH_ALEN); | 873 | memcpy(mgmt->da, bssid, ETH_ALEN); |
| 873 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); | 874 | memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); |
| 874 | memcpy(mgmt->bssid, bssid, ETH_ALEN); | 875 | memcpy(mgmt->bssid, bssid, ETH_ALEN); |
| 875 | mgmt->u.auth.auth_alg = cpu_to_le16(auth_alg); | 876 | mgmt->u.auth.auth_alg = cpu_to_le16(auth_alg); |
| 876 | mgmt->u.auth.auth_transaction = cpu_to_le16(transaction); | 877 | mgmt->u.auth.auth_transaction = cpu_to_le16(transaction); |
| @@ -893,43 +894,87 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, | |||
| 893 | enum ieee80211_band band) | 894 | enum ieee80211_band band) |
| 894 | { | 895 | { |
| 895 | struct ieee80211_supported_band *sband; | 896 | struct ieee80211_supported_band *sband; |
| 896 | u8 *pos, *supp_rates_len, *esupp_rates_len = NULL; | 897 | u8 *pos; |
| 897 | int i; | 898 | size_t offset = 0, noffset; |
| 899 | int supp_rates_len, i; | ||
| 898 | 900 | ||
| 899 | sband = local->hw.wiphy->bands[band]; | 901 | sband = local->hw.wiphy->bands[band]; |
| 900 | 902 | ||
| 901 | pos = buffer; | 903 | pos = buffer; |
| 902 | 904 | ||
| 905 | supp_rates_len = min_t(int, sband->n_bitrates, 8); | ||
| 906 | |||
| 903 | *pos++ = WLAN_EID_SUPP_RATES; | 907 | *pos++ = WLAN_EID_SUPP_RATES; |
| 904 | supp_rates_len = pos; | 908 | *pos++ = supp_rates_len; |
| 905 | *pos++ = 0; | 909 | |
| 906 | 910 | for (i = 0; i < supp_rates_len; i++) { | |
| 907 | for (i = 0; i < sband->n_bitrates; i++) { | 911 | int rate = sband->bitrates[i].bitrate; |
| 908 | struct ieee80211_rate *rate = &sband->bitrates[i]; | 912 | *pos++ = (u8) (rate / 5); |
| 909 | 913 | } | |
| 910 | if (esupp_rates_len) { | 914 | |
| 911 | *esupp_rates_len += 1; | 915 | /* insert "request information" if in custom IEs */ |
| 912 | } else if (*supp_rates_len == 8) { | 916 | if (ie && ie_len) { |
| 913 | *pos++ = WLAN_EID_EXT_SUPP_RATES; | 917 | static const u8 before_extrates[] = { |
| 914 | esupp_rates_len = pos; | 918 | WLAN_EID_SSID, |
| 915 | *pos++ = 1; | 919 | WLAN_EID_SUPP_RATES, |
| 916 | } else | 920 | WLAN_EID_REQUEST, |
| 917 | *supp_rates_len += 1; | 921 | }; |
| 922 | noffset = ieee80211_ie_split(ie, ie_len, | ||
| 923 | before_extrates, | ||
| 924 | ARRAY_SIZE(before_extrates), | ||
| 925 | offset); | ||
| 926 | memcpy(pos, ie + offset, noffset - offset); | ||
| 927 | pos += noffset - offset; | ||
| 928 | offset = noffset; | ||
| 929 | } | ||
| 930 | |||
| 931 | if (sband->n_bitrates > i) { | ||
| 932 | *pos++ = WLAN_EID_EXT_SUPP_RATES; | ||
| 933 | *pos++ = sband->n_bitrates - i; | ||
| 934 | |||
| 935 | for (; i < sband->n_bitrates; i++) { | ||
| 936 | int rate = sband->bitrates[i].bitrate; | ||
| 937 | *pos++ = (u8) (rate / 5); | ||
| 938 | } | ||
| 939 | } | ||
| 918 | 940 | ||
| 919 | *pos++ = rate->bitrate / 5; | 941 | /* insert custom IEs that go before HT */ |
| 942 | if (ie && ie_len) { | ||
| 943 | static const u8 before_ht[] = { | ||
| 944 | WLAN_EID_SSID, | ||
| 945 | WLAN_EID_SUPP_RATES, | ||
| 946 | WLAN_EID_REQUEST, | ||
| 947 | WLAN_EID_EXT_SUPP_RATES, | ||
| 948 | WLAN_EID_DS_PARAMS, | ||
| 949 | WLAN_EID_SUPPORTED_REGULATORY_CLASSES, | ||
| 950 | }; | ||
| 951 | noffset = ieee80211_ie_split(ie, ie_len, | ||
| 952 | before_ht, ARRAY_SIZE(before_ht), | ||
| 953 | offset); | ||
| 954 | memcpy(pos, ie + offset, noffset - offset); | ||
| 955 | pos += noffset - offset; | ||
| 956 | offset = noffset; | ||
| 920 | } | 957 | } |
| 921 | 958 | ||
| 922 | if (sband->ht_cap.ht_supported) { | 959 | if (sband->ht_cap.ht_supported) { |
| 923 | __le16 tmp = cpu_to_le16(sband->ht_cap.cap); | 960 | u16 cap = sband->ht_cap.cap; |
| 961 | __le16 tmp; | ||
| 962 | |||
| 963 | if (ieee80211_disable_40mhz_24ghz && | ||
| 964 | sband->band == IEEE80211_BAND_2GHZ) { | ||
| 965 | cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; | ||
| 966 | cap &= ~IEEE80211_HT_CAP_SGI_40; | ||
| 967 | } | ||
| 924 | 968 | ||
| 925 | *pos++ = WLAN_EID_HT_CAPABILITY; | 969 | *pos++ = WLAN_EID_HT_CAPABILITY; |
| 926 | *pos++ = sizeof(struct ieee80211_ht_cap); | 970 | *pos++ = sizeof(struct ieee80211_ht_cap); |
| 927 | memset(pos, 0, sizeof(struct ieee80211_ht_cap)); | 971 | memset(pos, 0, sizeof(struct ieee80211_ht_cap)); |
| 972 | tmp = cpu_to_le16(cap); | ||
| 928 | memcpy(pos, &tmp, sizeof(u16)); | 973 | memcpy(pos, &tmp, sizeof(u16)); |
| 929 | pos += sizeof(u16); | 974 | pos += sizeof(u16); |
| 930 | /* TODO: needs a define here for << 2 */ | ||
| 931 | *pos++ = sband->ht_cap.ampdu_factor | | 975 | *pos++ = sband->ht_cap.ampdu_factor | |
| 932 | (sband->ht_cap.ampdu_density << 2); | 976 | (sband->ht_cap.ampdu_density << |
| 977 | IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT); | ||
| 933 | memcpy(pos, &sband->ht_cap.mcs, sizeof(sband->ht_cap.mcs)); | 978 | memcpy(pos, &sband->ht_cap.mcs, sizeof(sband->ht_cap.mcs)); |
| 934 | pos += sizeof(sband->ht_cap.mcs); | 979 | pos += sizeof(sband->ht_cap.mcs); |
| 935 | pos += 2 + 4 + 1; /* ext info, BF cap, antsel */ | 980 | pos += 2 + 4 + 1; /* ext info, BF cap, antsel */ |
| @@ -940,9 +985,11 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, | |||
| 940 | * that calculates local->scan_ies_len. | 985 | * that calculates local->scan_ies_len. |
| 941 | */ | 986 | */ |
| 942 | 987 | ||
| 943 | if (ie) { | 988 | /* add any remaining custom IEs */ |
| 944 | memcpy(pos, ie, ie_len); | 989 | if (ie && ie_len) { |
| 945 | pos += ie_len; | 990 | noffset = ie_len; |
| 991 | memcpy(pos, ie + offset, noffset - offset); | ||
| 992 | pos += noffset - offset; | ||
| 946 | } | 993 | } |
| 947 | 994 | ||
| 948 | return pos - buffer; | 995 | return pos - buffer; |
| @@ -955,40 +1002,33 @@ void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, | |||
| 955 | struct ieee80211_local *local = sdata->local; | 1002 | struct ieee80211_local *local = sdata->local; |
| 956 | struct sk_buff *skb; | 1003 | struct sk_buff *skb; |
| 957 | struct ieee80211_mgmt *mgmt; | 1004 | struct ieee80211_mgmt *mgmt; |
| 958 | u8 *pos; | 1005 | size_t buf_len; |
| 959 | 1006 | u8 *buf; | |
| 960 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*mgmt) + 200 + | 1007 | |
| 961 | ie_len); | 1008 | /* FIXME: come up with a proper value */ |
| 962 | if (!skb) { | 1009 | buf = kmalloc(200 + ie_len, GFP_KERNEL); |
| 963 | printk(KERN_DEBUG "%s: failed to allocate buffer for probe " | 1010 | if (!buf) { |
| 964 | "request\n", sdata->dev->name); | 1011 | printk(KERN_DEBUG "%s: failed to allocate temporary IE " |
| 1012 | "buffer\n", sdata->name); | ||
| 965 | return; | 1013 | return; |
| 966 | } | 1014 | } |
| 967 | skb_reserve(skb, local->hw.extra_tx_headroom); | ||
| 968 | 1015 | ||
| 969 | mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); | 1016 | buf_len = ieee80211_build_preq_ies(local, buf, ie, ie_len, |
| 970 | memset(mgmt, 0, 24); | 1017 | local->hw.conf.channel->band); |
| 971 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | 1018 | |
| 972 | IEEE80211_STYPE_PROBE_REQ); | 1019 | skb = ieee80211_probereq_get(&local->hw, &sdata->vif, |
| 973 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); | 1020 | ssid, ssid_len, |
| 1021 | buf, buf_len); | ||
| 1022 | |||
| 974 | if (dst) { | 1023 | if (dst) { |
| 1024 | mgmt = (struct ieee80211_mgmt *) skb->data; | ||
| 975 | memcpy(mgmt->da, dst, ETH_ALEN); | 1025 | memcpy(mgmt->da, dst, ETH_ALEN); |
| 976 | memcpy(mgmt->bssid, dst, ETH_ALEN); | 1026 | memcpy(mgmt->bssid, dst, ETH_ALEN); |
| 977 | } else { | ||
| 978 | memset(mgmt->da, 0xff, ETH_ALEN); | ||
| 979 | memset(mgmt->bssid, 0xff, ETH_ALEN); | ||
| 980 | } | 1027 | } |
| 981 | pos = skb_put(skb, 2 + ssid_len); | ||
| 982 | *pos++ = WLAN_EID_SSID; | ||
| 983 | *pos++ = ssid_len; | ||
| 984 | memcpy(pos, ssid, ssid_len); | ||
| 985 | pos += ssid_len; | ||
| 986 | |||
| 987 | skb_put(skb, ieee80211_build_preq_ies(local, pos, ie, ie_len, | ||
| 988 | local->hw.conf.channel->band)); | ||
| 989 | 1028 | ||
| 990 | IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; | 1029 | IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; |
| 991 | ieee80211_tx_skb(sdata, skb); | 1030 | ieee80211_tx_skb(sdata, skb); |
| 1031 | kfree(buf); | ||
| 992 | } | 1032 | } |
| 993 | 1033 | ||
| 994 | u32 ieee80211_sta_get_rates(struct ieee80211_local *local, | 1034 | u32 ieee80211_sta_get_rates(struct ieee80211_local *local, |
| @@ -1032,18 +1072,16 @@ void ieee80211_stop_device(struct ieee80211_local *local) | |||
| 1032 | ieee80211_led_radio(local, false); | 1072 | ieee80211_led_radio(local, false); |
| 1033 | 1073 | ||
| 1034 | cancel_work_sync(&local->reconfig_filter); | 1074 | cancel_work_sync(&local->reconfig_filter); |
| 1035 | drv_stop(local); | ||
| 1036 | 1075 | ||
| 1037 | flush_workqueue(local->workqueue); | 1076 | flush_workqueue(local->workqueue); |
| 1077 | drv_stop(local); | ||
| 1038 | } | 1078 | } |
| 1039 | 1079 | ||
| 1040 | int ieee80211_reconfig(struct ieee80211_local *local) | 1080 | int ieee80211_reconfig(struct ieee80211_local *local) |
| 1041 | { | 1081 | { |
| 1042 | struct ieee80211_hw *hw = &local->hw; | 1082 | struct ieee80211_hw *hw = &local->hw; |
| 1043 | struct ieee80211_sub_if_data *sdata; | 1083 | struct ieee80211_sub_if_data *sdata; |
| 1044 | struct ieee80211_if_init_conf conf; | ||
| 1045 | struct sta_info *sta; | 1084 | struct sta_info *sta; |
| 1046 | unsigned long flags; | ||
| 1047 | int res; | 1085 | int res; |
| 1048 | 1086 | ||
| 1049 | if (local->suspended) | 1087 | if (local->suspended) |
| @@ -1061,7 +1099,7 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
| 1061 | if (res) { | 1099 | if (res) { |
| 1062 | WARN(local->suspended, "Harware became unavailable " | 1100 | WARN(local->suspended, "Harware became unavailable " |
| 1063 | "upon resume. This is could be a software issue" | 1101 | "upon resume. This is could be a software issue" |
| 1064 | "prior to suspend or a harware issue\n"); | 1102 | "prior to suspend or a hardware issue\n"); |
| 1065 | return res; | 1103 | return res; |
| 1066 | } | 1104 | } |
| 1067 | 1105 | ||
| @@ -1072,29 +1110,24 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
| 1072 | list_for_each_entry(sdata, &local->interfaces, list) { | 1110 | list_for_each_entry(sdata, &local->interfaces, list) { |
| 1073 | if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN && | 1111 | if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN && |
| 1074 | sdata->vif.type != NL80211_IFTYPE_MONITOR && | 1112 | sdata->vif.type != NL80211_IFTYPE_MONITOR && |
| 1075 | netif_running(sdata->dev)) { | 1113 | ieee80211_sdata_running(sdata)) |
| 1076 | conf.vif = &sdata->vif; | 1114 | res = drv_add_interface(local, &sdata->vif); |
| 1077 | conf.type = sdata->vif.type; | ||
| 1078 | conf.mac_addr = sdata->dev->dev_addr; | ||
| 1079 | res = drv_add_interface(local, &conf); | ||
| 1080 | } | ||
| 1081 | } | 1115 | } |
| 1082 | 1116 | ||
| 1083 | /* add STAs back */ | 1117 | /* add STAs back */ |
| 1084 | if (local->ops->sta_notify) { | 1118 | mutex_lock(&local->sta_mtx); |
| 1085 | spin_lock_irqsave(&local->sta_lock, flags); | 1119 | list_for_each_entry(sta, &local->sta_list, list) { |
| 1086 | list_for_each_entry(sta, &local->sta_list, list) { | 1120 | if (sta->uploaded) { |
| 1087 | sdata = sta->sdata; | 1121 | sdata = sta->sdata; |
| 1088 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | 1122 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) |
| 1089 | sdata = container_of(sdata->bss, | 1123 | sdata = container_of(sdata->bss, |
| 1090 | struct ieee80211_sub_if_data, | 1124 | struct ieee80211_sub_if_data, |
| 1091 | u.ap); | 1125 | u.ap); |
| 1092 | 1126 | ||
| 1093 | drv_sta_notify(local, &sdata->vif, STA_NOTIFY_ADD, | 1127 | WARN_ON(drv_sta_add(local, sdata, &sta->sta)); |
| 1094 | &sta->sta); | ||
| 1095 | } | 1128 | } |
| 1096 | spin_unlock_irqrestore(&local->sta_lock, flags); | ||
| 1097 | } | 1129 | } |
| 1130 | mutex_unlock(&local->sta_mtx); | ||
| 1098 | 1131 | ||
| 1099 | /* Clear Suspend state so that ADDBA requests can be processed */ | 1132 | /* Clear Suspend state so that ADDBA requests can be processed */ |
| 1100 | 1133 | ||
| @@ -1119,7 +1152,7 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
| 1119 | /* Finally also reconfigure all the BSS information */ | 1152 | /* Finally also reconfigure all the BSS information */ |
| 1120 | list_for_each_entry(sdata, &local->interfaces, list) { | 1153 | list_for_each_entry(sdata, &local->interfaces, list) { |
| 1121 | u32 changed = ~0; | 1154 | u32 changed = ~0; |
| 1122 | if (!netif_running(sdata->dev)) | 1155 | if (!ieee80211_sdata_running(sdata)) |
| 1123 | continue; | 1156 | continue; |
| 1124 | switch (sdata->vif.type) { | 1157 | switch (sdata->vif.type) { |
| 1125 | case NL80211_IFTYPE_STATION: | 1158 | case NL80211_IFTYPE_STATION: |
| @@ -1145,9 +1178,17 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
| 1145 | } | 1178 | } |
| 1146 | } | 1179 | } |
| 1147 | 1180 | ||
| 1181 | rcu_read_lock(); | ||
| 1182 | if (hw->flags & IEEE80211_HW_AMPDU_AGGREGATION) { | ||
| 1183 | list_for_each_entry_rcu(sta, &local->sta_list, list) { | ||
| 1184 | ieee80211_sta_tear_down_BA_sessions(sta); | ||
| 1185 | } | ||
| 1186 | } | ||
| 1187 | rcu_read_unlock(); | ||
| 1188 | |||
| 1148 | /* add back keys */ | 1189 | /* add back keys */ |
| 1149 | list_for_each_entry(sdata, &local->interfaces, list) | 1190 | list_for_each_entry(sdata, &local->interfaces, list) |
| 1150 | if (netif_running(sdata->dev)) | 1191 | if (ieee80211_sdata_running(sdata)) |
| 1151 | ieee80211_enable_keys(sdata); | 1192 | ieee80211_enable_keys(sdata); |
| 1152 | 1193 | ||
| 1153 | ieee80211_wake_queues_by_reason(hw, | 1194 | ieee80211_wake_queues_by_reason(hw, |
| @@ -1184,13 +1225,143 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
| 1184 | 1225 | ||
| 1185 | add_timer(&local->sta_cleanup); | 1226 | add_timer(&local->sta_cleanup); |
| 1186 | 1227 | ||
| 1187 | spin_lock_irqsave(&local->sta_lock, flags); | 1228 | mutex_lock(&local->sta_mtx); |
| 1188 | list_for_each_entry(sta, &local->sta_list, list) | 1229 | list_for_each_entry(sta, &local->sta_list, list) |
| 1189 | mesh_plink_restart(sta); | 1230 | mesh_plink_restart(sta); |
| 1190 | spin_unlock_irqrestore(&local->sta_lock, flags); | 1231 | mutex_unlock(&local->sta_mtx); |
| 1191 | #else | 1232 | #else |
| 1192 | WARN_ON(1); | 1233 | WARN_ON(1); |
| 1193 | #endif | 1234 | #endif |
| 1194 | return 0; | 1235 | return 0; |
| 1195 | } | 1236 | } |
| 1196 | 1237 | ||
| 1238 | static int check_mgd_smps(struct ieee80211_if_managed *ifmgd, | ||
| 1239 | enum ieee80211_smps_mode *smps_mode) | ||
| 1240 | { | ||
| 1241 | if (ifmgd->associated) { | ||
| 1242 | *smps_mode = ifmgd->ap_smps; | ||
| 1243 | |||
| 1244 | if (*smps_mode == IEEE80211_SMPS_AUTOMATIC) { | ||
| 1245 | if (ifmgd->powersave) | ||
| 1246 | *smps_mode = IEEE80211_SMPS_DYNAMIC; | ||
| 1247 | else | ||
| 1248 | *smps_mode = IEEE80211_SMPS_OFF; | ||
| 1249 | } | ||
| 1250 | |||
| 1251 | return 1; | ||
| 1252 | } | ||
| 1253 | |||
| 1254 | return 0; | ||
| 1255 | } | ||
| 1256 | |||
| 1257 | /* must hold iflist_mtx */ | ||
| 1258 | void ieee80211_recalc_smps(struct ieee80211_local *local, | ||
| 1259 | struct ieee80211_sub_if_data *forsdata) | ||
| 1260 | { | ||
| 1261 | struct ieee80211_sub_if_data *sdata; | ||
| 1262 | enum ieee80211_smps_mode smps_mode = IEEE80211_SMPS_OFF; | ||
| 1263 | int count = 0; | ||
| 1264 | |||
| 1265 | if (forsdata) | ||
| 1266 | WARN_ON(!mutex_is_locked(&forsdata->u.mgd.mtx)); | ||
| 1267 | |||
| 1268 | WARN_ON(!mutex_is_locked(&local->iflist_mtx)); | ||
| 1269 | |||
| 1270 | /* | ||
| 1271 | * This function could be improved to handle multiple | ||
| 1272 | * interfaces better, but right now it makes any | ||
| 1273 | * non-station interfaces force SM PS to be turned | ||
| 1274 | * off. If there are multiple station interfaces it | ||
| 1275 | * could also use the best possible mode, e.g. if | ||
| 1276 | * one is in static and the other in dynamic then | ||
| 1277 | * dynamic is ok. | ||
| 1278 | */ | ||
| 1279 | |||
| 1280 | list_for_each_entry(sdata, &local->interfaces, list) { | ||
| 1281 | if (!netif_running(sdata->dev)) | ||
| 1282 | continue; | ||
| 1283 | if (sdata->vif.type != NL80211_IFTYPE_STATION) | ||
| 1284 | goto set; | ||
| 1285 | if (sdata != forsdata) { | ||
| 1286 | /* | ||
| 1287 | * This nested is ok -- we are holding the iflist_mtx | ||
| 1288 | * so can't get here twice or so. But it's required | ||
| 1289 | * since normally we acquire it first and then the | ||
| 1290 | * iflist_mtx. | ||
| 1291 | */ | ||
| 1292 | mutex_lock_nested(&sdata->u.mgd.mtx, SINGLE_DEPTH_NESTING); | ||
| 1293 | count += check_mgd_smps(&sdata->u.mgd, &smps_mode); | ||
| 1294 | mutex_unlock(&sdata->u.mgd.mtx); | ||
| 1295 | } else | ||
| 1296 | count += check_mgd_smps(&sdata->u.mgd, &smps_mode); | ||
| 1297 | |||
| 1298 | if (count > 1) { | ||
| 1299 | smps_mode = IEEE80211_SMPS_OFF; | ||
| 1300 | break; | ||
| 1301 | } | ||
| 1302 | } | ||
| 1303 | |||
| 1304 | if (smps_mode == local->smps_mode) | ||
| 1305 | return; | ||
| 1306 | |||
| 1307 | set: | ||
| 1308 | local->smps_mode = smps_mode; | ||
| 1309 | /* changed flag is auto-detected for this */ | ||
| 1310 | ieee80211_hw_config(local, 0); | ||
| 1311 | } | ||
| 1312 | |||
| 1313 | static bool ieee80211_id_in_list(const u8 *ids, int n_ids, u8 id) | ||
| 1314 | { | ||
| 1315 | int i; | ||
| 1316 | |||
| 1317 | for (i = 0; i < n_ids; i++) | ||
| 1318 | if (ids[i] == id) | ||
| 1319 | return true; | ||
| 1320 | return false; | ||
| 1321 | } | ||
| 1322 | |||
| 1323 | /** | ||
| 1324 | * ieee80211_ie_split - split an IE buffer according to ordering | ||
| 1325 | * | ||
| 1326 | * @ies: the IE buffer | ||
| 1327 | * @ielen: the length of the IE buffer | ||
| 1328 | * @ids: an array with element IDs that are allowed before | ||
| 1329 | * the split | ||
| 1330 | * @n_ids: the size of the element ID array | ||
| 1331 | * @offset: offset where to start splitting in the buffer | ||
| 1332 | * | ||
| 1333 | * This function splits an IE buffer by updating the @offset | ||
| 1334 | * variable to point to the location where the buffer should be | ||
| 1335 | * split. | ||
| 1336 | * | ||
| 1337 | * It assumes that the given IE buffer is well-formed, this | ||
| 1338 | * has to be guaranteed by the caller! | ||
| 1339 | * | ||
| 1340 | * It also assumes that the IEs in the buffer are ordered | ||
| 1341 | * correctly, if not the result of using this function will not | ||
| 1342 | * be ordered correctly either, i.e. it does no reordering. | ||
| 1343 | * | ||
| 1344 | * The function returns the offset where the next part of the | ||
| 1345 | * buffer starts, which may be @ielen if the entire (remainder) | ||
| 1346 | * of the buffer should be used. | ||
| 1347 | */ | ||
| 1348 | size_t ieee80211_ie_split(const u8 *ies, size_t ielen, | ||
| 1349 | const u8 *ids, int n_ids, size_t offset) | ||
| 1350 | { | ||
| 1351 | size_t pos = offset; | ||
| 1352 | |||
| 1353 | while (pos < ielen && ieee80211_id_in_list(ids, n_ids, ies[pos])) | ||
| 1354 | pos += 2 + ies[pos + 1]; | ||
| 1355 | |||
| 1356 | return pos; | ||
| 1357 | } | ||
| 1358 | |||
| 1359 | size_t ieee80211_ie_split_vendor(const u8 *ies, size_t ielen, size_t offset) | ||
| 1360 | { | ||
| 1361 | size_t pos = offset; | ||
| 1362 | |||
| 1363 | while (pos < ielen && ies[pos] != WLAN_EID_VENDOR_SPECIFIC) | ||
| 1364 | pos += 2 + ies[pos + 1]; | ||
| 1365 | |||
| 1366 | return pos; | ||
| 1367 | } | ||
diff --git a/net/mac80211/wep.c b/net/mac80211/wep.c index 247123fe1a7a..5d745f2d7236 100644 --- a/net/mac80211/wep.c +++ b/net/mac80211/wep.c | |||
| @@ -305,20 +305,19 @@ static int wep_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb) | |||
| 305 | { | 305 | { |
| 306 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | 306 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
| 307 | 307 | ||
| 308 | if (!(tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) { | 308 | if (!info->control.hw_key) { |
| 309 | if (ieee80211_wep_encrypt(tx->local, skb, tx->key->conf.key, | 309 | if (ieee80211_wep_encrypt(tx->local, skb, tx->key->conf.key, |
| 310 | tx->key->conf.keylen, | 310 | tx->key->conf.keylen, |
| 311 | tx->key->conf.keyidx)) | 311 | tx->key->conf.keyidx)) |
| 312 | return -1; | 312 | return -1; |
| 313 | } else { | 313 | } else if (info->control.hw_key->flags & |
| 314 | info->control.hw_key = &tx->key->conf; | 314 | IEEE80211_KEY_FLAG_GENERATE_IV) { |
| 315 | if (tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV) { | 315 | if (!ieee80211_wep_add_iv(tx->local, skb, |
| 316 | if (!ieee80211_wep_add_iv(tx->local, skb, | 316 | tx->key->conf.keylen, |
| 317 | tx->key->conf.keylen, | 317 | tx->key->conf.keyidx)) |
| 318 | tx->key->conf.keyidx)) | 318 | return -1; |
| 319 | return -1; | ||
| 320 | } | ||
| 321 | } | 319 | } |
| 320 | |||
| 322 | return 0; | 321 | return 0; |
| 323 | } | 322 | } |
| 324 | 323 | ||
diff --git a/net/mac80211/wme.c b/net/mac80211/wme.c index 79d887dae738..34e6d02da779 100644 --- a/net/mac80211/wme.c +++ b/net/mac80211/wme.c | |||
| @@ -96,7 +96,7 @@ u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata, | |||
| 96 | } | 96 | } |
| 97 | 97 | ||
| 98 | if (!sta && ra && !is_multicast_ether_addr(ra)) { | 98 | if (!sta && ra && !is_multicast_ether_addr(ra)) { |
| 99 | sta = sta_info_get(local, ra); | 99 | sta = sta_info_get(sdata, ra); |
| 100 | if (sta) | 100 | if (sta) |
| 101 | sta_flags = get_sta_flags(sta); | 101 | sta_flags = get_sta_flags(sta); |
| 102 | } | 102 | } |
diff --git a/net/mac80211/work.c b/net/mac80211/work.c new file mode 100644 index 000000000000..1e1ea3007b06 --- /dev/null +++ b/net/mac80211/work.c | |||
| @@ -0,0 +1,1100 @@ | |||
| 1 | /* | ||
| 2 | * mac80211 work implementation | ||
| 3 | * | ||
| 4 | * Copyright 2003-2008, Jouni Malinen <j@w1.fi> | ||
| 5 | * Copyright 2004, Instant802 Networks, Inc. | ||
| 6 | * Copyright 2005, Devicescape Software, Inc. | ||
| 7 | * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz> | ||
| 8 | * Copyright 2007, Michael Wu <flamingice@sourmilk.net> | ||
| 9 | * Copyright 2009, Johannes Berg <johannes@sipsolutions.net> | ||
| 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/delay.h> | ||
| 17 | #include <linux/if_ether.h> | ||
| 18 | #include <linux/skbuff.h> | ||
| 19 | #include <linux/if_arp.h> | ||
| 20 | #include <linux/etherdevice.h> | ||
| 21 | #include <linux/crc32.h> | ||
| 22 | #include <net/mac80211.h> | ||
| 23 | #include <asm/unaligned.h> | ||
| 24 | |||
| 25 | #include "ieee80211_i.h" | ||
| 26 | #include "rate.h" | ||
| 27 | |||
| 28 | #define IEEE80211_AUTH_TIMEOUT (HZ / 5) | ||
| 29 | #define IEEE80211_AUTH_MAX_TRIES 3 | ||
| 30 | #define IEEE80211_ASSOC_TIMEOUT (HZ / 5) | ||
| 31 | #define IEEE80211_ASSOC_MAX_TRIES 3 | ||
| 32 | #define IEEE80211_MAX_PROBE_TRIES 5 | ||
| 33 | |||
| 34 | enum work_action { | ||
| 35 | WORK_ACT_NONE, | ||
| 36 | WORK_ACT_TIMEOUT, | ||
| 37 | WORK_ACT_DONE, | ||
| 38 | }; | ||
| 39 | |||
| 40 | |||
| 41 | /* utils */ | ||
| 42 | static inline void ASSERT_WORK_MTX(struct ieee80211_local *local) | ||
| 43 | { | ||
| 44 | WARN_ON(!mutex_is_locked(&local->work_mtx)); | ||
| 45 | } | ||
| 46 | |||
| 47 | /* | ||
| 48 | * We can have multiple work items (and connection probing) | ||
| 49 | * scheduling this timer, but we need to take care to only | ||
| 50 | * reschedule it when it should fire _earlier_ than it was | ||
| 51 | * asked for before, or if it's not pending right now. This | ||
| 52 | * function ensures that. Note that it then is required to | ||
| 53 | * run this function for all timeouts after the first one | ||
| 54 | * has happened -- the work that runs from this timer will | ||
| 55 | * do that. | ||
| 56 | */ | ||
| 57 | static void run_again(struct ieee80211_local *local, | ||
| 58 | unsigned long timeout) | ||
| 59 | { | ||
| 60 | ASSERT_WORK_MTX(local); | ||
| 61 | |||
| 62 | if (!timer_pending(&local->work_timer) || | ||
| 63 | time_before(timeout, local->work_timer.expires)) | ||
| 64 | mod_timer(&local->work_timer, timeout); | ||
| 65 | } | ||
| 66 | |||
| 67 | static void work_free_rcu(struct rcu_head *head) | ||
| 68 | { | ||
| 69 | struct ieee80211_work *wk = | ||
| 70 | container_of(head, struct ieee80211_work, rcu_head); | ||
| 71 | |||
| 72 | kfree(wk); | ||
| 73 | } | ||
| 74 | |||
| 75 | void free_work(struct ieee80211_work *wk) | ||
| 76 | { | ||
| 77 | call_rcu(&wk->rcu_head, work_free_rcu); | ||
| 78 | } | ||
| 79 | |||
| 80 | static int ieee80211_compatible_rates(const u8 *supp_rates, int supp_rates_len, | ||
| 81 | struct ieee80211_supported_band *sband, | ||
| 82 | u32 *rates) | ||
| 83 | { | ||
| 84 | int i, j, count; | ||
| 85 | *rates = 0; | ||
| 86 | count = 0; | ||
| 87 | for (i = 0; i < supp_rates_len; i++) { | ||
| 88 | int rate = (supp_rates[i] & 0x7F) * 5; | ||
| 89 | |||
| 90 | for (j = 0; j < sband->n_bitrates; j++) | ||
| 91 | if (sband->bitrates[j].bitrate == rate) { | ||
| 92 | *rates |= BIT(j); | ||
| 93 | count++; | ||
| 94 | break; | ||
| 95 | } | ||
| 96 | } | ||
| 97 | |||
| 98 | return count; | ||
| 99 | } | ||
| 100 | |||
| 101 | /* frame sending functions */ | ||
| 102 | |||
| 103 | static void ieee80211_add_ht_ie(struct sk_buff *skb, const u8 *ht_info_ie, | ||
| 104 | struct ieee80211_supported_band *sband, | ||
| 105 | struct ieee80211_channel *channel, | ||
| 106 | enum ieee80211_smps_mode smps) | ||
| 107 | { | ||
| 108 | struct ieee80211_ht_info *ht_info; | ||
| 109 | u8 *pos; | ||
| 110 | u32 flags = channel->flags; | ||
| 111 | u16 cap = sband->ht_cap.cap; | ||
| 112 | __le16 tmp; | ||
| 113 | |||
| 114 | if (!sband->ht_cap.ht_supported) | ||
| 115 | return; | ||
| 116 | |||
| 117 | if (!ht_info_ie) | ||
| 118 | return; | ||
| 119 | |||
| 120 | if (ht_info_ie[1] < sizeof(struct ieee80211_ht_info)) | ||
| 121 | return; | ||
| 122 | |||
| 123 | ht_info = (struct ieee80211_ht_info *)(ht_info_ie + 2); | ||
| 124 | |||
| 125 | /* determine capability flags */ | ||
| 126 | |||
| 127 | if (ieee80211_disable_40mhz_24ghz && | ||
| 128 | sband->band == IEEE80211_BAND_2GHZ) { | ||
| 129 | cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; | ||
| 130 | cap &= ~IEEE80211_HT_CAP_SGI_40; | ||
| 131 | } | ||
| 132 | |||
| 133 | switch (ht_info->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) { | ||
| 134 | case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: | ||
| 135 | if (flags & IEEE80211_CHAN_NO_HT40PLUS) { | ||
| 136 | cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; | ||
| 137 | cap &= ~IEEE80211_HT_CAP_SGI_40; | ||
| 138 | } | ||
| 139 | break; | ||
| 140 | case IEEE80211_HT_PARAM_CHA_SEC_BELOW: | ||
| 141 | if (flags & IEEE80211_CHAN_NO_HT40MINUS) { | ||
| 142 | cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; | ||
| 143 | cap &= ~IEEE80211_HT_CAP_SGI_40; | ||
| 144 | } | ||
| 145 | break; | ||
| 146 | } | ||
| 147 | |||
| 148 | /* set SM PS mode properly */ | ||
| 149 | cap &= ~IEEE80211_HT_CAP_SM_PS; | ||
| 150 | switch (smps) { | ||
| 151 | case IEEE80211_SMPS_AUTOMATIC: | ||
| 152 | case IEEE80211_SMPS_NUM_MODES: | ||
| 153 | WARN_ON(1); | ||
| 154 | case IEEE80211_SMPS_OFF: | ||
| 155 | cap |= WLAN_HT_CAP_SM_PS_DISABLED << | ||
| 156 | IEEE80211_HT_CAP_SM_PS_SHIFT; | ||
| 157 | break; | ||
| 158 | case IEEE80211_SMPS_STATIC: | ||
| 159 | cap |= WLAN_HT_CAP_SM_PS_STATIC << | ||
| 160 | IEEE80211_HT_CAP_SM_PS_SHIFT; | ||
| 161 | break; | ||
| 162 | case IEEE80211_SMPS_DYNAMIC: | ||
| 163 | cap |= WLAN_HT_CAP_SM_PS_DYNAMIC << | ||
| 164 | IEEE80211_HT_CAP_SM_PS_SHIFT; | ||
| 165 | break; | ||
| 166 | } | ||
| 167 | |||
| 168 | /* reserve and fill IE */ | ||
| 169 | |||
| 170 | pos = skb_put(skb, sizeof(struct ieee80211_ht_cap) + 2); | ||
| 171 | *pos++ = WLAN_EID_HT_CAPABILITY; | ||
| 172 | *pos++ = sizeof(struct ieee80211_ht_cap); | ||
| 173 | memset(pos, 0, sizeof(struct ieee80211_ht_cap)); | ||
| 174 | |||
| 175 | /* capability flags */ | ||
| 176 | tmp = cpu_to_le16(cap); | ||
| 177 | memcpy(pos, &tmp, sizeof(u16)); | ||
| 178 | pos += sizeof(u16); | ||
| 179 | |||
| 180 | /* AMPDU parameters */ | ||
| 181 | *pos++ = sband->ht_cap.ampdu_factor | | ||
| 182 | (sband->ht_cap.ampdu_density << | ||
| 183 | IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT); | ||
| 184 | |||
| 185 | /* MCS set */ | ||
| 186 | memcpy(pos, &sband->ht_cap.mcs, sizeof(sband->ht_cap.mcs)); | ||
| 187 | pos += sizeof(sband->ht_cap.mcs); | ||
| 188 | |||
| 189 | /* extended capabilities */ | ||
| 190 | pos += sizeof(__le16); | ||
| 191 | |||
| 192 | /* BF capabilities */ | ||
| 193 | pos += sizeof(__le32); | ||
| 194 | |||
| 195 | /* antenna selection */ | ||
| 196 | pos += sizeof(u8); | ||
| 197 | } | ||
| 198 | |||
| 199 | static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, | ||
| 200 | struct ieee80211_work *wk) | ||
| 201 | { | ||
| 202 | struct ieee80211_local *local = sdata->local; | ||
| 203 | struct sk_buff *skb; | ||
| 204 | struct ieee80211_mgmt *mgmt; | ||
| 205 | u8 *pos, qos_info; | ||
| 206 | const u8 *ies; | ||
| 207 | size_t offset = 0, noffset; | ||
| 208 | int i, len, count, rates_len, supp_rates_len; | ||
| 209 | u16 capab; | ||
| 210 | struct ieee80211_supported_band *sband; | ||
| 211 | u32 rates = 0; | ||
| 212 | |||
| 213 | sband = local->hw.wiphy->bands[wk->chan->band]; | ||
| 214 | |||
| 215 | /* | ||
| 216 | * Get all rates supported by the device and the AP as | ||
| 217 | * some APs don't like getting a superset of their rates | ||
| 218 | * in the association request (e.g. D-Link DAP 1353 in | ||
| 219 | * b-only mode)... | ||
| 220 | */ | ||
| 221 | rates_len = ieee80211_compatible_rates(wk->assoc.supp_rates, | ||
| 222 | wk->assoc.supp_rates_len, | ||
| 223 | sband, &rates); | ||
| 224 | |||
| 225 | skb = alloc_skb(local->hw.extra_tx_headroom + | ||
| 226 | sizeof(*mgmt) + /* bit too much but doesn't matter */ | ||
| 227 | 2 + wk->assoc.ssid_len + /* SSID */ | ||
| 228 | 4 + rates_len + /* (extended) rates */ | ||
| 229 | 4 + /* power capability */ | ||
| 230 | 2 + 2 * sband->n_channels + /* supported channels */ | ||
| 231 | 2 + sizeof(struct ieee80211_ht_cap) + /* HT */ | ||
| 232 | wk->ie_len + /* extra IEs */ | ||
| 233 | 9, /* WMM */ | ||
| 234 | GFP_KERNEL); | ||
| 235 | if (!skb) { | ||
| 236 | printk(KERN_DEBUG "%s: failed to allocate buffer for assoc " | ||
| 237 | "frame\n", sdata->name); | ||
| 238 | return; | ||
| 239 | } | ||
| 240 | skb_reserve(skb, local->hw.extra_tx_headroom); | ||
| 241 | |||
| 242 | capab = WLAN_CAPABILITY_ESS; | ||
| 243 | |||
| 244 | if (sband->band == IEEE80211_BAND_2GHZ) { | ||
| 245 | if (!(local->hw.flags & IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE)) | ||
| 246 | capab |= WLAN_CAPABILITY_SHORT_SLOT_TIME; | ||
| 247 | if (!(local->hw.flags & IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE)) | ||
| 248 | capab |= WLAN_CAPABILITY_SHORT_PREAMBLE; | ||
| 249 | } | ||
| 250 | |||
| 251 | if (wk->assoc.capability & WLAN_CAPABILITY_PRIVACY) | ||
| 252 | capab |= WLAN_CAPABILITY_PRIVACY; | ||
| 253 | |||
| 254 | if ((wk->assoc.capability & WLAN_CAPABILITY_SPECTRUM_MGMT) && | ||
| 255 | (local->hw.flags & IEEE80211_HW_SPECTRUM_MGMT)) | ||
| 256 | capab |= WLAN_CAPABILITY_SPECTRUM_MGMT; | ||
| 257 | |||
| 258 | mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); | ||
| 259 | memset(mgmt, 0, 24); | ||
| 260 | memcpy(mgmt->da, wk->filter_ta, ETH_ALEN); | ||
| 261 | memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); | ||
| 262 | memcpy(mgmt->bssid, wk->filter_ta, ETH_ALEN); | ||
| 263 | |||
| 264 | if (!is_zero_ether_addr(wk->assoc.prev_bssid)) { | ||
| 265 | skb_put(skb, 10); | ||
| 266 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | ||
| 267 | IEEE80211_STYPE_REASSOC_REQ); | ||
| 268 | mgmt->u.reassoc_req.capab_info = cpu_to_le16(capab); | ||
| 269 | mgmt->u.reassoc_req.listen_interval = | ||
| 270 | cpu_to_le16(local->hw.conf.listen_interval); | ||
| 271 | memcpy(mgmt->u.reassoc_req.current_ap, wk->assoc.prev_bssid, | ||
| 272 | ETH_ALEN); | ||
| 273 | } else { | ||
| 274 | skb_put(skb, 4); | ||
| 275 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | ||
| 276 | IEEE80211_STYPE_ASSOC_REQ); | ||
| 277 | mgmt->u.assoc_req.capab_info = cpu_to_le16(capab); | ||
| 278 | mgmt->u.assoc_req.listen_interval = | ||
| 279 | cpu_to_le16(local->hw.conf.listen_interval); | ||
| 280 | } | ||
| 281 | |||
| 282 | /* SSID */ | ||
| 283 | ies = pos = skb_put(skb, 2 + wk->assoc.ssid_len); | ||
| 284 | *pos++ = WLAN_EID_SSID; | ||
| 285 | *pos++ = wk->assoc.ssid_len; | ||
| 286 | memcpy(pos, wk->assoc.ssid, wk->assoc.ssid_len); | ||
| 287 | |||
| 288 | /* add all rates which were marked to be used above */ | ||
| 289 | supp_rates_len = rates_len; | ||
| 290 | if (supp_rates_len > 8) | ||
| 291 | supp_rates_len = 8; | ||
| 292 | |||
| 293 | len = sband->n_bitrates; | ||
| 294 | pos = skb_put(skb, supp_rates_len + 2); | ||
| 295 | *pos++ = WLAN_EID_SUPP_RATES; | ||
| 296 | *pos++ = supp_rates_len; | ||
| 297 | |||
| 298 | count = 0; | ||
| 299 | for (i = 0; i < sband->n_bitrates; i++) { | ||
| 300 | if (BIT(i) & rates) { | ||
| 301 | int rate = sband->bitrates[i].bitrate; | ||
| 302 | *pos++ = (u8) (rate / 5); | ||
| 303 | if (++count == 8) | ||
| 304 | break; | ||
| 305 | } | ||
| 306 | } | ||
| 307 | |||
| 308 | if (rates_len > count) { | ||
| 309 | pos = skb_put(skb, rates_len - count + 2); | ||
| 310 | *pos++ = WLAN_EID_EXT_SUPP_RATES; | ||
| 311 | *pos++ = rates_len - count; | ||
| 312 | |||
| 313 | for (i++; i < sband->n_bitrates; i++) { | ||
| 314 | if (BIT(i) & rates) { | ||
| 315 | int rate = sband->bitrates[i].bitrate; | ||
| 316 | *pos++ = (u8) (rate / 5); | ||
| 317 | } | ||
| 318 | } | ||
| 319 | } | ||
| 320 | |||
| 321 | if (capab & WLAN_CAPABILITY_SPECTRUM_MGMT) { | ||
| 322 | /* 1. power capabilities */ | ||
| 323 | pos = skb_put(skb, 4); | ||
| 324 | *pos++ = WLAN_EID_PWR_CAPABILITY; | ||
| 325 | *pos++ = 2; | ||
| 326 | *pos++ = 0; /* min tx power */ | ||
| 327 | *pos++ = wk->chan->max_power; /* max tx power */ | ||
| 328 | |||
| 329 | /* 2. supported channels */ | ||
| 330 | /* TODO: get this in reg domain format */ | ||
| 331 | pos = skb_put(skb, 2 * sband->n_channels + 2); | ||
| 332 | *pos++ = WLAN_EID_SUPPORTED_CHANNELS; | ||
| 333 | *pos++ = 2 * sband->n_channels; | ||
| 334 | for (i = 0; i < sband->n_channels; i++) { | ||
| 335 | *pos++ = ieee80211_frequency_to_channel( | ||
| 336 | sband->channels[i].center_freq); | ||
| 337 | *pos++ = 1; /* one channel in the subband*/ | ||
| 338 | } | ||
| 339 | } | ||
| 340 | |||
| 341 | /* if present, add any custom IEs that go before HT */ | ||
| 342 | if (wk->ie_len && wk->ie) { | ||
| 343 | static const u8 before_ht[] = { | ||
| 344 | WLAN_EID_SSID, | ||
| 345 | WLAN_EID_SUPP_RATES, | ||
| 346 | WLAN_EID_EXT_SUPP_RATES, | ||
| 347 | WLAN_EID_PWR_CAPABILITY, | ||
| 348 | WLAN_EID_SUPPORTED_CHANNELS, | ||
| 349 | WLAN_EID_RSN, | ||
| 350 | WLAN_EID_QOS_CAPA, | ||
| 351 | WLAN_EID_RRM_ENABLED_CAPABILITIES, | ||
| 352 | WLAN_EID_MOBILITY_DOMAIN, | ||
| 353 | WLAN_EID_SUPPORTED_REGULATORY_CLASSES, | ||
| 354 | }; | ||
| 355 | noffset = ieee80211_ie_split(wk->ie, wk->ie_len, | ||
| 356 | before_ht, ARRAY_SIZE(before_ht), | ||
| 357 | offset); | ||
| 358 | pos = skb_put(skb, noffset - offset); | ||
| 359 | memcpy(pos, wk->ie + offset, noffset - offset); | ||
| 360 | offset = noffset; | ||
| 361 | } | ||
| 362 | |||
| 363 | if (wk->assoc.use_11n && wk->assoc.wmm_used && | ||
| 364 | local->hw.queues >= 4) | ||
| 365 | ieee80211_add_ht_ie(skb, wk->assoc.ht_information_ie, | ||
| 366 | sband, wk->chan, wk->assoc.smps); | ||
| 367 | |||
| 368 | /* if present, add any custom non-vendor IEs that go after HT */ | ||
| 369 | if (wk->ie_len && wk->ie) { | ||
| 370 | noffset = ieee80211_ie_split_vendor(wk->ie, wk->ie_len, | ||
| 371 | offset); | ||
| 372 | pos = skb_put(skb, noffset - offset); | ||
| 373 | memcpy(pos, wk->ie + offset, noffset - offset); | ||
| 374 | offset = noffset; | ||
| 375 | } | ||
| 376 | |||
| 377 | if (wk->assoc.wmm_used && local->hw.queues >= 4) { | ||
| 378 | if (wk->assoc.uapsd_used) { | ||
| 379 | qos_info = local->uapsd_queues; | ||
| 380 | qos_info |= (local->uapsd_max_sp_len << | ||
| 381 | IEEE80211_WMM_IE_STA_QOSINFO_SP_SHIFT); | ||
| 382 | } else { | ||
| 383 | qos_info = 0; | ||
| 384 | } | ||
| 385 | |||
| 386 | pos = skb_put(skb, 9); | ||
| 387 | *pos++ = WLAN_EID_VENDOR_SPECIFIC; | ||
| 388 | *pos++ = 7; /* len */ | ||
| 389 | *pos++ = 0x00; /* Microsoft OUI 00:50:F2 */ | ||
| 390 | *pos++ = 0x50; | ||
| 391 | *pos++ = 0xf2; | ||
| 392 | *pos++ = 2; /* WME */ | ||
| 393 | *pos++ = 0; /* WME info */ | ||
| 394 | *pos++ = 1; /* WME ver */ | ||
| 395 | *pos++ = qos_info; | ||
| 396 | } | ||
| 397 | |||
| 398 | /* add any remaining custom (i.e. vendor specific here) IEs */ | ||
| 399 | if (wk->ie_len && wk->ie) { | ||
| 400 | noffset = wk->ie_len; | ||
| 401 | pos = skb_put(skb, noffset - offset); | ||
| 402 | memcpy(pos, wk->ie + offset, noffset - offset); | ||
| 403 | } | ||
| 404 | |||
| 405 | IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; | ||
| 406 | ieee80211_tx_skb(sdata, skb); | ||
| 407 | } | ||
| 408 | |||
| 409 | static void ieee80211_remove_auth_bss(struct ieee80211_local *local, | ||
| 410 | struct ieee80211_work *wk) | ||
| 411 | { | ||
| 412 | struct cfg80211_bss *cbss; | ||
| 413 | u16 capa_val = WLAN_CAPABILITY_ESS; | ||
| 414 | |||
| 415 | if (wk->probe_auth.privacy) | ||
| 416 | capa_val |= WLAN_CAPABILITY_PRIVACY; | ||
| 417 | |||
| 418 | cbss = cfg80211_get_bss(local->hw.wiphy, wk->chan, wk->filter_ta, | ||
| 419 | wk->probe_auth.ssid, wk->probe_auth.ssid_len, | ||
| 420 | WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_PRIVACY, | ||
| 421 | capa_val); | ||
| 422 | if (!cbss) | ||
| 423 | return; | ||
| 424 | |||
| 425 | cfg80211_unlink_bss(local->hw.wiphy, cbss); | ||
| 426 | cfg80211_put_bss(cbss); | ||
| 427 | } | ||
| 428 | |||
| 429 | static enum work_action __must_check | ||
| 430 | ieee80211_direct_probe(struct ieee80211_work *wk) | ||
| 431 | { | ||
| 432 | struct ieee80211_sub_if_data *sdata = wk->sdata; | ||
| 433 | struct ieee80211_local *local = sdata->local; | ||
| 434 | |||
| 435 | wk->probe_auth.tries++; | ||
| 436 | if (wk->probe_auth.tries > IEEE80211_AUTH_MAX_TRIES) { | ||
| 437 | printk(KERN_DEBUG "%s: direct probe to %pM timed out\n", | ||
| 438 | sdata->name, wk->filter_ta); | ||
| 439 | |||
| 440 | /* | ||
| 441 | * Most likely AP is not in the range so remove the | ||
| 442 | * bss struct for that AP. | ||
| 443 | */ | ||
| 444 | ieee80211_remove_auth_bss(local, wk); | ||
| 445 | |||
| 446 | return WORK_ACT_TIMEOUT; | ||
| 447 | } | ||
| 448 | |||
| 449 | printk(KERN_DEBUG "%s: direct probe to %pM (try %d)\n", | ||
| 450 | sdata->name, wk->filter_ta, wk->probe_auth.tries); | ||
| 451 | |||
| 452 | /* | ||
| 453 | * Direct probe is sent to broadcast address as some APs | ||
| 454 | * will not answer to direct packet in unassociated state. | ||
| 455 | */ | ||
| 456 | ieee80211_send_probe_req(sdata, NULL, wk->probe_auth.ssid, | ||
| 457 | wk->probe_auth.ssid_len, NULL, 0); | ||
| 458 | |||
| 459 | wk->timeout = jiffies + IEEE80211_AUTH_TIMEOUT; | ||
| 460 | run_again(local, wk->timeout); | ||
| 461 | |||
| 462 | return WORK_ACT_NONE; | ||
| 463 | } | ||
| 464 | |||
| 465 | |||
| 466 | static enum work_action __must_check | ||
| 467 | ieee80211_authenticate(struct ieee80211_work *wk) | ||
| 468 | { | ||
| 469 | struct ieee80211_sub_if_data *sdata = wk->sdata; | ||
| 470 | struct ieee80211_local *local = sdata->local; | ||
| 471 | |||
| 472 | wk->probe_auth.tries++; | ||
| 473 | if (wk->probe_auth.tries > IEEE80211_AUTH_MAX_TRIES) { | ||
| 474 | printk(KERN_DEBUG "%s: authentication with %pM" | ||
| 475 | " timed out\n", sdata->name, wk->filter_ta); | ||
| 476 | |||
| 477 | /* | ||
| 478 | * Most likely AP is not in the range so remove the | ||
| 479 | * bss struct for that AP. | ||
| 480 | */ | ||
| 481 | ieee80211_remove_auth_bss(local, wk); | ||
| 482 | |||
| 483 | return WORK_ACT_TIMEOUT; | ||
| 484 | } | ||
| 485 | |||
| 486 | printk(KERN_DEBUG "%s: authenticate with %pM (try %d)\n", | ||
| 487 | sdata->name, wk->filter_ta, wk->probe_auth.tries); | ||
| 488 | |||
| 489 | ieee80211_send_auth(sdata, 1, wk->probe_auth.algorithm, wk->ie, | ||
| 490 | wk->ie_len, wk->filter_ta, NULL, 0, 0); | ||
| 491 | wk->probe_auth.transaction = 2; | ||
| 492 | |||
| 493 | wk->timeout = jiffies + IEEE80211_AUTH_TIMEOUT; | ||
| 494 | run_again(local, wk->timeout); | ||
| 495 | |||
| 496 | return WORK_ACT_NONE; | ||
| 497 | } | ||
| 498 | |||
| 499 | static enum work_action __must_check | ||
| 500 | ieee80211_associate(struct ieee80211_work *wk) | ||
| 501 | { | ||
| 502 | struct ieee80211_sub_if_data *sdata = wk->sdata; | ||
| 503 | struct ieee80211_local *local = sdata->local; | ||
| 504 | |||
| 505 | wk->assoc.tries++; | ||
| 506 | if (wk->assoc.tries > IEEE80211_ASSOC_MAX_TRIES) { | ||
| 507 | printk(KERN_DEBUG "%s: association with %pM" | ||
| 508 | " timed out\n", | ||
| 509 | sdata->name, wk->filter_ta); | ||
| 510 | |||
| 511 | /* | ||
| 512 | * Most likely AP is not in the range so remove the | ||
| 513 | * bss struct for that AP. | ||
| 514 | */ | ||
| 515 | if (wk->assoc.bss) | ||
| 516 | cfg80211_unlink_bss(local->hw.wiphy, wk->assoc.bss); | ||
| 517 | |||
| 518 | return WORK_ACT_TIMEOUT; | ||
| 519 | } | ||
| 520 | |||
| 521 | printk(KERN_DEBUG "%s: associate with %pM (try %d)\n", | ||
| 522 | sdata->name, wk->filter_ta, wk->assoc.tries); | ||
| 523 | ieee80211_send_assoc(sdata, wk); | ||
| 524 | |||
| 525 | wk->timeout = jiffies + IEEE80211_ASSOC_TIMEOUT; | ||
| 526 | run_again(local, wk->timeout); | ||
| 527 | |||
| 528 | return WORK_ACT_NONE; | ||
| 529 | } | ||
| 530 | |||
| 531 | static enum work_action __must_check | ||
| 532 | ieee80211_remain_on_channel_timeout(struct ieee80211_work *wk) | ||
| 533 | { | ||
| 534 | /* | ||
| 535 | * First time we run, do nothing -- the generic code will | ||
| 536 | * have switched to the right channel etc. | ||
| 537 | */ | ||
| 538 | if (!wk->started) { | ||
| 539 | wk->timeout = jiffies + msecs_to_jiffies(wk->remain.duration); | ||
| 540 | |||
| 541 | cfg80211_ready_on_channel(wk->sdata->dev, (unsigned long) wk, | ||
| 542 | wk->chan, wk->chan_type, | ||
| 543 | wk->remain.duration, GFP_KERNEL); | ||
| 544 | |||
| 545 | return WORK_ACT_NONE; | ||
| 546 | } | ||
| 547 | |||
| 548 | return WORK_ACT_TIMEOUT; | ||
| 549 | } | ||
| 550 | |||
| 551 | static void ieee80211_auth_challenge(struct ieee80211_work *wk, | ||
| 552 | struct ieee80211_mgmt *mgmt, | ||
| 553 | size_t len) | ||
| 554 | { | ||
| 555 | struct ieee80211_sub_if_data *sdata = wk->sdata; | ||
| 556 | u8 *pos; | ||
| 557 | struct ieee802_11_elems elems; | ||
| 558 | |||
| 559 | pos = mgmt->u.auth.variable; | ||
| 560 | ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems); | ||
| 561 | if (!elems.challenge) | ||
| 562 | return; | ||
| 563 | ieee80211_send_auth(sdata, 3, wk->probe_auth.algorithm, | ||
| 564 | elems.challenge - 2, elems.challenge_len + 2, | ||
| 565 | wk->filter_ta, wk->probe_auth.key, | ||
| 566 | wk->probe_auth.key_len, wk->probe_auth.key_idx); | ||
| 567 | wk->probe_auth.transaction = 4; | ||
| 568 | } | ||
| 569 | |||
| 570 | static enum work_action __must_check | ||
| 571 | ieee80211_rx_mgmt_auth(struct ieee80211_work *wk, | ||
| 572 | struct ieee80211_mgmt *mgmt, size_t len) | ||
| 573 | { | ||
| 574 | u16 auth_alg, auth_transaction, status_code; | ||
| 575 | |||
| 576 | if (wk->type != IEEE80211_WORK_AUTH) | ||
| 577 | return WORK_ACT_NONE; | ||
| 578 | |||
| 579 | if (len < 24 + 6) | ||
| 580 | return WORK_ACT_NONE; | ||
| 581 | |||
| 582 | auth_alg = le16_to_cpu(mgmt->u.auth.auth_alg); | ||
| 583 | auth_transaction = le16_to_cpu(mgmt->u.auth.auth_transaction); | ||
| 584 | status_code = le16_to_cpu(mgmt->u.auth.status_code); | ||
| 585 | |||
| 586 | if (auth_alg != wk->probe_auth.algorithm || | ||
| 587 | auth_transaction != wk->probe_auth.transaction) | ||
| 588 | return WORK_ACT_NONE; | ||
| 589 | |||
| 590 | if (status_code != WLAN_STATUS_SUCCESS) { | ||
| 591 | printk(KERN_DEBUG "%s: %pM denied authentication (status %d)\n", | ||
| 592 | wk->sdata->name, mgmt->sa, status_code); | ||
| 593 | return WORK_ACT_DONE; | ||
| 594 | } | ||
| 595 | |||
| 596 | switch (wk->probe_auth.algorithm) { | ||
| 597 | case WLAN_AUTH_OPEN: | ||
| 598 | case WLAN_AUTH_LEAP: | ||
| 599 | case WLAN_AUTH_FT: | ||
| 600 | break; | ||
| 601 | case WLAN_AUTH_SHARED_KEY: | ||
| 602 | if (wk->probe_auth.transaction != 4) { | ||
| 603 | ieee80211_auth_challenge(wk, mgmt, len); | ||
| 604 | /* need another frame */ | ||
| 605 | return WORK_ACT_NONE; | ||
| 606 | } | ||
| 607 | break; | ||
| 608 | default: | ||
| 609 | WARN_ON(1); | ||
| 610 | return WORK_ACT_NONE; | ||
| 611 | } | ||
| 612 | |||
| 613 | printk(KERN_DEBUG "%s: authenticated\n", wk->sdata->name); | ||
| 614 | return WORK_ACT_DONE; | ||
| 615 | } | ||
| 616 | |||
| 617 | static enum work_action __must_check | ||
| 618 | ieee80211_rx_mgmt_assoc_resp(struct ieee80211_work *wk, | ||
| 619 | struct ieee80211_mgmt *mgmt, size_t len, | ||
| 620 | bool reassoc) | ||
| 621 | { | ||
| 622 | struct ieee80211_sub_if_data *sdata = wk->sdata; | ||
| 623 | struct ieee80211_local *local = sdata->local; | ||
| 624 | u16 capab_info, status_code, aid; | ||
| 625 | struct ieee802_11_elems elems; | ||
| 626 | u8 *pos; | ||
| 627 | |||
| 628 | /* | ||
| 629 | * AssocResp and ReassocResp have identical structure, so process both | ||
| 630 | * of them in this function. | ||
| 631 | */ | ||
| 632 | |||
| 633 | if (len < 24 + 6) | ||
| 634 | return WORK_ACT_NONE; | ||
| 635 | |||
| 636 | capab_info = le16_to_cpu(mgmt->u.assoc_resp.capab_info); | ||
| 637 | status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code); | ||
| 638 | aid = le16_to_cpu(mgmt->u.assoc_resp.aid); | ||
| 639 | |||
| 640 | printk(KERN_DEBUG "%s: RX %sssocResp from %pM (capab=0x%x " | ||
| 641 | "status=%d aid=%d)\n", | ||
| 642 | sdata->name, reassoc ? "Rea" : "A", mgmt->sa, | ||
| 643 | capab_info, status_code, (u16)(aid & ~(BIT(15) | BIT(14)))); | ||
| 644 | |||
| 645 | pos = mgmt->u.assoc_resp.variable; | ||
| 646 | ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems); | ||
| 647 | |||
| 648 | if (status_code == WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY && | ||
| 649 | elems.timeout_int && elems.timeout_int_len == 5 && | ||
| 650 | elems.timeout_int[0] == WLAN_TIMEOUT_ASSOC_COMEBACK) { | ||
| 651 | u32 tu, ms; | ||
| 652 | tu = get_unaligned_le32(elems.timeout_int + 1); | ||
| 653 | ms = tu * 1024 / 1000; | ||
| 654 | printk(KERN_DEBUG "%s: %pM rejected association temporarily; " | ||
| 655 | "comeback duration %u TU (%u ms)\n", | ||
| 656 | sdata->name, mgmt->sa, tu, ms); | ||
| 657 | wk->timeout = jiffies + msecs_to_jiffies(ms); | ||
| 658 | if (ms > IEEE80211_ASSOC_TIMEOUT) | ||
| 659 | run_again(local, wk->timeout); | ||
| 660 | return WORK_ACT_NONE; | ||
| 661 | } | ||
| 662 | |||
| 663 | if (status_code != WLAN_STATUS_SUCCESS) | ||
| 664 | printk(KERN_DEBUG "%s: %pM denied association (code=%d)\n", | ||
| 665 | sdata->name, mgmt->sa, status_code); | ||
| 666 | else | ||
| 667 | printk(KERN_DEBUG "%s: associated\n", sdata->name); | ||
| 668 | |||
| 669 | return WORK_ACT_DONE; | ||
| 670 | } | ||
| 671 | |||
| 672 | static enum work_action __must_check | ||
| 673 | ieee80211_rx_mgmt_probe_resp(struct ieee80211_work *wk, | ||
| 674 | struct ieee80211_mgmt *mgmt, size_t len, | ||
| 675 | struct ieee80211_rx_status *rx_status) | ||
| 676 | { | ||
| 677 | struct ieee80211_sub_if_data *sdata = wk->sdata; | ||
| 678 | struct ieee80211_local *local = sdata->local; | ||
| 679 | size_t baselen; | ||
| 680 | |||
| 681 | ASSERT_WORK_MTX(local); | ||
| 682 | |||
| 683 | baselen = (u8 *) mgmt->u.probe_resp.variable - (u8 *) mgmt; | ||
| 684 | if (baselen > len) | ||
| 685 | return WORK_ACT_NONE; | ||
| 686 | |||
| 687 | printk(KERN_DEBUG "%s: direct probe responded\n", sdata->name); | ||
| 688 | return WORK_ACT_DONE; | ||
| 689 | } | ||
| 690 | |||
| 691 | static void ieee80211_work_rx_queued_mgmt(struct ieee80211_local *local, | ||
| 692 | struct sk_buff *skb) | ||
| 693 | { | ||
| 694 | struct ieee80211_rx_status *rx_status; | ||
| 695 | struct ieee80211_mgmt *mgmt; | ||
| 696 | struct ieee80211_work *wk; | ||
| 697 | enum work_action rma = WORK_ACT_NONE; | ||
| 698 | u16 fc; | ||
| 699 | |||
| 700 | rx_status = (struct ieee80211_rx_status *) skb->cb; | ||
| 701 | mgmt = (struct ieee80211_mgmt *) skb->data; | ||
| 702 | fc = le16_to_cpu(mgmt->frame_control); | ||
| 703 | |||
| 704 | mutex_lock(&local->work_mtx); | ||
| 705 | |||
| 706 | list_for_each_entry(wk, &local->work_list, list) { | ||
| 707 | const u8 *bssid = NULL; | ||
| 708 | |||
| 709 | switch (wk->type) { | ||
| 710 | case IEEE80211_WORK_DIRECT_PROBE: | ||
| 711 | case IEEE80211_WORK_AUTH: | ||
| 712 | case IEEE80211_WORK_ASSOC: | ||
| 713 | bssid = wk->filter_ta; | ||
| 714 | break; | ||
| 715 | default: | ||
| 716 | continue; | ||
| 717 | } | ||
| 718 | |||
| 719 | /* | ||
| 720 | * Before queuing, we already verified mgmt->sa, | ||
| 721 | * so this is needed just for matching. | ||
| 722 | */ | ||
| 723 | if (compare_ether_addr(bssid, mgmt->bssid)) | ||
| 724 | continue; | ||
| 725 | |||
| 726 | switch (fc & IEEE80211_FCTL_STYPE) { | ||
| 727 | case IEEE80211_STYPE_PROBE_RESP: | ||
| 728 | rma = ieee80211_rx_mgmt_probe_resp(wk, mgmt, skb->len, | ||
| 729 | rx_status); | ||
| 730 | break; | ||
| 731 | case IEEE80211_STYPE_AUTH: | ||
| 732 | rma = ieee80211_rx_mgmt_auth(wk, mgmt, skb->len); | ||
| 733 | break; | ||
| 734 | case IEEE80211_STYPE_ASSOC_RESP: | ||
| 735 | rma = ieee80211_rx_mgmt_assoc_resp(wk, mgmt, | ||
| 736 | skb->len, false); | ||
| 737 | break; | ||
| 738 | case IEEE80211_STYPE_REASSOC_RESP: | ||
| 739 | rma = ieee80211_rx_mgmt_assoc_resp(wk, mgmt, | ||
| 740 | skb->len, true); | ||
| 741 | break; | ||
| 742 | default: | ||
| 743 | WARN_ON(1); | ||
| 744 | } | ||
| 745 | /* | ||
| 746 | * We've processed this frame for that work, so it can't | ||
| 747 | * belong to another work struct. | ||
| 748 | * NB: this is also required for correctness for 'rma'! | ||
| 749 | */ | ||
| 750 | break; | ||
| 751 | } | ||
| 752 | |||
| 753 | switch (rma) { | ||
| 754 | case WORK_ACT_NONE: | ||
| 755 | break; | ||
| 756 | case WORK_ACT_DONE: | ||
| 757 | list_del_rcu(&wk->list); | ||
| 758 | break; | ||
| 759 | default: | ||
| 760 | WARN(1, "unexpected: %d", rma); | ||
| 761 | } | ||
| 762 | |||
| 763 | mutex_unlock(&local->work_mtx); | ||
| 764 | |||
| 765 | if (rma != WORK_ACT_DONE) | ||
| 766 | goto out; | ||
| 767 | |||
| 768 | switch (wk->done(wk, skb)) { | ||
| 769 | case WORK_DONE_DESTROY: | ||
| 770 | free_work(wk); | ||
| 771 | break; | ||
| 772 | case WORK_DONE_REQUEUE: | ||
| 773 | synchronize_rcu(); | ||
| 774 | wk->started = false; /* restart */ | ||
| 775 | mutex_lock(&local->work_mtx); | ||
| 776 | list_add_tail(&wk->list, &local->work_list); | ||
| 777 | mutex_unlock(&local->work_mtx); | ||
| 778 | } | ||
| 779 | |||
| 780 | out: | ||
| 781 | kfree_skb(skb); | ||
| 782 | } | ||
| 783 | |||
| 784 | static void ieee80211_work_timer(unsigned long data) | ||
| 785 | { | ||
| 786 | struct ieee80211_local *local = (void *) data; | ||
| 787 | |||
| 788 | if (local->quiescing) | ||
| 789 | return; | ||
| 790 | |||
| 791 | ieee80211_queue_work(&local->hw, &local->work_work); | ||
| 792 | } | ||
| 793 | |||
| 794 | static void ieee80211_work_work(struct work_struct *work) | ||
| 795 | { | ||
| 796 | struct ieee80211_local *local = | ||
| 797 | container_of(work, struct ieee80211_local, work_work); | ||
| 798 | struct sk_buff *skb; | ||
| 799 | struct ieee80211_work *wk, *tmp; | ||
| 800 | LIST_HEAD(free_work); | ||
| 801 | enum work_action rma; | ||
| 802 | bool remain_off_channel = false; | ||
| 803 | |||
| 804 | if (local->scanning) | ||
| 805 | return; | ||
| 806 | |||
| 807 | /* | ||
| 808 | * ieee80211_queue_work() should have picked up most cases, | ||
| 809 | * here we'll pick the the rest. | ||
| 810 | */ | ||
| 811 | if (WARN(local->suspended, "work scheduled while going to suspend\n")) | ||
| 812 | return; | ||
| 813 | |||
| 814 | /* first process frames to avoid timing out while a frame is pending */ | ||
| 815 | while ((skb = skb_dequeue(&local->work_skb_queue))) | ||
| 816 | ieee80211_work_rx_queued_mgmt(local, skb); | ||
| 817 | |||
| 818 | ieee80211_recalc_idle(local); | ||
| 819 | |||
| 820 | mutex_lock(&local->work_mtx); | ||
| 821 | |||
| 822 | list_for_each_entry_safe(wk, tmp, &local->work_list, list) { | ||
| 823 | bool started = wk->started; | ||
| 824 | |||
| 825 | /* mark work as started if it's on the current off-channel */ | ||
| 826 | if (!started && local->tmp_channel && | ||
| 827 | wk->chan == local->tmp_channel && | ||
| 828 | wk->chan_type == local->tmp_channel_type) { | ||
| 829 | started = true; | ||
| 830 | wk->timeout = jiffies; | ||
| 831 | } | ||
| 832 | |||
| 833 | if (!started && !local->tmp_channel) { | ||
| 834 | /* | ||
| 835 | * TODO: could optimize this by leaving the | ||
| 836 | * station vifs in awake mode if they | ||
| 837 | * happen to be on the same channel as | ||
| 838 | * the requested channel | ||
| 839 | */ | ||
| 840 | ieee80211_offchannel_stop_beaconing(local); | ||
| 841 | ieee80211_offchannel_stop_station(local); | ||
| 842 | |||
| 843 | local->tmp_channel = wk->chan; | ||
| 844 | local->tmp_channel_type = wk->chan_type; | ||
| 845 | ieee80211_hw_config(local, 0); | ||
| 846 | started = true; | ||
| 847 | wk->timeout = jiffies; | ||
| 848 | } | ||
| 849 | |||
| 850 | /* don't try to work with items that aren't started */ | ||
| 851 | if (!started) | ||
| 852 | continue; | ||
| 853 | |||
| 854 | if (time_is_after_jiffies(wk->timeout)) { | ||
| 855 | /* | ||
| 856 | * This work item isn't supposed to be worked on | ||
| 857 | * right now, but take care to adjust the timer | ||
| 858 | * properly. | ||
| 859 | */ | ||
| 860 | run_again(local, wk->timeout); | ||
| 861 | continue; | ||
| 862 | } | ||
| 863 | |||
| 864 | switch (wk->type) { | ||
| 865 | default: | ||
| 866 | WARN_ON(1); | ||
| 867 | /* nothing */ | ||
| 868 | rma = WORK_ACT_NONE; | ||
| 869 | break; | ||
| 870 | case IEEE80211_WORK_ABORT: | ||
| 871 | rma = WORK_ACT_TIMEOUT; | ||
| 872 | break; | ||
| 873 | case IEEE80211_WORK_DIRECT_PROBE: | ||
| 874 | rma = ieee80211_direct_probe(wk); | ||
| 875 | break; | ||
| 876 | case IEEE80211_WORK_AUTH: | ||
| 877 | rma = ieee80211_authenticate(wk); | ||
| 878 | break; | ||
| 879 | case IEEE80211_WORK_ASSOC: | ||
| 880 | rma = ieee80211_associate(wk); | ||
| 881 | break; | ||
| 882 | case IEEE80211_WORK_REMAIN_ON_CHANNEL: | ||
| 883 | rma = ieee80211_remain_on_channel_timeout(wk); | ||
| 884 | break; | ||
| 885 | } | ||
| 886 | |||
| 887 | wk->started = started; | ||
| 888 | |||
| 889 | switch (rma) { | ||
| 890 | case WORK_ACT_NONE: | ||
| 891 | /* might have changed the timeout */ | ||
| 892 | run_again(local, wk->timeout); | ||
| 893 | break; | ||
| 894 | case WORK_ACT_TIMEOUT: | ||
| 895 | list_del_rcu(&wk->list); | ||
| 896 | synchronize_rcu(); | ||
| 897 | list_add(&wk->list, &free_work); | ||
| 898 | break; | ||
| 899 | default: | ||
| 900 | WARN(1, "unexpected: %d", rma); | ||
| 901 | } | ||
| 902 | } | ||
| 903 | |||
| 904 | list_for_each_entry(wk, &local->work_list, list) { | ||
| 905 | if (!wk->started) | ||
| 906 | continue; | ||
| 907 | if (wk->chan != local->tmp_channel) | ||
| 908 | continue; | ||
| 909 | if (wk->chan_type != local->tmp_channel_type) | ||
| 910 | continue; | ||
| 911 | remain_off_channel = true; | ||
| 912 | } | ||
| 913 | |||
| 914 | if (!remain_off_channel && local->tmp_channel) { | ||
| 915 | local->tmp_channel = NULL; | ||
| 916 | ieee80211_hw_config(local, 0); | ||
| 917 | ieee80211_offchannel_return(local, true); | ||
| 918 | /* give connection some time to breathe */ | ||
| 919 | run_again(local, jiffies + HZ/2); | ||
| 920 | } | ||
| 921 | |||
| 922 | if (list_empty(&local->work_list) && local->scan_req) | ||
| 923 | ieee80211_queue_delayed_work(&local->hw, | ||
| 924 | &local->scan_work, | ||
| 925 | round_jiffies_relative(0)); | ||
| 926 | |||
| 927 | mutex_unlock(&local->work_mtx); | ||
| 928 | |||
| 929 | ieee80211_recalc_idle(local); | ||
| 930 | |||
| 931 | list_for_each_entry_safe(wk, tmp, &free_work, list) { | ||
| 932 | wk->done(wk, NULL); | ||
| 933 | list_del(&wk->list); | ||
| 934 | kfree(wk); | ||
| 935 | } | ||
| 936 | } | ||
| 937 | |||
| 938 | void ieee80211_add_work(struct ieee80211_work *wk) | ||
| 939 | { | ||
| 940 | struct ieee80211_local *local; | ||
| 941 | |||
| 942 | if (WARN_ON(!wk->chan)) | ||
| 943 | return; | ||
| 944 | |||
| 945 | if (WARN_ON(!wk->sdata)) | ||
| 946 | return; | ||
| 947 | |||
| 948 | if (WARN_ON(!wk->done)) | ||
| 949 | return; | ||
| 950 | |||
| 951 | if (WARN_ON(!ieee80211_sdata_running(wk->sdata))) | ||
| 952 | return; | ||
| 953 | |||
| 954 | wk->started = false; | ||
| 955 | |||
| 956 | local = wk->sdata->local; | ||
| 957 | mutex_lock(&local->work_mtx); | ||
| 958 | list_add_tail(&wk->list, &local->work_list); | ||
| 959 | mutex_unlock(&local->work_mtx); | ||
| 960 | |||
| 961 | ieee80211_queue_work(&local->hw, &local->work_work); | ||
| 962 | } | ||
| 963 | |||
| 964 | void ieee80211_work_init(struct ieee80211_local *local) | ||
| 965 | { | ||
| 966 | mutex_init(&local->work_mtx); | ||
| 967 | INIT_LIST_HEAD(&local->work_list); | ||
| 968 | setup_timer(&local->work_timer, ieee80211_work_timer, | ||
| 969 | (unsigned long)local); | ||
| 970 | INIT_WORK(&local->work_work, ieee80211_work_work); | ||
| 971 | skb_queue_head_init(&local->work_skb_queue); | ||
| 972 | } | ||
| 973 | |||
| 974 | void ieee80211_work_purge(struct ieee80211_sub_if_data *sdata) | ||
| 975 | { | ||
| 976 | struct ieee80211_local *local = sdata->local; | ||
| 977 | struct ieee80211_work *wk; | ||
| 978 | |||
| 979 | mutex_lock(&local->work_mtx); | ||
| 980 | list_for_each_entry(wk, &local->work_list, list) { | ||
| 981 | if (wk->sdata != sdata) | ||
| 982 | continue; | ||
| 983 | wk->type = IEEE80211_WORK_ABORT; | ||
| 984 | wk->started = true; | ||
| 985 | wk->timeout = jiffies; | ||
| 986 | } | ||
| 987 | mutex_unlock(&local->work_mtx); | ||
| 988 | |||
| 989 | /* run cleanups etc. */ | ||
| 990 | ieee80211_work_work(&local->work_work); | ||
| 991 | |||
| 992 | mutex_lock(&local->work_mtx); | ||
| 993 | list_for_each_entry(wk, &local->work_list, list) { | ||
| 994 | if (wk->sdata != sdata) | ||
| 995 | continue; | ||
| 996 | WARN_ON(1); | ||
| 997 | break; | ||
| 998 | } | ||
| 999 | mutex_unlock(&local->work_mtx); | ||
| 1000 | } | ||
| 1001 | |||
| 1002 | ieee80211_rx_result ieee80211_work_rx_mgmt(struct ieee80211_sub_if_data *sdata, | ||
| 1003 | struct sk_buff *skb) | ||
| 1004 | { | ||
| 1005 | struct ieee80211_local *local = sdata->local; | ||
| 1006 | struct ieee80211_mgmt *mgmt; | ||
| 1007 | struct ieee80211_work *wk; | ||
| 1008 | u16 fc; | ||
| 1009 | |||
| 1010 | if (skb->len < 24) | ||
| 1011 | return RX_DROP_MONITOR; | ||
| 1012 | |||
| 1013 | mgmt = (struct ieee80211_mgmt *) skb->data; | ||
| 1014 | fc = le16_to_cpu(mgmt->frame_control); | ||
| 1015 | |||
| 1016 | list_for_each_entry_rcu(wk, &local->work_list, list) { | ||
| 1017 | if (sdata != wk->sdata) | ||
| 1018 | continue; | ||
| 1019 | if (compare_ether_addr(wk->filter_ta, mgmt->sa)) | ||
| 1020 | continue; | ||
| 1021 | if (compare_ether_addr(wk->filter_ta, mgmt->bssid)) | ||
| 1022 | continue; | ||
| 1023 | |||
| 1024 | switch (fc & IEEE80211_FCTL_STYPE) { | ||
| 1025 | case IEEE80211_STYPE_AUTH: | ||
| 1026 | case IEEE80211_STYPE_PROBE_RESP: | ||
| 1027 | case IEEE80211_STYPE_ASSOC_RESP: | ||
| 1028 | case IEEE80211_STYPE_REASSOC_RESP: | ||
| 1029 | skb_queue_tail(&local->work_skb_queue, skb); | ||
| 1030 | ieee80211_queue_work(&local->hw, &local->work_work); | ||
| 1031 | return RX_QUEUED; | ||
| 1032 | } | ||
| 1033 | } | ||
| 1034 | |||
| 1035 | return RX_CONTINUE; | ||
| 1036 | } | ||
| 1037 | |||
| 1038 | static enum work_done_result ieee80211_remain_done(struct ieee80211_work *wk, | ||
| 1039 | struct sk_buff *skb) | ||
| 1040 | { | ||
| 1041 | /* | ||
| 1042 | * We are done serving the remain-on-channel command. | ||
| 1043 | */ | ||
| 1044 | cfg80211_remain_on_channel_expired(wk->sdata->dev, (unsigned long) wk, | ||
| 1045 | wk->chan, wk->chan_type, | ||
| 1046 | GFP_KERNEL); | ||
| 1047 | |||
| 1048 | return WORK_DONE_DESTROY; | ||
| 1049 | } | ||
| 1050 | |||
| 1051 | int ieee80211_wk_remain_on_channel(struct ieee80211_sub_if_data *sdata, | ||
| 1052 | struct ieee80211_channel *chan, | ||
| 1053 | enum nl80211_channel_type channel_type, | ||
| 1054 | unsigned int duration, u64 *cookie) | ||
| 1055 | { | ||
| 1056 | struct ieee80211_work *wk; | ||
| 1057 | |||
| 1058 | wk = kzalloc(sizeof(*wk), GFP_KERNEL); | ||
| 1059 | if (!wk) | ||
| 1060 | return -ENOMEM; | ||
| 1061 | |||
| 1062 | wk->type = IEEE80211_WORK_REMAIN_ON_CHANNEL; | ||
| 1063 | wk->chan = chan; | ||
| 1064 | wk->chan_type = channel_type; | ||
| 1065 | wk->sdata = sdata; | ||
| 1066 | wk->done = ieee80211_remain_done; | ||
| 1067 | |||
| 1068 | wk->remain.duration = duration; | ||
| 1069 | |||
| 1070 | *cookie = (unsigned long) wk; | ||
| 1071 | |||
| 1072 | ieee80211_add_work(wk); | ||
| 1073 | |||
| 1074 | return 0; | ||
| 1075 | } | ||
| 1076 | |||
| 1077 | int ieee80211_wk_cancel_remain_on_channel(struct ieee80211_sub_if_data *sdata, | ||
| 1078 | u64 cookie) | ||
| 1079 | { | ||
| 1080 | struct ieee80211_local *local = sdata->local; | ||
| 1081 | struct ieee80211_work *wk, *tmp; | ||
| 1082 | bool found = false; | ||
| 1083 | |||
| 1084 | mutex_lock(&local->work_mtx); | ||
| 1085 | list_for_each_entry_safe(wk, tmp, &local->work_list, list) { | ||
| 1086 | if ((unsigned long) wk == cookie) { | ||
| 1087 | wk->timeout = jiffies; | ||
| 1088 | found = true; | ||
| 1089 | break; | ||
| 1090 | } | ||
| 1091 | } | ||
| 1092 | mutex_unlock(&local->work_mtx); | ||
| 1093 | |||
| 1094 | if (!found) | ||
| 1095 | return -ENOENT; | ||
| 1096 | |||
| 1097 | ieee80211_queue_work(&local->hw, &local->work_work); | ||
| 1098 | |||
| 1099 | return 0; | ||
| 1100 | } | ||
diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c index 5332014cb229..f4971cd45c64 100644 --- a/net/mac80211/wpa.c +++ b/net/mac80211/wpa.c | |||
| @@ -31,8 +31,8 @@ ieee80211_tx_h_michael_mic_add(struct ieee80211_tx_data *tx) | |||
| 31 | unsigned int hdrlen; | 31 | unsigned int hdrlen; |
| 32 | struct ieee80211_hdr *hdr; | 32 | struct ieee80211_hdr *hdr; |
| 33 | struct sk_buff *skb = tx->skb; | 33 | struct sk_buff *skb = tx->skb; |
| 34 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | ||
| 34 | int authenticator; | 35 | int authenticator; |
| 35 | int wpa_test = 0; | ||
| 36 | int tail; | 36 | int tail; |
| 37 | 37 | ||
| 38 | hdr = (struct ieee80211_hdr *)skb->data; | 38 | hdr = (struct ieee80211_hdr *)skb->data; |
| @@ -47,16 +47,15 @@ ieee80211_tx_h_michael_mic_add(struct ieee80211_tx_data *tx) | |||
| 47 | data = skb->data + hdrlen; | 47 | data = skb->data + hdrlen; |
| 48 | data_len = skb->len - hdrlen; | 48 | data_len = skb->len - hdrlen; |
| 49 | 49 | ||
| 50 | if ((tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) && | 50 | if (info->control.hw_key && |
| 51 | !(tx->flags & IEEE80211_TX_FRAGMENTED) && | 51 | !(tx->flags & IEEE80211_TX_FRAGMENTED) && |
| 52 | !(tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC) && | 52 | !(tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC)) { |
| 53 | !wpa_test) { | 53 | /* hwaccel - with no need for SW-generated MMIC */ |
| 54 | /* hwaccel - with no need for preallocated room for MMIC */ | ||
| 55 | return TX_CONTINUE; | 54 | return TX_CONTINUE; |
| 56 | } | 55 | } |
| 57 | 56 | ||
| 58 | tail = MICHAEL_MIC_LEN; | 57 | tail = MICHAEL_MIC_LEN; |
| 59 | if (!(tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) | 58 | if (!info->control.hw_key) |
| 60 | tail += TKIP_ICV_LEN; | 59 | tail += TKIP_ICV_LEN; |
| 61 | 60 | ||
| 62 | if (WARN_ON(skb_tailroom(skb) < tail || | 61 | if (WARN_ON(skb_tailroom(skb) < tail || |
| @@ -147,17 +146,16 @@ static int tkip_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb) | |||
| 147 | int len, tail; | 146 | int len, tail; |
| 148 | u8 *pos; | 147 | u8 *pos; |
| 149 | 148 | ||
| 150 | if ((tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) && | 149 | if (info->control.hw_key && |
| 151 | !(tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV)) { | 150 | !(info->control.hw_key->flags & IEEE80211_KEY_FLAG_GENERATE_IV)) { |
| 152 | /* hwaccel - with no need for preallocated room for IV/ICV */ | 151 | /* hwaccel - with no need for software-generated IV */ |
| 153 | info->control.hw_key = &tx->key->conf; | ||
| 154 | return 0; | 152 | return 0; |
| 155 | } | 153 | } |
| 156 | 154 | ||
| 157 | hdrlen = ieee80211_hdrlen(hdr->frame_control); | 155 | hdrlen = ieee80211_hdrlen(hdr->frame_control); |
| 158 | len = skb->len - hdrlen; | 156 | len = skb->len - hdrlen; |
| 159 | 157 | ||
| 160 | if (tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) | 158 | if (info->control.hw_key) |
| 161 | tail = 0; | 159 | tail = 0; |
| 162 | else | 160 | else |
| 163 | tail = TKIP_ICV_LEN; | 161 | tail = TKIP_ICV_LEN; |
| @@ -175,13 +173,11 @@ static int tkip_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb) | |||
| 175 | if (key->u.tkip.tx.iv16 == 0) | 173 | if (key->u.tkip.tx.iv16 == 0) |
| 176 | key->u.tkip.tx.iv32++; | 174 | key->u.tkip.tx.iv32++; |
| 177 | 175 | ||
| 178 | if (tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) { | 176 | pos = ieee80211_tkip_add_iv(pos, key, key->u.tkip.tx.iv16); |
| 179 | /* hwaccel - with preallocated room for IV */ | ||
| 180 | ieee80211_tkip_add_iv(pos, key, key->u.tkip.tx.iv16); | ||
| 181 | 177 | ||
| 182 | info->control.hw_key = &tx->key->conf; | 178 | /* hwaccel - with software IV */ |
| 179 | if (info->control.hw_key) | ||
| 183 | return 0; | 180 | return 0; |
| 184 | } | ||
| 185 | 181 | ||
| 186 | /* Add room for ICV */ | 182 | /* Add room for ICV */ |
| 187 | skb_put(skb, TKIP_ICV_LEN); | 183 | skb_put(skb, TKIP_ICV_LEN); |
| @@ -363,24 +359,20 @@ static int ccmp_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb) | |||
| 363 | int hdrlen, len, tail; | 359 | int hdrlen, len, tail; |
| 364 | u8 *pos, *pn; | 360 | u8 *pos, *pn; |
| 365 | int i; | 361 | int i; |
| 366 | bool skip_hw; | ||
| 367 | |||
| 368 | skip_hw = (tx->key->conf.flags & IEEE80211_KEY_FLAG_SW_MGMT) && | ||
| 369 | ieee80211_is_mgmt(hdr->frame_control); | ||
| 370 | 362 | ||
| 371 | if ((tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) && | 363 | if (info->control.hw_key && |
| 372 | !(tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV) && | 364 | !(info->control.hw_key->flags & IEEE80211_KEY_FLAG_GENERATE_IV)) { |
| 373 | !skip_hw) { | 365 | /* |
| 374 | /* hwaccel - with no need for preallocated room for CCMP | 366 | * hwaccel has no need for preallocated room for CCMP |
| 375 | * header or MIC fields */ | 367 | * header or MIC fields |
| 376 | info->control.hw_key = &tx->key->conf; | 368 | */ |
| 377 | return 0; | 369 | return 0; |
| 378 | } | 370 | } |
| 379 | 371 | ||
| 380 | hdrlen = ieee80211_hdrlen(hdr->frame_control); | 372 | hdrlen = ieee80211_hdrlen(hdr->frame_control); |
| 381 | len = skb->len - hdrlen; | 373 | len = skb->len - hdrlen; |
| 382 | 374 | ||
| 383 | if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) | 375 | if (info->control.hw_key) |
| 384 | tail = 0; | 376 | tail = 0; |
| 385 | else | 377 | else |
| 386 | tail = CCMP_MIC_LEN; | 378 | tail = CCMP_MIC_LEN; |
| @@ -405,11 +397,9 @@ static int ccmp_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb) | |||
| 405 | 397 | ||
| 406 | ccmp_pn2hdr(pos, pn, key->conf.keyidx); | 398 | ccmp_pn2hdr(pos, pn, key->conf.keyidx); |
| 407 | 399 | ||
| 408 | if ((key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) && !skip_hw) { | 400 | /* hwaccel - with software CCMP header */ |
| 409 | /* hwaccel - with preallocated room for CCMP header */ | 401 | if (info->control.hw_key) |
| 410 | info->control.hw_key = &tx->key->conf; | ||
| 411 | return 0; | 402 | return 0; |
| 412 | } | ||
| 413 | 403 | ||
| 414 | pos += CCMP_HDR_LEN; | 404 | pos += CCMP_HDR_LEN; |
| 415 | ccmp_special_blocks(skb, pn, key->u.ccmp.tx_crypto_buf, 0); | 405 | ccmp_special_blocks(skb, pn, key->u.ccmp.tx_crypto_buf, 0); |
| @@ -525,11 +515,8 @@ ieee80211_crypto_aes_cmac_encrypt(struct ieee80211_tx_data *tx) | |||
| 525 | u8 *pn, aad[20]; | 515 | u8 *pn, aad[20]; |
| 526 | int i; | 516 | int i; |
| 527 | 517 | ||
| 528 | if (tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) { | 518 | if (info->control.hw_key) |
| 529 | /* hwaccel */ | ||
| 530 | info->control.hw_key = &tx->key->conf; | ||
| 531 | return 0; | 519 | return 0; |
| 532 | } | ||
| 533 | 520 | ||
| 534 | if (WARN_ON(skb_tailroom(skb) < sizeof(*mmie))) | 521 | if (WARN_ON(skb_tailroom(skb) < sizeof(*mmie))) |
| 535 | return TX_DROP; | 522 | return TX_DROP; |
