diff options
Diffstat (limited to 'net/mac80211/main.c')
-rw-r--r-- | net/mac80211/main.c | 200 |
1 files changed, 62 insertions, 138 deletions
diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 092a017b237e..797f53942e5f 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c | |||
@@ -50,9 +50,9 @@ struct ieee80211_tx_status_rtap_hdr { | |||
50 | } __attribute__ ((packed)); | 50 | } __attribute__ ((packed)); |
51 | 51 | ||
52 | 52 | ||
53 | /* must be called under mdev tx lock */ | ||
54 | void ieee80211_configure_filter(struct ieee80211_local *local) | 53 | void ieee80211_configure_filter(struct ieee80211_local *local) |
55 | { | 54 | { |
55 | u64 mc; | ||
56 | unsigned int changed_flags; | 56 | unsigned int changed_flags; |
57 | unsigned int new_flags = 0; | 57 | unsigned int new_flags = 0; |
58 | 58 | ||
@@ -62,7 +62,7 @@ void ieee80211_configure_filter(struct ieee80211_local *local) | |||
62 | if (atomic_read(&local->iff_allmultis)) | 62 | if (atomic_read(&local->iff_allmultis)) |
63 | new_flags |= FIF_ALLMULTI; | 63 | new_flags |= FIF_ALLMULTI; |
64 | 64 | ||
65 | if (local->monitors) | 65 | if (local->monitors || local->scanning) |
66 | new_flags |= FIF_BCN_PRBRESP_PROMISC; | 66 | new_flags |= FIF_BCN_PRBRESP_PROMISC; |
67 | 67 | ||
68 | if (local->fif_fcsfail) | 68 | if (local->fif_fcsfail) |
@@ -77,77 +77,29 @@ void ieee80211_configure_filter(struct ieee80211_local *local) | |||
77 | if (local->fif_other_bss) | 77 | if (local->fif_other_bss) |
78 | new_flags |= FIF_OTHER_BSS; | 78 | new_flags |= FIF_OTHER_BSS; |
79 | 79 | ||
80 | if (local->fif_pspoll) | ||
81 | new_flags |= FIF_PSPOLL; | ||
82 | |||
83 | spin_lock_bh(&local->filter_lock); | ||
80 | changed_flags = local->filter_flags ^ new_flags; | 84 | changed_flags = local->filter_flags ^ new_flags; |
81 | 85 | ||
86 | mc = drv_prepare_multicast(local, local->mc_count, local->mc_list); | ||
87 | spin_unlock_bh(&local->filter_lock); | ||
88 | |||
82 | /* be a bit nasty */ | 89 | /* be a bit nasty */ |
83 | new_flags |= (1<<31); | 90 | new_flags |= (1<<31); |
84 | 91 | ||
85 | drv_configure_filter(local, changed_flags, &new_flags, | 92 | drv_configure_filter(local, changed_flags, &new_flags, mc); |
86 | local->mdev->mc_count, | ||
87 | local->mdev->mc_list); | ||
88 | 93 | ||
89 | WARN_ON(new_flags & (1<<31)); | 94 | WARN_ON(new_flags & (1<<31)); |
90 | 95 | ||
91 | local->filter_flags = new_flags & ~(1<<31); | 96 | local->filter_flags = new_flags & ~(1<<31); |
92 | } | 97 | } |
93 | 98 | ||
94 | /* master interface */ | 99 | static void ieee80211_reconfig_filter(struct work_struct *work) |
95 | |||
96 | static int header_parse_80211(const struct sk_buff *skb, unsigned char *haddr) | ||
97 | { | ||
98 | memcpy(haddr, skb_mac_header(skb) + 10, ETH_ALEN); /* addr2 */ | ||
99 | return ETH_ALEN; | ||
100 | } | ||
101 | |||
102 | static const struct header_ops ieee80211_header_ops = { | ||
103 | .create = eth_header, | ||
104 | .parse = header_parse_80211, | ||
105 | .rebuild = eth_rebuild_header, | ||
106 | .cache = eth_header_cache, | ||
107 | .cache_update = eth_header_cache_update, | ||
108 | }; | ||
109 | |||
110 | static int ieee80211_master_open(struct net_device *dev) | ||
111 | { | 100 | { |
112 | struct ieee80211_master_priv *mpriv = netdev_priv(dev); | 101 | struct ieee80211_local *local = |
113 | struct ieee80211_local *local = mpriv->local; | 102 | container_of(work, struct ieee80211_local, reconfig_filter); |
114 | struct ieee80211_sub_if_data *sdata; | ||
115 | int res = -EOPNOTSUPP; | ||
116 | |||
117 | /* we hold the RTNL here so can safely walk the list */ | ||
118 | list_for_each_entry(sdata, &local->interfaces, list) { | ||
119 | if (netif_running(sdata->dev)) { | ||
120 | res = 0; | ||
121 | break; | ||
122 | } | ||
123 | } | ||
124 | |||
125 | if (res) | ||
126 | return res; | ||
127 | |||
128 | netif_tx_start_all_queues(local->mdev); | ||
129 | |||
130 | return 0; | ||
131 | } | ||
132 | |||
133 | static int ieee80211_master_stop(struct net_device *dev) | ||
134 | { | ||
135 | struct ieee80211_master_priv *mpriv = netdev_priv(dev); | ||
136 | struct ieee80211_local *local = mpriv->local; | ||
137 | struct ieee80211_sub_if_data *sdata; | ||
138 | |||
139 | /* we hold the RTNL here so can safely walk the list */ | ||
140 | list_for_each_entry(sdata, &local->interfaces, list) | ||
141 | if (netif_running(sdata->dev)) | ||
142 | dev_close(sdata->dev); | ||
143 | |||
144 | return 0; | ||
145 | } | ||
146 | |||
147 | static void ieee80211_master_set_multicast_list(struct net_device *dev) | ||
148 | { | ||
149 | struct ieee80211_master_priv *mpriv = netdev_priv(dev); | ||
150 | struct ieee80211_local *local = mpriv->local; | ||
151 | 103 | ||
152 | ieee80211_configure_filter(local); | 104 | ieee80211_configure_filter(local); |
153 | } | 105 | } |
@@ -259,7 +211,8 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata, | |||
259 | } | 211 | } |
260 | 212 | ||
261 | if (changed & BSS_CHANGED_BEACON_ENABLED) { | 213 | if (changed & BSS_CHANGED_BEACON_ENABLED) { |
262 | if (local->sw_scanning) { | 214 | if (local->quiescing || !netif_running(sdata->dev) || |
215 | test_bit(SCAN_SW_SCANNING, &local->scanning)) { | ||
263 | sdata->vif.bss_conf.enable_beacon = false; | 216 | sdata->vif.bss_conf.enable_beacon = false; |
264 | } else { | 217 | } else { |
265 | /* | 218 | /* |
@@ -288,9 +241,6 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata, | |||
288 | 241 | ||
289 | drv_bss_info_changed(local, &sdata->vif, | 242 | drv_bss_info_changed(local, &sdata->vif, |
290 | &sdata->vif.bss_conf, changed); | 243 | &sdata->vif.bss_conf, changed); |
291 | |||
292 | /* DEPRECATED */ | ||
293 | local->hw.conf.beacon_int = sdata->vif.bss_conf.beacon_int; | ||
294 | } | 244 | } |
295 | 245 | ||
296 | u32 ieee80211_reset_erp_info(struct ieee80211_sub_if_data *sdata) | 246 | u32 ieee80211_reset_erp_info(struct ieee80211_sub_if_data *sdata) |
@@ -310,7 +260,6 @@ void ieee80211_tx_status_irqsafe(struct ieee80211_hw *hw, | |||
310 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | 260 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
311 | int tmp; | 261 | int tmp; |
312 | 262 | ||
313 | skb->dev = local->mdev; | ||
314 | skb->pkt_type = IEEE80211_TX_STATUS_MSG; | 263 | skb->pkt_type = IEEE80211_TX_STATUS_MSG; |
315 | skb_queue_tail(info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS ? | 264 | skb_queue_tail(info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS ? |
316 | &local->skb_queue : &local->skb_queue_unreliable, skb); | 265 | &local->skb_queue : &local->skb_queue_unreliable, skb); |
@@ -330,19 +279,16 @@ static void ieee80211_tasklet_handler(unsigned long data) | |||
330 | { | 279 | { |
331 | struct ieee80211_local *local = (struct ieee80211_local *) data; | 280 | struct ieee80211_local *local = (struct ieee80211_local *) data; |
332 | struct sk_buff *skb; | 281 | struct sk_buff *skb; |
333 | struct ieee80211_rx_status rx_status; | ||
334 | struct ieee80211_ra_tid *ra_tid; | 282 | struct ieee80211_ra_tid *ra_tid; |
335 | 283 | ||
336 | while ((skb = skb_dequeue(&local->skb_queue)) || | 284 | while ((skb = skb_dequeue(&local->skb_queue)) || |
337 | (skb = skb_dequeue(&local->skb_queue_unreliable))) { | 285 | (skb = skb_dequeue(&local->skb_queue_unreliable))) { |
338 | switch (skb->pkt_type) { | 286 | switch (skb->pkt_type) { |
339 | case IEEE80211_RX_MSG: | 287 | case IEEE80211_RX_MSG: |
340 | /* status is in skb->cb */ | ||
341 | memcpy(&rx_status, skb->cb, sizeof(rx_status)); | ||
342 | /* Clear skb->pkt_type in order to not confuse kernel | 288 | /* Clear skb->pkt_type in order to not confuse kernel |
343 | * netstack. */ | 289 | * netstack. */ |
344 | skb->pkt_type = 0; | 290 | skb->pkt_type = 0; |
345 | __ieee80211_rx(local_to_hw(local), skb, &rx_status); | 291 | ieee80211_rx(local_to_hw(local), skb); |
346 | break; | 292 | break; |
347 | case IEEE80211_TX_STATUS_MSG: | 293 | case IEEE80211_TX_STATUS_MSG: |
348 | skb->pkt_type = 0; | 294 | skb->pkt_type = 0; |
@@ -375,6 +321,31 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local, | |||
375 | { | 321 | { |
376 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | 322 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
377 | 323 | ||
324 | /* | ||
325 | * XXX: This is temporary! | ||
326 | * | ||
327 | * The problem here is that when we get here, the driver will | ||
328 | * quite likely have pretty much overwritten info->control by | ||
329 | * using info->driver_data or info->rate_driver_data. Thus, | ||
330 | * when passing out the frame to the driver again, we would be | ||
331 | * passing completely bogus data since the driver would then | ||
332 | * expect a properly filled info->control. In mac80211 itself | ||
333 | * the same problem occurs, since we need info->control.vif | ||
334 | * internally. | ||
335 | * | ||
336 | * To fix this, we should send the frame through TX processing | ||
337 | * again. However, it's not that simple, since the frame will | ||
338 | * have been software-encrypted (if applicable) already, and | ||
339 | * encrypting it again doesn't do much good. So to properly do | ||
340 | * that, we not only have to skip the actual 'raw' encryption | ||
341 | * (key selection etc. still has to be done!) but also the | ||
342 | * sequence number assignment since that impacts the crypto | ||
343 | * encapsulation, of course. | ||
344 | * | ||
345 | * Hence, for now, fix the bug by just dropping the frame. | ||
346 | */ | ||
347 | goto drop; | ||
348 | |||
378 | sta->tx_filtered_count++; | 349 | sta->tx_filtered_count++; |
379 | 350 | ||
380 | /* | 351 | /* |
@@ -428,6 +399,7 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local, | |||
428 | return; | 399 | return; |
429 | } | 400 | } |
430 | 401 | ||
402 | drop: | ||
431 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | 403 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG |
432 | if (net_ratelimit()) | 404 | if (net_ratelimit()) |
433 | printk(KERN_DEBUG "%s: dropped TX filtered frame, " | 405 | printk(KERN_DEBUG "%s: dropped TX filtered frame, " |
@@ -510,6 +482,8 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
510 | } | 482 | } |
511 | 483 | ||
512 | rate_control_tx_status(local, sband, sta, skb); | 484 | rate_control_tx_status(local, sband, sta, skb); |
485 | if (ieee80211_vif_is_mesh(&sta->sdata->vif)) | ||
486 | ieee80211s_update_metric(local, sta, skb); | ||
513 | } | 487 | } |
514 | 488 | ||
515 | rcu_read_unlock(); | 489 | rcu_read_unlock(); |
@@ -685,6 +659,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
685 | if (!wiphy) | 659 | if (!wiphy) |
686 | return NULL; | 660 | return NULL; |
687 | 661 | ||
662 | wiphy->netnsok = true; | ||
688 | wiphy->privid = mac80211_wiphy_privid; | 663 | wiphy->privid = mac80211_wiphy_privid; |
689 | 664 | ||
690 | /* Yes, putting cfg80211_bss into ieee80211_bss is a hack */ | 665 | /* Yes, putting cfg80211_bss into ieee80211_bss is a hack */ |
@@ -711,7 +686,6 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
711 | local->hw.max_rates = 1; | 686 | local->hw.max_rates = 1; |
712 | local->hw.conf.long_frame_max_tx_count = wiphy->retry_long; | 687 | local->hw.conf.long_frame_max_tx_count = wiphy->retry_long; |
713 | local->hw.conf.short_frame_max_tx_count = wiphy->retry_short; | 688 | local->hw.conf.short_frame_max_tx_count = wiphy->retry_short; |
714 | local->hw.conf.radio_enabled = true; | ||
715 | local->user_power_level = -1; | 689 | local->user_power_level = -1; |
716 | 690 | ||
717 | INIT_LIST_HEAD(&local->interfaces); | 691 | INIT_LIST_HEAD(&local->interfaces); |
@@ -719,13 +693,15 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
719 | mutex_init(&local->scan_mtx); | 693 | mutex_init(&local->scan_mtx); |
720 | 694 | ||
721 | spin_lock_init(&local->key_lock); | 695 | spin_lock_init(&local->key_lock); |
722 | 696 | spin_lock_init(&local->filter_lock); | |
723 | spin_lock_init(&local->queue_stop_reason_lock); | 697 | spin_lock_init(&local->queue_stop_reason_lock); |
724 | 698 | ||
725 | INIT_DELAYED_WORK(&local->scan_work, ieee80211_scan_work); | 699 | INIT_DELAYED_WORK(&local->scan_work, ieee80211_scan_work); |
726 | 700 | ||
727 | INIT_WORK(&local->restart_work, ieee80211_restart_work); | 701 | INIT_WORK(&local->restart_work, ieee80211_restart_work); |
728 | 702 | ||
703 | INIT_WORK(&local->reconfig_filter, ieee80211_reconfig_filter); | ||
704 | |||
729 | INIT_WORK(&local->dynamic_ps_enable_work, | 705 | INIT_WORK(&local->dynamic_ps_enable_work, |
730 | ieee80211_dynamic_ps_enable_work); | 706 | ieee80211_dynamic_ps_enable_work); |
731 | INIT_WORK(&local->dynamic_ps_disable_work, | 707 | INIT_WORK(&local->dynamic_ps_disable_work, |
@@ -739,12 +715,10 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
739 | skb_queue_head_init(&local->pending[i]); | 715 | skb_queue_head_init(&local->pending[i]); |
740 | tasklet_init(&local->tx_pending_tasklet, ieee80211_tx_pending, | 716 | tasklet_init(&local->tx_pending_tasklet, ieee80211_tx_pending, |
741 | (unsigned long)local); | 717 | (unsigned long)local); |
742 | tasklet_disable(&local->tx_pending_tasklet); | ||
743 | 718 | ||
744 | tasklet_init(&local->tasklet, | 719 | tasklet_init(&local->tasklet, |
745 | ieee80211_tasklet_handler, | 720 | ieee80211_tasklet_handler, |
746 | (unsigned long) local); | 721 | (unsigned long) local); |
747 | tasklet_disable(&local->tasklet); | ||
748 | 722 | ||
749 | skb_queue_head_init(&local->skb_queue); | 723 | skb_queue_head_init(&local->skb_queue); |
750 | skb_queue_head_init(&local->skb_queue_unreliable); | 724 | skb_queue_head_init(&local->skb_queue_unreliable); |
@@ -755,30 +729,11 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
755 | } | 729 | } |
756 | EXPORT_SYMBOL(ieee80211_alloc_hw); | 730 | EXPORT_SYMBOL(ieee80211_alloc_hw); |
757 | 731 | ||
758 | static const struct net_device_ops ieee80211_master_ops = { | ||
759 | .ndo_start_xmit = ieee80211_master_start_xmit, | ||
760 | .ndo_open = ieee80211_master_open, | ||
761 | .ndo_stop = ieee80211_master_stop, | ||
762 | .ndo_set_multicast_list = ieee80211_master_set_multicast_list, | ||
763 | .ndo_select_queue = ieee80211_select_queue, | ||
764 | }; | ||
765 | |||
766 | static void ieee80211_master_setup(struct net_device *mdev) | ||
767 | { | ||
768 | mdev->type = ARPHRD_IEEE80211; | ||
769 | mdev->netdev_ops = &ieee80211_master_ops; | ||
770 | mdev->header_ops = &ieee80211_header_ops; | ||
771 | mdev->tx_queue_len = 1000; | ||
772 | mdev->addr_len = ETH_ALEN; | ||
773 | } | ||
774 | |||
775 | int ieee80211_register_hw(struct ieee80211_hw *hw) | 732 | int ieee80211_register_hw(struct ieee80211_hw *hw) |
776 | { | 733 | { |
777 | struct ieee80211_local *local = hw_to_local(hw); | 734 | struct ieee80211_local *local = hw_to_local(hw); |
778 | int result; | 735 | int result; |
779 | enum ieee80211_band band; | 736 | enum ieee80211_band band; |
780 | struct net_device *mdev; | ||
781 | struct ieee80211_master_priv *mpriv; | ||
782 | int channels, i, j, max_bitrates; | 737 | int channels, i, j, max_bitrates; |
783 | bool supp_ht; | 738 | bool supp_ht; |
784 | static const u32 cipher_suites[] = { | 739 | static const u32 cipher_suites[] = { |
@@ -818,9 +773,9 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
818 | supp_ht = supp_ht || sband->ht_cap.ht_supported; | 773 | supp_ht = supp_ht || sband->ht_cap.ht_supported; |
819 | } | 774 | } |
820 | 775 | ||
821 | local->int_scan_req.n_channels = channels; | 776 | local->int_scan_req = kzalloc(sizeof(*local->int_scan_req) + |
822 | local->int_scan_req.channels = kzalloc(sizeof(void *) * channels, GFP_KERNEL); | 777 | sizeof(void *) * channels, GFP_KERNEL); |
823 | if (!local->int_scan_req.channels) | 778 | if (!local->int_scan_req) |
824 | return -ENOMEM; | 779 | return -ENOMEM; |
825 | 780 | ||
826 | /* if low-level driver supports AP, we also support VLAN */ | 781 | /* if low-level driver supports AP, we also support VLAN */ |
@@ -877,19 +832,9 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
877 | if (hw->queues > IEEE80211_MAX_QUEUES) | 832 | if (hw->queues > IEEE80211_MAX_QUEUES) |
878 | hw->queues = IEEE80211_MAX_QUEUES; | 833 | hw->queues = IEEE80211_MAX_QUEUES; |
879 | 834 | ||
880 | mdev = alloc_netdev_mq(sizeof(struct ieee80211_master_priv), | 835 | local->workqueue = |
881 | "wmaster%d", ieee80211_master_setup, | ||
882 | hw->queues); | ||
883 | if (!mdev) | ||
884 | goto fail_mdev_alloc; | ||
885 | |||
886 | mpriv = netdev_priv(mdev); | ||
887 | mpriv->local = local; | ||
888 | local->mdev = mdev; | ||
889 | |||
890 | local->hw.workqueue = | ||
891 | create_singlethread_workqueue(wiphy_name(local->hw.wiphy)); | 836 | create_singlethread_workqueue(wiphy_name(local->hw.wiphy)); |
892 | if (!local->hw.workqueue) { | 837 | if (!local->workqueue) { |
893 | result = -ENOMEM; | 838 | result = -ENOMEM; |
894 | goto fail_workqueue; | 839 | goto fail_workqueue; |
895 | } | 840 | } |
@@ -921,17 +866,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
921 | } | 866 | } |
922 | 867 | ||
923 | rtnl_lock(); | 868 | rtnl_lock(); |
924 | result = dev_alloc_name(local->mdev, local->mdev->name); | ||
925 | if (result < 0) | ||
926 | goto fail_dev; | ||
927 | |||
928 | memcpy(local->mdev->dev_addr, local->hw.wiphy->perm_addr, ETH_ALEN); | ||
929 | SET_NETDEV_DEV(local->mdev, wiphy_dev(local->hw.wiphy)); | ||
930 | local->mdev->features |= NETIF_F_NETNS_LOCAL; | ||
931 | |||
932 | result = register_netdevice(local->mdev); | ||
933 | if (result < 0) | ||
934 | goto fail_dev; | ||
935 | 869 | ||
936 | result = ieee80211_init_rate_ctrl_alg(local, | 870 | result = ieee80211_init_rate_ctrl_alg(local, |
937 | hw->rate_control_algorithm); | 871 | hw->rate_control_algorithm); |
@@ -956,13 +890,13 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
956 | 890 | ||
957 | /* alloc internal scan request */ | 891 | /* alloc internal scan request */ |
958 | i = 0; | 892 | i = 0; |
959 | local->int_scan_req.ssids = &local->scan_ssid; | 893 | local->int_scan_req->ssids = &local->scan_ssid; |
960 | local->int_scan_req.n_ssids = 1; | 894 | local->int_scan_req->n_ssids = 1; |
961 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) { | 895 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) { |
962 | if (!hw->wiphy->bands[band]) | 896 | if (!hw->wiphy->bands[band]) |
963 | continue; | 897 | continue; |
964 | for (j = 0; j < hw->wiphy->bands[band]->n_channels; j++) { | 898 | for (j = 0; j < hw->wiphy->bands[band]->n_channels; j++) { |
965 | local->int_scan_req.channels[i] = | 899 | local->int_scan_req->channels[i] = |
966 | &hw->wiphy->bands[band]->channels[j]; | 900 | &hw->wiphy->bands[band]->channels[j]; |
967 | i++; | 901 | i++; |
968 | } | 902 | } |
@@ -984,23 +918,17 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
984 | ieee80211_led_exit(local); | 918 | ieee80211_led_exit(local); |
985 | ieee80211_remove_interfaces(local); | 919 | ieee80211_remove_interfaces(local); |
986 | fail_rate: | 920 | fail_rate: |
987 | unregister_netdevice(local->mdev); | ||
988 | local->mdev = NULL; | ||
989 | fail_dev: | ||
990 | rtnl_unlock(); | 921 | rtnl_unlock(); |
991 | ieee80211_wep_free(local); | 922 | ieee80211_wep_free(local); |
992 | fail_wep: | 923 | fail_wep: |
993 | sta_info_stop(local); | 924 | sta_info_stop(local); |
994 | fail_sta_info: | 925 | fail_sta_info: |
995 | debugfs_hw_del(local); | 926 | debugfs_hw_del(local); |
996 | destroy_workqueue(local->hw.workqueue); | 927 | destroy_workqueue(local->workqueue); |
997 | fail_workqueue: | 928 | fail_workqueue: |
998 | if (local->mdev) | ||
999 | free_netdev(local->mdev); | ||
1000 | fail_mdev_alloc: | ||
1001 | wiphy_unregister(local->hw.wiphy); | 929 | wiphy_unregister(local->hw.wiphy); |
1002 | fail_wiphy_register: | 930 | fail_wiphy_register: |
1003 | kfree(local->int_scan_req.channels); | 931 | kfree(local->int_scan_req); |
1004 | return result; | 932 | return result; |
1005 | } | 933 | } |
1006 | EXPORT_SYMBOL(ieee80211_register_hw); | 934 | EXPORT_SYMBOL(ieee80211_register_hw); |
@@ -1022,15 +950,12 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw) | |||
1022 | * because the driver cannot be handing us frames any | 950 | * because the driver cannot be handing us frames any |
1023 | * more and the tasklet is killed. | 951 | * more and the tasklet is killed. |
1024 | */ | 952 | */ |
1025 | |||
1026 | /* First, we remove all virtual interfaces. */ | ||
1027 | ieee80211_remove_interfaces(local); | 953 | ieee80211_remove_interfaces(local); |
1028 | 954 | ||
1029 | /* then, finally, remove the master interface */ | ||
1030 | unregister_netdevice(local->mdev); | ||
1031 | |||
1032 | rtnl_unlock(); | 955 | rtnl_unlock(); |
1033 | 956 | ||
957 | cancel_work_sync(&local->reconfig_filter); | ||
958 | |||
1034 | ieee80211_clear_tx_pending(local); | 959 | ieee80211_clear_tx_pending(local); |
1035 | sta_info_stop(local); | 960 | sta_info_stop(local); |
1036 | rate_control_deinitialize(local); | 961 | rate_control_deinitialize(local); |
@@ -1043,12 +968,11 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw) | |||
1043 | skb_queue_purge(&local->skb_queue); | 968 | skb_queue_purge(&local->skb_queue); |
1044 | skb_queue_purge(&local->skb_queue_unreliable); | 969 | skb_queue_purge(&local->skb_queue_unreliable); |
1045 | 970 | ||
1046 | destroy_workqueue(local->hw.workqueue); | 971 | destroy_workqueue(local->workqueue); |
1047 | wiphy_unregister(local->hw.wiphy); | 972 | wiphy_unregister(local->hw.wiphy); |
1048 | ieee80211_wep_free(local); | 973 | ieee80211_wep_free(local); |
1049 | ieee80211_led_exit(local); | 974 | ieee80211_led_exit(local); |
1050 | free_netdev(local->mdev); | 975 | kfree(local->int_scan_req); |
1051 | kfree(local->int_scan_req.channels); | ||
1052 | } | 976 | } |
1053 | EXPORT_SYMBOL(ieee80211_unregister_hw); | 977 | EXPORT_SYMBOL(ieee80211_unregister_hw); |
1054 | 978 | ||