diff options
Diffstat (limited to 'net/mac80211/main.c')
-rw-r--r-- | net/mac80211/main.c | 124 |
1 files changed, 101 insertions, 23 deletions
diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 22a384dfab6..7cc4f913a43 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c | |||
@@ -20,6 +20,7 @@ | |||
20 | #include <linux/rtnetlink.h> | 20 | #include <linux/rtnetlink.h> |
21 | #include <linux/bitmap.h> | 21 | #include <linux/bitmap.h> |
22 | #include <linux/pm_qos_params.h> | 22 | #include <linux/pm_qos_params.h> |
23 | #include <linux/inetdevice.h> | ||
23 | #include <net/net_namespace.h> | 24 | #include <net/net_namespace.h> |
24 | #include <net/cfg80211.h> | 25 | #include <net/cfg80211.h> |
25 | 26 | ||
@@ -106,12 +107,15 @@ int ieee80211_hw_config(struct ieee80211_local *local, u32 changed) | |||
106 | if (scan_chan) { | 107 | if (scan_chan) { |
107 | chan = scan_chan; | 108 | chan = scan_chan; |
108 | channel_type = NL80211_CHAN_NO_HT; | 109 | channel_type = NL80211_CHAN_NO_HT; |
110 | local->hw.conf.flags |= IEEE80211_CONF_OFFCHANNEL; | ||
109 | } else if (local->tmp_channel) { | 111 | } else if (local->tmp_channel) { |
110 | chan = scan_chan = local->tmp_channel; | 112 | chan = scan_chan = local->tmp_channel; |
111 | channel_type = local->tmp_channel_type; | 113 | channel_type = local->tmp_channel_type; |
114 | local->hw.conf.flags |= IEEE80211_CONF_OFFCHANNEL; | ||
112 | } else { | 115 | } else { |
113 | chan = local->oper_channel; | 116 | chan = local->oper_channel; |
114 | channel_type = local->_oper_channel_type; | 117 | channel_type = local->_oper_channel_type; |
118 | local->hw.conf.flags &= ~IEEE80211_CONF_OFFCHANNEL; | ||
115 | } | 119 | } |
116 | 120 | ||
117 | if (chan != local->hw.conf.channel || | 121 | if (chan != local->hw.conf.channel || |
@@ -259,7 +263,6 @@ static void ieee80211_tasklet_handler(unsigned long data) | |||
259 | { | 263 | { |
260 | struct ieee80211_local *local = (struct ieee80211_local *) data; | 264 | struct ieee80211_local *local = (struct ieee80211_local *) data; |
261 | struct sk_buff *skb; | 265 | struct sk_buff *skb; |
262 | struct ieee80211_ra_tid *ra_tid; | ||
263 | 266 | ||
264 | while ((skb = skb_dequeue(&local->skb_queue)) || | 267 | while ((skb = skb_dequeue(&local->skb_queue)) || |
265 | (skb = skb_dequeue(&local->skb_queue_unreliable))) { | 268 | (skb = skb_dequeue(&local->skb_queue_unreliable))) { |
@@ -274,18 +277,6 @@ static void ieee80211_tasklet_handler(unsigned long data) | |||
274 | skb->pkt_type = 0; | 277 | skb->pkt_type = 0; |
275 | ieee80211_tx_status(local_to_hw(local), skb); | 278 | ieee80211_tx_status(local_to_hw(local), skb); |
276 | break; | 279 | break; |
277 | case IEEE80211_DELBA_MSG: | ||
278 | ra_tid = (struct ieee80211_ra_tid *) &skb->cb; | ||
279 | ieee80211_stop_tx_ba_cb(ra_tid->vif, ra_tid->ra, | ||
280 | ra_tid->tid); | ||
281 | dev_kfree_skb(skb); | ||
282 | break; | ||
283 | case IEEE80211_ADDBA_MSG: | ||
284 | ra_tid = (struct ieee80211_ra_tid *) &skb->cb; | ||
285 | ieee80211_start_tx_ba_cb(ra_tid->vif, ra_tid->ra, | ||
286 | ra_tid->tid); | ||
287 | dev_kfree_skb(skb); | ||
288 | break ; | ||
289 | default: | 280 | default: |
290 | WARN(1, "mac80211: Packet is of unknown type %d\n", | 281 | WARN(1, "mac80211: Packet is of unknown type %d\n", |
291 | skb->pkt_type); | 282 | skb->pkt_type); |
@@ -329,6 +320,76 @@ static void ieee80211_recalc_smps_work(struct work_struct *work) | |||
329 | mutex_unlock(&local->iflist_mtx); | 320 | mutex_unlock(&local->iflist_mtx); |
330 | } | 321 | } |
331 | 322 | ||
323 | #ifdef CONFIG_INET | ||
324 | static int ieee80211_ifa_changed(struct notifier_block *nb, | ||
325 | unsigned long data, void *arg) | ||
326 | { | ||
327 | struct in_ifaddr *ifa = arg; | ||
328 | struct ieee80211_local *local = | ||
329 | container_of(nb, struct ieee80211_local, | ||
330 | ifa_notifier); | ||
331 | struct net_device *ndev = ifa->ifa_dev->dev; | ||
332 | struct wireless_dev *wdev = ndev->ieee80211_ptr; | ||
333 | struct in_device *idev; | ||
334 | struct ieee80211_sub_if_data *sdata; | ||
335 | struct ieee80211_bss_conf *bss_conf; | ||
336 | struct ieee80211_if_managed *ifmgd; | ||
337 | int c = 0; | ||
338 | |||
339 | if (!netif_running(ndev)) | ||
340 | return NOTIFY_DONE; | ||
341 | |||
342 | /* Make sure it's our interface that got changed */ | ||
343 | if (!wdev) | ||
344 | return NOTIFY_DONE; | ||
345 | |||
346 | if (wdev->wiphy != local->hw.wiphy) | ||
347 | return NOTIFY_DONE; | ||
348 | |||
349 | sdata = IEEE80211_DEV_TO_SUB_IF(ndev); | ||
350 | bss_conf = &sdata->vif.bss_conf; | ||
351 | |||
352 | /* ARP filtering is only supported in managed mode */ | ||
353 | if (sdata->vif.type != NL80211_IFTYPE_STATION) | ||
354 | return NOTIFY_DONE; | ||
355 | |||
356 | idev = sdata->dev->ip_ptr; | ||
357 | if (!idev) | ||
358 | return NOTIFY_DONE; | ||
359 | |||
360 | ifmgd = &sdata->u.mgd; | ||
361 | mutex_lock(&ifmgd->mtx); | ||
362 | |||
363 | /* Copy the addresses to the bss_conf list */ | ||
364 | ifa = idev->ifa_list; | ||
365 | while (c < IEEE80211_BSS_ARP_ADDR_LIST_LEN && ifa) { | ||
366 | bss_conf->arp_addr_list[c] = ifa->ifa_address; | ||
367 | ifa = ifa->ifa_next; | ||
368 | c++; | ||
369 | } | ||
370 | |||
371 | /* If not all addresses fit the list, disable filtering */ | ||
372 | if (ifa) { | ||
373 | sdata->arp_filter_state = false; | ||
374 | c = 0; | ||
375 | } else { | ||
376 | sdata->arp_filter_state = true; | ||
377 | } | ||
378 | bss_conf->arp_addr_cnt = c; | ||
379 | |||
380 | /* Configure driver only if associated */ | ||
381 | if (ifmgd->associated) { | ||
382 | bss_conf->arp_filter_enabled = sdata->arp_filter_state; | ||
383 | ieee80211_bss_info_change_notify(sdata, | ||
384 | BSS_CHANGED_ARP_FILTER); | ||
385 | } | ||
386 | |||
387 | mutex_unlock(&ifmgd->mtx); | ||
388 | |||
389 | return NOTIFY_DONE; | ||
390 | } | ||
391 | #endif | ||
392 | |||
332 | struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | 393 | struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, |
333 | const struct ieee80211_ops *ops) | 394 | const struct ieee80211_ops *ops) |
334 | { | 395 | { |
@@ -396,7 +457,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
396 | mutex_init(&local->iflist_mtx); | 457 | mutex_init(&local->iflist_mtx); |
397 | mutex_init(&local->scan_mtx); | 458 | mutex_init(&local->scan_mtx); |
398 | 459 | ||
399 | spin_lock_init(&local->key_lock); | 460 | mutex_init(&local->key_mtx); |
400 | spin_lock_init(&local->filter_lock); | 461 | spin_lock_init(&local->filter_lock); |
401 | spin_lock_init(&local->queue_stop_reason_lock); | 462 | spin_lock_init(&local->queue_stop_reason_lock); |
402 | 463 | ||
@@ -419,8 +480,10 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
419 | 480 | ||
420 | sta_info_init(local); | 481 | sta_info_init(local); |
421 | 482 | ||
422 | for (i = 0; i < IEEE80211_MAX_QUEUES; i++) | 483 | for (i = 0; i < IEEE80211_MAX_QUEUES; i++) { |
423 | skb_queue_head_init(&local->pending[i]); | 484 | skb_queue_head_init(&local->pending[i]); |
485 | atomic_set(&local->agg_queue_stop[i], 0); | ||
486 | } | ||
424 | tasklet_init(&local->tx_pending_tasklet, ieee80211_tx_pending, | 487 | tasklet_init(&local->tx_pending_tasklet, ieee80211_tx_pending, |
425 | (unsigned long)local); | 488 | (unsigned long)local); |
426 | 489 | ||
@@ -431,8 +494,6 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
431 | skb_queue_head_init(&local->skb_queue); | 494 | skb_queue_head_init(&local->skb_queue); |
432 | skb_queue_head_init(&local->skb_queue_unreliable); | 495 | skb_queue_head_init(&local->skb_queue_unreliable); |
433 | 496 | ||
434 | spin_lock_init(&local->ampdu_lock); | ||
435 | |||
436 | return local_to_hw(local); | 497 | return local_to_hw(local); |
437 | } | 498 | } |
438 | EXPORT_SYMBOL(ieee80211_alloc_hw); | 499 | EXPORT_SYMBOL(ieee80211_alloc_hw); |
@@ -572,18 +633,16 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
572 | 633 | ||
573 | local->hw.conf.listen_interval = local->hw.max_listen_interval; | 634 | local->hw.conf.listen_interval = local->hw.max_listen_interval; |
574 | 635 | ||
575 | local->hw.conf.dynamic_ps_forced_timeout = -1; | 636 | local->dynamic_ps_forced_timeout = -1; |
576 | 637 | ||
577 | result = sta_info_start(local); | 638 | result = sta_info_start(local); |
578 | if (result < 0) | 639 | if (result < 0) |
579 | goto fail_sta_info; | 640 | goto fail_sta_info; |
580 | 641 | ||
581 | result = ieee80211_wep_init(local); | 642 | result = ieee80211_wep_init(local); |
582 | if (result < 0) { | 643 | if (result < 0) |
583 | printk(KERN_DEBUG "%s: Failed to initialize wep: %d\n", | 644 | printk(KERN_DEBUG "%s: Failed to initialize wep: %d\n", |
584 | wiphy_name(local->hw.wiphy), result); | 645 | wiphy_name(local->hw.wiphy), result); |
585 | goto fail_wep; | ||
586 | } | ||
587 | 646 | ||
588 | rtnl_lock(); | 647 | rtnl_lock(); |
589 | 648 | ||
@@ -612,21 +671,30 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
612 | ieee80211_max_network_latency; | 671 | ieee80211_max_network_latency; |
613 | result = pm_qos_add_notifier(PM_QOS_NETWORK_LATENCY, | 672 | result = pm_qos_add_notifier(PM_QOS_NETWORK_LATENCY, |
614 | &local->network_latency_notifier); | 673 | &local->network_latency_notifier); |
615 | |||
616 | if (result) { | 674 | if (result) { |
617 | rtnl_lock(); | 675 | rtnl_lock(); |
618 | goto fail_pm_qos; | 676 | goto fail_pm_qos; |
619 | } | 677 | } |
620 | 678 | ||
679 | #ifdef CONFIG_INET | ||
680 | local->ifa_notifier.notifier_call = ieee80211_ifa_changed; | ||
681 | result = register_inetaddr_notifier(&local->ifa_notifier); | ||
682 | if (result) | ||
683 | goto fail_ifa; | ||
684 | #endif | ||
685 | |||
621 | return 0; | 686 | return 0; |
622 | 687 | ||
688 | fail_ifa: | ||
689 | pm_qos_remove_notifier(PM_QOS_NETWORK_LATENCY, | ||
690 | &local->network_latency_notifier); | ||
691 | rtnl_lock(); | ||
623 | fail_pm_qos: | 692 | fail_pm_qos: |
624 | ieee80211_led_exit(local); | 693 | ieee80211_led_exit(local); |
625 | ieee80211_remove_interfaces(local); | 694 | ieee80211_remove_interfaces(local); |
626 | fail_rate: | 695 | fail_rate: |
627 | rtnl_unlock(); | 696 | rtnl_unlock(); |
628 | ieee80211_wep_free(local); | 697 | ieee80211_wep_free(local); |
629 | fail_wep: | ||
630 | sta_info_stop(local); | 698 | sta_info_stop(local); |
631 | fail_sta_info: | 699 | fail_sta_info: |
632 | destroy_workqueue(local->workqueue); | 700 | destroy_workqueue(local->workqueue); |
@@ -647,6 +715,9 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw) | |||
647 | 715 | ||
648 | pm_qos_remove_notifier(PM_QOS_NETWORK_LATENCY, | 716 | pm_qos_remove_notifier(PM_QOS_NETWORK_LATENCY, |
649 | &local->network_latency_notifier); | 717 | &local->network_latency_notifier); |
718 | #ifdef CONFIG_INET | ||
719 | unregister_inetaddr_notifier(&local->ifa_notifier); | ||
720 | #endif | ||
650 | 721 | ||
651 | rtnl_lock(); | 722 | rtnl_lock(); |
652 | 723 | ||
@@ -704,6 +775,10 @@ static int __init ieee80211_init(void) | |||
704 | if (ret) | 775 | if (ret) |
705 | return ret; | 776 | return ret; |
706 | 777 | ||
778 | ret = rc80211_minstrel_ht_init(); | ||
779 | if (ret) | ||
780 | goto err_minstrel; | ||
781 | |||
707 | ret = rc80211_pid_init(); | 782 | ret = rc80211_pid_init(); |
708 | if (ret) | 783 | if (ret) |
709 | goto err_pid; | 784 | goto err_pid; |
@@ -716,6 +791,8 @@ static int __init ieee80211_init(void) | |||
716 | err_netdev: | 791 | err_netdev: |
717 | rc80211_pid_exit(); | 792 | rc80211_pid_exit(); |
718 | err_pid: | 793 | err_pid: |
794 | rc80211_minstrel_ht_exit(); | ||
795 | err_minstrel: | ||
719 | rc80211_minstrel_exit(); | 796 | rc80211_minstrel_exit(); |
720 | 797 | ||
721 | return ret; | 798 | return ret; |
@@ -724,6 +801,7 @@ static int __init ieee80211_init(void) | |||
724 | static void __exit ieee80211_exit(void) | 801 | static void __exit ieee80211_exit(void) |
725 | { | 802 | { |
726 | rc80211_pid_exit(); | 803 | rc80211_pid_exit(); |
804 | rc80211_minstrel_ht_exit(); | ||
727 | rc80211_minstrel_exit(); | 805 | rc80211_minstrel_exit(); |
728 | 806 | ||
729 | /* | 807 | /* |