diff options
Diffstat (limited to 'net/mac80211/main.c')
-rw-r--r-- | net/mac80211/main.c | 175 |
1 files changed, 77 insertions, 98 deletions
diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 1b087fff93e7..1a8591b77a13 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c | |||
@@ -23,6 +23,7 @@ | |||
23 | #include <linux/inetdevice.h> | 23 | #include <linux/inetdevice.h> |
24 | #include <net/net_namespace.h> | 24 | #include <net/net_namespace.h> |
25 | #include <net/cfg80211.h> | 25 | #include <net/cfg80211.h> |
26 | #include <net/addrconf.h> | ||
26 | 27 | ||
27 | #include "ieee80211_i.h" | 28 | #include "ieee80211_i.h" |
28 | #include "driver-ops.h" | 29 | #include "driver-ops.h" |
@@ -33,8 +34,6 @@ | |||
33 | #include "cfg.h" | 34 | #include "cfg.h" |
34 | #include "debugfs.h" | 35 | #include "debugfs.h" |
35 | 36 | ||
36 | static struct lock_class_key ieee80211_rx_skb_queue_class; | ||
37 | |||
38 | void ieee80211_configure_filter(struct ieee80211_local *local) | 37 | void ieee80211_configure_filter(struct ieee80211_local *local) |
39 | { | 38 | { |
40 | u64 mc; | 39 | u64 mc; |
@@ -207,76 +206,10 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata, | |||
207 | u32 changed) | 206 | u32 changed) |
208 | { | 207 | { |
209 | struct ieee80211_local *local = sdata->local; | 208 | struct ieee80211_local *local = sdata->local; |
210 | static const u8 zero[ETH_ALEN] = { 0 }; | ||
211 | 209 | ||
212 | if (!changed) | 210 | if (!changed) |
213 | return; | 211 | return; |
214 | 212 | ||
215 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { | ||
216 | sdata->vif.bss_conf.bssid = sdata->u.mgd.bssid; | ||
217 | } else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) | ||
218 | sdata->vif.bss_conf.bssid = sdata->u.ibss.bssid; | ||
219 | else if (sdata->vif.type == NL80211_IFTYPE_AP) | ||
220 | sdata->vif.bss_conf.bssid = sdata->vif.addr; | ||
221 | else if (sdata->vif.type == NL80211_IFTYPE_WDS) | ||
222 | sdata->vif.bss_conf.bssid = NULL; | ||
223 | else if (ieee80211_vif_is_mesh(&sdata->vif)) { | ||
224 | sdata->vif.bss_conf.bssid = zero; | ||
225 | } else if (sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE) { | ||
226 | sdata->vif.bss_conf.bssid = sdata->vif.addr; | ||
227 | WARN_ONCE(changed & ~(BSS_CHANGED_IDLE), | ||
228 | "P2P Device BSS changed %#x", changed); | ||
229 | } else { | ||
230 | WARN_ON(1); | ||
231 | return; | ||
232 | } | ||
233 | |||
234 | switch (sdata->vif.type) { | ||
235 | case NL80211_IFTYPE_AP: | ||
236 | case NL80211_IFTYPE_ADHOC: | ||
237 | case NL80211_IFTYPE_WDS: | ||
238 | case NL80211_IFTYPE_MESH_POINT: | ||
239 | break; | ||
240 | default: | ||
241 | /* do not warn to simplify caller in scan.c */ | ||
242 | changed &= ~BSS_CHANGED_BEACON_ENABLED; | ||
243 | if (WARN_ON(changed & BSS_CHANGED_BEACON)) | ||
244 | return; | ||
245 | break; | ||
246 | } | ||
247 | |||
248 | if (changed & BSS_CHANGED_BEACON_ENABLED) { | ||
249 | if (local->quiescing || !ieee80211_sdata_running(sdata) || | ||
250 | test_bit(SDATA_STATE_OFFCHANNEL, &sdata->state)) { | ||
251 | sdata->vif.bss_conf.enable_beacon = false; | ||
252 | } else { | ||
253 | /* | ||
254 | * Beacon should be enabled, but AP mode must | ||
255 | * check whether there is a beacon configured. | ||
256 | */ | ||
257 | switch (sdata->vif.type) { | ||
258 | case NL80211_IFTYPE_AP: | ||
259 | sdata->vif.bss_conf.enable_beacon = | ||
260 | !!sdata->u.ap.beacon; | ||
261 | break; | ||
262 | case NL80211_IFTYPE_ADHOC: | ||
263 | sdata->vif.bss_conf.enable_beacon = | ||
264 | !!sdata->u.ibss.presp; | ||
265 | break; | ||
266 | #ifdef CONFIG_MAC80211_MESH | ||
267 | case NL80211_IFTYPE_MESH_POINT: | ||
268 | sdata->vif.bss_conf.enable_beacon = | ||
269 | !!sdata->u.mesh.mesh_id_len; | ||
270 | break; | ||
271 | #endif | ||
272 | default: | ||
273 | /* not reached */ | ||
274 | WARN_ON(1); | ||
275 | break; | ||
276 | } | ||
277 | } | ||
278 | } | ||
279 | |||
280 | drv_bss_info_changed(local, sdata, &sdata->vif.bss_conf, changed); | 213 | drv_bss_info_changed(local, sdata, &sdata->vif.bss_conf, changed); |
281 | } | 214 | } |
282 | 215 | ||
@@ -415,27 +348,19 @@ static int ieee80211_ifa_changed(struct notifier_block *nb, | |||
415 | 348 | ||
416 | /* Copy the addresses to the bss_conf list */ | 349 | /* Copy the addresses to the bss_conf list */ |
417 | ifa = idev->ifa_list; | 350 | ifa = idev->ifa_list; |
418 | while (c < IEEE80211_BSS_ARP_ADDR_LIST_LEN && ifa) { | 351 | while (ifa) { |
419 | bss_conf->arp_addr_list[c] = ifa->ifa_address; | 352 | if (c < IEEE80211_BSS_ARP_ADDR_LIST_LEN) |
353 | bss_conf->arp_addr_list[c] = ifa->ifa_address; | ||
420 | ifa = ifa->ifa_next; | 354 | ifa = ifa->ifa_next; |
421 | c++; | 355 | c++; |
422 | } | 356 | } |
423 | 357 | ||
424 | /* If not all addresses fit the list, disable filtering */ | ||
425 | if (ifa) { | ||
426 | sdata->arp_filter_state = false; | ||
427 | c = 0; | ||
428 | } else { | ||
429 | sdata->arp_filter_state = true; | ||
430 | } | ||
431 | bss_conf->arp_addr_cnt = c; | 358 | bss_conf->arp_addr_cnt = c; |
432 | 359 | ||
433 | /* Configure driver only if associated (which also implies it is up) */ | 360 | /* Configure driver only if associated (which also implies it is up) */ |
434 | if (ifmgd->associated) { | 361 | if (ifmgd->associated) |
435 | bss_conf->arp_filter_enabled = sdata->arp_filter_state; | ||
436 | ieee80211_bss_info_change_notify(sdata, | 362 | ieee80211_bss_info_change_notify(sdata, |
437 | BSS_CHANGED_ARP_FILTER); | 363 | BSS_CHANGED_ARP_FILTER); |
438 | } | ||
439 | 364 | ||
440 | mutex_unlock(&ifmgd->mtx); | 365 | mutex_unlock(&ifmgd->mtx); |
441 | 366 | ||
@@ -443,6 +368,37 @@ static int ieee80211_ifa_changed(struct notifier_block *nb, | |||
443 | } | 368 | } |
444 | #endif | 369 | #endif |
445 | 370 | ||
371 | #if IS_ENABLED(CONFIG_IPV6) | ||
372 | static int ieee80211_ifa6_changed(struct notifier_block *nb, | ||
373 | unsigned long data, void *arg) | ||
374 | { | ||
375 | struct inet6_ifaddr *ifa = (struct inet6_ifaddr *)arg; | ||
376 | struct inet6_dev *idev = ifa->idev; | ||
377 | struct net_device *ndev = ifa->idev->dev; | ||
378 | struct ieee80211_local *local = | ||
379 | container_of(nb, struct ieee80211_local, ifa6_notifier); | ||
380 | struct wireless_dev *wdev = ndev->ieee80211_ptr; | ||
381 | struct ieee80211_sub_if_data *sdata; | ||
382 | |||
383 | /* Make sure it's our interface that got changed */ | ||
384 | if (!wdev || wdev->wiphy != local->hw.wiphy) | ||
385 | return NOTIFY_DONE; | ||
386 | |||
387 | sdata = IEEE80211_DEV_TO_SUB_IF(ndev); | ||
388 | |||
389 | /* | ||
390 | * For now only support station mode. This is mostly because | ||
391 | * doing AP would have to handle AP_VLAN in some way ... | ||
392 | */ | ||
393 | if (sdata->vif.type != NL80211_IFTYPE_STATION) | ||
394 | return NOTIFY_DONE; | ||
395 | |||
396 | drv_ipv6_addr_change(local, sdata, idev); | ||
397 | |||
398 | return NOTIFY_DONE; | ||
399 | } | ||
400 | #endif | ||
401 | |||
446 | static int ieee80211_napi_poll(struct napi_struct *napi, int budget) | 402 | static int ieee80211_napi_poll(struct napi_struct *napi, int budget) |
447 | { | 403 | { |
448 | struct ieee80211_local *local = | 404 | struct ieee80211_local *local = |
@@ -537,6 +493,7 @@ static const struct ieee80211_ht_cap mac80211_ht_capa_mod_mask = { | |||
537 | 493 | ||
538 | .cap_info = cpu_to_le16(IEEE80211_HT_CAP_SUP_WIDTH_20_40 | | 494 | .cap_info = cpu_to_le16(IEEE80211_HT_CAP_SUP_WIDTH_20_40 | |
539 | IEEE80211_HT_CAP_MAX_AMSDU | | 495 | IEEE80211_HT_CAP_MAX_AMSDU | |
496 | IEEE80211_HT_CAP_SGI_20 | | ||
540 | IEEE80211_HT_CAP_SGI_40), | 497 | IEEE80211_HT_CAP_SGI_40), |
541 | .mcs = { | 498 | .mcs = { |
542 | .rx_mask = { 0xff, 0xff, 0xff, 0xff, 0xff, | 499 | .rx_mask = { 0xff, 0xff, 0xff, 0xff, 0xff, |
@@ -544,6 +501,11 @@ static const struct ieee80211_ht_cap mac80211_ht_capa_mod_mask = { | |||
544 | }, | 501 | }, |
545 | }; | 502 | }; |
546 | 503 | ||
504 | static const u8 extended_capabilities[] = { | ||
505 | 0, 0, 0, 0, 0, 0, 0, | ||
506 | WLAN_EXT_CAPA8_OPMODE_NOTIF, | ||
507 | }; | ||
508 | |||
547 | struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | 509 | struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, |
548 | const struct ieee80211_ops *ops) | 510 | const struct ieee80211_ops *ops) |
549 | { | 511 | { |
@@ -600,6 +562,10 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
600 | WIPHY_FLAG_REPORTS_OBSS | | 562 | WIPHY_FLAG_REPORTS_OBSS | |
601 | WIPHY_FLAG_OFFCHAN_TX; | 563 | WIPHY_FLAG_OFFCHAN_TX; |
602 | 564 | ||
565 | wiphy->extended_capabilities = extended_capabilities; | ||
566 | wiphy->extended_capabilities_mask = extended_capabilities; | ||
567 | wiphy->extended_capabilities_len = ARRAY_SIZE(extended_capabilities); | ||
568 | |||
603 | if (ops->remain_on_channel) | 569 | if (ops->remain_on_channel) |
604 | wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; | 570 | wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; |
605 | 571 | ||
@@ -653,25 +619,19 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
653 | 619 | ||
654 | mutex_init(&local->key_mtx); | 620 | mutex_init(&local->key_mtx); |
655 | spin_lock_init(&local->filter_lock); | 621 | spin_lock_init(&local->filter_lock); |
622 | spin_lock_init(&local->rx_path_lock); | ||
656 | spin_lock_init(&local->queue_stop_reason_lock); | 623 | spin_lock_init(&local->queue_stop_reason_lock); |
657 | 624 | ||
658 | INIT_LIST_HEAD(&local->chanctx_list); | 625 | INIT_LIST_HEAD(&local->chanctx_list); |
659 | mutex_init(&local->chanctx_mtx); | 626 | mutex_init(&local->chanctx_mtx); |
660 | 627 | ||
661 | /* | ||
662 | * The rx_skb_queue is only accessed from tasklets, | ||
663 | * but other SKB queues are used from within IRQ | ||
664 | * context. Therefore, this one needs a different | ||
665 | * locking class so our direct, non-irq-safe use of | ||
666 | * the queue's lock doesn't throw lockdep warnings. | ||
667 | */ | ||
668 | skb_queue_head_init_class(&local->rx_skb_queue, | ||
669 | &ieee80211_rx_skb_queue_class); | ||
670 | |||
671 | INIT_DELAYED_WORK(&local->scan_work, ieee80211_scan_work); | 628 | INIT_DELAYED_WORK(&local->scan_work, ieee80211_scan_work); |
672 | 629 | ||
673 | INIT_WORK(&local->restart_work, ieee80211_restart_work); | 630 | INIT_WORK(&local->restart_work, ieee80211_restart_work); |
674 | 631 | ||
632 | INIT_WORK(&local->radar_detected_work, | ||
633 | ieee80211_dfs_radar_detected_work); | ||
634 | |||
675 | INIT_WORK(&local->reconfig_filter, ieee80211_reconfig_filter); | 635 | INIT_WORK(&local->reconfig_filter, ieee80211_reconfig_filter); |
676 | local->smps_mode = IEEE80211_SMPS_OFF; | 636 | local->smps_mode = IEEE80211_SMPS_OFF; |
677 | 637 | ||
@@ -687,8 +647,6 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
687 | 647 | ||
688 | spin_lock_init(&local->ack_status_lock); | 648 | spin_lock_init(&local->ack_status_lock); |
689 | idr_init(&local->ack_status_frames); | 649 | idr_init(&local->ack_status_frames); |
690 | /* preallocate at least one entry */ | ||
691 | idr_pre_get(&local->ack_status_frames, GFP_KERNEL); | ||
692 | 650 | ||
693 | sta_info_init(local); | 651 | sta_info_init(local); |
694 | 652 | ||
@@ -747,9 +705,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
747 | return -EINVAL; | 705 | return -EINVAL; |
748 | #endif | 706 | #endif |
749 | 707 | ||
750 | if ((hw->flags & IEEE80211_HW_SCAN_WHILE_IDLE) && !local->ops->hw_scan) | ||
751 | return -EINVAL; | ||
752 | |||
753 | if (!local->use_chanctx) { | 708 | if (!local->use_chanctx) { |
754 | for (i = 0; i < local->hw.wiphy->n_iface_combinations; i++) { | 709 | for (i = 0; i < local->hw.wiphy->n_iface_combinations; i++) { |
755 | const struct ieee80211_iface_combination *comb; | 710 | const struct ieee80211_iface_combination *comb; |
@@ -767,6 +722,16 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
767 | */ | 722 | */ |
768 | if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_WDS)) | 723 | if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_WDS)) |
769 | return -EINVAL; | 724 | return -EINVAL; |
725 | |||
726 | /* DFS currently not supported with channel context drivers */ | ||
727 | for (i = 0; i < local->hw.wiphy->n_iface_combinations; i++) { | ||
728 | const struct ieee80211_iface_combination *comb; | ||
729 | |||
730 | comb = &local->hw.wiphy->iface_combinations[i]; | ||
731 | |||
732 | if (comb->radar_detect_widths) | ||
733 | return -EINVAL; | ||
734 | } | ||
770 | } | 735 | } |
771 | 736 | ||
772 | /* Only HW csum features are currently compatible with mac80211 */ | 737 | /* Only HW csum features are currently compatible with mac80211 */ |
@@ -1049,12 +1014,25 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
1049 | goto fail_ifa; | 1014 | goto fail_ifa; |
1050 | #endif | 1015 | #endif |
1051 | 1016 | ||
1017 | #if IS_ENABLED(CONFIG_IPV6) | ||
1018 | local->ifa6_notifier.notifier_call = ieee80211_ifa6_changed; | ||
1019 | result = register_inet6addr_notifier(&local->ifa6_notifier); | ||
1020 | if (result) | ||
1021 | goto fail_ifa6; | ||
1022 | #endif | ||
1023 | |||
1052 | netif_napi_add(&local->napi_dev, &local->napi, ieee80211_napi_poll, | 1024 | netif_napi_add(&local->napi_dev, &local->napi, ieee80211_napi_poll, |
1053 | local->hw.napi_weight); | 1025 | local->hw.napi_weight); |
1054 | 1026 | ||
1055 | return 0; | 1027 | return 0; |
1056 | 1028 | ||
1029 | #if IS_ENABLED(CONFIG_IPV6) | ||
1030 | fail_ifa6: | ||
1057 | #ifdef CONFIG_INET | 1031 | #ifdef CONFIG_INET |
1032 | unregister_inetaddr_notifier(&local->ifa_notifier); | ||
1033 | #endif | ||
1034 | #endif | ||
1035 | #if defined(CONFIG_INET) || defined(CONFIG_IPV6) | ||
1058 | fail_ifa: | 1036 | fail_ifa: |
1059 | pm_qos_remove_notifier(PM_QOS_NETWORK_LATENCY, | 1037 | pm_qos_remove_notifier(PM_QOS_NETWORK_LATENCY, |
1060 | &local->network_latency_notifier); | 1038 | &local->network_latency_notifier); |
@@ -1090,6 +1068,9 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw) | |||
1090 | #ifdef CONFIG_INET | 1068 | #ifdef CONFIG_INET |
1091 | unregister_inetaddr_notifier(&local->ifa_notifier); | 1069 | unregister_inetaddr_notifier(&local->ifa_notifier); |
1092 | #endif | 1070 | #endif |
1071 | #if IS_ENABLED(CONFIG_IPV6) | ||
1072 | unregister_inet6addr_notifier(&local->ifa6_notifier); | ||
1073 | #endif | ||
1093 | 1074 | ||
1094 | rtnl_lock(); | 1075 | rtnl_lock(); |
1095 | 1076 | ||
@@ -1113,7 +1094,6 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw) | |||
1113 | wiphy_warn(local->hw.wiphy, "skb_queue not empty\n"); | 1094 | wiphy_warn(local->hw.wiphy, "skb_queue not empty\n"); |
1114 | skb_queue_purge(&local->skb_queue); | 1095 | skb_queue_purge(&local->skb_queue); |
1115 | skb_queue_purge(&local->skb_queue_unreliable); | 1096 | skb_queue_purge(&local->skb_queue_unreliable); |
1116 | skb_queue_purge(&local->rx_skb_queue); | ||
1117 | 1097 | ||
1118 | destroy_workqueue(local->workqueue); | 1098 | destroy_workqueue(local->workqueue); |
1119 | wiphy_unregister(local->hw.wiphy); | 1099 | wiphy_unregister(local->hw.wiphy); |
@@ -1191,8 +1171,7 @@ static void __exit ieee80211_exit(void) | |||
1191 | rc80211_minstrel_ht_exit(); | 1171 | rc80211_minstrel_ht_exit(); |
1192 | rc80211_minstrel_exit(); | 1172 | rc80211_minstrel_exit(); |
1193 | 1173 | ||
1194 | if (mesh_allocated) | 1174 | ieee80211s_stop(); |
1195 | ieee80211s_stop(); | ||
1196 | 1175 | ||
1197 | ieee80211_iface_exit(); | 1176 | ieee80211_iface_exit(); |
1198 | 1177 | ||