diff options
author | David S. Miller <davem@davemloft.net> | 2008-12-21 22:57:10 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-12-21 22:57:10 -0500 |
commit | c2da953a46b18b7515ad476c1c1686640a12e93a (patch) | |
tree | b384f097718119e715cdebd74710ddceeb80fdc8 /net | |
parent | c94cb314503a69492bf4455dce4f6d300cff0851 (diff) | |
parent | 9cf7f247bd0cd21e475c71a4e018bb612ef02aab (diff) |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6
Diffstat (limited to 'net')
-rw-r--r-- | net/mac80211/cfg.c | 42 | ||||
-rw-r--r-- | net/mac80211/ht.c | 35 | ||||
-rw-r--r-- | net/mac80211/ieee80211_i.h | 25 | ||||
-rw-r--r-- | net/mac80211/main.c | 39 | ||||
-rw-r--r-- | net/mac80211/mlme.c | 70 | ||||
-rw-r--r-- | net/mac80211/rx.c | 59 | ||||
-rw-r--r-- | net/mac80211/tx.c | 13 | ||||
-rw-r--r-- | net/mac80211/util.c | 88 | ||||
-rw-r--r-- | net/mac80211/wext.c | 46 | ||||
-rw-r--r-- | net/wireless/nl80211.c | 85 |
10 files changed, 421 insertions, 81 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 7912eb14eca0..9d4e4d846ec1 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -310,12 +310,35 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) | |||
310 | 310 | ||
311 | sinfo->filled = STATION_INFO_INACTIVE_TIME | | 311 | sinfo->filled = STATION_INFO_INACTIVE_TIME | |
312 | STATION_INFO_RX_BYTES | | 312 | STATION_INFO_RX_BYTES | |
313 | STATION_INFO_TX_BYTES; | 313 | STATION_INFO_TX_BYTES | |
314 | STATION_INFO_TX_BITRATE; | ||
314 | 315 | ||
315 | sinfo->inactive_time = jiffies_to_msecs(jiffies - sta->last_rx); | 316 | sinfo->inactive_time = jiffies_to_msecs(jiffies - sta->last_rx); |
316 | sinfo->rx_bytes = sta->rx_bytes; | 317 | sinfo->rx_bytes = sta->rx_bytes; |
317 | sinfo->tx_bytes = sta->tx_bytes; | 318 | sinfo->tx_bytes = sta->tx_bytes; |
318 | 319 | ||
320 | if (sta->local->hw.flags & IEEE80211_HW_SIGNAL_DBM) { | ||
321 | sinfo->filled |= STATION_INFO_SIGNAL; | ||
322 | sinfo->signal = (s8)sta->last_signal; | ||
323 | } | ||
324 | |||
325 | sinfo->txrate.flags = 0; | ||
326 | if (sta->last_tx_rate.flags & IEEE80211_TX_RC_MCS) | ||
327 | sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS; | ||
328 | if (sta->last_tx_rate.flags & IEEE80211_TX_RC_40_MHZ_WIDTH) | ||
329 | sinfo->txrate.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH; | ||
330 | if (sta->last_tx_rate.flags & IEEE80211_TX_RC_SHORT_GI) | ||
331 | sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI; | ||
332 | |||
333 | if (!(sta->last_tx_rate.flags & IEEE80211_TX_RC_MCS)) { | ||
334 | struct ieee80211_supported_band *sband; | ||
335 | sband = sta->local->hw.wiphy->bands[ | ||
336 | sta->local->hw.conf.channel->band]; | ||
337 | sinfo->txrate.legacy = | ||
338 | sband->bitrates[sta->last_tx_rate.idx].bitrate; | ||
339 | } else | ||
340 | sinfo->txrate.mcs = sta->last_tx_rate.idx; | ||
341 | |||
319 | if (ieee80211_vif_is_mesh(&sdata->vif)) { | 342 | if (ieee80211_vif_is_mesh(&sdata->vif)) { |
320 | #ifdef CONFIG_MAC80211_MESH | 343 | #ifdef CONFIG_MAC80211_MESH |
321 | sinfo->filled |= STATION_INFO_LLID | | 344 | sinfo->filled |= STATION_INFO_LLID | |
@@ -663,6 +686,7 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev, | |||
663 | struct sta_info *sta; | 686 | struct sta_info *sta; |
664 | struct ieee80211_sub_if_data *sdata; | 687 | struct ieee80211_sub_if_data *sdata; |
665 | int err; | 688 | int err; |
689 | int layer2_update; | ||
666 | 690 | ||
667 | /* Prevent a race with changing the rate control algorithm */ | 691 | /* Prevent a race with changing the rate control algorithm */ |
668 | if (!netif_running(dev)) | 692 | if (!netif_running(dev)) |
@@ -693,17 +717,25 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev, | |||
693 | 717 | ||
694 | rate_control_rate_init(sta); | 718 | rate_control_rate_init(sta); |
695 | 719 | ||
720 | layer2_update = sdata->vif.type == NL80211_IFTYPE_AP_VLAN || | ||
721 | sdata->vif.type == NL80211_IFTYPE_AP; | ||
722 | |||
696 | rcu_read_lock(); | 723 | rcu_read_lock(); |
697 | 724 | ||
698 | err = sta_info_insert(sta); | 725 | err = sta_info_insert(sta); |
699 | if (err) { | 726 | if (err) { |
700 | /* STA has been freed */ | 727 | /* STA has been freed */ |
728 | if (err == -EEXIST && layer2_update) { | ||
729 | /* Need to update layer 2 devices on reassociation */ | ||
730 | sta = sta_info_get(local, mac); | ||
731 | if (sta) | ||
732 | ieee80211_send_layer2_update(sta); | ||
733 | } | ||
701 | rcu_read_unlock(); | 734 | rcu_read_unlock(); |
702 | return err; | 735 | return err; |
703 | } | 736 | } |
704 | 737 | ||
705 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN || | 738 | if (layer2_update) |
706 | sdata->vif.type == NL80211_IFTYPE_AP) | ||
707 | ieee80211_send_layer2_update(sta); | 739 | ieee80211_send_layer2_update(sta); |
708 | 740 | ||
709 | rcu_read_unlock(); | 741 | rcu_read_unlock(); |
@@ -1099,12 +1131,12 @@ static int ieee80211_set_txq_params(struct wiphy *wiphy, | |||
1099 | 1131 | ||
1100 | static int ieee80211_set_channel(struct wiphy *wiphy, | 1132 | static int ieee80211_set_channel(struct wiphy *wiphy, |
1101 | struct ieee80211_channel *chan, | 1133 | struct ieee80211_channel *chan, |
1102 | enum nl80211_sec_chan_offset sec_chan_offset) | 1134 | enum nl80211_channel_type channel_type) |
1103 | { | 1135 | { |
1104 | struct ieee80211_local *local = wiphy_priv(wiphy); | 1136 | struct ieee80211_local *local = wiphy_priv(wiphy); |
1105 | 1137 | ||
1106 | local->oper_channel = chan; | 1138 | local->oper_channel = chan; |
1107 | local->oper_sec_chan_offset = sec_chan_offset; | 1139 | local->oper_channel_type = channel_type; |
1108 | 1140 | ||
1109 | return ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); | 1141 | return ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); |
1110 | } | 1142 | } |
diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c index a1eed7032c9b..5f510a13b9f0 100644 --- a/net/mac80211/ht.c +++ b/net/mac80211/ht.c | |||
@@ -98,6 +98,7 @@ u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata, | |||
98 | struct ieee80211_bss_ht_conf ht; | 98 | struct ieee80211_bss_ht_conf ht; |
99 | u32 changed = 0; | 99 | u32 changed = 0; |
100 | bool enable_ht = true, ht_changed; | 100 | bool enable_ht = true, ht_changed; |
101 | enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT; | ||
101 | 102 | ||
102 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | 103 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; |
103 | 104 | ||
@@ -112,24 +113,36 @@ u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata, | |||
112 | ieee80211_channel_to_frequency(hti->control_chan)) | 113 | ieee80211_channel_to_frequency(hti->control_chan)) |
113 | enable_ht = false; | 114 | enable_ht = false; |
114 | 115 | ||
115 | /* | 116 | if (enable_ht) { |
116 | * XXX: This is totally incorrect when there are multiple virtual | 117 | channel_type = NL80211_CHAN_HT20; |
117 | * interfaces, needs to be fixed later. | 118 | |
118 | */ | 119 | if (!(ap_ht_cap_flags & IEEE80211_HT_CAP_40MHZ_INTOLERANT) && |
119 | ht_changed = local->hw.conf.ht.enabled != enable_ht; | 120 | (sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) && |
121 | (hti->ht_param & IEEE80211_HT_PARAM_CHAN_WIDTH_ANY)) { | ||
122 | switch(hti->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) { | ||
123 | case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: | ||
124 | channel_type = NL80211_CHAN_HT40PLUS; | ||
125 | break; | ||
126 | case IEEE80211_HT_PARAM_CHA_SEC_BELOW: | ||
127 | channel_type = NL80211_CHAN_HT40MINUS; | ||
128 | break; | ||
129 | } | ||
130 | } | ||
131 | } | ||
132 | |||
133 | ht_changed = local->hw.conf.ht.enabled != enable_ht || | ||
134 | channel_type != local->hw.conf.ht.channel_type; | ||
135 | |||
136 | local->oper_channel_type = channel_type; | ||
120 | local->hw.conf.ht.enabled = enable_ht; | 137 | local->hw.conf.ht.enabled = enable_ht; |
138 | |||
121 | if (ht_changed) | 139 | if (ht_changed) |
122 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_HT); | 140 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_HT); |
123 | 141 | ||
124 | /* disable HT */ | 142 | /* disable HT */ |
125 | if (!enable_ht) | 143 | if (!enable_ht) |
126 | return 0; | 144 | return 0; |
127 | ht.secondary_channel_offset = | 145 | |
128 | hti->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET; | ||
129 | ht.width_40_ok = | ||
130 | !(ap_ht_cap_flags & IEEE80211_HT_CAP_40MHZ_INTOLERANT) && | ||
131 | (sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) && | ||
132 | (hti->ht_param & IEEE80211_HT_PARAM_CHAN_WIDTH_ANY); | ||
133 | ht.operation_mode = le16_to_cpu(hti->operation_mode); | 146 | ht.operation_mode = le16_to_cpu(hti->operation_mode); |
134 | 147 | ||
135 | /* if bss configuration changed store the new one */ | 148 | /* if bss configuration changed store the new one */ |
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 6f59e11d7b33..f3eec989662b 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -538,6 +538,11 @@ enum { | |||
538 | IEEE80211_ADDBA_MSG = 4, | 538 | IEEE80211_ADDBA_MSG = 4, |
539 | }; | 539 | }; |
540 | 540 | ||
541 | enum queue_stop_reason { | ||
542 | IEEE80211_QUEUE_STOP_REASON_DRIVER, | ||
543 | IEEE80211_QUEUE_STOP_REASON_PS, | ||
544 | }; | ||
545 | |||
541 | /* maximum number of hardware queues we support. */ | 546 | /* maximum number of hardware queues we support. */ |
542 | #define QD_MAX_QUEUES (IEEE80211_MAX_AMPDU_QUEUES + IEEE80211_MAX_QUEUES) | 547 | #define QD_MAX_QUEUES (IEEE80211_MAX_AMPDU_QUEUES + IEEE80211_MAX_QUEUES) |
543 | 548 | ||
@@ -554,7 +559,8 @@ struct ieee80211_local { | |||
554 | const struct ieee80211_ops *ops; | 559 | const struct ieee80211_ops *ops; |
555 | 560 | ||
556 | unsigned long queue_pool[BITS_TO_LONGS(QD_MAX_QUEUES)]; | 561 | unsigned long queue_pool[BITS_TO_LONGS(QD_MAX_QUEUES)]; |
557 | 562 | unsigned long queue_stop_reasons[IEEE80211_MAX_QUEUES]; | |
563 | spinlock_t queue_stop_reason_lock; | ||
558 | struct net_device *mdev; /* wmaster# - "master" 802.11 device */ | 564 | struct net_device *mdev; /* wmaster# - "master" 802.11 device */ |
559 | int open_count; | 565 | int open_count; |
560 | int monitors, cooked_mntrs; | 566 | int monitors, cooked_mntrs; |
@@ -625,7 +631,7 @@ struct ieee80211_local { | |||
625 | struct delayed_work scan_work; | 631 | struct delayed_work scan_work; |
626 | struct ieee80211_sub_if_data *scan_sdata; | 632 | struct ieee80211_sub_if_data *scan_sdata; |
627 | struct ieee80211_channel *oper_channel, *scan_channel; | 633 | struct ieee80211_channel *oper_channel, *scan_channel; |
628 | enum nl80211_sec_chan_offset oper_sec_chan_offset; | 634 | enum nl80211_channel_type oper_channel_type; |
629 | u8 scan_ssid[IEEE80211_MAX_SSID_LEN]; | 635 | u8 scan_ssid[IEEE80211_MAX_SSID_LEN]; |
630 | size_t scan_ssid_len; | 636 | size_t scan_ssid_len; |
631 | struct list_head bss_list; | 637 | struct list_head bss_list; |
@@ -689,6 +695,12 @@ struct ieee80211_local { | |||
689 | int wifi_wme_noack_test; | 695 | int wifi_wme_noack_test; |
690 | unsigned int wmm_acm; /* bit field of ACM bits (BIT(802.1D tag)) */ | 696 | unsigned int wmm_acm; /* bit field of ACM bits (BIT(802.1D tag)) */ |
691 | 697 | ||
698 | bool powersave; | ||
699 | int dynamic_ps_timeout; | ||
700 | struct work_struct dynamic_ps_enable_work; | ||
701 | struct work_struct dynamic_ps_disable_work; | ||
702 | struct timer_list dynamic_ps_timer; | ||
703 | |||
692 | #ifdef CONFIG_MAC80211_DEBUGFS | 704 | #ifdef CONFIG_MAC80211_DEBUGFS |
693 | struct local_debugfsdentries { | 705 | struct local_debugfsdentries { |
694 | struct dentry *rcdir; | 706 | struct dentry *rcdir; |
@@ -971,6 +983,15 @@ int ieee80211_set_freq(struct ieee80211_sub_if_data *sdata, int freq); | |||
971 | u64 ieee80211_mandatory_rates(struct ieee80211_local *local, | 983 | u64 ieee80211_mandatory_rates(struct ieee80211_local *local, |
972 | enum ieee80211_band band); | 984 | enum ieee80211_band band); |
973 | 985 | ||
986 | void ieee80211_dynamic_ps_enable_work(struct work_struct *work); | ||
987 | void ieee80211_dynamic_ps_disable_work(struct work_struct *work); | ||
988 | void ieee80211_dynamic_ps_timer(unsigned long data); | ||
989 | |||
990 | void ieee80211_wake_queues_by_reason(struct ieee80211_hw *hw, | ||
991 | enum queue_stop_reason reason); | ||
992 | void ieee80211_stop_queues_by_reason(struct ieee80211_hw *hw, | ||
993 | enum queue_stop_reason reason); | ||
994 | |||
974 | #ifdef CONFIG_MAC80211_NOINLINE | 995 | #ifdef CONFIG_MAC80211_NOINLINE |
975 | #define debug_noinline noinline | 996 | #define debug_noinline noinline |
976 | #else | 997 | #else |
diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 6d8710327d14..24b14363d6e7 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c | |||
@@ -195,37 +195,30 @@ int ieee80211_hw_config(struct ieee80211_local *local, u32 changed) | |||
195 | struct ieee80211_channel *chan; | 195 | struct ieee80211_channel *chan; |
196 | int ret = 0; | 196 | int ret = 0; |
197 | int power; | 197 | int power; |
198 | enum nl80211_sec_chan_offset sec_chan_offset; | 198 | enum nl80211_channel_type channel_type; |
199 | 199 | ||
200 | might_sleep(); | 200 | might_sleep(); |
201 | 201 | ||
202 | if (local->sw_scanning) { | 202 | if (local->sw_scanning) { |
203 | chan = local->scan_channel; | 203 | chan = local->scan_channel; |
204 | sec_chan_offset = NL80211_SEC_CHAN_NO_HT; | 204 | channel_type = NL80211_CHAN_NO_HT; |
205 | } else { | 205 | } else { |
206 | chan = local->oper_channel; | 206 | chan = local->oper_channel; |
207 | sec_chan_offset = local->oper_sec_chan_offset; | 207 | channel_type = local->oper_channel_type; |
208 | } | 208 | } |
209 | 209 | ||
210 | if (chan != local->hw.conf.channel || | 210 | if (chan != local->hw.conf.channel || |
211 | sec_chan_offset != local->hw.conf.ht.sec_chan_offset) { | 211 | channel_type != local->hw.conf.ht.channel_type) { |
212 | local->hw.conf.channel = chan; | 212 | local->hw.conf.channel = chan; |
213 | switch (sec_chan_offset) { | 213 | local->hw.conf.ht.channel_type = channel_type; |
214 | case NL80211_SEC_CHAN_NO_HT: | 214 | switch (channel_type) { |
215 | case NL80211_CHAN_NO_HT: | ||
215 | local->hw.conf.ht.enabled = false; | 216 | local->hw.conf.ht.enabled = false; |
216 | local->hw.conf.ht.sec_chan_offset = 0; | ||
217 | break; | 217 | break; |
218 | case NL80211_SEC_CHAN_DISABLED: | 218 | case NL80211_CHAN_HT20: |
219 | case NL80211_CHAN_HT40MINUS: | ||
220 | case NL80211_CHAN_HT40PLUS: | ||
219 | local->hw.conf.ht.enabled = true; | 221 | local->hw.conf.ht.enabled = true; |
220 | local->hw.conf.ht.sec_chan_offset = 0; | ||
221 | break; | ||
222 | case NL80211_SEC_CHAN_BELOW: | ||
223 | local->hw.conf.ht.enabled = true; | ||
224 | local->hw.conf.ht.sec_chan_offset = -1; | ||
225 | break; | ||
226 | case NL80211_SEC_CHAN_ABOVE: | ||
227 | local->hw.conf.ht.enabled = true; | ||
228 | local->hw.conf.ht.sec_chan_offset = 1; | ||
229 | break; | 222 | break; |
230 | } | 223 | } |
231 | changed |= IEEE80211_CONF_CHANGE_CHANNEL; | 224 | changed |= IEEE80211_CONF_CHANGE_CHANNEL; |
@@ -348,7 +341,8 @@ static void ieee80211_tasklet_handler(unsigned long data) | |||
348 | dev_kfree_skb(skb); | 341 | dev_kfree_skb(skb); |
349 | break ; | 342 | break ; |
350 | default: | 343 | default: |
351 | WARN_ON(1); | 344 | WARN(1, "mac80211: Packet is of unknown type %d\n", |
345 | skb->pkt_type); | ||
352 | dev_kfree_skb(skb); | 346 | dev_kfree_skb(skb); |
353 | break; | 347 | break; |
354 | } | 348 | } |
@@ -731,8 +725,17 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
731 | 725 | ||
732 | spin_lock_init(&local->key_lock); | 726 | spin_lock_init(&local->key_lock); |
733 | 727 | ||
728 | spin_lock_init(&local->queue_stop_reason_lock); | ||
729 | |||
734 | INIT_DELAYED_WORK(&local->scan_work, ieee80211_scan_work); | 730 | INIT_DELAYED_WORK(&local->scan_work, ieee80211_scan_work); |
735 | 731 | ||
732 | INIT_WORK(&local->dynamic_ps_enable_work, | ||
733 | ieee80211_dynamic_ps_enable_work); | ||
734 | INIT_WORK(&local->dynamic_ps_disable_work, | ||
735 | ieee80211_dynamic_ps_disable_work); | ||
736 | setup_timer(&local->dynamic_ps_timer, | ||
737 | ieee80211_dynamic_ps_timer, (unsigned long) local); | ||
738 | |||
736 | sta_info_init(local); | 739 | sta_info_init(local); |
737 | 740 | ||
738 | tasklet_init(&local->tx_pending_tasklet, ieee80211_tx_pending, | 741 | tasklet_init(&local->tx_pending_tasklet, ieee80211_tx_pending, |
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 290b0017ef2e..5ba721b6a399 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -309,7 +309,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, | |||
309 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | 309 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | |
310 | IEEE80211_STYPE_ASSOC_REQ); | 310 | IEEE80211_STYPE_ASSOC_REQ); |
311 | mgmt->u.assoc_req.capab_info = cpu_to_le16(capab); | 311 | mgmt->u.assoc_req.capab_info = cpu_to_le16(capab); |
312 | mgmt->u.reassoc_req.listen_interval = | 312 | mgmt->u.assoc_req.listen_interval = |
313 | cpu_to_le16(local->hw.conf.listen_interval); | 313 | cpu_to_le16(local->hw.conf.listen_interval); |
314 | } | 314 | } |
315 | 315 | ||
@@ -744,6 +744,17 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, | |||
744 | bss_info_changed |= BSS_CHANGED_BASIC_RATES; | 744 | bss_info_changed |= BSS_CHANGED_BASIC_RATES; |
745 | ieee80211_bss_info_change_notify(sdata, bss_info_changed); | 745 | ieee80211_bss_info_change_notify(sdata, bss_info_changed); |
746 | 746 | ||
747 | if (local->powersave) { | ||
748 | if (local->dynamic_ps_timeout > 0) | ||
749 | mod_timer(&local->dynamic_ps_timer, jiffies + | ||
750 | msecs_to_jiffies(local->dynamic_ps_timeout)); | ||
751 | else { | ||
752 | conf->flags |= IEEE80211_CONF_PS; | ||
753 | ieee80211_hw_config(local, | ||
754 | IEEE80211_CONF_CHANGE_PS); | ||
755 | } | ||
756 | } | ||
757 | |||
747 | netif_tx_start_all_queues(sdata->dev); | 758 | netif_tx_start_all_queues(sdata->dev); |
748 | netif_carrier_on(sdata->dev); | 759 | netif_carrier_on(sdata->dev); |
749 | 760 | ||
@@ -812,7 +823,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, | |||
812 | { | 823 | { |
813 | struct ieee80211_local *local = sdata->local; | 824 | struct ieee80211_local *local = sdata->local; |
814 | struct sta_info *sta; | 825 | struct sta_info *sta; |
815 | u32 changed = 0; | 826 | u32 changed = 0, config_changed = 0; |
816 | 827 | ||
817 | rcu_read_lock(); | 828 | rcu_read_lock(); |
818 | 829 | ||
@@ -858,8 +869,18 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, | |||
858 | rcu_read_unlock(); | 869 | rcu_read_unlock(); |
859 | 870 | ||
860 | local->hw.conf.ht.enabled = false; | 871 | local->hw.conf.ht.enabled = false; |
861 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_HT); | 872 | local->oper_channel_type = NL80211_CHAN_NO_HT; |
873 | config_changed |= IEEE80211_CONF_CHANGE_HT; | ||
874 | |||
875 | del_timer_sync(&local->dynamic_ps_timer); | ||
876 | cancel_work_sync(&local->dynamic_ps_enable_work); | ||
862 | 877 | ||
878 | if (local->hw.conf.flags & IEEE80211_CONF_PS) { | ||
879 | local->hw.conf.flags &= ~IEEE80211_CONF_PS; | ||
880 | config_changed |= IEEE80211_CONF_CHANGE_PS; | ||
881 | } | ||
882 | |||
883 | ieee80211_hw_config(local, config_changed); | ||
863 | ieee80211_bss_info_change_notify(sdata, changed); | 884 | ieee80211_bss_info_change_notify(sdata, changed); |
864 | 885 | ||
865 | rcu_read_lock(); | 886 | rcu_read_lock(); |
@@ -1612,8 +1633,13 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | |||
1612 | * e.g: at 1 MBit that means mactime is 192 usec earlier | 1633 | * e.g: at 1 MBit that means mactime is 192 usec earlier |
1613 | * (=24 bytes * 8 usecs/byte) than the beacon timestamp. | 1634 | * (=24 bytes * 8 usecs/byte) than the beacon timestamp. |
1614 | */ | 1635 | */ |
1615 | int rate = local->hw.wiphy->bands[band]-> | 1636 | int rate; |
1637 | if (rx_status->flag & RX_FLAG_HT) { | ||
1638 | rate = 65; /* TODO: HT rates */ | ||
1639 | } else { | ||
1640 | rate = local->hw.wiphy->bands[band]-> | ||
1616 | bitrates[rx_status->rate_idx].bitrate; | 1641 | bitrates[rx_status->rate_idx].bitrate; |
1642 | } | ||
1617 | rx_timestamp = rx_status->mactime + (24 * 8 * 10 / rate); | 1643 | rx_timestamp = rx_status->mactime + (24 * 8 * 10 / rate); |
1618 | } else if (local && local->ops && local->ops->get_tsf) | 1644 | } else if (local && local->ops && local->ops->get_tsf) |
1619 | /* second best option: get current TSF */ | 1645 | /* second best option: get current TSF */ |
@@ -2576,3 +2602,39 @@ void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local) | |||
2576 | ieee80211_restart_sta_timer(sdata); | 2602 | ieee80211_restart_sta_timer(sdata); |
2577 | rcu_read_unlock(); | 2603 | rcu_read_unlock(); |
2578 | } | 2604 | } |
2605 | |||
2606 | void ieee80211_dynamic_ps_disable_work(struct work_struct *work) | ||
2607 | { | ||
2608 | struct ieee80211_local *local = | ||
2609 | container_of(work, struct ieee80211_local, | ||
2610 | dynamic_ps_disable_work); | ||
2611 | |||
2612 | if (local->hw.conf.flags & IEEE80211_CONF_PS) { | ||
2613 | local->hw.conf.flags &= ~IEEE80211_CONF_PS; | ||
2614 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); | ||
2615 | } | ||
2616 | |||
2617 | ieee80211_wake_queues_by_reason(&local->hw, | ||
2618 | IEEE80211_QUEUE_STOP_REASON_PS); | ||
2619 | } | ||
2620 | |||
2621 | void ieee80211_dynamic_ps_enable_work(struct work_struct *work) | ||
2622 | { | ||
2623 | struct ieee80211_local *local = | ||
2624 | container_of(work, struct ieee80211_local, | ||
2625 | dynamic_ps_enable_work); | ||
2626 | |||
2627 | if (local->hw.conf.flags & IEEE80211_CONF_PS) | ||
2628 | return; | ||
2629 | |||
2630 | local->hw.conf.flags |= IEEE80211_CONF_PS; | ||
2631 | |||
2632 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); | ||
2633 | } | ||
2634 | |||
2635 | void ieee80211_dynamic_ps_timer(unsigned long data) | ||
2636 | { | ||
2637 | struct ieee80211_local *local = (void *) data; | ||
2638 | |||
2639 | queue_work(local->hw.workqueue, &local->dynamic_ps_enable_work); | ||
2640 | } | ||
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 73cf126cef49..7175ae80c36a 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
@@ -123,7 +123,6 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, | |||
123 | /* radiotap header, set always present flags */ | 123 | /* radiotap header, set always present flags */ |
124 | rthdr->it_present = | 124 | rthdr->it_present = |
125 | cpu_to_le32((1 << IEEE80211_RADIOTAP_FLAGS) | | 125 | cpu_to_le32((1 << IEEE80211_RADIOTAP_FLAGS) | |
126 | (1 << IEEE80211_RADIOTAP_RATE) | | ||
127 | (1 << IEEE80211_RADIOTAP_CHANNEL) | | 126 | (1 << IEEE80211_RADIOTAP_CHANNEL) | |
128 | (1 << IEEE80211_RADIOTAP_ANTENNA) | | 127 | (1 << IEEE80211_RADIOTAP_ANTENNA) | |
129 | (1 << IEEE80211_RADIOTAP_RX_FLAGS)); | 128 | (1 << IEEE80211_RADIOTAP_RX_FLAGS)); |
@@ -149,7 +148,19 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, | |||
149 | pos++; | 148 | pos++; |
150 | 149 | ||
151 | /* IEEE80211_RADIOTAP_RATE */ | 150 | /* IEEE80211_RADIOTAP_RATE */ |
152 | *pos = rate->bitrate / 5; | 151 | if (status->flag & RX_FLAG_HT) { |
152 | /* | ||
153 | * TODO: add following information into radiotap header once | ||
154 | * suitable fields are defined for it: | ||
155 | * - MCS index (status->rate_idx) | ||
156 | * - HT40 (status->flag & RX_FLAG_40MHZ) | ||
157 | * - short-GI (status->flag & RX_FLAG_SHORT_GI) | ||
158 | */ | ||
159 | *pos = 0; | ||
160 | } else { | ||
161 | rthdr->it_present |= (1 << IEEE80211_RADIOTAP_RATE); | ||
162 | *pos = rate->bitrate / 5; | ||
163 | } | ||
153 | pos++; | 164 | pos++; |
154 | 165 | ||
155 | /* IEEE80211_RADIOTAP_CHANNEL */ | 166 | /* IEEE80211_RADIOTAP_CHANNEL */ |
@@ -1849,9 +1860,15 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata, | |||
1849 | if (!(sdata->dev->flags & IFF_PROMISC)) | 1860 | if (!(sdata->dev->flags & IFF_PROMISC)) |
1850 | return 0; | 1861 | return 0; |
1851 | rx->flags &= ~IEEE80211_RX_RA_MATCH; | 1862 | rx->flags &= ~IEEE80211_RX_RA_MATCH; |
1852 | } else if (!rx->sta) | 1863 | } else if (!rx->sta) { |
1864 | int rate_idx; | ||
1865 | if (rx->status->flag & RX_FLAG_HT) | ||
1866 | rate_idx = 0; /* TODO: HT rates */ | ||
1867 | else | ||
1868 | rate_idx = rx->status->rate_idx; | ||
1853 | rx->sta = ieee80211_ibss_add_sta(sdata, bssid, hdr->addr2, | 1869 | rx->sta = ieee80211_ibss_add_sta(sdata, bssid, hdr->addr2, |
1854 | BIT(rx->status->rate_idx)); | 1870 | BIT(rate_idx)); |
1871 | } | ||
1855 | break; | 1872 | break; |
1856 | case NL80211_IFTYPE_MESH_POINT: | 1873 | case NL80211_IFTYPE_MESH_POINT: |
1857 | if (!multicast && | 1874 | if (!multicast && |
@@ -2057,7 +2074,13 @@ static u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw, | |||
2057 | tid_agg_rx->reorder_buf[index]->cb, | 2074 | tid_agg_rx->reorder_buf[index]->cb, |
2058 | sizeof(status)); | 2075 | sizeof(status)); |
2059 | sband = local->hw.wiphy->bands[status.band]; | 2076 | sband = local->hw.wiphy->bands[status.band]; |
2060 | rate = &sband->bitrates[status.rate_idx]; | 2077 | if (status.flag & RX_FLAG_HT) { |
2078 | /* TODO: HT rates */ | ||
2079 | rate = sband->bitrates; | ||
2080 | } else { | ||
2081 | rate = &sband->bitrates | ||
2082 | [status.rate_idx]; | ||
2083 | } | ||
2061 | __ieee80211_rx_handle_packet(hw, | 2084 | __ieee80211_rx_handle_packet(hw, |
2062 | tid_agg_rx->reorder_buf[index], | 2085 | tid_agg_rx->reorder_buf[index], |
2063 | &status, rate); | 2086 | &status, rate); |
@@ -2101,7 +2124,10 @@ static u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw, | |||
2101 | memcpy(&status, tid_agg_rx->reorder_buf[index]->cb, | 2124 | memcpy(&status, tid_agg_rx->reorder_buf[index]->cb, |
2102 | sizeof(status)); | 2125 | sizeof(status)); |
2103 | sband = local->hw.wiphy->bands[status.band]; | 2126 | sband = local->hw.wiphy->bands[status.band]; |
2104 | rate = &sband->bitrates[status.rate_idx]; | 2127 | if (status.flag & RX_FLAG_HT) |
2128 | rate = sband->bitrates; /* TODO: HT rates */ | ||
2129 | else | ||
2130 | rate = &sband->bitrates[status.rate_idx]; | ||
2105 | __ieee80211_rx_handle_packet(hw, tid_agg_rx->reorder_buf[index], | 2131 | __ieee80211_rx_handle_packet(hw, tid_agg_rx->reorder_buf[index], |
2106 | &status, rate); | 2132 | &status, rate); |
2107 | tid_agg_rx->stored_mpdu_num--; | 2133 | tid_agg_rx->stored_mpdu_num--; |
@@ -2189,15 +2215,26 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb, | |||
2189 | } | 2215 | } |
2190 | 2216 | ||
2191 | sband = local->hw.wiphy->bands[status->band]; | 2217 | sband = local->hw.wiphy->bands[status->band]; |
2192 | 2218 | if (!sband) { | |
2193 | if (!sband || | ||
2194 | status->rate_idx < 0 || | ||
2195 | status->rate_idx >= sband->n_bitrates) { | ||
2196 | WARN_ON(1); | 2219 | WARN_ON(1); |
2197 | return; | 2220 | return; |
2198 | } | 2221 | } |
2199 | 2222 | ||
2200 | rate = &sband->bitrates[status->rate_idx]; | 2223 | if (status->flag & RX_FLAG_HT) { |
2224 | /* rate_idx is MCS index */ | ||
2225 | if (WARN_ON(status->rate_idx < 0 || | ||
2226 | status->rate_idx >= 76)) | ||
2227 | return; | ||
2228 | /* HT rates are not in the table - use the highest legacy rate | ||
2229 | * for now since other parts of mac80211 may not yet be fully | ||
2230 | * MCS aware. */ | ||
2231 | rate = &sband->bitrates[sband->n_bitrates - 1]; | ||
2232 | } else { | ||
2233 | if (WARN_ON(status->rate_idx < 0 || | ||
2234 | status->rate_idx >= sband->n_bitrates)) | ||
2235 | return; | ||
2236 | rate = &sband->bitrates[status->rate_idx]; | ||
2237 | } | ||
2201 | 2238 | ||
2202 | /* | 2239 | /* |
2203 | * key references and virtual interfaces are protected using RCU | 2240 | * key references and virtual interfaces are protected using RCU |
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index b098c58d216f..a4af3a124cce 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c | |||
@@ -1473,6 +1473,19 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
1473 | goto fail; | 1473 | goto fail; |
1474 | } | 1474 | } |
1475 | 1475 | ||
1476 | if (!(local->hw.flags & IEEE80211_HW_NO_STACK_DYNAMIC_PS) && | ||
1477 | local->dynamic_ps_timeout > 0) { | ||
1478 | if (local->hw.conf.flags & IEEE80211_CONF_PS) { | ||
1479 | ieee80211_stop_queues_by_reason(&local->hw, | ||
1480 | IEEE80211_QUEUE_STOP_REASON_PS); | ||
1481 | queue_work(local->hw.workqueue, | ||
1482 | &local->dynamic_ps_disable_work); | ||
1483 | } | ||
1484 | |||
1485 | mod_timer(&local->dynamic_ps_timer, jiffies + | ||
1486 | msecs_to_jiffies(local->dynamic_ps_timeout)); | ||
1487 | } | ||
1488 | |||
1476 | nh_pos = skb_network_header(skb) - skb->data; | 1489 | nh_pos = skb_network_header(skb) - skb->data; |
1477 | h_pos = skb_transport_header(skb) - skb->data; | 1490 | h_pos = skb_transport_header(skb) - skb->data; |
1478 | 1491 | ||
diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 505d68f344ce..fb89e1d0aa03 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c | |||
@@ -330,10 +330,20 @@ __le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw, | |||
330 | } | 330 | } |
331 | EXPORT_SYMBOL(ieee80211_ctstoself_duration); | 331 | EXPORT_SYMBOL(ieee80211_ctstoself_duration); |
332 | 332 | ||
333 | void ieee80211_wake_queue(struct ieee80211_hw *hw, int queue) | 333 | static void __ieee80211_wake_queue(struct ieee80211_hw *hw, int queue, |
334 | enum queue_stop_reason reason) | ||
334 | { | 335 | { |
335 | struct ieee80211_local *local = hw_to_local(hw); | 336 | struct ieee80211_local *local = hw_to_local(hw); |
336 | 337 | ||
338 | /* we don't need to track ampdu queues */ | ||
339 | if (queue < ieee80211_num_regular_queues(hw)) { | ||
340 | __clear_bit(reason, &local->queue_stop_reasons[queue]); | ||
341 | |||
342 | if (local->queue_stop_reasons[queue] != 0) | ||
343 | /* someone still has this queue stopped */ | ||
344 | return; | ||
345 | } | ||
346 | |||
337 | if (test_bit(queue, local->queues_pending)) { | 347 | if (test_bit(queue, local->queues_pending)) { |
338 | set_bit(queue, local->queues_pending_run); | 348 | set_bit(queue, local->queues_pending_run); |
339 | tasklet_schedule(&local->tx_pending_tasklet); | 349 | tasklet_schedule(&local->tx_pending_tasklet); |
@@ -341,22 +351,74 @@ void ieee80211_wake_queue(struct ieee80211_hw *hw, int queue) | |||
341 | netif_wake_subqueue(local->mdev, queue); | 351 | netif_wake_subqueue(local->mdev, queue); |
342 | } | 352 | } |
343 | } | 353 | } |
354 | |||
355 | void ieee80211_wake_queue_by_reason(struct ieee80211_hw *hw, int queue, | ||
356 | enum queue_stop_reason reason) | ||
357 | { | ||
358 | struct ieee80211_local *local = hw_to_local(hw); | ||
359 | unsigned long flags; | ||
360 | |||
361 | spin_lock_irqsave(&local->queue_stop_reason_lock, flags); | ||
362 | __ieee80211_wake_queue(hw, queue, reason); | ||
363 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); | ||
364 | } | ||
365 | |||
366 | void ieee80211_wake_queue(struct ieee80211_hw *hw, int queue) | ||
367 | { | ||
368 | ieee80211_wake_queue_by_reason(hw, queue, | ||
369 | IEEE80211_QUEUE_STOP_REASON_DRIVER); | ||
370 | } | ||
344 | EXPORT_SYMBOL(ieee80211_wake_queue); | 371 | EXPORT_SYMBOL(ieee80211_wake_queue); |
345 | 372 | ||
346 | void ieee80211_stop_queue(struct ieee80211_hw *hw, int queue) | 373 | static void __ieee80211_stop_queue(struct ieee80211_hw *hw, int queue, |
374 | enum queue_stop_reason reason) | ||
347 | { | 375 | { |
348 | struct ieee80211_local *local = hw_to_local(hw); | 376 | struct ieee80211_local *local = hw_to_local(hw); |
349 | 377 | ||
378 | /* we don't need to track ampdu queues */ | ||
379 | if (queue < ieee80211_num_regular_queues(hw)) | ||
380 | __set_bit(reason, &local->queue_stop_reasons[queue]); | ||
381 | |||
350 | netif_stop_subqueue(local->mdev, queue); | 382 | netif_stop_subqueue(local->mdev, queue); |
351 | } | 383 | } |
384 | |||
385 | void ieee80211_stop_queue_by_reason(struct ieee80211_hw *hw, int queue, | ||
386 | enum queue_stop_reason reason) | ||
387 | { | ||
388 | struct ieee80211_local *local = hw_to_local(hw); | ||
389 | unsigned long flags; | ||
390 | |||
391 | spin_lock_irqsave(&local->queue_stop_reason_lock, flags); | ||
392 | __ieee80211_stop_queue(hw, queue, reason); | ||
393 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); | ||
394 | } | ||
395 | |||
396 | void ieee80211_stop_queue(struct ieee80211_hw *hw, int queue) | ||
397 | { | ||
398 | ieee80211_stop_queue_by_reason(hw, queue, | ||
399 | IEEE80211_QUEUE_STOP_REASON_DRIVER); | ||
400 | } | ||
352 | EXPORT_SYMBOL(ieee80211_stop_queue); | 401 | EXPORT_SYMBOL(ieee80211_stop_queue); |
353 | 402 | ||
354 | void ieee80211_stop_queues(struct ieee80211_hw *hw) | 403 | void ieee80211_stop_queues_by_reason(struct ieee80211_hw *hw, |
404 | enum queue_stop_reason reason) | ||
355 | { | 405 | { |
406 | struct ieee80211_local *local = hw_to_local(hw); | ||
407 | unsigned long flags; | ||
356 | int i; | 408 | int i; |
357 | 409 | ||
410 | spin_lock_irqsave(&local->queue_stop_reason_lock, flags); | ||
411 | |||
358 | for (i = 0; i < ieee80211_num_queues(hw); i++) | 412 | for (i = 0; i < ieee80211_num_queues(hw); i++) |
359 | ieee80211_stop_queue(hw, i); | 413 | __ieee80211_stop_queue(hw, i, reason); |
414 | |||
415 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); | ||
416 | } | ||
417 | |||
418 | void ieee80211_stop_queues(struct ieee80211_hw *hw) | ||
419 | { | ||
420 | ieee80211_stop_queues_by_reason(hw, | ||
421 | IEEE80211_QUEUE_STOP_REASON_DRIVER); | ||
360 | } | 422 | } |
361 | EXPORT_SYMBOL(ieee80211_stop_queues); | 423 | EXPORT_SYMBOL(ieee80211_stop_queues); |
362 | 424 | ||
@@ -367,12 +429,24 @@ int ieee80211_queue_stopped(struct ieee80211_hw *hw, int queue) | |||
367 | } | 429 | } |
368 | EXPORT_SYMBOL(ieee80211_queue_stopped); | 430 | EXPORT_SYMBOL(ieee80211_queue_stopped); |
369 | 431 | ||
370 | void ieee80211_wake_queues(struct ieee80211_hw *hw) | 432 | void ieee80211_wake_queues_by_reason(struct ieee80211_hw *hw, |
433 | enum queue_stop_reason reason) | ||
371 | { | 434 | { |
435 | struct ieee80211_local *local = hw_to_local(hw); | ||
436 | unsigned long flags; | ||
372 | int i; | 437 | int i; |
373 | 438 | ||
439 | spin_lock_irqsave(&local->queue_stop_reason_lock, flags); | ||
440 | |||
374 | for (i = 0; i < hw->queues + hw->ampdu_queues; i++) | 441 | for (i = 0; i < hw->queues + hw->ampdu_queues; i++) |
375 | ieee80211_wake_queue(hw, i); | 442 | __ieee80211_wake_queue(hw, i, reason); |
443 | |||
444 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); | ||
445 | } | ||
446 | |||
447 | void ieee80211_wake_queues(struct ieee80211_hw *hw) | ||
448 | { | ||
449 | ieee80211_wake_queues_by_reason(hw, IEEE80211_QUEUE_STOP_REASON_DRIVER); | ||
376 | } | 450 | } |
377 | EXPORT_SYMBOL(ieee80211_wake_queues); | 451 | EXPORT_SYMBOL(ieee80211_wake_queues); |
378 | 452 | ||
@@ -641,7 +715,7 @@ int ieee80211_set_freq(struct ieee80211_sub_if_data *sdata, int freqMHz) | |||
641 | chan->flags & IEEE80211_CHAN_NO_IBSS) | 715 | chan->flags & IEEE80211_CHAN_NO_IBSS) |
642 | return ret; | 716 | return ret; |
643 | local->oper_channel = chan; | 717 | local->oper_channel = chan; |
644 | local->oper_sec_chan_offset = NL80211_SEC_CHAN_NO_HT; | 718 | local->oper_channel_type = NL80211_CHAN_NO_HT; |
645 | 719 | ||
646 | if (local->sw_scanning || local->hw_scanning) | 720 | if (local->sw_scanning || local->hw_scanning) |
647 | ret = 0; | 721 | ret = 0; |
diff --git a/net/mac80211/wext.c b/net/mac80211/wext.c index 15428048d01a..7162d5816f39 100644 --- a/net/mac80211/wext.c +++ b/net/mac80211/wext.c | |||
@@ -830,25 +830,56 @@ static int ieee80211_ioctl_siwpower(struct net_device *dev, | |||
830 | struct iw_param *wrq, | 830 | struct iw_param *wrq, |
831 | char *extra) | 831 | char *extra) |
832 | { | 832 | { |
833 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
833 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 834 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); |
834 | struct ieee80211_conf *conf = &local->hw.conf; | 835 | struct ieee80211_conf *conf = &local->hw.conf; |
836 | int ret = 0, timeout = 0; | ||
837 | bool ps; | ||
838 | |||
839 | if (sdata->vif.type != NL80211_IFTYPE_STATION) | ||
840 | return -EINVAL; | ||
835 | 841 | ||
836 | if (wrq->disabled) { | 842 | if (wrq->disabled) { |
837 | conf->flags &= ~IEEE80211_CONF_PS; | 843 | ps = false; |
838 | return ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); | 844 | timeout = 0; |
845 | goto set; | ||
839 | } | 846 | } |
840 | 847 | ||
841 | switch (wrq->flags & IW_POWER_MODE) { | 848 | switch (wrq->flags & IW_POWER_MODE) { |
842 | case IW_POWER_ON: /* If not specified */ | 849 | case IW_POWER_ON: /* If not specified */ |
843 | case IW_POWER_MODE: /* If set all mask */ | 850 | case IW_POWER_MODE: /* If set all mask */ |
844 | case IW_POWER_ALL_R: /* If explicitely state all */ | 851 | case IW_POWER_ALL_R: /* If explicitely state all */ |
845 | conf->flags |= IEEE80211_CONF_PS; | 852 | ps = true; |
853 | break; | ||
854 | default: /* Otherwise we ignore */ | ||
846 | break; | 855 | break; |
847 | default: /* Otherwise we don't support it */ | ||
848 | return -EINVAL; | ||
849 | } | 856 | } |
850 | 857 | ||
851 | return ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); | 858 | if (wrq->flags & IW_POWER_TIMEOUT) |
859 | timeout = wrq->value / 1000; | ||
860 | |||
861 | set: | ||
862 | if (ps == local->powersave && timeout == local->dynamic_ps_timeout) | ||
863 | return ret; | ||
864 | |||
865 | local->powersave = ps; | ||
866 | local->dynamic_ps_timeout = timeout; | ||
867 | |||
868 | if (sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED) { | ||
869 | if (!(local->hw.flags & IEEE80211_HW_NO_STACK_DYNAMIC_PS) && | ||
870 | local->dynamic_ps_timeout > 0) | ||
871 | mod_timer(&local->dynamic_ps_timer, jiffies + | ||
872 | msecs_to_jiffies(local->dynamic_ps_timeout)); | ||
873 | else { | ||
874 | if (local->powersave) | ||
875 | conf->flags |= IEEE80211_CONF_PS; | ||
876 | else | ||
877 | conf->flags &= ~IEEE80211_CONF_PS; | ||
878 | } | ||
879 | ret = ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); | ||
880 | } | ||
881 | |||
882 | return ret; | ||
852 | } | 883 | } |
853 | 884 | ||
854 | static int ieee80211_ioctl_giwpower(struct net_device *dev, | 885 | static int ieee80211_ioctl_giwpower(struct net_device *dev, |
@@ -857,9 +888,8 @@ static int ieee80211_ioctl_giwpower(struct net_device *dev, | |||
857 | char *extra) | 888 | char *extra) |
858 | { | 889 | { |
859 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 890 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); |
860 | struct ieee80211_conf *conf = &local->hw.conf; | ||
861 | 891 | ||
862 | wrqu->power.disabled = !(conf->flags & IEEE80211_CONF_PS); | 892 | wrqu->power.disabled = !local->powersave; |
863 | 893 | ||
864 | return 0; | 894 | return 0; |
865 | } | 895 | } |
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 4335f76be71f..1e728fff474e 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -60,7 +60,7 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = { | |||
60 | .len = BUS_ID_SIZE-1 }, | 60 | .len = BUS_ID_SIZE-1 }, |
61 | [NL80211_ATTR_WIPHY_TXQ_PARAMS] = { .type = NLA_NESTED }, | 61 | [NL80211_ATTR_WIPHY_TXQ_PARAMS] = { .type = NLA_NESTED }, |
62 | [NL80211_ATTR_WIPHY_FREQ] = { .type = NLA_U32 }, | 62 | [NL80211_ATTR_WIPHY_FREQ] = { .type = NLA_U32 }, |
63 | [NL80211_ATTR_WIPHY_SEC_CHAN_OFFSET] = { .type = NLA_U32 }, | 63 | [NL80211_ATTR_WIPHY_CHANNEL_TYPE] = { .type = NLA_U32 }, |
64 | 64 | ||
65 | [NL80211_ATTR_IFTYPE] = { .type = NLA_U32 }, | 65 | [NL80211_ATTR_IFTYPE] = { .type = NLA_U32 }, |
66 | [NL80211_ATTR_IFINDEX] = { .type = NLA_U32 }, | 66 | [NL80211_ATTR_IFINDEX] = { .type = NLA_U32 }, |
@@ -362,8 +362,7 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) | |||
362 | } | 362 | } |
363 | 363 | ||
364 | if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) { | 364 | if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) { |
365 | enum nl80211_sec_chan_offset sec_chan_offset = | 365 | enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT; |
366 | NL80211_SEC_CHAN_NO_HT; | ||
367 | struct ieee80211_channel *chan; | 366 | struct ieee80211_channel *chan; |
368 | struct ieee80211_sta_ht_cap *ht_cap; | 367 | struct ieee80211_sta_ht_cap *ht_cap; |
369 | u32 freq, sec_freq; | 368 | u32 freq, sec_freq; |
@@ -375,13 +374,13 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) | |||
375 | 374 | ||
376 | result = -EINVAL; | 375 | result = -EINVAL; |
377 | 376 | ||
378 | if (info->attrs[NL80211_ATTR_WIPHY_SEC_CHAN_OFFSET]) { | 377 | if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) { |
379 | sec_chan_offset = nla_get_u32(info->attrs[ | 378 | channel_type = nla_get_u32(info->attrs[ |
380 | NL80211_ATTR_WIPHY_SEC_CHAN_OFFSET]); | 379 | NL80211_ATTR_WIPHY_CHANNEL_TYPE]); |
381 | if (sec_chan_offset != NL80211_SEC_CHAN_NO_HT && | 380 | if (channel_type != NL80211_CHAN_NO_HT && |
382 | sec_chan_offset != NL80211_SEC_CHAN_DISABLED && | 381 | channel_type != NL80211_CHAN_HT20 && |
383 | sec_chan_offset != NL80211_SEC_CHAN_BELOW && | 382 | channel_type != NL80211_CHAN_HT40PLUS && |
384 | sec_chan_offset != NL80211_SEC_CHAN_ABOVE) | 383 | channel_type != NL80211_CHAN_HT40MINUS) |
385 | goto bad_res; | 384 | goto bad_res; |
386 | } | 385 | } |
387 | 386 | ||
@@ -392,9 +391,9 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) | |||
392 | if (!chan || chan->flags & IEEE80211_CHAN_DISABLED) | 391 | if (!chan || chan->flags & IEEE80211_CHAN_DISABLED) |
393 | goto bad_res; | 392 | goto bad_res; |
394 | 393 | ||
395 | if (sec_chan_offset == NL80211_SEC_CHAN_BELOW) | 394 | if (channel_type == NL80211_CHAN_HT40MINUS) |
396 | sec_freq = freq - 20; | 395 | sec_freq = freq - 20; |
397 | else if (sec_chan_offset == NL80211_SEC_CHAN_ABOVE) | 396 | else if (channel_type == NL80211_CHAN_HT40PLUS) |
398 | sec_freq = freq + 20; | 397 | sec_freq = freq + 20; |
399 | else | 398 | else |
400 | sec_freq = 0; | 399 | sec_freq = 0; |
@@ -402,7 +401,7 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) | |||
402 | ht_cap = &rdev->wiphy.bands[chan->band]->ht_cap; | 401 | ht_cap = &rdev->wiphy.bands[chan->band]->ht_cap; |
403 | 402 | ||
404 | /* no HT capabilities */ | 403 | /* no HT capabilities */ |
405 | if (sec_chan_offset != NL80211_SEC_CHAN_NO_HT && | 404 | if (channel_type != NL80211_CHAN_NO_HT && |
406 | !ht_cap->ht_supported) | 405 | !ht_cap->ht_supported) |
407 | goto bad_res; | 406 | goto bad_res; |
408 | 407 | ||
@@ -422,7 +421,7 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) | |||
422 | } | 421 | } |
423 | 422 | ||
424 | result = rdev->ops->set_channel(&rdev->wiphy, chan, | 423 | result = rdev->ops->set_channel(&rdev->wiphy, chan, |
425 | sec_chan_offset); | 424 | channel_type); |
426 | if (result) | 425 | if (result) |
427 | goto bad_res; | 426 | goto bad_res; |
428 | } | 427 | } |
@@ -1091,12 +1090,46 @@ static int parse_station_flags(struct nlattr *nla, u32 *staflags) | |||
1091 | return 0; | 1090 | return 0; |
1092 | } | 1091 | } |
1093 | 1092 | ||
1093 | static u16 nl80211_calculate_bitrate(struct rate_info *rate) | ||
1094 | { | ||
1095 | int modulation, streams, bitrate; | ||
1096 | |||
1097 | if (!(rate->flags & RATE_INFO_FLAGS_MCS)) | ||
1098 | return rate->legacy; | ||
1099 | |||
1100 | /* the formula below does only work for MCS values smaller than 32 */ | ||
1101 | if (rate->mcs >= 32) | ||
1102 | return 0; | ||
1103 | |||
1104 | modulation = rate->mcs & 7; | ||
1105 | streams = (rate->mcs >> 3) + 1; | ||
1106 | |||
1107 | bitrate = (rate->flags & RATE_INFO_FLAGS_40_MHZ_WIDTH) ? | ||
1108 | 13500000 : 6500000; | ||
1109 | |||
1110 | if (modulation < 4) | ||
1111 | bitrate *= (modulation + 1); | ||
1112 | else if (modulation == 4) | ||
1113 | bitrate *= (modulation + 2); | ||
1114 | else | ||
1115 | bitrate *= (modulation + 3); | ||
1116 | |||
1117 | bitrate *= streams; | ||
1118 | |||
1119 | if (rate->flags & RATE_INFO_FLAGS_SHORT_GI) | ||
1120 | bitrate = (bitrate / 9) * 10; | ||
1121 | |||
1122 | /* do NOT round down here */ | ||
1123 | return (bitrate + 50000) / 100000; | ||
1124 | } | ||
1125 | |||
1094 | static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq, | 1126 | static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq, |
1095 | int flags, struct net_device *dev, | 1127 | int flags, struct net_device *dev, |
1096 | u8 *mac_addr, struct station_info *sinfo) | 1128 | u8 *mac_addr, struct station_info *sinfo) |
1097 | { | 1129 | { |
1098 | void *hdr; | 1130 | void *hdr; |
1099 | struct nlattr *sinfoattr; | 1131 | struct nlattr *sinfoattr, *txrate; |
1132 | u16 bitrate; | ||
1100 | 1133 | ||
1101 | hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_STATION); | 1134 | hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_STATION); |
1102 | if (!hdr) | 1135 | if (!hdr) |
@@ -1126,7 +1159,29 @@ static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq, | |||
1126 | if (sinfo->filled & STATION_INFO_PLINK_STATE) | 1159 | if (sinfo->filled & STATION_INFO_PLINK_STATE) |
1127 | NLA_PUT_U8(msg, NL80211_STA_INFO_PLINK_STATE, | 1160 | NLA_PUT_U8(msg, NL80211_STA_INFO_PLINK_STATE, |
1128 | sinfo->plink_state); | 1161 | sinfo->plink_state); |
1162 | if (sinfo->filled & STATION_INFO_SIGNAL) | ||
1163 | NLA_PUT_U8(msg, NL80211_STA_INFO_SIGNAL, | ||
1164 | sinfo->signal); | ||
1165 | if (sinfo->filled & STATION_INFO_TX_BITRATE) { | ||
1166 | txrate = nla_nest_start(msg, NL80211_STA_INFO_TX_BITRATE); | ||
1167 | if (!txrate) | ||
1168 | goto nla_put_failure; | ||
1169 | |||
1170 | /* nl80211_calculate_bitrate will return 0 for mcs >= 32 */ | ||
1171 | bitrate = nl80211_calculate_bitrate(&sinfo->txrate); | ||
1172 | if (bitrate > 0) | ||
1173 | NLA_PUT_U16(msg, NL80211_RATE_INFO_BITRATE, bitrate); | ||
1129 | 1174 | ||
1175 | if (sinfo->txrate.flags & RATE_INFO_FLAGS_MCS) | ||
1176 | NLA_PUT_U8(msg, NL80211_RATE_INFO_MCS, | ||
1177 | sinfo->txrate.mcs); | ||
1178 | if (sinfo->txrate.flags & RATE_INFO_FLAGS_40_MHZ_WIDTH) | ||
1179 | NLA_PUT_FLAG(msg, NL80211_RATE_INFO_40_MHZ_WIDTH); | ||
1180 | if (sinfo->txrate.flags & RATE_INFO_FLAGS_SHORT_GI) | ||
1181 | NLA_PUT_FLAG(msg, NL80211_RATE_INFO_SHORT_GI); | ||
1182 | |||
1183 | nla_nest_end(msg, txrate); | ||
1184 | } | ||
1130 | nla_nest_end(msg, sinfoattr); | 1185 | nla_nest_end(msg, sinfoattr); |
1131 | 1186 | ||
1132 | return genlmsg_end(msg, hdr); | 1187 | return genlmsg_end(msg, hdr); |