diff options
Diffstat (limited to 'net/mac80211/main.c')
-rw-r--r-- | net/mac80211/main.c | 185 |
1 files changed, 126 insertions, 59 deletions
diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 24b14363d6e7..a6f1d8a869bc 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c | |||
@@ -161,30 +161,67 @@ int ieee80211_if_config(struct ieee80211_sub_if_data *sdata, u32 changed) | |||
161 | if (WARN_ON(!netif_running(sdata->dev))) | 161 | if (WARN_ON(!netif_running(sdata->dev))) |
162 | return 0; | 162 | return 0; |
163 | 163 | ||
164 | if (WARN_ON(sdata->vif.type == NL80211_IFTYPE_AP_VLAN)) | ||
165 | return -EINVAL; | ||
166 | |||
167 | if (!local->ops->config_interface) | ||
168 | return 0; | ||
169 | |||
170 | memset(&conf, 0, sizeof(conf)); | 164 | memset(&conf, 0, sizeof(conf)); |
171 | conf.changed = changed; | ||
172 | 165 | ||
173 | if (sdata->vif.type == NL80211_IFTYPE_STATION || | 166 | if (sdata->vif.type == NL80211_IFTYPE_STATION) |
174 | sdata->vif.type == NL80211_IFTYPE_ADHOC) | 167 | conf.bssid = sdata->u.mgd.bssid; |
175 | conf.bssid = sdata->u.sta.bssid; | 168 | else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) |
169 | conf.bssid = sdata->u.ibss.bssid; | ||
176 | else if (sdata->vif.type == NL80211_IFTYPE_AP) | 170 | else if (sdata->vif.type == NL80211_IFTYPE_AP) |
177 | conf.bssid = sdata->dev->dev_addr; | 171 | conf.bssid = sdata->dev->dev_addr; |
178 | else if (ieee80211_vif_is_mesh(&sdata->vif)) { | 172 | else if (ieee80211_vif_is_mesh(&sdata->vif)) { |
179 | u8 zero[ETH_ALEN] = { 0 }; | 173 | static const u8 zero[ETH_ALEN] = { 0 }; |
180 | conf.bssid = zero; | 174 | conf.bssid = zero; |
181 | } else { | 175 | } else { |
182 | WARN_ON(1); | 176 | WARN_ON(1); |
183 | return -EINVAL; | 177 | return -EINVAL; |
184 | } | 178 | } |
185 | 179 | ||
186 | if (WARN_ON(!conf.bssid && (changed & IEEE80211_IFCC_BSSID))) | 180 | if (!local->ops->config_interface) |
187 | return -EINVAL; | 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; | ||
188 | 225 | ||
189 | return local->ops->config_interface(local_to_hw(local), | 226 | return local->ops->config_interface(local_to_hw(local), |
190 | &sdata->vif, &conf); | 227 | &sdata->vif, &conf); |
@@ -208,26 +245,22 @@ int ieee80211_hw_config(struct ieee80211_local *local, u32 changed) | |||
208 | } | 245 | } |
209 | 246 | ||
210 | if (chan != local->hw.conf.channel || | 247 | if (chan != local->hw.conf.channel || |
211 | channel_type != local->hw.conf.ht.channel_type) { | 248 | channel_type != local->hw.conf.channel_type) { |
212 | local->hw.conf.channel = chan; | 249 | local->hw.conf.channel = chan; |
213 | local->hw.conf.ht.channel_type = channel_type; | 250 | local->hw.conf.channel_type = channel_type; |
214 | switch (channel_type) { | ||
215 | case NL80211_CHAN_NO_HT: | ||
216 | local->hw.conf.ht.enabled = false; | ||
217 | break; | ||
218 | case NL80211_CHAN_HT20: | ||
219 | case NL80211_CHAN_HT40MINUS: | ||
220 | case NL80211_CHAN_HT40PLUS: | ||
221 | local->hw.conf.ht.enabled = true; | ||
222 | break; | ||
223 | } | ||
224 | changed |= IEEE80211_CONF_CHANGE_CHANNEL; | 251 | changed |= IEEE80211_CONF_CHANGE_CHANNEL; |
225 | } | 252 | } |
226 | 253 | ||
227 | if (!local->hw.conf.power_level) | 254 | if (local->sw_scanning) |
228 | power = chan->max_power; | 255 | power = chan->max_power; |
229 | else | 256 | else |
230 | power = min(chan->max_power, local->hw.conf.power_level); | 257 | power = local->power_constr_level ? |
258 | (chan->max_power - local->power_constr_level) : | ||
259 | chan->max_power; | ||
260 | |||
261 | if (local->user_power_level) | ||
262 | power = min(power, local->user_power_level); | ||
263 | |||
231 | if (local->hw.conf.power_level != power) { | 264 | if (local->hw.conf.power_level != power) { |
232 | changed |= IEEE80211_CONF_CHANGE_POWER; | 265 | changed |= IEEE80211_CONF_CHANGE_POWER; |
233 | local->hw.conf.power_level = power; | 266 | local->hw.conf.power_level = power; |
@@ -667,7 +700,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
667 | const struct ieee80211_ops *ops) | 700 | const struct ieee80211_ops *ops) |
668 | { | 701 | { |
669 | struct ieee80211_local *local; | 702 | struct ieee80211_local *local; |
670 | int priv_size; | 703 | int priv_size, i; |
671 | struct wiphy *wiphy; | 704 | struct wiphy *wiphy; |
672 | 705 | ||
673 | /* Ensure 32-byte alignment of our private data and hw private data. | 706 | /* Ensure 32-byte alignment of our private data and hw private data. |
@@ -695,6 +728,10 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
695 | return NULL; | 728 | return NULL; |
696 | 729 | ||
697 | wiphy->privid = mac80211_wiphy_privid; | 730 | wiphy->privid = mac80211_wiphy_privid; |
731 | wiphy->max_scan_ssids = 4; | ||
732 | /* Yes, putting cfg80211_bss into ieee80211_bss is a hack */ | ||
733 | wiphy->bss_priv_size = sizeof(struct ieee80211_bss) - | ||
734 | sizeof(struct cfg80211_bss); | ||
698 | 735 | ||
699 | local = wiphy_priv(wiphy); | 736 | local = wiphy_priv(wiphy); |
700 | local->hw.wiphy = wiphy; | 737 | local->hw.wiphy = wiphy; |
@@ -722,6 +759,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
722 | local->hw.conf.radio_enabled = true; | 759 | local->hw.conf.radio_enabled = true; |
723 | 760 | ||
724 | INIT_LIST_HEAD(&local->interfaces); | 761 | INIT_LIST_HEAD(&local->interfaces); |
762 | mutex_init(&local->iflist_mtx); | ||
725 | 763 | ||
726 | spin_lock_init(&local->key_lock); | 764 | spin_lock_init(&local->key_lock); |
727 | 765 | ||
@@ -738,6 +776,8 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
738 | 776 | ||
739 | sta_info_init(local); | 777 | sta_info_init(local); |
740 | 778 | ||
779 | for (i = 0; i < IEEE80211_MAX_QUEUES; i++) | ||
780 | skb_queue_head_init(&local->pending[i]); | ||
741 | tasklet_init(&local->tx_pending_tasklet, ieee80211_tx_pending, | 781 | tasklet_init(&local->tx_pending_tasklet, ieee80211_tx_pending, |
742 | (unsigned long)local); | 782 | (unsigned long)local); |
743 | tasklet_disable(&local->tx_pending_tasklet); | 783 | tasklet_disable(&local->tx_pending_tasklet); |
@@ -750,10 +790,29 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
750 | skb_queue_head_init(&local->skb_queue); | 790 | skb_queue_head_init(&local->skb_queue); |
751 | skb_queue_head_init(&local->skb_queue_unreliable); | 791 | skb_queue_head_init(&local->skb_queue_unreliable); |
752 | 792 | ||
793 | spin_lock_init(&local->ampdu_lock); | ||
794 | |||
753 | return local_to_hw(local); | 795 | return local_to_hw(local); |
754 | } | 796 | } |
755 | EXPORT_SYMBOL(ieee80211_alloc_hw); | 797 | EXPORT_SYMBOL(ieee80211_alloc_hw); |
756 | 798 | ||
799 | static const struct net_device_ops ieee80211_master_ops = { | ||
800 | .ndo_start_xmit = ieee80211_master_start_xmit, | ||
801 | .ndo_open = ieee80211_master_open, | ||
802 | .ndo_stop = ieee80211_master_stop, | ||
803 | .ndo_set_multicast_list = ieee80211_master_set_multicast_list, | ||
804 | .ndo_select_queue = ieee80211_select_queue, | ||
805 | }; | ||
806 | |||
807 | static void ieee80211_master_setup(struct net_device *mdev) | ||
808 | { | ||
809 | mdev->type = ARPHRD_IEEE80211; | ||
810 | mdev->netdev_ops = &ieee80211_master_ops; | ||
811 | mdev->header_ops = &ieee80211_header_ops; | ||
812 | mdev->tx_queue_len = 1000; | ||
813 | mdev->addr_len = ETH_ALEN; | ||
814 | } | ||
815 | |||
757 | int ieee80211_register_hw(struct ieee80211_hw *hw) | 816 | int ieee80211_register_hw(struct ieee80211_hw *hw) |
758 | { | 817 | { |
759 | struct ieee80211_local *local = hw_to_local(hw); | 818 | struct ieee80211_local *local = hw_to_local(hw); |
@@ -761,25 +820,33 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
761 | enum ieee80211_band band; | 820 | enum ieee80211_band band; |
762 | struct net_device *mdev; | 821 | struct net_device *mdev; |
763 | struct ieee80211_master_priv *mpriv; | 822 | struct ieee80211_master_priv *mpriv; |
823 | int channels, i, j; | ||
764 | 824 | ||
765 | /* | 825 | /* |
766 | * generic code guarantees at least one band, | 826 | * generic code guarantees at least one band, |
767 | * set this very early because much code assumes | 827 | * set this very early because much code assumes |
768 | * that hw.conf.channel is assigned | 828 | * that hw.conf.channel is assigned |
769 | */ | 829 | */ |
830 | channels = 0; | ||
770 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) { | 831 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) { |
771 | struct ieee80211_supported_band *sband; | 832 | struct ieee80211_supported_band *sband; |
772 | 833 | ||
773 | sband = local->hw.wiphy->bands[band]; | 834 | sband = local->hw.wiphy->bands[band]; |
774 | if (sband) { | 835 | if (sband && !local->oper_channel) { |
775 | /* init channel we're on */ | 836 | /* init channel we're on */ |
776 | local->hw.conf.channel = | 837 | local->hw.conf.channel = |
777 | local->oper_channel = | 838 | local->oper_channel = |
778 | local->scan_channel = &sband->channels[0]; | 839 | local->scan_channel = &sband->channels[0]; |
779 | break; | ||
780 | } | 840 | } |
841 | if (sband) | ||
842 | channels += sband->n_channels; | ||
781 | } | 843 | } |
782 | 844 | ||
845 | local->int_scan_req.n_channels = channels; | ||
846 | local->int_scan_req.channels = kzalloc(sizeof(void *) * channels, GFP_KERNEL); | ||
847 | if (!local->int_scan_req.channels) | ||
848 | return -ENOMEM; | ||
849 | |||
783 | /* if low-level driver supports AP, we also support VLAN */ | 850 | /* if low-level driver supports AP, we also support VLAN */ |
784 | if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_AP)) | 851 | if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_AP)) |
785 | local->hw.wiphy->interface_modes |= BIT(NL80211_IFTYPE_AP_VLAN); | 852 | local->hw.wiphy->interface_modes |= BIT(NL80211_IFTYPE_AP_VLAN); |
@@ -787,9 +854,14 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
787 | /* mac80211 always supports monitor */ | 854 | /* mac80211 always supports monitor */ |
788 | local->hw.wiphy->interface_modes |= BIT(NL80211_IFTYPE_MONITOR); | 855 | local->hw.wiphy->interface_modes |= BIT(NL80211_IFTYPE_MONITOR); |
789 | 856 | ||
857 | if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM) | ||
858 | local->hw.wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; | ||
859 | else if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC) | ||
860 | local->hw.wiphy->signal_type = CFG80211_SIGNAL_TYPE_UNSPEC; | ||
861 | |||
790 | result = wiphy_register(local->hw.wiphy); | 862 | result = wiphy_register(local->hw.wiphy); |
791 | if (result < 0) | 863 | if (result < 0) |
792 | return result; | 864 | goto fail_wiphy_register; |
793 | 865 | ||
794 | /* | 866 | /* |
795 | * We use the number of queues for feature tests (QoS, HT) internally | 867 | * We use the number of queues for feature tests (QoS, HT) internally |
@@ -797,14 +869,10 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
797 | */ | 869 | */ |
798 | if (hw->queues > IEEE80211_MAX_QUEUES) | 870 | if (hw->queues > IEEE80211_MAX_QUEUES) |
799 | hw->queues = IEEE80211_MAX_QUEUES; | 871 | hw->queues = IEEE80211_MAX_QUEUES; |
800 | if (hw->ampdu_queues > IEEE80211_MAX_AMPDU_QUEUES) | ||
801 | hw->ampdu_queues = IEEE80211_MAX_AMPDU_QUEUES; | ||
802 | if (hw->queues < 4) | ||
803 | hw->ampdu_queues = 0; | ||
804 | 872 | ||
805 | mdev = alloc_netdev_mq(sizeof(struct ieee80211_master_priv), | 873 | mdev = alloc_netdev_mq(sizeof(struct ieee80211_master_priv), |
806 | "wmaster%d", ether_setup, | 874 | "wmaster%d", ieee80211_master_setup, |
807 | ieee80211_num_queues(hw)); | 875 | hw->queues); |
808 | if (!mdev) | 876 | if (!mdev) |
809 | goto fail_mdev_alloc; | 877 | goto fail_mdev_alloc; |
810 | 878 | ||
@@ -812,17 +880,8 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
812 | mpriv->local = local; | 880 | mpriv->local = local; |
813 | local->mdev = mdev; | 881 | local->mdev = mdev; |
814 | 882 | ||
815 | ieee80211_rx_bss_list_init(local); | ||
816 | |||
817 | mdev->hard_start_xmit = ieee80211_master_start_xmit; | ||
818 | mdev->open = ieee80211_master_open; | ||
819 | mdev->stop = ieee80211_master_stop; | ||
820 | mdev->type = ARPHRD_IEEE80211; | ||
821 | mdev->header_ops = &ieee80211_header_ops; | ||
822 | mdev->set_multicast_list = ieee80211_master_set_multicast_list; | ||
823 | |||
824 | local->hw.workqueue = | 883 | local->hw.workqueue = |
825 | create_freezeable_workqueue(wiphy_name(local->hw.wiphy)); | 884 | create_singlethread_workqueue(wiphy_name(local->hw.wiphy)); |
826 | if (!local->hw.workqueue) { | 885 | if (!local->hw.workqueue) { |
827 | result = -ENOMEM; | 886 | result = -ENOMEM; |
828 | goto fail_workqueue; | 887 | goto fail_workqueue; |
@@ -846,15 +905,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
846 | 905 | ||
847 | local->hw.conf.listen_interval = local->hw.max_listen_interval; | 906 | local->hw.conf.listen_interval = local->hw.max_listen_interval; |
848 | 907 | ||
849 | local->wstats_flags |= local->hw.flags & (IEEE80211_HW_SIGNAL_UNSPEC | | ||
850 | IEEE80211_HW_SIGNAL_DB | | ||
851 | IEEE80211_HW_SIGNAL_DBM) ? | ||
852 | IW_QUAL_QUAL_UPDATED : IW_QUAL_QUAL_INVALID; | ||
853 | local->wstats_flags |= local->hw.flags & IEEE80211_HW_NOISE_DBM ? | ||
854 | IW_QUAL_NOISE_UPDATED : IW_QUAL_NOISE_INVALID; | ||
855 | if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM) | ||
856 | local->wstats_flags |= IW_QUAL_DBM; | ||
857 | |||
858 | result = sta_info_start(local); | 908 | result = sta_info_start(local); |
859 | if (result < 0) | 909 | if (result < 0) |
860 | goto fail_sta_info; | 910 | goto fail_sta_info; |
@@ -866,6 +916,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
866 | 916 | ||
867 | memcpy(local->mdev->dev_addr, local->hw.wiphy->perm_addr, ETH_ALEN); | 917 | memcpy(local->mdev->dev_addr, local->hw.wiphy->perm_addr, ETH_ALEN); |
868 | SET_NETDEV_DEV(local->mdev, wiphy_dev(local->hw.wiphy)); | 918 | SET_NETDEV_DEV(local->mdev, wiphy_dev(local->hw.wiphy)); |
919 | local->mdev->features |= NETIF_F_NETNS_LOCAL; | ||
869 | 920 | ||
870 | result = register_netdevice(local->mdev); | 921 | result = register_netdevice(local->mdev); |
871 | if (result < 0) | 922 | if (result < 0) |
@@ -887,8 +938,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
887 | goto fail_wep; | 938 | goto fail_wep; |
888 | } | 939 | } |
889 | 940 | ||
890 | local->mdev->select_queue = ieee80211_select_queue; | ||
891 | |||
892 | /* add one default STA interface if supported */ | 941 | /* add one default STA interface if supported */ |
893 | if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_STATION)) { | 942 | if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_STATION)) { |
894 | result = ieee80211_if_add(local, "wlan%d", NULL, | 943 | result = ieee80211_if_add(local, "wlan%d", NULL, |
@@ -902,6 +951,20 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
902 | 951 | ||
903 | ieee80211_led_init(local); | 952 | ieee80211_led_init(local); |
904 | 953 | ||
954 | /* alloc internal scan request */ | ||
955 | i = 0; | ||
956 | local->int_scan_req.ssids = &local->scan_ssid; | ||
957 | local->int_scan_req.n_ssids = 1; | ||
958 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) { | ||
959 | if (!hw->wiphy->bands[band]) | ||
960 | continue; | ||
961 | for (j = 0; j < hw->wiphy->bands[band]->n_channels; j++) { | ||
962 | local->int_scan_req.channels[i] = | ||
963 | &hw->wiphy->bands[band]->channels[j]; | ||
964 | i++; | ||
965 | } | ||
966 | } | ||
967 | |||
905 | return 0; | 968 | return 0; |
906 | 969 | ||
907 | fail_wep: | 970 | fail_wep: |
@@ -920,6 +983,8 @@ fail_workqueue: | |||
920 | free_netdev(local->mdev); | 983 | free_netdev(local->mdev); |
921 | fail_mdev_alloc: | 984 | fail_mdev_alloc: |
922 | wiphy_unregister(local->hw.wiphy); | 985 | wiphy_unregister(local->hw.wiphy); |
986 | fail_wiphy_register: | ||
987 | kfree(local->int_scan_req.channels); | ||
923 | return result; | 988 | return result; |
924 | } | 989 | } |
925 | EXPORT_SYMBOL(ieee80211_register_hw); | 990 | EXPORT_SYMBOL(ieee80211_register_hw); |
@@ -947,7 +1012,6 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw) | |||
947 | 1012 | ||
948 | rtnl_unlock(); | 1013 | rtnl_unlock(); |
949 | 1014 | ||
950 | ieee80211_rx_bss_list_deinit(local); | ||
951 | ieee80211_clear_tx_pending(local); | 1015 | ieee80211_clear_tx_pending(local); |
952 | sta_info_stop(local); | 1016 | sta_info_stop(local); |
953 | rate_control_deinitialize(local); | 1017 | rate_control_deinitialize(local); |
@@ -965,6 +1029,7 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw) | |||
965 | ieee80211_wep_free(local); | 1029 | ieee80211_wep_free(local); |
966 | ieee80211_led_exit(local); | 1030 | ieee80211_led_exit(local); |
967 | free_netdev(local->mdev); | 1031 | free_netdev(local->mdev); |
1032 | kfree(local->int_scan_req.channels); | ||
968 | } | 1033 | } |
969 | EXPORT_SYMBOL(ieee80211_unregister_hw); | 1034 | EXPORT_SYMBOL(ieee80211_unregister_hw); |
970 | 1035 | ||
@@ -972,6 +1037,8 @@ void ieee80211_free_hw(struct ieee80211_hw *hw) | |||
972 | { | 1037 | { |
973 | struct ieee80211_local *local = hw_to_local(hw); | 1038 | struct ieee80211_local *local = hw_to_local(hw); |
974 | 1039 | ||
1040 | mutex_destroy(&local->iflist_mtx); | ||
1041 | |||
975 | wiphy_free(local->hw.wiphy); | 1042 | wiphy_free(local->hw.wiphy); |
976 | } | 1043 | } |
977 | EXPORT_SYMBOL(ieee80211_free_hw); | 1044 | EXPORT_SYMBOL(ieee80211_free_hw); |