diff options
Diffstat (limited to 'net/mac80211/main.c')
-rw-r--r-- | net/mac80211/main.c | 172 |
1 files changed, 125 insertions, 47 deletions
diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 24b14363d6e7..f38db4d37e5d 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c | |||
@@ -168,24 +168,67 @@ int ieee80211_if_config(struct ieee80211_sub_if_data *sdata, u32 changed) | |||
168 | return 0; | 168 | return 0; |
169 | 169 | ||
170 | memset(&conf, 0, sizeof(conf)); | 170 | memset(&conf, 0, sizeof(conf)); |
171 | conf.changed = changed; | ||
172 | 171 | ||
173 | if (sdata->vif.type == NL80211_IFTYPE_STATION || | 172 | if (sdata->vif.type == NL80211_IFTYPE_STATION) |
174 | sdata->vif.type == NL80211_IFTYPE_ADHOC) | 173 | conf.bssid = sdata->u.mgd.bssid; |
175 | conf.bssid = sdata->u.sta.bssid; | 174 | else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) |
175 | conf.bssid = sdata->u.ibss.bssid; | ||
176 | else if (sdata->vif.type == NL80211_IFTYPE_AP) | 176 | else if (sdata->vif.type == NL80211_IFTYPE_AP) |
177 | conf.bssid = sdata->dev->dev_addr; | 177 | conf.bssid = sdata->dev->dev_addr; |
178 | else if (ieee80211_vif_is_mesh(&sdata->vif)) { | 178 | else if (ieee80211_vif_is_mesh(&sdata->vif)) { |
179 | u8 zero[ETH_ALEN] = { 0 }; | 179 | static const u8 zero[ETH_ALEN] = { 0 }; |
180 | conf.bssid = zero; | 180 | conf.bssid = zero; |
181 | } else { | 181 | } else { |
182 | WARN_ON(1); | 182 | WARN_ON(1); |
183 | return -EINVAL; | 183 | return -EINVAL; |
184 | } | 184 | } |
185 | 185 | ||
186 | switch (sdata->vif.type) { | ||
187 | case NL80211_IFTYPE_AP: | ||
188 | case NL80211_IFTYPE_ADHOC: | ||
189 | case NL80211_IFTYPE_MESH_POINT: | ||
190 | break; | ||
191 | default: | ||
192 | /* do not warn to simplify caller in scan.c */ | ||
193 | changed &= ~IEEE80211_IFCC_BEACON_ENABLED; | ||
194 | if (WARN_ON(changed & IEEE80211_IFCC_BEACON)) | ||
195 | return -EINVAL; | ||
196 | changed &= ~IEEE80211_IFCC_BEACON; | ||
197 | break; | ||
198 | } | ||
199 | |||
200 | if (changed & IEEE80211_IFCC_BEACON_ENABLED) { | ||
201 | if (local->sw_scanning) { | ||
202 | conf.enable_beacon = false; | ||
203 | } else { | ||
204 | /* | ||
205 | * Beacon should be enabled, but AP mode must | ||
206 | * check whether there is a beacon configured. | ||
207 | */ | ||
208 | switch (sdata->vif.type) { | ||
209 | case NL80211_IFTYPE_AP: | ||
210 | conf.enable_beacon = | ||
211 | !!rcu_dereference(sdata->u.ap.beacon); | ||
212 | break; | ||
213 | case NL80211_IFTYPE_ADHOC: | ||
214 | conf.enable_beacon = !!sdata->u.ibss.probe_resp; | ||
215 | break; | ||
216 | case NL80211_IFTYPE_MESH_POINT: | ||
217 | conf.enable_beacon = true; | ||
218 | break; | ||
219 | default: | ||
220 | /* not reached */ | ||
221 | WARN_ON(1); | ||
222 | break; | ||
223 | } | ||
224 | } | ||
225 | } | ||
226 | |||
186 | if (WARN_ON(!conf.bssid && (changed & IEEE80211_IFCC_BSSID))) | 227 | if (WARN_ON(!conf.bssid && (changed & IEEE80211_IFCC_BSSID))) |
187 | return -EINVAL; | 228 | return -EINVAL; |
188 | 229 | ||
230 | conf.changed = changed; | ||
231 | |||
189 | return local->ops->config_interface(local_to_hw(local), | 232 | return local->ops->config_interface(local_to_hw(local), |
190 | &sdata->vif, &conf); | 233 | &sdata->vif, &conf); |
191 | } | 234 | } |
@@ -208,26 +251,22 @@ int ieee80211_hw_config(struct ieee80211_local *local, u32 changed) | |||
208 | } | 251 | } |
209 | 252 | ||
210 | if (chan != local->hw.conf.channel || | 253 | if (chan != local->hw.conf.channel || |
211 | channel_type != local->hw.conf.ht.channel_type) { | 254 | channel_type != local->hw.conf.channel_type) { |
212 | local->hw.conf.channel = chan; | 255 | local->hw.conf.channel = chan; |
213 | local->hw.conf.ht.channel_type = channel_type; | 256 | 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; | 257 | changed |= IEEE80211_CONF_CHANGE_CHANNEL; |
225 | } | 258 | } |
226 | 259 | ||
227 | if (!local->hw.conf.power_level) | 260 | if (local->sw_scanning) |
228 | power = chan->max_power; | 261 | power = chan->max_power; |
229 | else | 262 | else |
230 | power = min(chan->max_power, local->hw.conf.power_level); | 263 | power = local->power_constr_level ? |
264 | (chan->max_power - local->power_constr_level) : | ||
265 | chan->max_power; | ||
266 | |||
267 | if (local->user_power_level) | ||
268 | power = min(power, local->user_power_level); | ||
269 | |||
231 | if (local->hw.conf.power_level != power) { | 270 | if (local->hw.conf.power_level != power) { |
232 | changed |= IEEE80211_CONF_CHANGE_POWER; | 271 | changed |= IEEE80211_CONF_CHANGE_POWER; |
233 | local->hw.conf.power_level = power; | 272 | local->hw.conf.power_level = power; |
@@ -667,7 +706,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
667 | const struct ieee80211_ops *ops) | 706 | const struct ieee80211_ops *ops) |
668 | { | 707 | { |
669 | struct ieee80211_local *local; | 708 | struct ieee80211_local *local; |
670 | int priv_size; | 709 | int priv_size, i; |
671 | struct wiphy *wiphy; | 710 | struct wiphy *wiphy; |
672 | 711 | ||
673 | /* Ensure 32-byte alignment of our private data and hw private data. | 712 | /* Ensure 32-byte alignment of our private data and hw private data. |
@@ -695,6 +734,10 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
695 | return NULL; | 734 | return NULL; |
696 | 735 | ||
697 | wiphy->privid = mac80211_wiphy_privid; | 736 | wiphy->privid = mac80211_wiphy_privid; |
737 | wiphy->max_scan_ssids = 4; | ||
738 | /* Yes, putting cfg80211_bss into ieee80211_bss is a hack */ | ||
739 | wiphy->bss_priv_size = sizeof(struct ieee80211_bss) - | ||
740 | sizeof(struct cfg80211_bss); | ||
698 | 741 | ||
699 | local = wiphy_priv(wiphy); | 742 | local = wiphy_priv(wiphy); |
700 | local->hw.wiphy = wiphy; | 743 | local->hw.wiphy = wiphy; |
@@ -722,6 +765,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
722 | local->hw.conf.radio_enabled = true; | 765 | local->hw.conf.radio_enabled = true; |
723 | 766 | ||
724 | INIT_LIST_HEAD(&local->interfaces); | 767 | INIT_LIST_HEAD(&local->interfaces); |
768 | mutex_init(&local->iflist_mtx); | ||
725 | 769 | ||
726 | spin_lock_init(&local->key_lock); | 770 | spin_lock_init(&local->key_lock); |
727 | 771 | ||
@@ -736,6 +780,11 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
736 | setup_timer(&local->dynamic_ps_timer, | 780 | setup_timer(&local->dynamic_ps_timer, |
737 | ieee80211_dynamic_ps_timer, (unsigned long) local); | 781 | ieee80211_dynamic_ps_timer, (unsigned long) local); |
738 | 782 | ||
783 | for (i = 0; i < IEEE80211_MAX_AMPDU_QUEUES; i++) | ||
784 | local->ampdu_ac_queue[i] = -1; | ||
785 | /* using an s8 won't work with more than that */ | ||
786 | BUILD_BUG_ON(IEEE80211_MAX_AMPDU_QUEUES > 127); | ||
787 | |||
739 | sta_info_init(local); | 788 | sta_info_init(local); |
740 | 789 | ||
741 | tasklet_init(&local->tx_pending_tasklet, ieee80211_tx_pending, | 790 | tasklet_init(&local->tx_pending_tasklet, ieee80211_tx_pending, |
@@ -754,6 +803,23 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
754 | } | 803 | } |
755 | EXPORT_SYMBOL(ieee80211_alloc_hw); | 804 | EXPORT_SYMBOL(ieee80211_alloc_hw); |
756 | 805 | ||
806 | static const struct net_device_ops ieee80211_master_ops = { | ||
807 | .ndo_start_xmit = ieee80211_master_start_xmit, | ||
808 | .ndo_open = ieee80211_master_open, | ||
809 | .ndo_stop = ieee80211_master_stop, | ||
810 | .ndo_set_multicast_list = ieee80211_master_set_multicast_list, | ||
811 | .ndo_select_queue = ieee80211_select_queue, | ||
812 | }; | ||
813 | |||
814 | static void ieee80211_master_setup(struct net_device *mdev) | ||
815 | { | ||
816 | mdev->type = ARPHRD_IEEE80211; | ||
817 | mdev->netdev_ops = &ieee80211_master_ops; | ||
818 | mdev->header_ops = &ieee80211_header_ops; | ||
819 | mdev->tx_queue_len = 1000; | ||
820 | mdev->addr_len = ETH_ALEN; | ||
821 | } | ||
822 | |||
757 | int ieee80211_register_hw(struct ieee80211_hw *hw) | 823 | int ieee80211_register_hw(struct ieee80211_hw *hw) |
758 | { | 824 | { |
759 | struct ieee80211_local *local = hw_to_local(hw); | 825 | struct ieee80211_local *local = hw_to_local(hw); |
@@ -761,25 +827,33 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
761 | enum ieee80211_band band; | 827 | enum ieee80211_band band; |
762 | struct net_device *mdev; | 828 | struct net_device *mdev; |
763 | struct ieee80211_master_priv *mpriv; | 829 | struct ieee80211_master_priv *mpriv; |
830 | int channels, i, j; | ||
764 | 831 | ||
765 | /* | 832 | /* |
766 | * generic code guarantees at least one band, | 833 | * generic code guarantees at least one band, |
767 | * set this very early because much code assumes | 834 | * set this very early because much code assumes |
768 | * that hw.conf.channel is assigned | 835 | * that hw.conf.channel is assigned |
769 | */ | 836 | */ |
837 | channels = 0; | ||
770 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) { | 838 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) { |
771 | struct ieee80211_supported_band *sband; | 839 | struct ieee80211_supported_band *sband; |
772 | 840 | ||
773 | sband = local->hw.wiphy->bands[band]; | 841 | sband = local->hw.wiphy->bands[band]; |
774 | if (sband) { | 842 | if (sband && !local->oper_channel) { |
775 | /* init channel we're on */ | 843 | /* init channel we're on */ |
776 | local->hw.conf.channel = | 844 | local->hw.conf.channel = |
777 | local->oper_channel = | 845 | local->oper_channel = |
778 | local->scan_channel = &sband->channels[0]; | 846 | local->scan_channel = &sband->channels[0]; |
779 | break; | ||
780 | } | 847 | } |
848 | if (sband) | ||
849 | channels += sband->n_channels; | ||
781 | } | 850 | } |
782 | 851 | ||
852 | local->int_scan_req.n_channels = channels; | ||
853 | local->int_scan_req.channels = kzalloc(sizeof(void *) * channels, GFP_KERNEL); | ||
854 | if (!local->int_scan_req.channels) | ||
855 | return -ENOMEM; | ||
856 | |||
783 | /* if low-level driver supports AP, we also support VLAN */ | 857 | /* if low-level driver supports AP, we also support VLAN */ |
784 | if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_AP)) | 858 | if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_AP)) |
785 | local->hw.wiphy->interface_modes |= BIT(NL80211_IFTYPE_AP_VLAN); | 859 | local->hw.wiphy->interface_modes |= BIT(NL80211_IFTYPE_AP_VLAN); |
@@ -787,9 +861,14 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
787 | /* mac80211 always supports monitor */ | 861 | /* mac80211 always supports monitor */ |
788 | local->hw.wiphy->interface_modes |= BIT(NL80211_IFTYPE_MONITOR); | 862 | local->hw.wiphy->interface_modes |= BIT(NL80211_IFTYPE_MONITOR); |
789 | 863 | ||
864 | if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM) | ||
865 | local->hw.wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; | ||
866 | else if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC) | ||
867 | local->hw.wiphy->signal_type = CFG80211_SIGNAL_TYPE_UNSPEC; | ||
868 | |||
790 | result = wiphy_register(local->hw.wiphy); | 869 | result = wiphy_register(local->hw.wiphy); |
791 | if (result < 0) | 870 | if (result < 0) |
792 | return result; | 871 | goto fail_wiphy_register; |
793 | 872 | ||
794 | /* | 873 | /* |
795 | * We use the number of queues for feature tests (QoS, HT) internally | 874 | * We use the number of queues for feature tests (QoS, HT) internally |
@@ -803,8 +882,8 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
803 | hw->ampdu_queues = 0; | 882 | hw->ampdu_queues = 0; |
804 | 883 | ||
805 | mdev = alloc_netdev_mq(sizeof(struct ieee80211_master_priv), | 884 | mdev = alloc_netdev_mq(sizeof(struct ieee80211_master_priv), |
806 | "wmaster%d", ether_setup, | 885 | "wmaster%d", ieee80211_master_setup, |
807 | ieee80211_num_queues(hw)); | 886 | hw->queues); |
808 | if (!mdev) | 887 | if (!mdev) |
809 | goto fail_mdev_alloc; | 888 | goto fail_mdev_alloc; |
810 | 889 | ||
@@ -812,17 +891,8 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
812 | mpriv->local = local; | 891 | mpriv->local = local; |
813 | local->mdev = mdev; | 892 | local->mdev = mdev; |
814 | 893 | ||
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 = | 894 | local->hw.workqueue = |
825 | create_freezeable_workqueue(wiphy_name(local->hw.wiphy)); | 895 | create_singlethread_workqueue(wiphy_name(local->hw.wiphy)); |
826 | if (!local->hw.workqueue) { | 896 | if (!local->hw.workqueue) { |
827 | result = -ENOMEM; | 897 | result = -ENOMEM; |
828 | goto fail_workqueue; | 898 | goto fail_workqueue; |
@@ -846,15 +916,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
846 | 916 | ||
847 | local->hw.conf.listen_interval = local->hw.max_listen_interval; | 917 | local->hw.conf.listen_interval = local->hw.max_listen_interval; |
848 | 918 | ||
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); | 919 | result = sta_info_start(local); |
859 | if (result < 0) | 920 | if (result < 0) |
860 | goto fail_sta_info; | 921 | goto fail_sta_info; |
@@ -866,6 +927,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
866 | 927 | ||
867 | memcpy(local->mdev->dev_addr, local->hw.wiphy->perm_addr, ETH_ALEN); | 928 | memcpy(local->mdev->dev_addr, local->hw.wiphy->perm_addr, ETH_ALEN); |
868 | SET_NETDEV_DEV(local->mdev, wiphy_dev(local->hw.wiphy)); | 929 | SET_NETDEV_DEV(local->mdev, wiphy_dev(local->hw.wiphy)); |
930 | local->mdev->features |= NETIF_F_NETNS_LOCAL; | ||
869 | 931 | ||
870 | result = register_netdevice(local->mdev); | 932 | result = register_netdevice(local->mdev); |
871 | if (result < 0) | 933 | if (result < 0) |
@@ -887,8 +949,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
887 | goto fail_wep; | 949 | goto fail_wep; |
888 | } | 950 | } |
889 | 951 | ||
890 | local->mdev->select_queue = ieee80211_select_queue; | ||
891 | |||
892 | /* add one default STA interface if supported */ | 952 | /* add one default STA interface if supported */ |
893 | if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_STATION)) { | 953 | if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_STATION)) { |
894 | result = ieee80211_if_add(local, "wlan%d", NULL, | 954 | result = ieee80211_if_add(local, "wlan%d", NULL, |
@@ -902,6 +962,20 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
902 | 962 | ||
903 | ieee80211_led_init(local); | 963 | ieee80211_led_init(local); |
904 | 964 | ||
965 | /* alloc internal scan request */ | ||
966 | i = 0; | ||
967 | local->int_scan_req.ssids = &local->scan_ssid; | ||
968 | local->int_scan_req.n_ssids = 1; | ||
969 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) { | ||
970 | if (!hw->wiphy->bands[band]) | ||
971 | continue; | ||
972 | for (j = 0; j < hw->wiphy->bands[band]->n_channels; j++) { | ||
973 | local->int_scan_req.channels[i] = | ||
974 | &hw->wiphy->bands[band]->channels[j]; | ||
975 | i++; | ||
976 | } | ||
977 | } | ||
978 | |||
905 | return 0; | 979 | return 0; |
906 | 980 | ||
907 | fail_wep: | 981 | fail_wep: |
@@ -920,6 +994,8 @@ fail_workqueue: | |||
920 | free_netdev(local->mdev); | 994 | free_netdev(local->mdev); |
921 | fail_mdev_alloc: | 995 | fail_mdev_alloc: |
922 | wiphy_unregister(local->hw.wiphy); | 996 | wiphy_unregister(local->hw.wiphy); |
997 | fail_wiphy_register: | ||
998 | kfree(local->int_scan_req.channels); | ||
923 | return result; | 999 | return result; |
924 | } | 1000 | } |
925 | EXPORT_SYMBOL(ieee80211_register_hw); | 1001 | EXPORT_SYMBOL(ieee80211_register_hw); |
@@ -947,7 +1023,6 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw) | |||
947 | 1023 | ||
948 | rtnl_unlock(); | 1024 | rtnl_unlock(); |
949 | 1025 | ||
950 | ieee80211_rx_bss_list_deinit(local); | ||
951 | ieee80211_clear_tx_pending(local); | 1026 | ieee80211_clear_tx_pending(local); |
952 | sta_info_stop(local); | 1027 | sta_info_stop(local); |
953 | rate_control_deinitialize(local); | 1028 | rate_control_deinitialize(local); |
@@ -965,6 +1040,7 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw) | |||
965 | ieee80211_wep_free(local); | 1040 | ieee80211_wep_free(local); |
966 | ieee80211_led_exit(local); | 1041 | ieee80211_led_exit(local); |
967 | free_netdev(local->mdev); | 1042 | free_netdev(local->mdev); |
1043 | kfree(local->int_scan_req.channels); | ||
968 | } | 1044 | } |
969 | EXPORT_SYMBOL(ieee80211_unregister_hw); | 1045 | EXPORT_SYMBOL(ieee80211_unregister_hw); |
970 | 1046 | ||
@@ -972,6 +1048,8 @@ void ieee80211_free_hw(struct ieee80211_hw *hw) | |||
972 | { | 1048 | { |
973 | struct ieee80211_local *local = hw_to_local(hw); | 1049 | struct ieee80211_local *local = hw_to_local(hw); |
974 | 1050 | ||
1051 | mutex_destroy(&local->iflist_mtx); | ||
1052 | |||
975 | wiphy_free(local->hw.wiphy); | 1053 | wiphy_free(local->hw.wiphy); |
976 | } | 1054 | } |
977 | EXPORT_SYMBOL(ieee80211_free_hw); | 1055 | EXPORT_SYMBOL(ieee80211_free_hw); |