| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * This is the linux wireless configuration interface. |
|---|
| 3 | 4 | * |
|---|
| 4 | 5 | * Copyright 2006-2010 Johannes Berg <johannes@sipsolutions.net> |
|---|
| 5 | 6 | * Copyright 2013-2014 Intel Mobile Communications GmbH |
|---|
| 6 | 7 | * Copyright 2015-2017 Intel Deutschland GmbH |
|---|
| 8 | + * Copyright (C) 2018-2021 Intel Corporation |
|---|
| 7 | 9 | */ |
|---|
| 8 | 10 | |
|---|
| 9 | 11 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
|---|
| .. | .. |
|---|
| 140 | 142 | if (result) |
|---|
| 141 | 143 | return result; |
|---|
| 142 | 144 | |
|---|
| 143 | | - if (rdev->wiphy.debugfsdir && |
|---|
| 144 | | - !debugfs_rename(rdev->wiphy.debugfsdir->d_parent, |
|---|
| 145 | | - rdev->wiphy.debugfsdir, |
|---|
| 146 | | - rdev->wiphy.debugfsdir->d_parent, |
|---|
| 147 | | - newname)) |
|---|
| 148 | | - pr_err("failed to rename debugfs dir to %s!\n", newname); |
|---|
| 145 | + if (!IS_ERR_OR_NULL(rdev->wiphy.debugfsdir)) |
|---|
| 146 | + debugfs_rename(rdev->wiphy.debugfsdir->d_parent, |
|---|
| 147 | + rdev->wiphy.debugfsdir, |
|---|
| 148 | + rdev->wiphy.debugfsdir->d_parent, newname); |
|---|
| 149 | 149 | |
|---|
| 150 | 150 | nl80211_notify_wiphy(rdev, NL80211_CMD_NEW_WIPHY); |
|---|
| 151 | 151 | |
|---|
| .. | .. |
|---|
| 190 | 190 | return err; |
|---|
| 191 | 191 | } |
|---|
| 192 | 192 | |
|---|
| 193 | + list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) { |
|---|
| 194 | + if (!wdev->netdev) |
|---|
| 195 | + continue; |
|---|
| 196 | + nl80211_notify_iface(rdev, wdev, NL80211_CMD_DEL_INTERFACE); |
|---|
| 197 | + } |
|---|
| 198 | + nl80211_notify_wiphy(rdev, NL80211_CMD_DEL_WIPHY); |
|---|
| 199 | + |
|---|
| 193 | 200 | wiphy_net_set(&rdev->wiphy, net); |
|---|
| 194 | 201 | |
|---|
| 195 | 202 | err = device_rename(&rdev->wiphy.dev, dev_name(&rdev->wiphy.dev)); |
|---|
| 196 | 203 | WARN_ON(err); |
|---|
| 204 | + |
|---|
| 205 | + nl80211_notify_wiphy(rdev, NL80211_CMD_NEW_WIPHY); |
|---|
| 206 | + list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) { |
|---|
| 207 | + if (!wdev->netdev) |
|---|
| 208 | + continue; |
|---|
| 209 | + nl80211_notify_iface(rdev, wdev, NL80211_CMD_NEW_INTERFACE); |
|---|
| 210 | + } |
|---|
| 197 | 211 | |
|---|
| 198 | 212 | return 0; |
|---|
| 199 | 213 | } |
|---|
| .. | .. |
|---|
| 222 | 236 | rdev->opencount--; |
|---|
| 223 | 237 | |
|---|
| 224 | 238 | if (rdev->scan_req && rdev->scan_req->wdev == wdev) { |
|---|
| 225 | | - if (WARN_ON(!rdev->scan_req->notified)) |
|---|
| 239 | + if (WARN_ON(!rdev->scan_req->notified && |
|---|
| 240 | + (!rdev->int_scan_req || |
|---|
| 241 | + !rdev->int_scan_req->notified))) |
|---|
| 226 | 242 | rdev->scan_req->info.aborted = true; |
|---|
| 227 | 243 | ___cfg80211_scan_done(rdev, false); |
|---|
| 228 | 244 | } |
|---|
| .. | .. |
|---|
| 286 | 302 | return 0; |
|---|
| 287 | 303 | } |
|---|
| 288 | 304 | |
|---|
| 289 | | -static void cfg80211_rfkill_sync_work(struct work_struct *work) |
|---|
| 305 | +static void cfg80211_rfkill_block_work(struct work_struct *work) |
|---|
| 290 | 306 | { |
|---|
| 291 | 307 | struct cfg80211_registered_device *rdev; |
|---|
| 292 | 308 | |
|---|
| 293 | | - rdev = container_of(work, struct cfg80211_registered_device, rfkill_sync); |
|---|
| 294 | | - cfg80211_rfkill_set_block(rdev, rfkill_blocked(rdev->rfkill)); |
|---|
| 309 | + rdev = container_of(work, struct cfg80211_registered_device, |
|---|
| 310 | + rfkill_block); |
|---|
| 311 | + cfg80211_rfkill_set_block(rdev, true); |
|---|
| 295 | 312 | } |
|---|
| 296 | 313 | |
|---|
| 297 | 314 | static void cfg80211_event_work(struct work_struct *work) |
|---|
| .. | .. |
|---|
| 465 | 482 | INIT_LIST_HEAD(&rdev->bss_list); |
|---|
| 466 | 483 | INIT_LIST_HEAD(&rdev->sched_scan_req_list); |
|---|
| 467 | 484 | INIT_WORK(&rdev->scan_done_wk, __cfg80211_scan_done); |
|---|
| 468 | | - INIT_LIST_HEAD(&rdev->mlme_unreg); |
|---|
| 469 | | - spin_lock_init(&rdev->mlme_unreg_lock); |
|---|
| 470 | | - INIT_WORK(&rdev->mlme_unreg_wk, cfg80211_mlme_unreg_wk); |
|---|
| 471 | 485 | INIT_DELAYED_WORK(&rdev->dfs_update_channels_wk, |
|---|
| 472 | 486 | cfg80211_dfs_channels_update_work); |
|---|
| 473 | 487 | #ifdef CONFIG_CFG80211_WEXT |
|---|
| .. | .. |
|---|
| 485 | 499 | INIT_WORK(&rdev->propagate_radar_detect_wk, |
|---|
| 486 | 500 | cfg80211_propagate_radar_detect_wk); |
|---|
| 487 | 501 | INIT_WORK(&rdev->propagate_cac_done_wk, cfg80211_propagate_cac_done_wk); |
|---|
| 502 | + INIT_WORK(&rdev->mgmt_registrations_update_wk, |
|---|
| 503 | + cfg80211_mgmt_registrations_update_wk); |
|---|
| 504 | + spin_lock_init(&rdev->mgmt_registrations_lock); |
|---|
| 488 | 505 | |
|---|
| 489 | 506 | #ifdef CONFIG_CFG80211_DEFAULT_PS |
|---|
| 490 | 507 | rdev->wiphy.flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT; |
|---|
| .. | .. |
|---|
| 502 | 519 | return NULL; |
|---|
| 503 | 520 | } |
|---|
| 504 | 521 | |
|---|
| 505 | | - INIT_WORK(&rdev->rfkill_sync, cfg80211_rfkill_sync_work); |
|---|
| 522 | + INIT_WORK(&rdev->rfkill_block, cfg80211_rfkill_block_work); |
|---|
| 506 | 523 | INIT_WORK(&rdev->conn_work, cfg80211_conn_work); |
|---|
| 507 | 524 | INIT_WORK(&rdev->event_work, cfg80211_event_work); |
|---|
| 508 | 525 | |
|---|
| .. | .. |
|---|
| 664 | 681 | return -EINVAL; |
|---|
| 665 | 682 | #endif |
|---|
| 666 | 683 | |
|---|
| 684 | + if (WARN_ON(wiphy->pmsr_capa && !wiphy->pmsr_capa->ftm.supported)) |
|---|
| 685 | + return -EINVAL; |
|---|
| 686 | + |
|---|
| 687 | + if (wiphy->pmsr_capa && wiphy->pmsr_capa->ftm.supported) { |
|---|
| 688 | + if (WARN_ON(!wiphy->pmsr_capa->ftm.asap && |
|---|
| 689 | + !wiphy->pmsr_capa->ftm.non_asap)) |
|---|
| 690 | + return -EINVAL; |
|---|
| 691 | + if (WARN_ON(!wiphy->pmsr_capa->ftm.preambles || |
|---|
| 692 | + !wiphy->pmsr_capa->ftm.bandwidths)) |
|---|
| 693 | + return -EINVAL; |
|---|
| 694 | + if (WARN_ON(wiphy->pmsr_capa->ftm.preambles & |
|---|
| 695 | + ~(BIT(NL80211_PREAMBLE_LEGACY) | |
|---|
| 696 | + BIT(NL80211_PREAMBLE_HT) | |
|---|
| 697 | + BIT(NL80211_PREAMBLE_VHT) | |
|---|
| 698 | + BIT(NL80211_PREAMBLE_HE) | |
|---|
| 699 | + BIT(NL80211_PREAMBLE_DMG)))) |
|---|
| 700 | + return -EINVAL; |
|---|
| 701 | + if (WARN_ON((wiphy->pmsr_capa->ftm.trigger_based || |
|---|
| 702 | + wiphy->pmsr_capa->ftm.non_trigger_based) && |
|---|
| 703 | + !(wiphy->pmsr_capa->ftm.preambles & |
|---|
| 704 | + BIT(NL80211_PREAMBLE_HE)))) |
|---|
| 705 | + return -EINVAL; |
|---|
| 706 | + if (WARN_ON(wiphy->pmsr_capa->ftm.bandwidths & |
|---|
| 707 | + ~(BIT(NL80211_CHAN_WIDTH_20_NOHT) | |
|---|
| 708 | + BIT(NL80211_CHAN_WIDTH_20) | |
|---|
| 709 | + BIT(NL80211_CHAN_WIDTH_40) | |
|---|
| 710 | + BIT(NL80211_CHAN_WIDTH_80) | |
|---|
| 711 | + BIT(NL80211_CHAN_WIDTH_80P80) | |
|---|
| 712 | + BIT(NL80211_CHAN_WIDTH_160) | |
|---|
| 713 | + BIT(NL80211_CHAN_WIDTH_5) | |
|---|
| 714 | + BIT(NL80211_CHAN_WIDTH_10)))) |
|---|
| 715 | + return -EINVAL; |
|---|
| 716 | + } |
|---|
| 717 | + |
|---|
| 667 | 718 | /* |
|---|
| 668 | 719 | * if a wiphy has unsupported modes for regulatory channel enforcement, |
|---|
| 669 | 720 | * opt-out of enforcement checking |
|---|
| .. | .. |
|---|
| 745 | 796 | /* sanity check supported bands/channels */ |
|---|
| 746 | 797 | for (band = 0; band < NUM_NL80211_BANDS; band++) { |
|---|
| 747 | 798 | u16 types = 0; |
|---|
| 799 | + bool have_he = false; |
|---|
| 748 | 800 | |
|---|
| 749 | 801 | sband = wiphy->bands[band]; |
|---|
| 750 | 802 | if (!sband) |
|---|
| .. | .. |
|---|
| 754 | 806 | if (WARN_ON(!sband->n_channels)) |
|---|
| 755 | 807 | return -EINVAL; |
|---|
| 756 | 808 | /* |
|---|
| 757 | | - * on 60GHz band, there are no legacy rates, so |
|---|
| 809 | + * on 60GHz or sub-1Ghz band, there are no legacy rates, so |
|---|
| 758 | 810 | * n_bitrates is 0 |
|---|
| 759 | 811 | */ |
|---|
| 760 | | - if (WARN_ON(band != NL80211_BAND_60GHZ && |
|---|
| 812 | + if (WARN_ON((band != NL80211_BAND_60GHZ && |
|---|
| 813 | + band != NL80211_BAND_S1GHZ) && |
|---|
| 761 | 814 | !sband->n_bitrates)) |
|---|
| 815 | + return -EINVAL; |
|---|
| 816 | + |
|---|
| 817 | + if (WARN_ON(band == NL80211_BAND_6GHZ && |
|---|
| 818 | + (sband->ht_cap.ht_supported || |
|---|
| 819 | + sband->vht_cap.vht_supported))) |
|---|
| 762 | 820 | return -EINVAL; |
|---|
| 763 | 821 | |
|---|
| 764 | 822 | /* |
|---|
| .. | .. |
|---|
| 788 | 846 | sband->channels[i].orig_mpwr = |
|---|
| 789 | 847 | sband->channels[i].max_power; |
|---|
| 790 | 848 | sband->channels[i].band = band; |
|---|
| 849 | + |
|---|
| 850 | + if (WARN_ON(sband->channels[i].freq_offset >= 1000)) |
|---|
| 851 | + return -EINVAL; |
|---|
| 791 | 852 | } |
|---|
| 792 | 853 | |
|---|
| 793 | 854 | for (i = 0; i < sband->n_iftype_data; i++) { |
|---|
| .. | .. |
|---|
| 805 | 866 | return -EINVAL; |
|---|
| 806 | 867 | |
|---|
| 807 | 868 | types |= iftd->types_mask; |
|---|
| 869 | + |
|---|
| 870 | + if (i == 0) |
|---|
| 871 | + have_he = iftd->he_cap.has_he; |
|---|
| 872 | + else |
|---|
| 873 | + have_he = have_he && |
|---|
| 874 | + iftd->he_cap.has_he; |
|---|
| 808 | 875 | } |
|---|
| 876 | + |
|---|
| 877 | + if (WARN_ON(!have_he && band == NL80211_BAND_6GHZ)) |
|---|
| 878 | + return -EINVAL; |
|---|
| 809 | 879 | |
|---|
| 810 | 880 | have_band = true; |
|---|
| 811 | 881 | } |
|---|
| .. | .. |
|---|
| 813 | 883 | if (!have_band) { |
|---|
| 814 | 884 | WARN_ON(1); |
|---|
| 815 | 885 | return -EINVAL; |
|---|
| 886 | + } |
|---|
| 887 | + |
|---|
| 888 | + for (i = 0; i < rdev->wiphy.n_vendor_commands; i++) { |
|---|
| 889 | + /* |
|---|
| 890 | + * Validate we have a policy (can be explicitly set to |
|---|
| 891 | + * VENDOR_CMD_RAW_DATA which is non-NULL) and also that |
|---|
| 892 | + * we have at least one of doit/dumpit. |
|---|
| 893 | + */ |
|---|
| 894 | + if (WARN_ON(!rdev->wiphy.vendor_commands[i].policy)) |
|---|
| 895 | + return -EINVAL; |
|---|
| 896 | + if (WARN_ON(!rdev->wiphy.vendor_commands[i].doit && |
|---|
| 897 | + !rdev->wiphy.vendor_commands[i].dumpit)) |
|---|
| 898 | + return -EINVAL; |
|---|
| 816 | 899 | } |
|---|
| 817 | 900 | |
|---|
| 818 | 901 | #ifdef CONFIG_PM |
|---|
| .. | .. |
|---|
| 835 | 918 | return res; |
|---|
| 836 | 919 | } |
|---|
| 837 | 920 | |
|---|
| 838 | | - /* set up regulatory info */ |
|---|
| 839 | | - wiphy_regulatory_register(wiphy); |
|---|
| 840 | | - |
|---|
| 841 | 921 | list_add_rcu(&rdev->list, &cfg80211_rdev_list); |
|---|
| 842 | 922 | cfg80211_rdev_list_generation++; |
|---|
| 843 | 923 | |
|---|
| 844 | 924 | /* add to debugfs */ |
|---|
| 845 | | - rdev->wiphy.debugfsdir = |
|---|
| 846 | | - debugfs_create_dir(wiphy_name(&rdev->wiphy), |
|---|
| 847 | | - ieee80211_debugfs_dir); |
|---|
| 848 | | - if (IS_ERR(rdev->wiphy.debugfsdir)) |
|---|
| 849 | | - rdev->wiphy.debugfsdir = NULL; |
|---|
| 925 | + rdev->wiphy.debugfsdir = debugfs_create_dir(wiphy_name(&rdev->wiphy), |
|---|
| 926 | + ieee80211_debugfs_dir); |
|---|
| 850 | 927 | |
|---|
| 851 | 928 | cfg80211_debugfs_rdev_add(rdev); |
|---|
| 852 | 929 | nl80211_notify_wiphy(rdev, NL80211_CMD_NEW_WIPHY); |
|---|
| 930 | + |
|---|
| 931 | + /* set up regulatory info */ |
|---|
| 932 | + wiphy_regulatory_register(wiphy); |
|---|
| 853 | 933 | |
|---|
| 854 | 934 | if (wiphy->regulatory_flags & REGULATORY_CUSTOM_REG) { |
|---|
| 855 | 935 | struct regulatory_request request; |
|---|
| .. | .. |
|---|
| 971 | 1051 | cancel_delayed_work_sync(&rdev->dfs_update_channels_wk); |
|---|
| 972 | 1052 | flush_work(&rdev->destroy_work); |
|---|
| 973 | 1053 | flush_work(&rdev->sched_scan_stop_wk); |
|---|
| 974 | | - flush_work(&rdev->mlme_unreg_wk); |
|---|
| 975 | 1054 | flush_work(&rdev->propagate_radar_detect_wk); |
|---|
| 976 | 1055 | flush_work(&rdev->propagate_cac_done_wk); |
|---|
| 1056 | + flush_work(&rdev->mgmt_registrations_update_wk); |
|---|
| 977 | 1057 | |
|---|
| 978 | 1058 | #ifdef CONFIG_PM |
|---|
| 979 | 1059 | if (rdev->wiphy.wowlan_config && rdev->ops->set_wakeup) |
|---|
| .. | .. |
|---|
| 1009 | 1089 | struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); |
|---|
| 1010 | 1090 | |
|---|
| 1011 | 1091 | if (rfkill_set_hw_state(rdev->rfkill, blocked)) |
|---|
| 1012 | | - schedule_work(&rdev->rfkill_sync); |
|---|
| 1092 | + schedule_work(&rdev->rfkill_block); |
|---|
| 1013 | 1093 | } |
|---|
| 1014 | 1094 | EXPORT_SYMBOL(wiphy_rfkill_set_hw_state); |
|---|
| 1015 | 1095 | |
|---|
| .. | .. |
|---|
| 1019 | 1099 | wdev->cqm_config = NULL; |
|---|
| 1020 | 1100 | } |
|---|
| 1021 | 1101 | |
|---|
| 1022 | | -void cfg80211_unregister_wdev(struct wireless_dev *wdev) |
|---|
| 1102 | +static void __cfg80211_unregister_wdev(struct wireless_dev *wdev, bool sync) |
|---|
| 1023 | 1103 | { |
|---|
| 1024 | 1104 | struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); |
|---|
| 1025 | 1105 | |
|---|
| 1026 | 1106 | ASSERT_RTNL(); |
|---|
| 1027 | 1107 | |
|---|
| 1028 | | - if (WARN_ON(wdev->netdev)) |
|---|
| 1029 | | - return; |
|---|
| 1108 | + flush_work(&wdev->pmsr_free_wk); |
|---|
| 1030 | 1109 | |
|---|
| 1031 | 1110 | nl80211_notify_iface(rdev, wdev, NL80211_CMD_DEL_INTERFACE); |
|---|
| 1032 | 1111 | |
|---|
| 1033 | 1112 | list_del_rcu(&wdev->list); |
|---|
| 1034 | | - synchronize_rcu(); |
|---|
| 1113 | + if (sync) |
|---|
| 1114 | + synchronize_rcu(); |
|---|
| 1035 | 1115 | rdev->devlist_generation++; |
|---|
| 1116 | + |
|---|
| 1117 | + cfg80211_mlme_purge_registrations(wdev); |
|---|
| 1036 | 1118 | |
|---|
| 1037 | 1119 | switch (wdev->iftype) { |
|---|
| 1038 | 1120 | case NL80211_IFTYPE_P2P_DEVICE: |
|---|
| 1039 | | - cfg80211_mlme_purge_registrations(wdev); |
|---|
| 1040 | 1121 | cfg80211_stop_p2p_device(rdev, wdev); |
|---|
| 1041 | 1122 | break; |
|---|
| 1042 | 1123 | case NL80211_IFTYPE_NAN: |
|---|
| 1043 | 1124 | cfg80211_stop_nan(rdev, wdev); |
|---|
| 1044 | 1125 | break; |
|---|
| 1045 | 1126 | default: |
|---|
| 1046 | | - WARN_ON_ONCE(1); |
|---|
| 1047 | 1127 | break; |
|---|
| 1048 | 1128 | } |
|---|
| 1049 | 1129 | |
|---|
| 1130 | +#ifdef CONFIG_CFG80211_WEXT |
|---|
| 1131 | + kfree_sensitive(wdev->wext.keys); |
|---|
| 1132 | + wdev->wext.keys = NULL; |
|---|
| 1133 | +#endif |
|---|
| 1134 | + /* only initialized if we have a netdev */ |
|---|
| 1135 | + if (wdev->netdev) |
|---|
| 1136 | + flush_work(&wdev->disconnect_wk); |
|---|
| 1137 | + |
|---|
| 1050 | 1138 | cfg80211_cqm_config_free(wdev); |
|---|
| 1139 | +} |
|---|
| 1140 | + |
|---|
| 1141 | +void cfg80211_unregister_wdev(struct wireless_dev *wdev) |
|---|
| 1142 | +{ |
|---|
| 1143 | + if (WARN_ON(wdev->netdev)) |
|---|
| 1144 | + return; |
|---|
| 1145 | + |
|---|
| 1146 | + __cfg80211_unregister_wdev(wdev, true); |
|---|
| 1051 | 1147 | } |
|---|
| 1052 | 1148 | EXPORT_SYMBOL(cfg80211_unregister_wdev); |
|---|
| 1053 | 1149 | |
|---|
| .. | .. |
|---|
| 1073 | 1169 | |
|---|
| 1074 | 1170 | ASSERT_RTNL(); |
|---|
| 1075 | 1171 | ASSERT_WDEV_LOCK(wdev); |
|---|
| 1172 | + |
|---|
| 1173 | + cfg80211_pmsr_wdev_down(wdev); |
|---|
| 1076 | 1174 | |
|---|
| 1077 | 1175 | switch (wdev->iftype) { |
|---|
| 1078 | 1176 | case NL80211_IFTYPE_ADHOC: |
|---|
| .. | .. |
|---|
| 1153 | 1251 | } |
|---|
| 1154 | 1252 | EXPORT_SYMBOL(cfg80211_stop_iface); |
|---|
| 1155 | 1253 | |
|---|
| 1254 | +void cfg80211_init_wdev(struct wireless_dev *wdev) |
|---|
| 1255 | +{ |
|---|
| 1256 | + mutex_init(&wdev->mtx); |
|---|
| 1257 | + INIT_LIST_HEAD(&wdev->event_list); |
|---|
| 1258 | + spin_lock_init(&wdev->event_lock); |
|---|
| 1259 | + INIT_LIST_HEAD(&wdev->mgmt_registrations); |
|---|
| 1260 | + INIT_LIST_HEAD(&wdev->pmsr_list); |
|---|
| 1261 | + spin_lock_init(&wdev->pmsr_lock); |
|---|
| 1262 | + INIT_WORK(&wdev->pmsr_free_wk, cfg80211_pmsr_free_wk); |
|---|
| 1263 | + |
|---|
| 1264 | +#ifdef CONFIG_CFG80211_WEXT |
|---|
| 1265 | + wdev->wext.default_key = -1; |
|---|
| 1266 | + wdev->wext.default_mgmt_key = -1; |
|---|
| 1267 | + wdev->wext.connect.auth_type = NL80211_AUTHTYPE_AUTOMATIC; |
|---|
| 1268 | +#endif |
|---|
| 1269 | + |
|---|
| 1270 | + if (wdev->wiphy->flags & WIPHY_FLAG_PS_ON_BY_DEFAULT) |
|---|
| 1271 | + wdev->ps = true; |
|---|
| 1272 | + else |
|---|
| 1273 | + wdev->ps = false; |
|---|
| 1274 | + /* allow mac80211 to determine the timeout */ |
|---|
| 1275 | + wdev->ps_timeout = -1; |
|---|
| 1276 | + |
|---|
| 1277 | + if ((wdev->iftype == NL80211_IFTYPE_STATION || |
|---|
| 1278 | + wdev->iftype == NL80211_IFTYPE_P2P_CLIENT || |
|---|
| 1279 | + wdev->iftype == NL80211_IFTYPE_ADHOC) && !wdev->use_4addr) |
|---|
| 1280 | + wdev->netdev->priv_flags |= IFF_DONT_BRIDGE; |
|---|
| 1281 | + |
|---|
| 1282 | + INIT_WORK(&wdev->disconnect_wk, cfg80211_autodisconnect_wk); |
|---|
| 1283 | +} |
|---|
| 1284 | + |
|---|
| 1285 | +void cfg80211_register_wdev(struct cfg80211_registered_device *rdev, |
|---|
| 1286 | + struct wireless_dev *wdev) |
|---|
| 1287 | +{ |
|---|
| 1288 | + /* |
|---|
| 1289 | + * We get here also when the interface changes network namespaces, |
|---|
| 1290 | + * as it's registered into the new one, but we don't want it to |
|---|
| 1291 | + * change ID in that case. Checking if the ID is already assigned |
|---|
| 1292 | + * works, because 0 isn't considered a valid ID and the memory is |
|---|
| 1293 | + * 0-initialized. |
|---|
| 1294 | + */ |
|---|
| 1295 | + if (!wdev->identifier) |
|---|
| 1296 | + wdev->identifier = ++rdev->wdev_id; |
|---|
| 1297 | + list_add_rcu(&wdev->list, &rdev->wiphy.wdev_list); |
|---|
| 1298 | + rdev->devlist_generation++; |
|---|
| 1299 | + |
|---|
| 1300 | + nl80211_notify_iface(rdev, wdev, NL80211_CMD_NEW_INTERFACE); |
|---|
| 1301 | +} |
|---|
| 1302 | + |
|---|
| 1156 | 1303 | static int cfg80211_netdev_notifier_call(struct notifier_block *nb, |
|---|
| 1157 | 1304 | unsigned long state, void *ptr) |
|---|
| 1158 | 1305 | { |
|---|
| .. | .. |
|---|
| 1171 | 1318 | switch (state) { |
|---|
| 1172 | 1319 | case NETDEV_POST_INIT: |
|---|
| 1173 | 1320 | SET_NETDEV_DEVTYPE(dev, &wiphy_type); |
|---|
| 1321 | + wdev->netdev = dev; |
|---|
| 1322 | + /* can only change netns with wiphy */ |
|---|
| 1323 | + dev->features |= NETIF_F_NETNS_LOCAL; |
|---|
| 1324 | + |
|---|
| 1325 | + cfg80211_init_wdev(wdev); |
|---|
| 1174 | 1326 | break; |
|---|
| 1175 | 1327 | case NETDEV_REGISTER: |
|---|
| 1176 | 1328 | /* |
|---|
| .. | .. |
|---|
| 1178 | 1330 | * called within code protected by it when interfaces |
|---|
| 1179 | 1331 | * are added with nl80211. |
|---|
| 1180 | 1332 | */ |
|---|
| 1181 | | - mutex_init(&wdev->mtx); |
|---|
| 1182 | | - INIT_LIST_HEAD(&wdev->event_list); |
|---|
| 1183 | | - spin_lock_init(&wdev->event_lock); |
|---|
| 1184 | | - INIT_LIST_HEAD(&wdev->mgmt_registrations); |
|---|
| 1185 | | - spin_lock_init(&wdev->mgmt_registrations_lock); |
|---|
| 1186 | | - |
|---|
| 1187 | | - /* |
|---|
| 1188 | | - * We get here also when the interface changes network namespaces, |
|---|
| 1189 | | - * as it's registered into the new one, but we don't want it to |
|---|
| 1190 | | - * change ID in that case. Checking if the ID is already assigned |
|---|
| 1191 | | - * works, because 0 isn't considered a valid ID and the memory is |
|---|
| 1192 | | - * 0-initialized. |
|---|
| 1193 | | - */ |
|---|
| 1194 | | - if (!wdev->identifier) |
|---|
| 1195 | | - wdev->identifier = ++rdev->wdev_id; |
|---|
| 1196 | | - list_add_rcu(&wdev->list, &rdev->wiphy.wdev_list); |
|---|
| 1197 | | - rdev->devlist_generation++; |
|---|
| 1198 | | - /* can only change netns with wiphy */ |
|---|
| 1199 | | - dev->features |= NETIF_F_NETNS_LOCAL; |
|---|
| 1200 | | - |
|---|
| 1201 | 1333 | if (sysfs_create_link(&dev->dev.kobj, &rdev->wiphy.dev.kobj, |
|---|
| 1202 | 1334 | "phy80211")) { |
|---|
| 1203 | 1335 | pr_err("failed to add phy80211 symlink to netdev!\n"); |
|---|
| 1204 | 1336 | } |
|---|
| 1205 | | - wdev->netdev = dev; |
|---|
| 1206 | | -#ifdef CONFIG_CFG80211_WEXT |
|---|
| 1207 | | - wdev->wext.default_key = -1; |
|---|
| 1208 | | - wdev->wext.default_mgmt_key = -1; |
|---|
| 1209 | | - wdev->wext.connect.auth_type = NL80211_AUTHTYPE_AUTOMATIC; |
|---|
| 1210 | | -#endif |
|---|
| 1211 | 1337 | |
|---|
| 1212 | | - if (wdev->wiphy->flags & WIPHY_FLAG_PS_ON_BY_DEFAULT) |
|---|
| 1213 | | - wdev->ps = true; |
|---|
| 1214 | | - else |
|---|
| 1215 | | - wdev->ps = false; |
|---|
| 1216 | | - /* allow mac80211 to determine the timeout */ |
|---|
| 1217 | | - wdev->ps_timeout = -1; |
|---|
| 1218 | | - |
|---|
| 1219 | | - if ((wdev->iftype == NL80211_IFTYPE_STATION || |
|---|
| 1220 | | - wdev->iftype == NL80211_IFTYPE_P2P_CLIENT || |
|---|
| 1221 | | - wdev->iftype == NL80211_IFTYPE_ADHOC) && !wdev->use_4addr) |
|---|
| 1222 | | - dev->priv_flags |= IFF_DONT_BRIDGE; |
|---|
| 1223 | | - |
|---|
| 1224 | | - INIT_WORK(&wdev->disconnect_wk, cfg80211_autodisconnect_wk); |
|---|
| 1225 | | - |
|---|
| 1226 | | - nl80211_notify_iface(rdev, wdev, NL80211_CMD_NEW_INTERFACE); |
|---|
| 1338 | + cfg80211_register_wdev(rdev, wdev); |
|---|
| 1227 | 1339 | break; |
|---|
| 1228 | 1340 | case NETDEV_GOING_DOWN: |
|---|
| 1229 | 1341 | cfg80211_leave(rdev, wdev); |
|---|
| .. | .. |
|---|
| 1231 | 1343 | case NETDEV_DOWN: |
|---|
| 1232 | 1344 | cfg80211_update_iface_num(rdev, wdev->iftype, -1); |
|---|
| 1233 | 1345 | if (rdev->scan_req && rdev->scan_req->wdev == wdev) { |
|---|
| 1234 | | - if (WARN_ON(!rdev->scan_req->notified)) |
|---|
| 1346 | + if (WARN_ON(!rdev->scan_req->notified && |
|---|
| 1347 | + (!rdev->int_scan_req || |
|---|
| 1348 | + !rdev->int_scan_req->notified))) |
|---|
| 1235 | 1349 | rdev->scan_req->info.aborted = true; |
|---|
| 1236 | 1350 | ___cfg80211_scan_done(rdev, false); |
|---|
| 1237 | 1351 | } |
|---|
| 1238 | 1352 | |
|---|
| 1239 | 1353 | list_for_each_entry_safe(pos, tmp, |
|---|
| 1240 | 1354 | &rdev->sched_scan_req_list, list) { |
|---|
| 1241 | | - if (WARN_ON(pos && pos->dev == wdev->netdev)) |
|---|
| 1355 | + if (WARN_ON(pos->dev == wdev->netdev)) |
|---|
| 1242 | 1356 | cfg80211_stop_sched_scan_req(rdev, pos, false); |
|---|
| 1243 | 1357 | } |
|---|
| 1244 | 1358 | |
|---|
| .. | .. |
|---|
| 1302 | 1416 | * remove and clean it up. |
|---|
| 1303 | 1417 | */ |
|---|
| 1304 | 1418 | if (!list_empty(&wdev->list)) { |
|---|
| 1305 | | - nl80211_notify_iface(rdev, wdev, |
|---|
| 1306 | | - NL80211_CMD_DEL_INTERFACE); |
|---|
| 1419 | + __cfg80211_unregister_wdev(wdev, false); |
|---|
| 1307 | 1420 | sysfs_remove_link(&dev->dev.kobj, "phy80211"); |
|---|
| 1308 | | - list_del_rcu(&wdev->list); |
|---|
| 1309 | | - rdev->devlist_generation++; |
|---|
| 1310 | | - cfg80211_mlme_purge_registrations(wdev); |
|---|
| 1311 | | -#ifdef CONFIG_CFG80211_WEXT |
|---|
| 1312 | | - kzfree(wdev->wext.keys); |
|---|
| 1313 | | -#endif |
|---|
| 1314 | | - flush_work(&wdev->disconnect_wk); |
|---|
| 1315 | | - cfg80211_cqm_config_free(wdev); |
|---|
| 1316 | 1421 | } |
|---|
| 1317 | 1422 | /* |
|---|
| 1318 | 1423 | * synchronise (so that we won't find this netdev |
|---|