diff options
author | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2009-06-16 20:24:53 -0400 |
---|---|---|
committer | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2009-06-16 20:24:53 -0400 |
commit | 492b057c426e4aa747484958e18e9da29003985d (patch) | |
tree | 34e08c24618688d8bcc190523028b5f94cce0c0b /net/mac80211/main.c | |
parent | 313485175da221c388f6a8ecf4c30062ba9bea17 (diff) | |
parent | 300df7dc89cc276377fc020704e34875d5c473b6 (diff) |
Merge commit 'origin/master' into next
Diffstat (limited to 'net/mac80211/main.c')
-rw-r--r-- | net/mac80211/main.c | 368 |
1 files changed, 194 insertions, 174 deletions
diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 14134193cd17..092a017b237e 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c | |||
@@ -21,10 +21,12 @@ | |||
21 | #include <linux/wireless.h> | 21 | #include <linux/wireless.h> |
22 | #include <linux/rtnetlink.h> | 22 | #include <linux/rtnetlink.h> |
23 | #include <linux/bitmap.h> | 23 | #include <linux/bitmap.h> |
24 | #include <linux/pm_qos_params.h> | ||
24 | #include <net/net_namespace.h> | 25 | #include <net/net_namespace.h> |
25 | #include <net/cfg80211.h> | 26 | #include <net/cfg80211.h> |
26 | 27 | ||
27 | #include "ieee80211_i.h" | 28 | #include "ieee80211_i.h" |
29 | #include "driver-ops.h" | ||
28 | #include "rate.h" | 30 | #include "rate.h" |
29 | #include "mesh.h" | 31 | #include "mesh.h" |
30 | #include "wep.h" | 32 | #include "wep.h" |
@@ -80,10 +82,9 @@ void ieee80211_configure_filter(struct ieee80211_local *local) | |||
80 | /* be a bit nasty */ | 82 | /* be a bit nasty */ |
81 | new_flags |= (1<<31); | 83 | new_flags |= (1<<31); |
82 | 84 | ||
83 | local->ops->configure_filter(local_to_hw(local), | 85 | drv_configure_filter(local, changed_flags, &new_flags, |
84 | changed_flags, &new_flags, | 86 | local->mdev->mc_count, |
85 | local->mdev->mc_count, | 87 | local->mdev->mc_list); |
86 | local->mdev->mc_list); | ||
87 | 88 | ||
88 | WARN_ON(new_flags & (1<<31)); | 89 | WARN_ON(new_flags & (1<<31)); |
89 | 90 | ||
@@ -151,93 +152,19 @@ static void ieee80211_master_set_multicast_list(struct net_device *dev) | |||
151 | ieee80211_configure_filter(local); | 152 | ieee80211_configure_filter(local); |
152 | } | 153 | } |
153 | 154 | ||
154 | /* everything else */ | ||
155 | |||
156 | int ieee80211_if_config(struct ieee80211_sub_if_data *sdata, u32 changed) | ||
157 | { | ||
158 | struct ieee80211_local *local = sdata->local; | ||
159 | struct ieee80211_if_conf conf; | ||
160 | |||
161 | if (WARN_ON(!netif_running(sdata->dev))) | ||
162 | return 0; | ||
163 | |||
164 | memset(&conf, 0, sizeof(conf)); | ||
165 | |||
166 | if (sdata->vif.type == NL80211_IFTYPE_STATION) | ||
167 | conf.bssid = sdata->u.mgd.bssid; | ||
168 | else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) | ||
169 | conf.bssid = sdata->u.ibss.bssid; | ||
170 | else if (sdata->vif.type == NL80211_IFTYPE_AP) | ||
171 | conf.bssid = sdata->dev->dev_addr; | ||
172 | else if (ieee80211_vif_is_mesh(&sdata->vif)) { | ||
173 | static const u8 zero[ETH_ALEN] = { 0 }; | ||
174 | conf.bssid = zero; | ||
175 | } else { | ||
176 | WARN_ON(1); | ||
177 | return -EINVAL; | ||
178 | } | ||
179 | |||
180 | if (!local->ops->config_interface) | ||
181 | return 0; | ||
182 | |||
183 | switch (sdata->vif.type) { | ||
184 | case NL80211_IFTYPE_AP: | ||
185 | case NL80211_IFTYPE_ADHOC: | ||
186 | case NL80211_IFTYPE_MESH_POINT: | ||
187 | break; | ||
188 | default: | ||
189 | /* do not warn to simplify caller in scan.c */ | ||
190 | changed &= ~IEEE80211_IFCC_BEACON_ENABLED; | ||
191 | if (WARN_ON(changed & IEEE80211_IFCC_BEACON)) | ||
192 | return -EINVAL; | ||
193 | changed &= ~IEEE80211_IFCC_BEACON; | ||
194 | break; | ||
195 | } | ||
196 | |||
197 | if (changed & IEEE80211_IFCC_BEACON_ENABLED) { | ||
198 | if (local->sw_scanning) { | ||
199 | conf.enable_beacon = false; | ||
200 | } else { | ||
201 | /* | ||
202 | * Beacon should be enabled, but AP mode must | ||
203 | * check whether there is a beacon configured. | ||
204 | */ | ||
205 | switch (sdata->vif.type) { | ||
206 | case NL80211_IFTYPE_AP: | ||
207 | conf.enable_beacon = | ||
208 | !!rcu_dereference(sdata->u.ap.beacon); | ||
209 | break; | ||
210 | case NL80211_IFTYPE_ADHOC: | ||
211 | conf.enable_beacon = !!sdata->u.ibss.probe_resp; | ||
212 | break; | ||
213 | case NL80211_IFTYPE_MESH_POINT: | ||
214 | conf.enable_beacon = true; | ||
215 | break; | ||
216 | default: | ||
217 | /* not reached */ | ||
218 | WARN_ON(1); | ||
219 | break; | ||
220 | } | ||
221 | } | ||
222 | } | ||
223 | |||
224 | conf.changed = changed; | ||
225 | |||
226 | return local->ops->config_interface(local_to_hw(local), | ||
227 | &sdata->vif, &conf); | ||
228 | } | ||
229 | |||
230 | int ieee80211_hw_config(struct ieee80211_local *local, u32 changed) | 155 | int ieee80211_hw_config(struct ieee80211_local *local, u32 changed) |
231 | { | 156 | { |
232 | struct ieee80211_channel *chan; | 157 | struct ieee80211_channel *chan, *scan_chan; |
233 | int ret = 0; | 158 | int ret = 0; |
234 | int power; | 159 | int power; |
235 | enum nl80211_channel_type channel_type; | 160 | enum nl80211_channel_type channel_type; |
236 | 161 | ||
237 | might_sleep(); | 162 | might_sleep(); |
238 | 163 | ||
239 | if (local->sw_scanning) { | 164 | scan_chan = local->scan_channel; |
240 | chan = local->scan_channel; | 165 | |
166 | if (scan_chan) { | ||
167 | chan = scan_chan; | ||
241 | channel_type = NL80211_CHAN_NO_HT; | 168 | channel_type = NL80211_CHAN_NO_HT; |
242 | } else { | 169 | } else { |
243 | chan = local->oper_channel; | 170 | chan = local->oper_channel; |
@@ -251,7 +178,7 @@ int ieee80211_hw_config(struct ieee80211_local *local, u32 changed) | |||
251 | changed |= IEEE80211_CONF_CHANGE_CHANNEL; | 178 | changed |= IEEE80211_CONF_CHANGE_CHANNEL; |
252 | } | 179 | } |
253 | 180 | ||
254 | if (local->sw_scanning) | 181 | if (scan_chan) |
255 | power = chan->max_power; | 182 | power = chan->max_power; |
256 | else | 183 | else |
257 | power = local->power_constr_level ? | 184 | power = local->power_constr_level ? |
@@ -267,7 +194,7 @@ int ieee80211_hw_config(struct ieee80211_local *local, u32 changed) | |||
267 | } | 194 | } |
268 | 195 | ||
269 | if (changed && local->open_count) { | 196 | if (changed && local->open_count) { |
270 | ret = local->ops->config(local_to_hw(local), changed); | 197 | ret = drv_config(local, changed); |
271 | /* | 198 | /* |
272 | * Goal: | 199 | * Goal: |
273 | * HW reconfiguration should never fail, the driver has told | 200 | * HW reconfiguration should never fail, the driver has told |
@@ -292,18 +219,78 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata, | |||
292 | u32 changed) | 219 | u32 changed) |
293 | { | 220 | { |
294 | struct ieee80211_local *local = sdata->local; | 221 | struct ieee80211_local *local = sdata->local; |
222 | static const u8 zero[ETH_ALEN] = { 0 }; | ||
295 | 223 | ||
296 | if (WARN_ON(sdata->vif.type == NL80211_IFTYPE_AP_VLAN)) | 224 | if (!changed) |
297 | return; | 225 | return; |
298 | 226 | ||
299 | if (!changed) | 227 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { |
228 | /* | ||
229 | * While not associated, claim a BSSID of all-zeroes | ||
230 | * so that drivers don't do any weird things with the | ||
231 | * BSSID at that time. | ||
232 | */ | ||
233 | if (sdata->vif.bss_conf.assoc) | ||
234 | sdata->vif.bss_conf.bssid = sdata->u.mgd.bssid; | ||
235 | else | ||
236 | sdata->vif.bss_conf.bssid = zero; | ||
237 | } else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) | ||
238 | sdata->vif.bss_conf.bssid = sdata->u.ibss.bssid; | ||
239 | else if (sdata->vif.type == NL80211_IFTYPE_AP) | ||
240 | sdata->vif.bss_conf.bssid = sdata->dev->dev_addr; | ||
241 | else if (ieee80211_vif_is_mesh(&sdata->vif)) { | ||
242 | sdata->vif.bss_conf.bssid = zero; | ||
243 | } else { | ||
244 | WARN_ON(1); | ||
300 | return; | 245 | return; |
246 | } | ||
247 | |||
248 | switch (sdata->vif.type) { | ||
249 | case NL80211_IFTYPE_AP: | ||
250 | case NL80211_IFTYPE_ADHOC: | ||
251 | case NL80211_IFTYPE_MESH_POINT: | ||
252 | break; | ||
253 | default: | ||
254 | /* do not warn to simplify caller in scan.c */ | ||
255 | changed &= ~BSS_CHANGED_BEACON_ENABLED; | ||
256 | if (WARN_ON(changed & BSS_CHANGED_BEACON)) | ||
257 | return; | ||
258 | break; | ||
259 | } | ||
260 | |||
261 | if (changed & BSS_CHANGED_BEACON_ENABLED) { | ||
262 | if (local->sw_scanning) { | ||
263 | sdata->vif.bss_conf.enable_beacon = false; | ||
264 | } else { | ||
265 | /* | ||
266 | * Beacon should be enabled, but AP mode must | ||
267 | * check whether there is a beacon configured. | ||
268 | */ | ||
269 | switch (sdata->vif.type) { | ||
270 | case NL80211_IFTYPE_AP: | ||
271 | sdata->vif.bss_conf.enable_beacon = | ||
272 | !!rcu_dereference(sdata->u.ap.beacon); | ||
273 | break; | ||
274 | case NL80211_IFTYPE_ADHOC: | ||
275 | sdata->vif.bss_conf.enable_beacon = | ||
276 | !!rcu_dereference(sdata->u.ibss.presp); | ||
277 | break; | ||
278 | case NL80211_IFTYPE_MESH_POINT: | ||
279 | sdata->vif.bss_conf.enable_beacon = true; | ||
280 | break; | ||
281 | default: | ||
282 | /* not reached */ | ||
283 | WARN_ON(1); | ||
284 | break; | ||
285 | } | ||
286 | } | ||
287 | } | ||
288 | |||
289 | drv_bss_info_changed(local, &sdata->vif, | ||
290 | &sdata->vif.bss_conf, changed); | ||
301 | 291 | ||
302 | if (local->ops->bss_info_changed) | 292 | /* DEPRECATED */ |
303 | local->ops->bss_info_changed(local_to_hw(local), | 293 | local->hw.conf.beacon_int = sdata->vif.bss_conf.beacon_int; |
304 | &sdata->vif, | ||
305 | &sdata->vif.bss_conf, | ||
306 | changed); | ||
307 | } | 294 | } |
308 | 295 | ||
309 | u32 ieee80211_reset_erp_info(struct ieee80211_sub_if_data *sdata) | 296 | u32 ieee80211_reset_erp_info(struct ieee80211_sub_if_data *sdata) |
@@ -382,60 +369,12 @@ static void ieee80211_tasklet_handler(unsigned long data) | |||
382 | } | 369 | } |
383 | } | 370 | } |
384 | 371 | ||
385 | /* Remove added headers (e.g., QoS control), encryption header/MIC, etc. to | ||
386 | * make a prepared TX frame (one that has been given to hw) to look like brand | ||
387 | * new IEEE 802.11 frame that is ready to go through TX processing again. | ||
388 | */ | ||
389 | static void ieee80211_remove_tx_extra(struct ieee80211_local *local, | ||
390 | struct ieee80211_key *key, | ||
391 | struct sk_buff *skb) | ||
392 | { | ||
393 | unsigned int hdrlen, iv_len, mic_len; | ||
394 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; | ||
395 | |||
396 | hdrlen = ieee80211_hdrlen(hdr->frame_control); | ||
397 | |||
398 | if (!key) | ||
399 | goto no_key; | ||
400 | |||
401 | switch (key->conf.alg) { | ||
402 | case ALG_WEP: | ||
403 | iv_len = WEP_IV_LEN; | ||
404 | mic_len = WEP_ICV_LEN; | ||
405 | break; | ||
406 | case ALG_TKIP: | ||
407 | iv_len = TKIP_IV_LEN; | ||
408 | mic_len = TKIP_ICV_LEN; | ||
409 | break; | ||
410 | case ALG_CCMP: | ||
411 | iv_len = CCMP_HDR_LEN; | ||
412 | mic_len = CCMP_MIC_LEN; | ||
413 | break; | ||
414 | default: | ||
415 | goto no_key; | ||
416 | } | ||
417 | |||
418 | if (skb->len >= hdrlen + mic_len && | ||
419 | !(key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) | ||
420 | skb_trim(skb, skb->len - mic_len); | ||
421 | if (skb->len >= hdrlen + iv_len) { | ||
422 | memmove(skb->data + iv_len, skb->data, hdrlen); | ||
423 | hdr = (struct ieee80211_hdr *)skb_pull(skb, iv_len); | ||
424 | } | ||
425 | |||
426 | no_key: | ||
427 | if (ieee80211_is_data_qos(hdr->frame_control)) { | ||
428 | hdr->frame_control &= ~cpu_to_le16(IEEE80211_STYPE_QOS_DATA); | ||
429 | memmove(skb->data + IEEE80211_QOS_CTL_LEN, skb->data, | ||
430 | hdrlen - IEEE80211_QOS_CTL_LEN); | ||
431 | skb_pull(skb, IEEE80211_QOS_CTL_LEN); | ||
432 | } | ||
433 | } | ||
434 | |||
435 | static void ieee80211_handle_filtered_frame(struct ieee80211_local *local, | 372 | static void ieee80211_handle_filtered_frame(struct ieee80211_local *local, |
436 | struct sta_info *sta, | 373 | struct sta_info *sta, |
437 | struct sk_buff *skb) | 374 | struct sk_buff *skb) |
438 | { | 375 | { |
376 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | ||
377 | |||
439 | sta->tx_filtered_count++; | 378 | sta->tx_filtered_count++; |
440 | 379 | ||
441 | /* | 380 | /* |
@@ -477,16 +416,15 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local, | |||
477 | */ | 416 | */ |
478 | if (test_sta_flags(sta, WLAN_STA_PS) && | 417 | if (test_sta_flags(sta, WLAN_STA_PS) && |
479 | skb_queue_len(&sta->tx_filtered) < STA_MAX_TX_BUFFER) { | 418 | skb_queue_len(&sta->tx_filtered) < STA_MAX_TX_BUFFER) { |
480 | ieee80211_remove_tx_extra(local, sta->key, skb); | ||
481 | skb_queue_tail(&sta->tx_filtered, skb); | 419 | skb_queue_tail(&sta->tx_filtered, skb); |
482 | return; | 420 | return; |
483 | } | 421 | } |
484 | 422 | ||
485 | if (!test_sta_flags(sta, WLAN_STA_PS) && !skb->requeue) { | 423 | if (!test_sta_flags(sta, WLAN_STA_PS) && |
424 | !(info->flags & IEEE80211_TX_INTFL_RETRIED)) { | ||
486 | /* Software retry the packet once */ | 425 | /* Software retry the packet once */ |
487 | skb->requeue = 1; | 426 | info->flags |= IEEE80211_TX_INTFL_RETRIED; |
488 | ieee80211_remove_tx_extra(local, sta->key, skb); | 427 | ieee80211_add_pending_skb(local, skb); |
489 | dev_queue_xmit(skb); | ||
490 | return; | 428 | return; |
491 | } | 429 | } |
492 | 430 | ||
@@ -696,6 +634,28 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
696 | } | 634 | } |
697 | EXPORT_SYMBOL(ieee80211_tx_status); | 635 | EXPORT_SYMBOL(ieee80211_tx_status); |
698 | 636 | ||
637 | static void ieee80211_restart_work(struct work_struct *work) | ||
638 | { | ||
639 | struct ieee80211_local *local = | ||
640 | container_of(work, struct ieee80211_local, restart_work); | ||
641 | |||
642 | rtnl_lock(); | ||
643 | ieee80211_reconfig(local); | ||
644 | rtnl_unlock(); | ||
645 | } | ||
646 | |||
647 | void ieee80211_restart_hw(struct ieee80211_hw *hw) | ||
648 | { | ||
649 | struct ieee80211_local *local = hw_to_local(hw); | ||
650 | |||
651 | /* use this reason, __ieee80211_resume will unblock it */ | ||
652 | ieee80211_stop_queues_by_reason(hw, | ||
653 | IEEE80211_QUEUE_STOP_REASON_SUSPEND); | ||
654 | |||
655 | schedule_work(&local->restart_work); | ||
656 | } | ||
657 | EXPORT_SYMBOL(ieee80211_restart_hw); | ||
658 | |||
699 | struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | 659 | struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, |
700 | const struct ieee80211_ops *ops) | 660 | const struct ieee80211_ops *ops) |
701 | { | 661 | { |
@@ -718,9 +678,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
718 | * +-------------------------+ | 678 | * +-------------------------+ |
719 | * | 679 | * |
720 | */ | 680 | */ |
721 | priv_size = ((sizeof(struct ieee80211_local) + | 681 | priv_size = ALIGN(sizeof(*local), NETDEV_ALIGN) + priv_data_len; |
722 | NETDEV_ALIGN_CONST) & ~NETDEV_ALIGN_CONST) + | ||
723 | priv_data_len; | ||
724 | 682 | ||
725 | wiphy = wiphy_new(&mac80211_config_ops, priv_size); | 683 | wiphy = wiphy_new(&mac80211_config_ops, priv_size); |
726 | 684 | ||
@@ -728,17 +686,16 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
728 | return NULL; | 686 | return NULL; |
729 | 687 | ||
730 | wiphy->privid = mac80211_wiphy_privid; | 688 | wiphy->privid = mac80211_wiphy_privid; |
731 | wiphy->max_scan_ssids = 4; | 689 | |
732 | /* Yes, putting cfg80211_bss into ieee80211_bss is a hack */ | 690 | /* Yes, putting cfg80211_bss into ieee80211_bss is a hack */ |
733 | wiphy->bss_priv_size = sizeof(struct ieee80211_bss) - | 691 | wiphy->bss_priv_size = sizeof(struct ieee80211_bss) - |
734 | sizeof(struct cfg80211_bss); | 692 | sizeof(struct cfg80211_bss); |
735 | 693 | ||
736 | local = wiphy_priv(wiphy); | 694 | local = wiphy_priv(wiphy); |
695 | |||
737 | local->hw.wiphy = wiphy; | 696 | local->hw.wiphy = wiphy; |
738 | 697 | ||
739 | local->hw.priv = (char *)local + | 698 | local->hw.priv = (char *)local + ALIGN(sizeof(*local), NETDEV_ALIGN); |
740 | ((sizeof(struct ieee80211_local) + | ||
741 | NETDEV_ALIGN_CONST) & ~NETDEV_ALIGN_CONST); | ||
742 | 699 | ||
743 | BUG_ON(!ops->tx); | 700 | BUG_ON(!ops->tx); |
744 | BUG_ON(!ops->start); | 701 | BUG_ON(!ops->start); |
@@ -752,15 +709,14 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
752 | /* set up some defaults */ | 709 | /* set up some defaults */ |
753 | local->hw.queues = 1; | 710 | local->hw.queues = 1; |
754 | local->hw.max_rates = 1; | 711 | local->hw.max_rates = 1; |
755 | local->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD; | 712 | local->hw.conf.long_frame_max_tx_count = wiphy->retry_long; |
756 | local->fragmentation_threshold = IEEE80211_MAX_FRAG_THRESHOLD; | 713 | local->hw.conf.short_frame_max_tx_count = wiphy->retry_short; |
757 | local->hw.conf.long_frame_max_tx_count = 4; | ||
758 | local->hw.conf.short_frame_max_tx_count = 7; | ||
759 | local->hw.conf.radio_enabled = true; | 714 | local->hw.conf.radio_enabled = true; |
760 | local->user_power_level = -1; | 715 | local->user_power_level = -1; |
761 | 716 | ||
762 | INIT_LIST_HEAD(&local->interfaces); | 717 | INIT_LIST_HEAD(&local->interfaces); |
763 | mutex_init(&local->iflist_mtx); | 718 | mutex_init(&local->iflist_mtx); |
719 | mutex_init(&local->scan_mtx); | ||
764 | 720 | ||
765 | spin_lock_init(&local->key_lock); | 721 | spin_lock_init(&local->key_lock); |
766 | 722 | ||
@@ -768,6 +724,8 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
768 | 724 | ||
769 | INIT_DELAYED_WORK(&local->scan_work, ieee80211_scan_work); | 725 | INIT_DELAYED_WORK(&local->scan_work, ieee80211_scan_work); |
770 | 726 | ||
727 | INIT_WORK(&local->restart_work, ieee80211_restart_work); | ||
728 | |||
771 | INIT_WORK(&local->dynamic_ps_enable_work, | 729 | INIT_WORK(&local->dynamic_ps_enable_work, |
772 | ieee80211_dynamic_ps_enable_work); | 730 | ieee80211_dynamic_ps_enable_work); |
773 | INIT_WORK(&local->dynamic_ps_disable_work, | 731 | INIT_WORK(&local->dynamic_ps_disable_work, |
@@ -821,7 +779,17 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
821 | enum ieee80211_band band; | 779 | enum ieee80211_band band; |
822 | struct net_device *mdev; | 780 | struct net_device *mdev; |
823 | struct ieee80211_master_priv *mpriv; | 781 | struct ieee80211_master_priv *mpriv; |
824 | int channels, i, j; | 782 | int channels, i, j, max_bitrates; |
783 | bool supp_ht; | ||
784 | static const u32 cipher_suites[] = { | ||
785 | WLAN_CIPHER_SUITE_WEP40, | ||
786 | WLAN_CIPHER_SUITE_WEP104, | ||
787 | WLAN_CIPHER_SUITE_TKIP, | ||
788 | WLAN_CIPHER_SUITE_CCMP, | ||
789 | |||
790 | /* keep last -- depends on hw flags! */ | ||
791 | WLAN_CIPHER_SUITE_AES_CMAC | ||
792 | }; | ||
825 | 793 | ||
826 | /* | 794 | /* |
827 | * generic code guarantees at least one band, | 795 | * generic code guarantees at least one band, |
@@ -829,18 +797,25 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
829 | * that hw.conf.channel is assigned | 797 | * that hw.conf.channel is assigned |
830 | */ | 798 | */ |
831 | channels = 0; | 799 | channels = 0; |
800 | max_bitrates = 0; | ||
801 | supp_ht = false; | ||
832 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) { | 802 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) { |
833 | struct ieee80211_supported_band *sband; | 803 | struct ieee80211_supported_band *sband; |
834 | 804 | ||
835 | sband = local->hw.wiphy->bands[band]; | 805 | sband = local->hw.wiphy->bands[band]; |
836 | if (sband && !local->oper_channel) { | 806 | if (!sband) |
807 | continue; | ||
808 | if (!local->oper_channel) { | ||
837 | /* init channel we're on */ | 809 | /* init channel we're on */ |
838 | local->hw.conf.channel = | 810 | local->hw.conf.channel = |
839 | local->oper_channel = | 811 | local->oper_channel = &sband->channels[0]; |
840 | local->scan_channel = &sband->channels[0]; | 812 | local->hw.conf.channel_type = NL80211_CHAN_NO_HT; |
841 | } | 813 | } |
842 | if (sband) | 814 | channels += sband->n_channels; |
843 | channels += sband->n_channels; | 815 | |
816 | if (max_bitrates < sband->n_bitrates) | ||
817 | max_bitrates = sband->n_bitrates; | ||
818 | supp_ht = supp_ht || sband->ht_cap.ht_supported; | ||
844 | } | 819 | } |
845 | 820 | ||
846 | local->int_scan_req.n_channels = channels; | 821 | local->int_scan_req.n_channels = channels; |
@@ -860,6 +835,37 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
860 | else if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC) | 835 | else if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC) |
861 | local->hw.wiphy->signal_type = CFG80211_SIGNAL_TYPE_UNSPEC; | 836 | local->hw.wiphy->signal_type = CFG80211_SIGNAL_TYPE_UNSPEC; |
862 | 837 | ||
838 | /* | ||
839 | * Calculate scan IE length -- we need this to alloc | ||
840 | * memory and to subtract from the driver limit. It | ||
841 | * includes the (extended) supported rates and HT | ||
842 | * information -- SSID is the driver's responsibility. | ||
843 | */ | ||
844 | local->scan_ies_len = 4 + max_bitrates; /* (ext) supp rates */ | ||
845 | if (supp_ht) | ||
846 | local->scan_ies_len += 2 + sizeof(struct ieee80211_ht_cap); | ||
847 | |||
848 | if (!local->ops->hw_scan) { | ||
849 | /* For hw_scan, driver needs to set these up. */ | ||
850 | local->hw.wiphy->max_scan_ssids = 4; | ||
851 | local->hw.wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN; | ||
852 | } | ||
853 | |||
854 | /* | ||
855 | * If the driver supports any scan IEs, then assume the | ||
856 | * limit includes the IEs mac80211 will add, otherwise | ||
857 | * leave it at zero and let the driver sort it out; we | ||
858 | * still pass our IEs to the driver but userspace will | ||
859 | * not be allowed to in that case. | ||
860 | */ | ||
861 | if (local->hw.wiphy->max_scan_ie_len) | ||
862 | local->hw.wiphy->max_scan_ie_len -= local->scan_ies_len; | ||
863 | |||
864 | local->hw.wiphy->cipher_suites = cipher_suites; | ||
865 | local->hw.wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites); | ||
866 | if (!(local->hw.flags & IEEE80211_HW_MFP_CAPABLE)) | ||
867 | local->hw.wiphy->n_cipher_suites--; | ||
868 | |||
863 | result = wiphy_register(local->hw.wiphy); | 869 | result = wiphy_register(local->hw.wiphy); |
864 | if (result < 0) | 870 | if (result < 0) |
865 | goto fail_wiphy_register; | 871 | goto fail_wiphy_register; |
@@ -898,9 +904,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
898 | 904 | ||
899 | debugfs_hw_add(local); | 905 | debugfs_hw_add(local); |
900 | 906 | ||
901 | if (local->hw.conf.beacon_int < 10) | ||
902 | local->hw.conf.beacon_int = 100; | ||
903 | |||
904 | if (local->hw.max_listen_interval == 0) | 907 | if (local->hw.max_listen_interval == 0) |
905 | local->hw.max_listen_interval = 1; | 908 | local->hw.max_listen_interval = 1; |
906 | 909 | ||
@@ -965,25 +968,38 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
965 | } | 968 | } |
966 | } | 969 | } |
967 | 970 | ||
971 | local->network_latency_notifier.notifier_call = | ||
972 | ieee80211_max_network_latency; | ||
973 | result = pm_qos_add_notifier(PM_QOS_NETWORK_LATENCY, | ||
974 | &local->network_latency_notifier); | ||
975 | |||
976 | if (result) { | ||
977 | rtnl_lock(); | ||
978 | goto fail_pm_qos; | ||
979 | } | ||
980 | |||
968 | return 0; | 981 | return 0; |
969 | 982 | ||
970 | fail_rate: | 983 | fail_pm_qos: |
984 | ieee80211_led_exit(local); | ||
985 | ieee80211_remove_interfaces(local); | ||
986 | fail_rate: | ||
971 | unregister_netdevice(local->mdev); | 987 | unregister_netdevice(local->mdev); |
972 | local->mdev = NULL; | 988 | local->mdev = NULL; |
973 | fail_dev: | 989 | fail_dev: |
974 | rtnl_unlock(); | 990 | rtnl_unlock(); |
975 | ieee80211_wep_free(local); | 991 | ieee80211_wep_free(local); |
976 | fail_wep: | 992 | fail_wep: |
977 | sta_info_stop(local); | 993 | sta_info_stop(local); |
978 | fail_sta_info: | 994 | fail_sta_info: |
979 | debugfs_hw_del(local); | 995 | debugfs_hw_del(local); |
980 | destroy_workqueue(local->hw.workqueue); | 996 | destroy_workqueue(local->hw.workqueue); |
981 | fail_workqueue: | 997 | fail_workqueue: |
982 | if (local->mdev) | 998 | if (local->mdev) |
983 | free_netdev(local->mdev); | 999 | free_netdev(local->mdev); |
984 | fail_mdev_alloc: | 1000 | fail_mdev_alloc: |
985 | wiphy_unregister(local->hw.wiphy); | 1001 | wiphy_unregister(local->hw.wiphy); |
986 | fail_wiphy_register: | 1002 | fail_wiphy_register: |
987 | kfree(local->int_scan_req.channels); | 1003 | kfree(local->int_scan_req.channels); |
988 | return result; | 1004 | return result; |
989 | } | 1005 | } |
@@ -996,6 +1012,9 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw) | |||
996 | tasklet_kill(&local->tx_pending_tasklet); | 1012 | tasklet_kill(&local->tx_pending_tasklet); |
997 | tasklet_kill(&local->tasklet); | 1013 | tasklet_kill(&local->tasklet); |
998 | 1014 | ||
1015 | pm_qos_remove_notifier(PM_QOS_NETWORK_LATENCY, | ||
1016 | &local->network_latency_notifier); | ||
1017 | |||
999 | rtnl_lock(); | 1018 | rtnl_lock(); |
1000 | 1019 | ||
1001 | /* | 1020 | /* |
@@ -1038,6 +1057,7 @@ void ieee80211_free_hw(struct ieee80211_hw *hw) | |||
1038 | struct ieee80211_local *local = hw_to_local(hw); | 1057 | struct ieee80211_local *local = hw_to_local(hw); |
1039 | 1058 | ||
1040 | mutex_destroy(&local->iflist_mtx); | 1059 | mutex_destroy(&local->iflist_mtx); |
1060 | mutex_destroy(&local->scan_mtx); | ||
1041 | 1061 | ||
1042 | wiphy_free(local->hw.wiphy); | 1062 | wiphy_free(local->hw.wiphy); |
1043 | } | 1063 | } |