diff options
author | David S. Miller <davem@davemloft.net> | 2015-01-15 19:16:56 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2015-01-15 19:16:56 -0500 |
commit | 27f097177defdd5858f03500e4b5aa8a97b1627b (patch) | |
tree | 186ea28b6f15075df1803acbab7b5a0e9f21cc31 /net/wireless | |
parent | 615612dc4e583ae5eeb8eb1ece2d3c70be72296d (diff) | |
parent | baf1b99ba169bdd3324ac9d99bc2a00c25534429 (diff) |
Merge tag 'mac80211-next-for-davem-2015-01-15' of git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next
Here's a big pile of changes for this round.
We have
* a lot of regulatory code changes to deal with the
way newer Intel devices handle this
* a change to drop packets while disconnecting from
an AP instead of trying to wait for them
* a new attempt at improving the tailroom accounting
to not kick in too much for performance reasons
* improvements in wireless link statistics
* many other small improvements and small fixes that
didn't seem necessary for 3.19 (e.g. in hwsim which
is testing only code)
Conflicts:
drivers/staging/rtl8723au/os_dep/ioctl_cfg80211.c
Minor overlapping changes.
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/wireless')
-rw-r--r-- | net/wireless/core.c | 40 | ||||
-rw-r--r-- | net/wireless/core.h | 11 | ||||
-rw-r--r-- | net/wireless/nl80211.c | 627 | ||||
-rw-r--r-- | net/wireless/nl80211.h | 16 | ||||
-rw-r--r-- | net/wireless/reg.c | 160 | ||||
-rw-r--r-- | net/wireless/reg.h | 1 | ||||
-rw-r--r-- | net/wireless/scan.c | 13 | ||||
-rw-r--r-- | net/wireless/trace.h | 31 | ||||
-rw-r--r-- | net/wireless/wext-compat.c | 10 |
9 files changed, 676 insertions, 233 deletions
diff --git a/net/wireless/core.c b/net/wireless/core.c index 53dda7728f86..456e4c38c279 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c | |||
@@ -21,6 +21,7 @@ | |||
21 | #include <linux/sched.h> | 21 | #include <linux/sched.h> |
22 | #include <net/genetlink.h> | 22 | #include <net/genetlink.h> |
23 | #include <net/cfg80211.h> | 23 | #include <net/cfg80211.h> |
24 | #include <net/rtnetlink.h> | ||
24 | #include "nl80211.h" | 25 | #include "nl80211.h" |
25 | #include "core.h" | 26 | #include "core.h" |
26 | #include "sysfs.h" | 27 | #include "sysfs.h" |
@@ -320,6 +321,20 @@ static void cfg80211_destroy_iface_wk(struct work_struct *work) | |||
320 | rtnl_unlock(); | 321 | rtnl_unlock(); |
321 | } | 322 | } |
322 | 323 | ||
324 | static void cfg80211_sched_scan_stop_wk(struct work_struct *work) | ||
325 | { | ||
326 | struct cfg80211_registered_device *rdev; | ||
327 | |||
328 | rdev = container_of(work, struct cfg80211_registered_device, | ||
329 | sched_scan_stop_wk); | ||
330 | |||
331 | rtnl_lock(); | ||
332 | |||
333 | __cfg80211_stop_sched_scan(rdev, false); | ||
334 | |||
335 | rtnl_unlock(); | ||
336 | } | ||
337 | |||
323 | /* exported functions */ | 338 | /* exported functions */ |
324 | 339 | ||
325 | struct wiphy *wiphy_new_nm(const struct cfg80211_ops *ops, int sizeof_priv, | 340 | struct wiphy *wiphy_new_nm(const struct cfg80211_ops *ops, int sizeof_priv, |
@@ -406,6 +421,7 @@ use_default_name: | |||
406 | INIT_LIST_HEAD(&rdev->destroy_list); | 421 | INIT_LIST_HEAD(&rdev->destroy_list); |
407 | spin_lock_init(&rdev->destroy_list_lock); | 422 | spin_lock_init(&rdev->destroy_list_lock); |
408 | INIT_WORK(&rdev->destroy_work, cfg80211_destroy_iface_wk); | 423 | INIT_WORK(&rdev->destroy_work, cfg80211_destroy_iface_wk); |
424 | INIT_WORK(&rdev->sched_scan_stop_wk, cfg80211_sched_scan_stop_wk); | ||
409 | 425 | ||
410 | #ifdef CONFIG_CFG80211_DEFAULT_PS | 426 | #ifdef CONFIG_CFG80211_DEFAULT_PS |
411 | rdev->wiphy.flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT; | 427 | rdev->wiphy.flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT; |
@@ -560,6 +576,14 @@ int wiphy_register(struct wiphy *wiphy) | |||
560 | BIT(NL80211_IFTYPE_MONITOR))) | 576 | BIT(NL80211_IFTYPE_MONITOR))) |
561 | wiphy->regulatory_flags |= REGULATORY_IGNORE_STALE_KICKOFF; | 577 | wiphy->regulatory_flags |= REGULATORY_IGNORE_STALE_KICKOFF; |
562 | 578 | ||
579 | if (WARN_ON((wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED) && | ||
580 | (wiphy->regulatory_flags & | ||
581 | (REGULATORY_CUSTOM_REG | | ||
582 | REGULATORY_STRICT_REG | | ||
583 | REGULATORY_COUNTRY_IE_FOLLOW_POWER | | ||
584 | REGULATORY_COUNTRY_IE_IGNORE)))) | ||
585 | return -EINVAL; | ||
586 | |||
563 | if (WARN_ON(wiphy->coalesce && | 587 | if (WARN_ON(wiphy->coalesce && |
564 | (!wiphy->coalesce->n_rules || | 588 | (!wiphy->coalesce->n_rules || |
565 | !wiphy->coalesce->n_patterns) && | 589 | !wiphy->coalesce->n_patterns) && |
@@ -778,6 +802,7 @@ void wiphy_unregister(struct wiphy *wiphy) | |||
778 | flush_work(&rdev->event_work); | 802 | flush_work(&rdev->event_work); |
779 | cancel_delayed_work_sync(&rdev->dfs_update_channels_wk); | 803 | cancel_delayed_work_sync(&rdev->dfs_update_channels_wk); |
780 | flush_work(&rdev->destroy_work); | 804 | flush_work(&rdev->destroy_work); |
805 | flush_work(&rdev->sched_scan_stop_wk); | ||
781 | 806 | ||
782 | #ifdef CONFIG_PM | 807 | #ifdef CONFIG_PM |
783 | if (rdev->wiphy.wowlan_config && rdev->ops->set_wakeup) | 808 | if (rdev->wiphy.wowlan_config && rdev->ops->set_wakeup) |
@@ -858,6 +883,7 @@ void __cfg80211_leave(struct cfg80211_registered_device *rdev, | |||
858 | struct wireless_dev *wdev) | 883 | struct wireless_dev *wdev) |
859 | { | 884 | { |
860 | struct net_device *dev = wdev->netdev; | 885 | struct net_device *dev = wdev->netdev; |
886 | struct cfg80211_sched_scan_request *sched_scan_req; | ||
861 | 887 | ||
862 | ASSERT_RTNL(); | 888 | ASSERT_RTNL(); |
863 | ASSERT_WDEV_LOCK(wdev); | 889 | ASSERT_WDEV_LOCK(wdev); |
@@ -868,7 +894,8 @@ void __cfg80211_leave(struct cfg80211_registered_device *rdev, | |||
868 | break; | 894 | break; |
869 | case NL80211_IFTYPE_P2P_CLIENT: | 895 | case NL80211_IFTYPE_P2P_CLIENT: |
870 | case NL80211_IFTYPE_STATION: | 896 | case NL80211_IFTYPE_STATION: |
871 | if (rdev->sched_scan_req && dev == rdev->sched_scan_req->dev) | 897 | sched_scan_req = rtnl_dereference(rdev->sched_scan_req); |
898 | if (sched_scan_req && dev == sched_scan_req->dev) | ||
872 | __cfg80211_stop_sched_scan(rdev, false); | 899 | __cfg80211_stop_sched_scan(rdev, false); |
873 | 900 | ||
874 | #ifdef CONFIG_CFG80211_WEXT | 901 | #ifdef CONFIG_CFG80211_WEXT |
@@ -937,12 +964,17 @@ void cfg80211_stop_iface(struct wiphy *wiphy, struct wireless_dev *wdev, | |||
937 | } | 964 | } |
938 | EXPORT_SYMBOL(cfg80211_stop_iface); | 965 | EXPORT_SYMBOL(cfg80211_stop_iface); |
939 | 966 | ||
967 | static const struct rtnl_link_ops wireless_link_ops = { | ||
968 | .kind = "wlan", | ||
969 | }; | ||
970 | |||
940 | static int cfg80211_netdev_notifier_call(struct notifier_block *nb, | 971 | static int cfg80211_netdev_notifier_call(struct notifier_block *nb, |
941 | unsigned long state, void *ptr) | 972 | unsigned long state, void *ptr) |
942 | { | 973 | { |
943 | struct net_device *dev = netdev_notifier_info_to_dev(ptr); | 974 | struct net_device *dev = netdev_notifier_info_to_dev(ptr); |
944 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 975 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
945 | struct cfg80211_registered_device *rdev; | 976 | struct cfg80211_registered_device *rdev; |
977 | struct cfg80211_sched_scan_request *sched_scan_req; | ||
946 | 978 | ||
947 | if (!wdev) | 979 | if (!wdev) |
948 | return NOTIFY_DONE; | 980 | return NOTIFY_DONE; |
@@ -954,6 +986,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb, | |||
954 | switch (state) { | 986 | switch (state) { |
955 | case NETDEV_POST_INIT: | 987 | case NETDEV_POST_INIT: |
956 | SET_NETDEV_DEVTYPE(dev, &wiphy_type); | 988 | SET_NETDEV_DEVTYPE(dev, &wiphy_type); |
989 | dev->rtnl_link_ops = &wireless_link_ops; | ||
957 | break; | 990 | break; |
958 | case NETDEV_REGISTER: | 991 | case NETDEV_REGISTER: |
959 | /* | 992 | /* |
@@ -1007,8 +1040,9 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb, | |||
1007 | ___cfg80211_scan_done(rdev, false); | 1040 | ___cfg80211_scan_done(rdev, false); |
1008 | } | 1041 | } |
1009 | 1042 | ||
1010 | if (WARN_ON(rdev->sched_scan_req && | 1043 | sched_scan_req = rtnl_dereference(rdev->sched_scan_req); |
1011 | rdev->sched_scan_req->dev == wdev->netdev)) { | 1044 | if (WARN_ON(sched_scan_req && |
1045 | sched_scan_req->dev == wdev->netdev)) { | ||
1012 | __cfg80211_stop_sched_scan(rdev, false); | 1046 | __cfg80211_stop_sched_scan(rdev, false); |
1013 | } | 1047 | } |
1014 | 1048 | ||
diff --git a/net/wireless/core.h b/net/wireless/core.h index faa5b1609aae..801cd49c5a0c 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h | |||
@@ -36,6 +36,13 @@ struct cfg80211_registered_device { | |||
36 | * the country on the country IE changed. */ | 36 | * the country on the country IE changed. */ |
37 | char country_ie_alpha2[2]; | 37 | char country_ie_alpha2[2]; |
38 | 38 | ||
39 | /* | ||
40 | * the driver requests the regulatory core to set this regulatory | ||
41 | * domain as the wiphy's. Only used for %REGULATORY_WIPHY_SELF_MANAGED | ||
42 | * devices using the regulatory_set_wiphy_regd() API | ||
43 | */ | ||
44 | const struct ieee80211_regdomain *requested_regd; | ||
45 | |||
39 | /* If a Country IE has been received this tells us the environment | 46 | /* If a Country IE has been received this tells us the environment |
40 | * which its telling us its in. This defaults to ENVIRON_ANY */ | 47 | * which its telling us its in. This defaults to ENVIRON_ANY */ |
41 | enum environment_cap env; | 48 | enum environment_cap env; |
@@ -63,7 +70,7 @@ struct cfg80211_registered_device { | |||
63 | u32 bss_generation; | 70 | u32 bss_generation; |
64 | struct cfg80211_scan_request *scan_req; /* protected by RTNL */ | 71 | struct cfg80211_scan_request *scan_req; /* protected by RTNL */ |
65 | struct sk_buff *scan_msg; | 72 | struct sk_buff *scan_msg; |
66 | struct cfg80211_sched_scan_request *sched_scan_req; | 73 | struct cfg80211_sched_scan_request __rcu *sched_scan_req; |
67 | unsigned long suspend_at; | 74 | unsigned long suspend_at; |
68 | struct work_struct scan_done_wk; | 75 | struct work_struct scan_done_wk; |
69 | struct work_struct sched_scan_results_wk; | 76 | struct work_struct sched_scan_results_wk; |
@@ -84,6 +91,8 @@ struct cfg80211_registered_device { | |||
84 | struct list_head destroy_list; | 91 | struct list_head destroy_list; |
85 | struct work_struct destroy_work; | 92 | struct work_struct destroy_work; |
86 | 93 | ||
94 | struct work_struct sched_scan_stop_wk; | ||
95 | |||
87 | /* must be last because of the way we do wiphy_priv(), | 96 | /* must be last because of the way we do wiphy_priv(), |
88 | * and it should at least be aligned to NETDEV_ALIGN */ | 97 | * and it should at least be aligned to NETDEV_ALIGN */ |
89 | struct wiphy wiphy __aligned(NETDEV_ALIGN); | 98 | struct wiphy wiphy __aligned(NETDEV_ALIGN); |
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 7ca4b5133123..380784378df8 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -59,13 +59,13 @@ enum nl80211_multicast_groups { | |||
59 | }; | 59 | }; |
60 | 60 | ||
61 | static const struct genl_multicast_group nl80211_mcgrps[] = { | 61 | static const struct genl_multicast_group nl80211_mcgrps[] = { |
62 | [NL80211_MCGRP_CONFIG] = { .name = "config", }, | 62 | [NL80211_MCGRP_CONFIG] = { .name = NL80211_MULTICAST_GROUP_CONFIG }, |
63 | [NL80211_MCGRP_SCAN] = { .name = "scan", }, | 63 | [NL80211_MCGRP_SCAN] = { .name = NL80211_MULTICAST_GROUP_SCAN }, |
64 | [NL80211_MCGRP_REGULATORY] = { .name = "regulatory", }, | 64 | [NL80211_MCGRP_REGULATORY] = { .name = NL80211_MULTICAST_GROUP_REG }, |
65 | [NL80211_MCGRP_MLME] = { .name = "mlme", }, | 65 | [NL80211_MCGRP_MLME] = { .name = NL80211_MULTICAST_GROUP_MLME }, |
66 | [NL80211_MCGRP_VENDOR] = { .name = "vendor", }, | 66 | [NL80211_MCGRP_VENDOR] = { .name = NL80211_MULTICAST_GROUP_VENDOR }, |
67 | #ifdef CONFIG_NL80211_TESTMODE | 67 | #ifdef CONFIG_NL80211_TESTMODE |
68 | [NL80211_MCGRP_TESTMODE] = { .name = "testmode", } | 68 | [NL80211_MCGRP_TESTMODE] = { .name = NL80211_MULTICAST_GROUP_TESTMODE } |
69 | #endif | 69 | #endif |
70 | }; | 70 | }; |
71 | 71 | ||
@@ -396,6 +396,7 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = { | |||
396 | [NL80211_ATTR_ADMITTED_TIME] = { .type = NLA_U16 }, | 396 | [NL80211_ATTR_ADMITTED_TIME] = { .type = NLA_U16 }, |
397 | [NL80211_ATTR_SMPS_MODE] = { .type = NLA_U8 }, | 397 | [NL80211_ATTR_SMPS_MODE] = { .type = NLA_U8 }, |
398 | [NL80211_ATTR_MAC_MASK] = { .len = ETH_ALEN }, | 398 | [NL80211_ATTR_MAC_MASK] = { .len = ETH_ALEN }, |
399 | [NL80211_ATTR_WIPHY_SELF_MANAGED_REG] = { .type = NLA_FLAG }, | ||
399 | }; | 400 | }; |
400 | 401 | ||
401 | /* policy for the key attributes */ | 402 | /* policy for the key attributes */ |
@@ -1087,6 +1088,11 @@ static int nl80211_send_wowlan(struct sk_buff *msg, | |||
1087 | return -ENOBUFS; | 1088 | return -ENOBUFS; |
1088 | } | 1089 | } |
1089 | 1090 | ||
1091 | if ((rdev->wiphy.wowlan->flags & WIPHY_WOWLAN_NET_DETECT) && | ||
1092 | nla_put_u32(msg, NL80211_WOWLAN_TRIG_NET_DETECT, | ||
1093 | rdev->wiphy.wowlan->max_nd_match_sets)) | ||
1094 | return -ENOBUFS; | ||
1095 | |||
1090 | if (large && nl80211_send_wowlan_tcp_caps(rdev, msg)) | 1096 | if (large && nl80211_send_wowlan_tcp_caps(rdev, msg)) |
1091 | return -ENOBUFS; | 1097 | return -ENOBUFS; |
1092 | 1098 | ||
@@ -1701,6 +1707,15 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev, | |||
1701 | rdev->wiphy.max_num_csa_counters)) | 1707 | rdev->wiphy.max_num_csa_counters)) |
1702 | goto nla_put_failure; | 1708 | goto nla_put_failure; |
1703 | 1709 | ||
1710 | if (rdev->wiphy.regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED && | ||
1711 | nla_put_flag(msg, NL80211_ATTR_WIPHY_SELF_MANAGED_REG)) | ||
1712 | goto nla_put_failure; | ||
1713 | |||
1714 | if (nla_put(msg, NL80211_ATTR_EXT_FEATURES, | ||
1715 | sizeof(rdev->wiphy.ext_features), | ||
1716 | rdev->wiphy.ext_features)) | ||
1717 | goto nla_put_failure; | ||
1718 | |||
1704 | /* done */ | 1719 | /* done */ |
1705 | state->split_start = 0; | 1720 | state->split_start = 0; |
1706 | break; | 1721 | break; |
@@ -3640,8 +3655,8 @@ static bool nl80211_put_signal(struct sk_buff *msg, u8 mask, s8 *signal, | |||
3640 | return true; | 3655 | return true; |
3641 | } | 3656 | } |
3642 | 3657 | ||
3643 | static int nl80211_send_station(struct sk_buff *msg, u32 portid, u32 seq, | 3658 | static int nl80211_send_station(struct sk_buff *msg, u32 cmd, u32 portid, |
3644 | int flags, | 3659 | u32 seq, int flags, |
3645 | struct cfg80211_registered_device *rdev, | 3660 | struct cfg80211_registered_device *rdev, |
3646 | struct net_device *dev, | 3661 | struct net_device *dev, |
3647 | const u8 *mac_addr, struct station_info *sinfo) | 3662 | const u8 *mac_addr, struct station_info *sinfo) |
@@ -3649,7 +3664,7 @@ static int nl80211_send_station(struct sk_buff *msg, u32 portid, u32 seq, | |||
3649 | void *hdr; | 3664 | void *hdr; |
3650 | struct nlattr *sinfoattr, *bss_param; | 3665 | struct nlattr *sinfoattr, *bss_param; |
3651 | 3666 | ||
3652 | hdr = nl80211hdr_put(msg, portid, seq, flags, NL80211_CMD_NEW_STATION); | 3667 | hdr = nl80211hdr_put(msg, portid, seq, flags, cmd); |
3653 | if (!hdr) | 3668 | if (!hdr) |
3654 | return -1; | 3669 | return -1; |
3655 | 3670 | ||
@@ -3661,115 +3676,77 @@ static int nl80211_send_station(struct sk_buff *msg, u32 portid, u32 seq, | |||
3661 | sinfoattr = nla_nest_start(msg, NL80211_ATTR_STA_INFO); | 3676 | sinfoattr = nla_nest_start(msg, NL80211_ATTR_STA_INFO); |
3662 | if (!sinfoattr) | 3677 | if (!sinfoattr) |
3663 | goto nla_put_failure; | 3678 | goto nla_put_failure; |
3664 | if ((sinfo->filled & STATION_INFO_CONNECTED_TIME) && | 3679 | |
3665 | nla_put_u32(msg, NL80211_STA_INFO_CONNECTED_TIME, | 3680 | #define PUT_SINFO(attr, memb, type) do { \ |
3666 | sinfo->connected_time)) | 3681 | if (sinfo->filled & BIT(NL80211_STA_INFO_ ## attr) && \ |
3667 | goto nla_put_failure; | 3682 | nla_put_ ## type(msg, NL80211_STA_INFO_ ## attr, \ |
3668 | if ((sinfo->filled & STATION_INFO_INACTIVE_TIME) && | 3683 | sinfo->memb)) \ |
3669 | nla_put_u32(msg, NL80211_STA_INFO_INACTIVE_TIME, | 3684 | goto nla_put_failure; \ |
3670 | sinfo->inactive_time)) | 3685 | } while (0) |
3671 | goto nla_put_failure; | 3686 | |
3672 | if ((sinfo->filled & (STATION_INFO_RX_BYTES | | 3687 | PUT_SINFO(CONNECTED_TIME, connected_time, u32); |
3673 | STATION_INFO_RX_BYTES64)) && | 3688 | PUT_SINFO(INACTIVE_TIME, inactive_time, u32); |
3689 | |||
3690 | if (sinfo->filled & (BIT(NL80211_STA_INFO_RX_BYTES) | | ||
3691 | BIT(NL80211_STA_INFO_RX_BYTES64)) && | ||
3674 | nla_put_u32(msg, NL80211_STA_INFO_RX_BYTES, | 3692 | nla_put_u32(msg, NL80211_STA_INFO_RX_BYTES, |
3675 | (u32)sinfo->rx_bytes)) | 3693 | (u32)sinfo->rx_bytes)) |
3676 | goto nla_put_failure; | 3694 | goto nla_put_failure; |
3677 | if ((sinfo->filled & (STATION_INFO_TX_BYTES | | 3695 | |
3678 | STATION_INFO_TX_BYTES64)) && | 3696 | if (sinfo->filled & (BIT(NL80211_STA_INFO_TX_BYTES) | |
3697 | BIT(NL80211_STA_INFO_TX_BYTES64)) && | ||
3679 | nla_put_u32(msg, NL80211_STA_INFO_TX_BYTES, | 3698 | nla_put_u32(msg, NL80211_STA_INFO_TX_BYTES, |
3680 | (u32)sinfo->tx_bytes)) | 3699 | (u32)sinfo->tx_bytes)) |
3681 | goto nla_put_failure; | 3700 | goto nla_put_failure; |
3682 | if ((sinfo->filled & STATION_INFO_RX_BYTES64) && | 3701 | |
3683 | nla_put_u64(msg, NL80211_STA_INFO_RX_BYTES64, | 3702 | PUT_SINFO(RX_BYTES64, rx_bytes, u64); |
3684 | sinfo->rx_bytes)) | 3703 | PUT_SINFO(TX_BYTES64, tx_bytes, u64); |
3685 | goto nla_put_failure; | 3704 | PUT_SINFO(LLID, llid, u16); |
3686 | if ((sinfo->filled & STATION_INFO_TX_BYTES64) && | 3705 | PUT_SINFO(PLID, plid, u16); |
3687 | nla_put_u64(msg, NL80211_STA_INFO_TX_BYTES64, | 3706 | PUT_SINFO(PLINK_STATE, plink_state, u8); |
3688 | sinfo->tx_bytes)) | 3707 | |
3689 | goto nla_put_failure; | ||
3690 | if ((sinfo->filled & STATION_INFO_LLID) && | ||
3691 | nla_put_u16(msg, NL80211_STA_INFO_LLID, sinfo->llid)) | ||
3692 | goto nla_put_failure; | ||
3693 | if ((sinfo->filled & STATION_INFO_PLID) && | ||
3694 | nla_put_u16(msg, NL80211_STA_INFO_PLID, sinfo->plid)) | ||
3695 | goto nla_put_failure; | ||
3696 | if ((sinfo->filled & STATION_INFO_PLINK_STATE) && | ||
3697 | nla_put_u8(msg, NL80211_STA_INFO_PLINK_STATE, | ||
3698 | sinfo->plink_state)) | ||
3699 | goto nla_put_failure; | ||
3700 | switch (rdev->wiphy.signal_type) { | 3708 | switch (rdev->wiphy.signal_type) { |
3701 | case CFG80211_SIGNAL_TYPE_MBM: | 3709 | case CFG80211_SIGNAL_TYPE_MBM: |
3702 | if ((sinfo->filled & STATION_INFO_SIGNAL) && | 3710 | PUT_SINFO(SIGNAL, signal, u8); |
3703 | nla_put_u8(msg, NL80211_STA_INFO_SIGNAL, | 3711 | PUT_SINFO(SIGNAL_AVG, signal_avg, u8); |
3704 | sinfo->signal)) | ||
3705 | goto nla_put_failure; | ||
3706 | if ((sinfo->filled & STATION_INFO_SIGNAL_AVG) && | ||
3707 | nla_put_u8(msg, NL80211_STA_INFO_SIGNAL_AVG, | ||
3708 | sinfo->signal_avg)) | ||
3709 | goto nla_put_failure; | ||
3710 | break; | 3712 | break; |
3711 | default: | 3713 | default: |
3712 | break; | 3714 | break; |
3713 | } | 3715 | } |
3714 | if (sinfo->filled & STATION_INFO_CHAIN_SIGNAL) { | 3716 | if (sinfo->filled & BIT(NL80211_STA_INFO_CHAIN_SIGNAL)) { |
3715 | if (!nl80211_put_signal(msg, sinfo->chains, | 3717 | if (!nl80211_put_signal(msg, sinfo->chains, |
3716 | sinfo->chain_signal, | 3718 | sinfo->chain_signal, |
3717 | NL80211_STA_INFO_CHAIN_SIGNAL)) | 3719 | NL80211_STA_INFO_CHAIN_SIGNAL)) |
3718 | goto nla_put_failure; | 3720 | goto nla_put_failure; |
3719 | } | 3721 | } |
3720 | if (sinfo->filled & STATION_INFO_CHAIN_SIGNAL_AVG) { | 3722 | if (sinfo->filled & BIT(NL80211_STA_INFO_CHAIN_SIGNAL_AVG)) { |
3721 | if (!nl80211_put_signal(msg, sinfo->chains, | 3723 | if (!nl80211_put_signal(msg, sinfo->chains, |
3722 | sinfo->chain_signal_avg, | 3724 | sinfo->chain_signal_avg, |
3723 | NL80211_STA_INFO_CHAIN_SIGNAL_AVG)) | 3725 | NL80211_STA_INFO_CHAIN_SIGNAL_AVG)) |
3724 | goto nla_put_failure; | 3726 | goto nla_put_failure; |
3725 | } | 3727 | } |
3726 | if (sinfo->filled & STATION_INFO_TX_BITRATE) { | 3728 | if (sinfo->filled & BIT(NL80211_STA_INFO_TX_BITRATE)) { |
3727 | if (!nl80211_put_sta_rate(msg, &sinfo->txrate, | 3729 | if (!nl80211_put_sta_rate(msg, &sinfo->txrate, |
3728 | NL80211_STA_INFO_TX_BITRATE)) | 3730 | NL80211_STA_INFO_TX_BITRATE)) |
3729 | goto nla_put_failure; | 3731 | goto nla_put_failure; |
3730 | } | 3732 | } |
3731 | if (sinfo->filled & STATION_INFO_RX_BITRATE) { | 3733 | if (sinfo->filled & BIT(NL80211_STA_INFO_RX_BITRATE)) { |
3732 | if (!nl80211_put_sta_rate(msg, &sinfo->rxrate, | 3734 | if (!nl80211_put_sta_rate(msg, &sinfo->rxrate, |
3733 | NL80211_STA_INFO_RX_BITRATE)) | 3735 | NL80211_STA_INFO_RX_BITRATE)) |
3734 | goto nla_put_failure; | 3736 | goto nla_put_failure; |
3735 | } | 3737 | } |
3736 | if ((sinfo->filled & STATION_INFO_RX_PACKETS) && | 3738 | |
3737 | nla_put_u32(msg, NL80211_STA_INFO_RX_PACKETS, | 3739 | PUT_SINFO(RX_PACKETS, rx_packets, u32); |
3738 | sinfo->rx_packets)) | 3740 | PUT_SINFO(TX_PACKETS, tx_packets, u32); |
3739 | goto nla_put_failure; | 3741 | PUT_SINFO(TX_RETRIES, tx_retries, u32); |
3740 | if ((sinfo->filled & STATION_INFO_TX_PACKETS) && | 3742 | PUT_SINFO(TX_FAILED, tx_failed, u32); |
3741 | nla_put_u32(msg, NL80211_STA_INFO_TX_PACKETS, | 3743 | PUT_SINFO(EXPECTED_THROUGHPUT, expected_throughput, u32); |
3742 | sinfo->tx_packets)) | 3744 | PUT_SINFO(BEACON_LOSS, beacon_loss_count, u32); |
3743 | goto nla_put_failure; | 3745 | PUT_SINFO(LOCAL_PM, local_pm, u32); |
3744 | if ((sinfo->filled & STATION_INFO_TX_RETRIES) && | 3746 | PUT_SINFO(PEER_PM, peer_pm, u32); |
3745 | nla_put_u32(msg, NL80211_STA_INFO_TX_RETRIES, | 3747 | PUT_SINFO(NONPEER_PM, nonpeer_pm, u32); |
3746 | sinfo->tx_retries)) | 3748 | |
3747 | goto nla_put_failure; | 3749 | if (sinfo->filled & BIT(NL80211_STA_INFO_BSS_PARAM)) { |
3748 | if ((sinfo->filled & STATION_INFO_TX_FAILED) && | ||
3749 | nla_put_u32(msg, NL80211_STA_INFO_TX_FAILED, | ||
3750 | sinfo->tx_failed)) | ||
3751 | goto nla_put_failure; | ||
3752 | if ((sinfo->filled & STATION_INFO_EXPECTED_THROUGHPUT) && | ||
3753 | nla_put_u32(msg, NL80211_STA_INFO_EXPECTED_THROUGHPUT, | ||
3754 | sinfo->expected_throughput)) | ||
3755 | goto nla_put_failure; | ||
3756 | if ((sinfo->filled & STATION_INFO_BEACON_LOSS_COUNT) && | ||
3757 | nla_put_u32(msg, NL80211_STA_INFO_BEACON_LOSS, | ||
3758 | sinfo->beacon_loss_count)) | ||
3759 | goto nla_put_failure; | ||
3760 | if ((sinfo->filled & STATION_INFO_LOCAL_PM) && | ||
3761 | nla_put_u32(msg, NL80211_STA_INFO_LOCAL_PM, | ||
3762 | sinfo->local_pm)) | ||
3763 | goto nla_put_failure; | ||
3764 | if ((sinfo->filled & STATION_INFO_PEER_PM) && | ||
3765 | nla_put_u32(msg, NL80211_STA_INFO_PEER_PM, | ||
3766 | sinfo->peer_pm)) | ||
3767 | goto nla_put_failure; | ||
3768 | if ((sinfo->filled & STATION_INFO_NONPEER_PM) && | ||
3769 | nla_put_u32(msg, NL80211_STA_INFO_NONPEER_PM, | ||
3770 | sinfo->nonpeer_pm)) | ||
3771 | goto nla_put_failure; | ||
3772 | if (sinfo->filled & STATION_INFO_BSS_PARAM) { | ||
3773 | bss_param = nla_nest_start(msg, NL80211_STA_INFO_BSS_PARAM); | 3750 | bss_param = nla_nest_start(msg, NL80211_STA_INFO_BSS_PARAM); |
3774 | if (!bss_param) | 3751 | if (!bss_param) |
3775 | goto nla_put_failure; | 3752 | goto nla_put_failure; |
@@ -3788,18 +3765,62 @@ static int nl80211_send_station(struct sk_buff *msg, u32 portid, u32 seq, | |||
3788 | 3765 | ||
3789 | nla_nest_end(msg, bss_param); | 3766 | nla_nest_end(msg, bss_param); |
3790 | } | 3767 | } |
3791 | if ((sinfo->filled & STATION_INFO_STA_FLAGS) && | 3768 | if ((sinfo->filled & BIT(NL80211_STA_INFO_STA_FLAGS)) && |
3792 | nla_put(msg, NL80211_STA_INFO_STA_FLAGS, | 3769 | nla_put(msg, NL80211_STA_INFO_STA_FLAGS, |
3793 | sizeof(struct nl80211_sta_flag_update), | 3770 | sizeof(struct nl80211_sta_flag_update), |
3794 | &sinfo->sta_flags)) | 3771 | &sinfo->sta_flags)) |
3795 | goto nla_put_failure; | 3772 | goto nla_put_failure; |
3796 | if ((sinfo->filled & STATION_INFO_T_OFFSET) && | 3773 | |
3797 | nla_put_u64(msg, NL80211_STA_INFO_T_OFFSET, | 3774 | PUT_SINFO(T_OFFSET, t_offset, u64); |
3798 | sinfo->t_offset)) | 3775 | PUT_SINFO(RX_DROP_MISC, rx_dropped_misc, u64); |
3799 | goto nla_put_failure; | 3776 | PUT_SINFO(BEACON_RX, rx_beacon, u64); |
3777 | PUT_SINFO(BEACON_SIGNAL_AVG, rx_beacon_signal_avg, u8); | ||
3778 | |||
3779 | #undef PUT_SINFO | ||
3780 | |||
3781 | if (sinfo->filled & BIT(NL80211_STA_INFO_TID_STATS)) { | ||
3782 | struct nlattr *tidsattr; | ||
3783 | int tid; | ||
3784 | |||
3785 | tidsattr = nla_nest_start(msg, NL80211_STA_INFO_TID_STATS); | ||
3786 | if (!tidsattr) | ||
3787 | goto nla_put_failure; | ||
3788 | |||
3789 | for (tid = 0; tid < IEEE80211_NUM_TIDS + 1; tid++) { | ||
3790 | struct cfg80211_tid_stats *tidstats; | ||
3791 | struct nlattr *tidattr; | ||
3792 | |||
3793 | tidstats = &sinfo->pertid[tid]; | ||
3794 | |||
3795 | if (!tidstats->filled) | ||
3796 | continue; | ||
3797 | |||
3798 | tidattr = nla_nest_start(msg, tid + 1); | ||
3799 | if (!tidattr) | ||
3800 | goto nla_put_failure; | ||
3801 | |||
3802 | #define PUT_TIDVAL(attr, memb, type) do { \ | ||
3803 | if (tidstats->filled & BIT(NL80211_TID_STATS_ ## attr) && \ | ||
3804 | nla_put_ ## type(msg, NL80211_TID_STATS_ ## attr, \ | ||
3805 | tidstats->memb)) \ | ||
3806 | goto nla_put_failure; \ | ||
3807 | } while (0) | ||
3808 | |||
3809 | PUT_TIDVAL(RX_MSDU, rx_msdu, u64); | ||
3810 | PUT_TIDVAL(TX_MSDU, tx_msdu, u64); | ||
3811 | PUT_TIDVAL(TX_MSDU_RETRIES, tx_msdu_retries, u64); | ||
3812 | PUT_TIDVAL(TX_MSDU_FAILED, tx_msdu_failed, u64); | ||
3813 | |||
3814 | #undef PUT_TIDVAL | ||
3815 | nla_nest_end(msg, tidattr); | ||
3816 | } | ||
3817 | |||
3818 | nla_nest_end(msg, tidsattr); | ||
3819 | } | ||
3820 | |||
3800 | nla_nest_end(msg, sinfoattr); | 3821 | nla_nest_end(msg, sinfoattr); |
3801 | 3822 | ||
3802 | if ((sinfo->filled & STATION_INFO_ASSOC_REQ_IES) && | 3823 | if (sinfo->assoc_req_ies_len && |
3803 | nla_put(msg, NL80211_ATTR_IE, sinfo->assoc_req_ies_len, | 3824 | nla_put(msg, NL80211_ATTR_IE, sinfo->assoc_req_ies_len, |
3804 | sinfo->assoc_req_ies)) | 3825 | sinfo->assoc_req_ies)) |
3805 | goto nla_put_failure; | 3826 | goto nla_put_failure; |
@@ -3844,7 +3865,7 @@ static int nl80211_dump_station(struct sk_buff *skb, | |||
3844 | if (err) | 3865 | if (err) |
3845 | goto out_err; | 3866 | goto out_err; |
3846 | 3867 | ||
3847 | if (nl80211_send_station(skb, | 3868 | if (nl80211_send_station(skb, NL80211_CMD_NEW_STATION, |
3848 | NETLINK_CB(cb->skb).portid, | 3869 | NETLINK_CB(cb->skb).portid, |
3849 | cb->nlh->nlmsg_seq, NLM_F_MULTI, | 3870 | cb->nlh->nlmsg_seq, NLM_F_MULTI, |
3850 | rdev, wdev->netdev, mac_addr, | 3871 | rdev, wdev->netdev, mac_addr, |
@@ -3891,7 +3912,8 @@ static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info) | |||
3891 | if (!msg) | 3912 | if (!msg) |
3892 | return -ENOMEM; | 3913 | return -ENOMEM; |
3893 | 3914 | ||
3894 | if (nl80211_send_station(msg, info->snd_portid, info->snd_seq, 0, | 3915 | if (nl80211_send_station(msg, NL80211_CMD_NEW_STATION, |
3916 | info->snd_portid, info->snd_seq, 0, | ||
3895 | rdev, dev, mac_addr, &sinfo) < 0) { | 3917 | rdev, dev, mac_addr, &sinfo) < 0) { |
3896 | nlmsg_free(msg); | 3918 | nlmsg_free(msg); |
3897 | return -ENOBUFS; | 3919 | return -ENOBUFS; |
@@ -5327,42 +5349,20 @@ static int nl80211_update_mesh_config(struct sk_buff *skb, | |||
5327 | return err; | 5349 | return err; |
5328 | } | 5350 | } |
5329 | 5351 | ||
5330 | static int nl80211_get_reg(struct sk_buff *skb, struct genl_info *info) | 5352 | static int nl80211_put_regdom(const struct ieee80211_regdomain *regdom, |
5353 | struct sk_buff *msg) | ||
5331 | { | 5354 | { |
5332 | const struct ieee80211_regdomain *regdom; | ||
5333 | struct sk_buff *msg; | ||
5334 | void *hdr = NULL; | ||
5335 | struct nlattr *nl_reg_rules; | 5355 | struct nlattr *nl_reg_rules; |
5336 | unsigned int i; | 5356 | unsigned int i; |
5337 | 5357 | ||
5338 | if (!cfg80211_regdomain) | ||
5339 | return -EINVAL; | ||
5340 | |||
5341 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | ||
5342 | if (!msg) | ||
5343 | return -ENOBUFS; | ||
5344 | |||
5345 | hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0, | ||
5346 | NL80211_CMD_GET_REG); | ||
5347 | if (!hdr) | ||
5348 | goto put_failure; | ||
5349 | |||
5350 | if (reg_last_request_cell_base() && | ||
5351 | nla_put_u32(msg, NL80211_ATTR_USER_REG_HINT_TYPE, | ||
5352 | NL80211_USER_REG_HINT_CELL_BASE)) | ||
5353 | goto nla_put_failure; | ||
5354 | |||
5355 | rcu_read_lock(); | ||
5356 | regdom = rcu_dereference(cfg80211_regdomain); | ||
5357 | |||
5358 | if (nla_put_string(msg, NL80211_ATTR_REG_ALPHA2, regdom->alpha2) || | 5358 | if (nla_put_string(msg, NL80211_ATTR_REG_ALPHA2, regdom->alpha2) || |
5359 | (regdom->dfs_region && | 5359 | (regdom->dfs_region && |
5360 | nla_put_u8(msg, NL80211_ATTR_DFS_REGION, regdom->dfs_region))) | 5360 | nla_put_u8(msg, NL80211_ATTR_DFS_REGION, regdom->dfs_region))) |
5361 | goto nla_put_failure_rcu; | 5361 | goto nla_put_failure; |
5362 | 5362 | ||
5363 | nl_reg_rules = nla_nest_start(msg, NL80211_ATTR_REG_RULES); | 5363 | nl_reg_rules = nla_nest_start(msg, NL80211_ATTR_REG_RULES); |
5364 | if (!nl_reg_rules) | 5364 | if (!nl_reg_rules) |
5365 | goto nla_put_failure_rcu; | 5365 | goto nla_put_failure; |
5366 | 5366 | ||
5367 | for (i = 0; i < regdom->n_reg_rules; i++) { | 5367 | for (i = 0; i < regdom->n_reg_rules; i++) { |
5368 | struct nlattr *nl_reg_rule; | 5368 | struct nlattr *nl_reg_rule; |
@@ -5377,7 +5377,7 @@ static int nl80211_get_reg(struct sk_buff *skb, struct genl_info *info) | |||
5377 | 5377 | ||
5378 | nl_reg_rule = nla_nest_start(msg, i); | 5378 | nl_reg_rule = nla_nest_start(msg, i); |
5379 | if (!nl_reg_rule) | 5379 | if (!nl_reg_rule) |
5380 | goto nla_put_failure_rcu; | 5380 | goto nla_put_failure; |
5381 | 5381 | ||
5382 | max_bandwidth_khz = freq_range->max_bandwidth_khz; | 5382 | max_bandwidth_khz = freq_range->max_bandwidth_khz; |
5383 | if (!max_bandwidth_khz) | 5383 | if (!max_bandwidth_khz) |
@@ -5398,13 +5398,74 @@ static int nl80211_get_reg(struct sk_buff *skb, struct genl_info *info) | |||
5398 | power_rule->max_eirp) || | 5398 | power_rule->max_eirp) || |
5399 | nla_put_u32(msg, NL80211_ATTR_DFS_CAC_TIME, | 5399 | nla_put_u32(msg, NL80211_ATTR_DFS_CAC_TIME, |
5400 | reg_rule->dfs_cac_ms)) | 5400 | reg_rule->dfs_cac_ms)) |
5401 | goto nla_put_failure_rcu; | 5401 | goto nla_put_failure; |
5402 | 5402 | ||
5403 | nla_nest_end(msg, nl_reg_rule); | 5403 | nla_nest_end(msg, nl_reg_rule); |
5404 | } | 5404 | } |
5405 | rcu_read_unlock(); | ||
5406 | 5405 | ||
5407 | nla_nest_end(msg, nl_reg_rules); | 5406 | nla_nest_end(msg, nl_reg_rules); |
5407 | return 0; | ||
5408 | |||
5409 | nla_put_failure: | ||
5410 | return -EMSGSIZE; | ||
5411 | } | ||
5412 | |||
5413 | static int nl80211_get_reg_do(struct sk_buff *skb, struct genl_info *info) | ||
5414 | { | ||
5415 | const struct ieee80211_regdomain *regdom = NULL; | ||
5416 | struct cfg80211_registered_device *rdev; | ||
5417 | struct wiphy *wiphy = NULL; | ||
5418 | struct sk_buff *msg; | ||
5419 | void *hdr; | ||
5420 | |||
5421 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | ||
5422 | if (!msg) | ||
5423 | return -ENOBUFS; | ||
5424 | |||
5425 | hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0, | ||
5426 | NL80211_CMD_GET_REG); | ||
5427 | if (!hdr) | ||
5428 | goto put_failure; | ||
5429 | |||
5430 | if (info->attrs[NL80211_ATTR_WIPHY]) { | ||
5431 | bool self_managed; | ||
5432 | |||
5433 | rdev = cfg80211_get_dev_from_info(genl_info_net(info), info); | ||
5434 | if (IS_ERR(rdev)) { | ||
5435 | nlmsg_free(msg); | ||
5436 | return PTR_ERR(rdev); | ||
5437 | } | ||
5438 | |||
5439 | wiphy = &rdev->wiphy; | ||
5440 | self_managed = wiphy->regulatory_flags & | ||
5441 | REGULATORY_WIPHY_SELF_MANAGED; | ||
5442 | regdom = get_wiphy_regdom(wiphy); | ||
5443 | |||
5444 | /* a self-managed-reg device must have a private regdom */ | ||
5445 | if (WARN_ON(!regdom && self_managed)) { | ||
5446 | nlmsg_free(msg); | ||
5447 | return -EINVAL; | ||
5448 | } | ||
5449 | |||
5450 | if (regdom && | ||
5451 | nla_put_u32(msg, NL80211_ATTR_WIPHY, get_wiphy_idx(wiphy))) | ||
5452 | goto nla_put_failure; | ||
5453 | } | ||
5454 | |||
5455 | if (!wiphy && reg_last_request_cell_base() && | ||
5456 | nla_put_u32(msg, NL80211_ATTR_USER_REG_HINT_TYPE, | ||
5457 | NL80211_USER_REG_HINT_CELL_BASE)) | ||
5458 | goto nla_put_failure; | ||
5459 | |||
5460 | rcu_read_lock(); | ||
5461 | |||
5462 | if (!regdom) | ||
5463 | regdom = rcu_dereference(cfg80211_regdomain); | ||
5464 | |||
5465 | if (nl80211_put_regdom(regdom, msg)) | ||
5466 | goto nla_put_failure_rcu; | ||
5467 | |||
5468 | rcu_read_unlock(); | ||
5408 | 5469 | ||
5409 | genlmsg_end(msg, hdr); | 5470 | genlmsg_end(msg, hdr); |
5410 | return genlmsg_reply(msg, info); | 5471 | return genlmsg_reply(msg, info); |
@@ -5418,6 +5479,83 @@ put_failure: | |||
5418 | return -EMSGSIZE; | 5479 | return -EMSGSIZE; |
5419 | } | 5480 | } |
5420 | 5481 | ||
5482 | static int nl80211_send_regdom(struct sk_buff *msg, struct netlink_callback *cb, | ||
5483 | u32 seq, int flags, struct wiphy *wiphy, | ||
5484 | const struct ieee80211_regdomain *regdom) | ||
5485 | { | ||
5486 | void *hdr = nl80211hdr_put(msg, NETLINK_CB(cb->skb).portid, seq, flags, | ||
5487 | NL80211_CMD_GET_REG); | ||
5488 | |||
5489 | if (!hdr) | ||
5490 | return -1; | ||
5491 | |||
5492 | genl_dump_check_consistent(cb, hdr, &nl80211_fam); | ||
5493 | |||
5494 | if (nl80211_put_regdom(regdom, msg)) | ||
5495 | goto nla_put_failure; | ||
5496 | |||
5497 | if (!wiphy && reg_last_request_cell_base() && | ||
5498 | nla_put_u32(msg, NL80211_ATTR_USER_REG_HINT_TYPE, | ||
5499 | NL80211_USER_REG_HINT_CELL_BASE)) | ||
5500 | goto nla_put_failure; | ||
5501 | |||
5502 | if (wiphy && | ||
5503 | nla_put_u32(msg, NL80211_ATTR_WIPHY, get_wiphy_idx(wiphy))) | ||
5504 | goto nla_put_failure; | ||
5505 | |||
5506 | if (wiphy && wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED && | ||
5507 | nla_put_flag(msg, NL80211_ATTR_WIPHY_SELF_MANAGED_REG)) | ||
5508 | goto nla_put_failure; | ||
5509 | |||
5510 | return genlmsg_end(msg, hdr); | ||
5511 | |||
5512 | nla_put_failure: | ||
5513 | genlmsg_cancel(msg, hdr); | ||
5514 | return -EMSGSIZE; | ||
5515 | } | ||
5516 | |||
5517 | static int nl80211_get_reg_dump(struct sk_buff *skb, | ||
5518 | struct netlink_callback *cb) | ||
5519 | { | ||
5520 | const struct ieee80211_regdomain *regdom = NULL; | ||
5521 | struct cfg80211_registered_device *rdev; | ||
5522 | int err, reg_idx, start = cb->args[2]; | ||
5523 | |||
5524 | rtnl_lock(); | ||
5525 | |||
5526 | if (cfg80211_regdomain && start == 0) { | ||
5527 | err = nl80211_send_regdom(skb, cb, cb->nlh->nlmsg_seq, | ||
5528 | NLM_F_MULTI, NULL, | ||
5529 | rtnl_dereference(cfg80211_regdomain)); | ||
5530 | if (err < 0) | ||
5531 | goto out_err; | ||
5532 | } | ||
5533 | |||
5534 | /* the global regdom is idx 0 */ | ||
5535 | reg_idx = 1; | ||
5536 | list_for_each_entry(rdev, &cfg80211_rdev_list, list) { | ||
5537 | regdom = get_wiphy_regdom(&rdev->wiphy); | ||
5538 | if (!regdom) | ||
5539 | continue; | ||
5540 | |||
5541 | if (++reg_idx <= start) | ||
5542 | continue; | ||
5543 | |||
5544 | err = nl80211_send_regdom(skb, cb, cb->nlh->nlmsg_seq, | ||
5545 | NLM_F_MULTI, &rdev->wiphy, regdom); | ||
5546 | if (err < 0) { | ||
5547 | reg_idx--; | ||
5548 | break; | ||
5549 | } | ||
5550 | } | ||
5551 | |||
5552 | cb->args[2] = reg_idx; | ||
5553 | err = skb->len; | ||
5554 | out_err: | ||
5555 | rtnl_unlock(); | ||
5556 | return err; | ||
5557 | } | ||
5558 | |||
5421 | static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info) | 5559 | static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info) |
5422 | { | 5560 | { |
5423 | struct nlattr *tb[NL80211_REG_RULE_ATTR_MAX + 1]; | 5561 | struct nlattr *tb[NL80211_REG_RULE_ATTR_MAX + 1]; |
@@ -6069,6 +6207,7 @@ static int nl80211_start_sched_scan(struct sk_buff *skb, | |||
6069 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 6207 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
6070 | struct net_device *dev = info->user_ptr[1]; | 6208 | struct net_device *dev = info->user_ptr[1]; |
6071 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 6209 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
6210 | struct cfg80211_sched_scan_request *sched_scan_req; | ||
6072 | int err; | 6211 | int err; |
6073 | 6212 | ||
6074 | if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN) || | 6213 | if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN) || |
@@ -6078,27 +6217,32 @@ static int nl80211_start_sched_scan(struct sk_buff *skb, | |||
6078 | if (rdev->sched_scan_req) | 6217 | if (rdev->sched_scan_req) |
6079 | return -EINPROGRESS; | 6218 | return -EINPROGRESS; |
6080 | 6219 | ||
6081 | rdev->sched_scan_req = nl80211_parse_sched_scan(&rdev->wiphy, wdev, | 6220 | sched_scan_req = nl80211_parse_sched_scan(&rdev->wiphy, wdev, |
6082 | info->attrs); | 6221 | info->attrs); |
6083 | err = PTR_ERR_OR_ZERO(rdev->sched_scan_req); | 6222 | |
6223 | err = PTR_ERR_OR_ZERO(sched_scan_req); | ||
6084 | if (err) | 6224 | if (err) |
6085 | goto out_err; | 6225 | goto out_err; |
6086 | 6226 | ||
6087 | err = rdev_sched_scan_start(rdev, dev, rdev->sched_scan_req); | 6227 | err = rdev_sched_scan_start(rdev, dev, sched_scan_req); |
6088 | if (err) | 6228 | if (err) |
6089 | goto out_free; | 6229 | goto out_free; |
6090 | 6230 | ||
6091 | rdev->sched_scan_req->dev = dev; | 6231 | sched_scan_req->dev = dev; |
6092 | rdev->sched_scan_req->wiphy = &rdev->wiphy; | 6232 | sched_scan_req->wiphy = &rdev->wiphy; |
6233 | |||
6234 | if (info->attrs[NL80211_ATTR_SOCKET_OWNER]) | ||
6235 | sched_scan_req->owner_nlportid = info->snd_portid; | ||
6236 | |||
6237 | rcu_assign_pointer(rdev->sched_scan_req, sched_scan_req); | ||
6093 | 6238 | ||
6094 | nl80211_send_sched_scan(rdev, dev, | 6239 | nl80211_send_sched_scan(rdev, dev, |
6095 | NL80211_CMD_START_SCHED_SCAN); | 6240 | NL80211_CMD_START_SCHED_SCAN); |
6096 | return 0; | 6241 | return 0; |
6097 | 6242 | ||
6098 | out_free: | 6243 | out_free: |
6099 | kfree(rdev->sched_scan_req); | 6244 | kfree(sched_scan_req); |
6100 | out_err: | 6245 | out_err: |
6101 | rdev->sched_scan_req = NULL; | ||
6102 | return err; | 6246 | return err; |
6103 | } | 6247 | } |
6104 | 6248 | ||
@@ -6481,12 +6625,17 @@ static int nl80211_dump_scan(struct sk_buff *skb, struct netlink_callback *cb) | |||
6481 | } | 6625 | } |
6482 | 6626 | ||
6483 | static int nl80211_send_survey(struct sk_buff *msg, u32 portid, u32 seq, | 6627 | static int nl80211_send_survey(struct sk_buff *msg, u32 portid, u32 seq, |
6484 | int flags, struct net_device *dev, | 6628 | int flags, struct net_device *dev, |
6485 | struct survey_info *survey) | 6629 | bool allow_radio_stats, |
6630 | struct survey_info *survey) | ||
6486 | { | 6631 | { |
6487 | void *hdr; | 6632 | void *hdr; |
6488 | struct nlattr *infoattr; | 6633 | struct nlattr *infoattr; |
6489 | 6634 | ||
6635 | /* skip radio stats if userspace didn't request them */ | ||
6636 | if (!survey->channel && !allow_radio_stats) | ||
6637 | return 0; | ||
6638 | |||
6490 | hdr = nl80211hdr_put(msg, portid, seq, flags, | 6639 | hdr = nl80211hdr_put(msg, portid, seq, flags, |
6491 | NL80211_CMD_NEW_SURVEY_RESULTS); | 6640 | NL80211_CMD_NEW_SURVEY_RESULTS); |
6492 | if (!hdr) | 6641 | if (!hdr) |
@@ -6499,7 +6648,8 @@ static int nl80211_send_survey(struct sk_buff *msg, u32 portid, u32 seq, | |||
6499 | if (!infoattr) | 6648 | if (!infoattr) |
6500 | goto nla_put_failure; | 6649 | goto nla_put_failure; |
6501 | 6650 | ||
6502 | if (nla_put_u32(msg, NL80211_SURVEY_INFO_FREQUENCY, | 6651 | if (survey->channel && |
6652 | nla_put_u32(msg, NL80211_SURVEY_INFO_FREQUENCY, | ||
6503 | survey->channel->center_freq)) | 6653 | survey->channel->center_freq)) |
6504 | goto nla_put_failure; | 6654 | goto nla_put_failure; |
6505 | 6655 | ||
@@ -6509,25 +6659,29 @@ static int nl80211_send_survey(struct sk_buff *msg, u32 portid, u32 seq, | |||
6509 | if ((survey->filled & SURVEY_INFO_IN_USE) && | 6659 | if ((survey->filled & SURVEY_INFO_IN_USE) && |
6510 | nla_put_flag(msg, NL80211_SURVEY_INFO_IN_USE)) | 6660 | nla_put_flag(msg, NL80211_SURVEY_INFO_IN_USE)) |
6511 | goto nla_put_failure; | 6661 | goto nla_put_failure; |
6512 | if ((survey->filled & SURVEY_INFO_CHANNEL_TIME) && | 6662 | if ((survey->filled & SURVEY_INFO_TIME) && |
6513 | nla_put_u64(msg, NL80211_SURVEY_INFO_CHANNEL_TIME, | 6663 | nla_put_u64(msg, NL80211_SURVEY_INFO_TIME, |
6514 | survey->channel_time)) | 6664 | survey->time)) |
6515 | goto nla_put_failure; | 6665 | goto nla_put_failure; |
6516 | if ((survey->filled & SURVEY_INFO_CHANNEL_TIME_BUSY) && | 6666 | if ((survey->filled & SURVEY_INFO_TIME_BUSY) && |
6517 | nla_put_u64(msg, NL80211_SURVEY_INFO_CHANNEL_TIME_BUSY, | 6667 | nla_put_u64(msg, NL80211_SURVEY_INFO_TIME_BUSY, |
6518 | survey->channel_time_busy)) | 6668 | survey->time_busy)) |
6519 | goto nla_put_failure; | 6669 | goto nla_put_failure; |
6520 | if ((survey->filled & SURVEY_INFO_CHANNEL_TIME_EXT_BUSY) && | 6670 | if ((survey->filled & SURVEY_INFO_TIME_EXT_BUSY) && |
6521 | nla_put_u64(msg, NL80211_SURVEY_INFO_CHANNEL_TIME_EXT_BUSY, | 6671 | nla_put_u64(msg, NL80211_SURVEY_INFO_TIME_EXT_BUSY, |
6522 | survey->channel_time_ext_busy)) | 6672 | survey->time_ext_busy)) |
6523 | goto nla_put_failure; | 6673 | goto nla_put_failure; |
6524 | if ((survey->filled & SURVEY_INFO_CHANNEL_TIME_RX) && | 6674 | if ((survey->filled & SURVEY_INFO_TIME_RX) && |
6525 | nla_put_u64(msg, NL80211_SURVEY_INFO_CHANNEL_TIME_RX, | 6675 | nla_put_u64(msg, NL80211_SURVEY_INFO_TIME_RX, |
6526 | survey->channel_time_rx)) | 6676 | survey->time_rx)) |
6527 | goto nla_put_failure; | 6677 | goto nla_put_failure; |
6528 | if ((survey->filled & SURVEY_INFO_CHANNEL_TIME_TX) && | 6678 | if ((survey->filled & SURVEY_INFO_TIME_TX) && |
6529 | nla_put_u64(msg, NL80211_SURVEY_INFO_CHANNEL_TIME_TX, | 6679 | nla_put_u64(msg, NL80211_SURVEY_INFO_TIME_TX, |
6530 | survey->channel_time_tx)) | 6680 | survey->time_tx)) |
6681 | goto nla_put_failure; | ||
6682 | if ((survey->filled & SURVEY_INFO_TIME_SCAN) && | ||
6683 | nla_put_u64(msg, NL80211_SURVEY_INFO_TIME_SCAN, | ||
6684 | survey->time_scan)) | ||
6531 | goto nla_put_failure; | 6685 | goto nla_put_failure; |
6532 | 6686 | ||
6533 | nla_nest_end(msg, infoattr); | 6687 | nla_nest_end(msg, infoattr); |
@@ -6539,19 +6693,22 @@ static int nl80211_send_survey(struct sk_buff *msg, u32 portid, u32 seq, | |||
6539 | return -EMSGSIZE; | 6693 | return -EMSGSIZE; |
6540 | } | 6694 | } |
6541 | 6695 | ||
6542 | static int nl80211_dump_survey(struct sk_buff *skb, | 6696 | static int nl80211_dump_survey(struct sk_buff *skb, struct netlink_callback *cb) |
6543 | struct netlink_callback *cb) | ||
6544 | { | 6697 | { |
6545 | struct survey_info survey; | 6698 | struct survey_info survey; |
6546 | struct cfg80211_registered_device *rdev; | 6699 | struct cfg80211_registered_device *rdev; |
6547 | struct wireless_dev *wdev; | 6700 | struct wireless_dev *wdev; |
6548 | int survey_idx = cb->args[2]; | 6701 | int survey_idx = cb->args[2]; |
6549 | int res; | 6702 | int res; |
6703 | bool radio_stats; | ||
6550 | 6704 | ||
6551 | res = nl80211_prepare_wdev_dump(skb, cb, &rdev, &wdev); | 6705 | res = nl80211_prepare_wdev_dump(skb, cb, &rdev, &wdev); |
6552 | if (res) | 6706 | if (res) |
6553 | return res; | 6707 | return res; |
6554 | 6708 | ||
6709 | /* prepare_wdev_dump parsed the attributes */ | ||
6710 | radio_stats = nl80211_fam.attrbuf[NL80211_ATTR_SURVEY_RADIO_STATS]; | ||
6711 | |||
6555 | if (!wdev->netdev) { | 6712 | if (!wdev->netdev) { |
6556 | res = -EINVAL; | 6713 | res = -EINVAL; |
6557 | goto out_err; | 6714 | goto out_err; |
@@ -6569,13 +6726,9 @@ static int nl80211_dump_survey(struct sk_buff *skb, | |||
6569 | if (res) | 6726 | if (res) |
6570 | goto out_err; | 6727 | goto out_err; |
6571 | 6728 | ||
6572 | /* Survey without a channel doesn't make sense */ | 6729 | /* don't send disabled channels, but do send non-channel data */ |
6573 | if (!survey.channel) { | 6730 | if (survey.channel && |
6574 | res = -EINVAL; | 6731 | survey.channel->flags & IEEE80211_CHAN_DISABLED) { |
6575 | goto out; | ||
6576 | } | ||
6577 | |||
6578 | if (survey.channel->flags & IEEE80211_CHAN_DISABLED) { | ||
6579 | survey_idx++; | 6732 | survey_idx++; |
6580 | continue; | 6733 | continue; |
6581 | } | 6734 | } |
@@ -6583,7 +6736,7 @@ static int nl80211_dump_survey(struct sk_buff *skb, | |||
6583 | if (nl80211_send_survey(skb, | 6736 | if (nl80211_send_survey(skb, |
6584 | NETLINK_CB(cb->skb).portid, | 6737 | NETLINK_CB(cb->skb).portid, |
6585 | cb->nlh->nlmsg_seq, NLM_F_MULTI, | 6738 | cb->nlh->nlmsg_seq, NLM_F_MULTI, |
6586 | wdev->netdev, &survey) < 0) | 6739 | wdev->netdev, radio_stats, &survey) < 0) |
6587 | goto out; | 6740 | goto out; |
6588 | survey_idx++; | 6741 | survey_idx++; |
6589 | } | 6742 | } |
@@ -8599,6 +8752,48 @@ static int nl80211_send_wowlan_tcp(struct sk_buff *msg, | |||
8599 | return 0; | 8752 | return 0; |
8600 | } | 8753 | } |
8601 | 8754 | ||
8755 | static int nl80211_send_wowlan_nd(struct sk_buff *msg, | ||
8756 | struct cfg80211_sched_scan_request *req) | ||
8757 | { | ||
8758 | struct nlattr *nd, *freqs, *matches, *match; | ||
8759 | int i; | ||
8760 | |||
8761 | if (!req) | ||
8762 | return 0; | ||
8763 | |||
8764 | nd = nla_nest_start(msg, NL80211_WOWLAN_TRIG_NET_DETECT); | ||
8765 | if (!nd) | ||
8766 | return -ENOBUFS; | ||
8767 | |||
8768 | if (nla_put_u32(msg, NL80211_ATTR_SCHED_SCAN_INTERVAL, req->interval)) | ||
8769 | return -ENOBUFS; | ||
8770 | |||
8771 | freqs = nla_nest_start(msg, NL80211_ATTR_SCAN_FREQUENCIES); | ||
8772 | if (!freqs) | ||
8773 | return -ENOBUFS; | ||
8774 | |||
8775 | for (i = 0; i < req->n_channels; i++) | ||
8776 | nla_put_u32(msg, i, req->channels[i]->center_freq); | ||
8777 | |||
8778 | nla_nest_end(msg, freqs); | ||
8779 | |||
8780 | if (req->n_match_sets) { | ||
8781 | matches = nla_nest_start(msg, NL80211_ATTR_SCHED_SCAN_MATCH); | ||
8782 | for (i = 0; i < req->n_match_sets; i++) { | ||
8783 | match = nla_nest_start(msg, i); | ||
8784 | nla_put(msg, NL80211_SCHED_SCAN_MATCH_ATTR_SSID, | ||
8785 | req->match_sets[i].ssid.ssid_len, | ||
8786 | req->match_sets[i].ssid.ssid); | ||
8787 | nla_nest_end(msg, match); | ||
8788 | } | ||
8789 | nla_nest_end(msg, matches); | ||
8790 | } | ||
8791 | |||
8792 | nla_nest_end(msg, nd); | ||
8793 | |||
8794 | return 0; | ||
8795 | } | ||
8796 | |||
8602 | static int nl80211_get_wowlan(struct sk_buff *skb, struct genl_info *info) | 8797 | static int nl80211_get_wowlan(struct sk_buff *skb, struct genl_info *info) |
8603 | { | 8798 | { |
8604 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 8799 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
@@ -8656,6 +8851,11 @@ static int nl80211_get_wowlan(struct sk_buff *skb, struct genl_info *info) | |||
8656 | rdev->wiphy.wowlan_config->tcp)) | 8851 | rdev->wiphy.wowlan_config->tcp)) |
8657 | goto nla_put_failure; | 8852 | goto nla_put_failure; |
8658 | 8853 | ||
8854 | if (nl80211_send_wowlan_nd( | ||
8855 | msg, | ||
8856 | rdev->wiphy.wowlan_config->nd_config)) | ||
8857 | goto nla_put_failure; | ||
8858 | |||
8659 | nla_nest_end(msg, nl_wowlan); | 8859 | nla_nest_end(msg, nl_wowlan); |
8660 | } | 8860 | } |
8661 | 8861 | ||
@@ -10225,7 +10425,8 @@ static const struct genl_ops nl80211_ops[] = { | |||
10225 | }, | 10425 | }, |
10226 | { | 10426 | { |
10227 | .cmd = NL80211_CMD_GET_REG, | 10427 | .cmd = NL80211_CMD_GET_REG, |
10228 | .doit = nl80211_get_reg, | 10428 | .doit = nl80211_get_reg_do, |
10429 | .dumpit = nl80211_get_reg_dump, | ||
10229 | .policy = nl80211_policy, | 10430 | .policy = nl80211_policy, |
10230 | .internal_flags = NL80211_FLAG_NEED_RTNL, | 10431 | .internal_flags = NL80211_FLAG_NEED_RTNL, |
10231 | /* can be retrieved by unprivileged users */ | 10432 | /* can be retrieved by unprivileged users */ |
@@ -10939,25 +11140,9 @@ void nl80211_send_sched_scan(struct cfg80211_registered_device *rdev, | |||
10939 | NL80211_MCGRP_SCAN, GFP_KERNEL); | 11140 | NL80211_MCGRP_SCAN, GFP_KERNEL); |
10940 | } | 11141 | } |
10941 | 11142 | ||
10942 | /* | 11143 | static bool nl80211_reg_change_event_fill(struct sk_buff *msg, |
10943 | * This can happen on global regulatory changes or device specific settings | 11144 | struct regulatory_request *request) |
10944 | * based on custom world regulatory domains. | ||
10945 | */ | ||
10946 | void nl80211_send_reg_change_event(struct regulatory_request *request) | ||
10947 | { | 11145 | { |
10948 | struct sk_buff *msg; | ||
10949 | void *hdr; | ||
10950 | |||
10951 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | ||
10952 | if (!msg) | ||
10953 | return; | ||
10954 | |||
10955 | hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_REG_CHANGE); | ||
10956 | if (!hdr) { | ||
10957 | nlmsg_free(msg); | ||
10958 | return; | ||
10959 | } | ||
10960 | |||
10961 | /* Userspace can always count this one always being set */ | 11146 | /* Userspace can always count this one always being set */ |
10962 | if (nla_put_u8(msg, NL80211_ATTR_REG_INITIATOR, request->initiator)) | 11147 | if (nla_put_u8(msg, NL80211_ATTR_REG_INITIATOR, request->initiator)) |
10963 | goto nla_put_failure; | 11148 | goto nla_put_failure; |
@@ -10983,8 +11168,46 @@ void nl80211_send_reg_change_event(struct regulatory_request *request) | |||
10983 | goto nla_put_failure; | 11168 | goto nla_put_failure; |
10984 | } | 11169 | } |
10985 | 11170 | ||
10986 | if (request->wiphy_idx != WIPHY_IDX_INVALID && | 11171 | if (request->wiphy_idx != WIPHY_IDX_INVALID) { |
10987 | nla_put_u32(msg, NL80211_ATTR_WIPHY, request->wiphy_idx)) | 11172 | struct wiphy *wiphy = wiphy_idx_to_wiphy(request->wiphy_idx); |
11173 | |||
11174 | if (wiphy && | ||
11175 | nla_put_u32(msg, NL80211_ATTR_WIPHY, request->wiphy_idx)) | ||
11176 | goto nla_put_failure; | ||
11177 | |||
11178 | if (wiphy && | ||
11179 | wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED && | ||
11180 | nla_put_flag(msg, NL80211_ATTR_WIPHY_SELF_MANAGED_REG)) | ||
11181 | goto nla_put_failure; | ||
11182 | } | ||
11183 | |||
11184 | return true; | ||
11185 | |||
11186 | nla_put_failure: | ||
11187 | return false; | ||
11188 | } | ||
11189 | |||
11190 | /* | ||
11191 | * This can happen on global regulatory changes or device specific settings | ||
11192 | * based on custom regulatory domains. | ||
11193 | */ | ||
11194 | void nl80211_common_reg_change_event(enum nl80211_commands cmd_id, | ||
11195 | struct regulatory_request *request) | ||
11196 | { | ||
11197 | struct sk_buff *msg; | ||
11198 | void *hdr; | ||
11199 | |||
11200 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | ||
11201 | if (!msg) | ||
11202 | return; | ||
11203 | |||
11204 | hdr = nl80211hdr_put(msg, 0, 0, 0, cmd_id); | ||
11205 | if (!hdr) { | ||
11206 | nlmsg_free(msg); | ||
11207 | return; | ||
11208 | } | ||
11209 | |||
11210 | if (nl80211_reg_change_event_fill(msg, request) == false) | ||
10988 | goto nla_put_failure; | 11211 | goto nla_put_failure; |
10989 | 11212 | ||
10990 | genlmsg_end(msg, hdr); | 11213 | genlmsg_end(msg, hdr); |
@@ -11523,7 +11746,7 @@ void cfg80211_new_sta(struct net_device *dev, const u8 *mac_addr, | |||
11523 | if (!msg) | 11746 | if (!msg) |
11524 | return; | 11747 | return; |
11525 | 11748 | ||
11526 | if (nl80211_send_station(msg, 0, 0, 0, | 11749 | if (nl80211_send_station(msg, NL80211_CMD_NEW_STATION, 0, 0, 0, |
11527 | rdev, dev, mac_addr, sinfo) < 0) { | 11750 | rdev, dev, mac_addr, sinfo) < 0) { |
11528 | nlmsg_free(msg); | 11751 | nlmsg_free(msg); |
11529 | return; | 11752 | return; |
@@ -11534,12 +11757,16 @@ void cfg80211_new_sta(struct net_device *dev, const u8 *mac_addr, | |||
11534 | } | 11757 | } |
11535 | EXPORT_SYMBOL(cfg80211_new_sta); | 11758 | EXPORT_SYMBOL(cfg80211_new_sta); |
11536 | 11759 | ||
11537 | void cfg80211_del_sta(struct net_device *dev, const u8 *mac_addr, gfp_t gfp) | 11760 | void cfg80211_del_sta_sinfo(struct net_device *dev, const u8 *mac_addr, |
11761 | struct station_info *sinfo, gfp_t gfp) | ||
11538 | { | 11762 | { |
11539 | struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; | 11763 | struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; |
11540 | struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); | 11764 | struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); |
11541 | struct sk_buff *msg; | 11765 | struct sk_buff *msg; |
11542 | void *hdr; | 11766 | struct station_info empty_sinfo = {}; |
11767 | |||
11768 | if (!sinfo) | ||
11769 | sinfo = &empty_sinfo; | ||
11543 | 11770 | ||
11544 | trace_cfg80211_del_sta(dev, mac_addr); | 11771 | trace_cfg80211_del_sta(dev, mac_addr); |
11545 | 11772 | ||
@@ -11547,27 +11774,16 @@ void cfg80211_del_sta(struct net_device *dev, const u8 *mac_addr, gfp_t gfp) | |||
11547 | if (!msg) | 11774 | if (!msg) |
11548 | return; | 11775 | return; |
11549 | 11776 | ||
11550 | hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_DEL_STATION); | 11777 | if (nl80211_send_station(msg, NL80211_CMD_DEL_STATION, 0, 0, 0, |
11551 | if (!hdr) { | 11778 | rdev, dev, mac_addr, sinfo)) { |
11552 | nlmsg_free(msg); | 11779 | nlmsg_free(msg); |
11553 | return; | 11780 | return; |
11554 | } | 11781 | } |
11555 | 11782 | ||
11556 | if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) || | ||
11557 | nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr)) | ||
11558 | goto nla_put_failure; | ||
11559 | |||
11560 | genlmsg_end(msg, hdr); | ||
11561 | |||
11562 | genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, | 11783 | genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, |
11563 | NL80211_MCGRP_MLME, gfp); | 11784 | NL80211_MCGRP_MLME, gfp); |
11564 | return; | ||
11565 | |||
11566 | nla_put_failure: | ||
11567 | genlmsg_cancel(msg, hdr); | ||
11568 | nlmsg_free(msg); | ||
11569 | } | 11785 | } |
11570 | EXPORT_SYMBOL(cfg80211_del_sta); | 11786 | EXPORT_SYMBOL(cfg80211_del_sta_sinfo); |
11571 | 11787 | ||
11572 | void cfg80211_conn_failed(struct net_device *dev, const u8 *mac_addr, | 11788 | void cfg80211_conn_failed(struct net_device *dev, const u8 *mac_addr, |
11573 | enum nl80211_connect_failed_reason reason, | 11789 | enum nl80211_connect_failed_reason reason, |
@@ -12471,6 +12687,13 @@ static int nl80211_netlink_notify(struct notifier_block * nb, | |||
12471 | 12687 | ||
12472 | list_for_each_entry_rcu(rdev, &cfg80211_rdev_list, list) { | 12688 | list_for_each_entry_rcu(rdev, &cfg80211_rdev_list, list) { |
12473 | bool schedule_destroy_work = false; | 12689 | bool schedule_destroy_work = false; |
12690 | bool schedule_scan_stop = false; | ||
12691 | struct cfg80211_sched_scan_request *sched_scan_req = | ||
12692 | rcu_dereference(rdev->sched_scan_req); | ||
12693 | |||
12694 | if (sched_scan_req && notify->portid && | ||
12695 | sched_scan_req->owner_nlportid == notify->portid) | ||
12696 | schedule_scan_stop = true; | ||
12474 | 12697 | ||
12475 | list_for_each_entry_rcu(wdev, &rdev->wdev_list, list) { | 12698 | list_for_each_entry_rcu(wdev, &rdev->wdev_list, list) { |
12476 | cfg80211_mlme_unregister_socket(wdev, notify->portid); | 12699 | cfg80211_mlme_unregister_socket(wdev, notify->portid); |
@@ -12501,6 +12724,12 @@ static int nl80211_netlink_notify(struct notifier_block * nb, | |||
12501 | spin_unlock(&rdev->destroy_list_lock); | 12724 | spin_unlock(&rdev->destroy_list_lock); |
12502 | schedule_work(&rdev->destroy_work); | 12725 | schedule_work(&rdev->destroy_work); |
12503 | } | 12726 | } |
12727 | } else if (schedule_scan_stop) { | ||
12728 | sched_scan_req->owner_nlportid = 0; | ||
12729 | |||
12730 | if (rdev->ops->sched_scan_stop && | ||
12731 | rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN) | ||
12732 | schedule_work(&rdev->sched_scan_stop_wk); | ||
12504 | } | 12733 | } |
12505 | } | 12734 | } |
12506 | 12735 | ||
diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h index 7ad70d6f0cc6..84d4edf1d545 100644 --- a/net/wireless/nl80211.h +++ b/net/wireless/nl80211.h | |||
@@ -17,7 +17,21 @@ void nl80211_send_sched_scan(struct cfg80211_registered_device *rdev, | |||
17 | struct net_device *netdev, u32 cmd); | 17 | struct net_device *netdev, u32 cmd); |
18 | void nl80211_send_sched_scan_results(struct cfg80211_registered_device *rdev, | 18 | void nl80211_send_sched_scan_results(struct cfg80211_registered_device *rdev, |
19 | struct net_device *netdev); | 19 | struct net_device *netdev); |
20 | void nl80211_send_reg_change_event(struct regulatory_request *request); | 20 | void nl80211_common_reg_change_event(enum nl80211_commands cmd_id, |
21 | struct regulatory_request *request); | ||
22 | |||
23 | static inline void | ||
24 | nl80211_send_reg_change_event(struct regulatory_request *request) | ||
25 | { | ||
26 | nl80211_common_reg_change_event(NL80211_CMD_REG_CHANGE, request); | ||
27 | } | ||
28 | |||
29 | static inline void | ||
30 | nl80211_send_wiphy_reg_change_event(struct regulatory_request *request) | ||
31 | { | ||
32 | nl80211_common_reg_change_event(NL80211_CMD_WIPHY_REG_CHANGE, request); | ||
33 | } | ||
34 | |||
21 | void nl80211_send_rx_auth(struct cfg80211_registered_device *rdev, | 35 | void nl80211_send_rx_auth(struct cfg80211_registered_device *rdev, |
22 | struct net_device *netdev, | 36 | struct net_device *netdev, |
23 | const u8 *buf, size_t len, gfp_t gfp); | 37 | const u8 *buf, size_t len, gfp_t gfp); |
diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 7b8309840d4e..886cc7cb5566 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c | |||
@@ -109,7 +109,7 @@ static struct regulatory_request core_request_world = { | |||
109 | * protected by RTNL (and can be accessed with RCU protection) | 109 | * protected by RTNL (and can be accessed with RCU protection) |
110 | */ | 110 | */ |
111 | static struct regulatory_request __rcu *last_request = | 111 | static struct regulatory_request __rcu *last_request = |
112 | (void __rcu *)&core_request_world; | 112 | (void __force __rcu *)&core_request_world; |
113 | 113 | ||
114 | /* To trigger userspace events */ | 114 | /* To trigger userspace events */ |
115 | static struct platform_device *reg_pdev; | 115 | static struct platform_device *reg_pdev; |
@@ -142,7 +142,7 @@ static const struct ieee80211_regdomain *get_cfg80211_regdom(void) | |||
142 | return rtnl_dereference(cfg80211_regdomain); | 142 | return rtnl_dereference(cfg80211_regdomain); |
143 | } | 143 | } |
144 | 144 | ||
145 | static const struct ieee80211_regdomain *get_wiphy_regdom(struct wiphy *wiphy) | 145 | const struct ieee80211_regdomain *get_wiphy_regdom(struct wiphy *wiphy) |
146 | { | 146 | { |
147 | return rtnl_dereference(wiphy->regd); | 147 | return rtnl_dereference(wiphy->regd); |
148 | } | 148 | } |
@@ -1307,6 +1307,9 @@ static bool ignore_reg_update(struct wiphy *wiphy, | |||
1307 | { | 1307 | { |
1308 | struct regulatory_request *lr = get_last_request(); | 1308 | struct regulatory_request *lr = get_last_request(); |
1309 | 1309 | ||
1310 | if (wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED) | ||
1311 | return true; | ||
1312 | |||
1310 | if (!lr) { | 1313 | if (!lr) { |
1311 | REG_DBG_PRINT("Ignoring regulatory request set by %s " | 1314 | REG_DBG_PRINT("Ignoring regulatory request set by %s " |
1312 | "since last_request is not set\n", | 1315 | "since last_request is not set\n", |
@@ -1683,8 +1686,12 @@ static void handle_channel_custom(struct wiphy *wiphy, | |||
1683 | if (IS_ERR(reg_rule)) { | 1686 | if (IS_ERR(reg_rule)) { |
1684 | REG_DBG_PRINT("Disabling freq %d MHz as custom regd has no rule that fits it\n", | 1687 | REG_DBG_PRINT("Disabling freq %d MHz as custom regd has no rule that fits it\n", |
1685 | chan->center_freq); | 1688 | chan->center_freq); |
1686 | chan->orig_flags |= IEEE80211_CHAN_DISABLED; | 1689 | if (wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED) { |
1687 | chan->flags = chan->orig_flags; | 1690 | chan->flags |= IEEE80211_CHAN_DISABLED; |
1691 | } else { | ||
1692 | chan->orig_flags |= IEEE80211_CHAN_DISABLED; | ||
1693 | chan->flags = chan->orig_flags; | ||
1694 | } | ||
1688 | return; | 1695 | return; |
1689 | } | 1696 | } |
1690 | 1697 | ||
@@ -1709,7 +1716,13 @@ static void handle_channel_custom(struct wiphy *wiphy, | |||
1709 | chan->dfs_state = NL80211_DFS_USABLE; | 1716 | chan->dfs_state = NL80211_DFS_USABLE; |
1710 | 1717 | ||
1711 | chan->beacon_found = false; | 1718 | chan->beacon_found = false; |
1712 | chan->flags |= map_regdom_flags(reg_rule->flags) | bw_flags; | 1719 | |
1720 | if (wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED) | ||
1721 | chan->flags = chan->orig_flags | bw_flags | | ||
1722 | map_regdom_flags(reg_rule->flags); | ||
1723 | else | ||
1724 | chan->flags |= map_regdom_flags(reg_rule->flags) | bw_flags; | ||
1725 | |||
1713 | chan->max_antenna_gain = (int) MBI_TO_DBI(power_rule->max_antenna_gain); | 1726 | chan->max_antenna_gain = (int) MBI_TO_DBI(power_rule->max_antenna_gain); |
1714 | chan->max_reg_power = chan->max_power = | 1727 | chan->max_reg_power = chan->max_power = |
1715 | (int) MBM_TO_DBM(power_rule->max_eirp); | 1728 | (int) MBM_TO_DBM(power_rule->max_eirp); |
@@ -2095,6 +2108,26 @@ out_free: | |||
2095 | reg_free_request(reg_request); | 2108 | reg_free_request(reg_request); |
2096 | } | 2109 | } |
2097 | 2110 | ||
2111 | static bool reg_only_self_managed_wiphys(void) | ||
2112 | { | ||
2113 | struct cfg80211_registered_device *rdev; | ||
2114 | struct wiphy *wiphy; | ||
2115 | bool self_managed_found = false; | ||
2116 | |||
2117 | ASSERT_RTNL(); | ||
2118 | |||
2119 | list_for_each_entry(rdev, &cfg80211_rdev_list, list) { | ||
2120 | wiphy = &rdev->wiphy; | ||
2121 | if (wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED) | ||
2122 | self_managed_found = true; | ||
2123 | else | ||
2124 | return false; | ||
2125 | } | ||
2126 | |||
2127 | /* make sure at least one self-managed wiphy exists */ | ||
2128 | return self_managed_found; | ||
2129 | } | ||
2130 | |||
2098 | /* | 2131 | /* |
2099 | * Processes regulatory hints, this is all the NL80211_REGDOM_SET_BY_* | 2132 | * Processes regulatory hints, this is all the NL80211_REGDOM_SET_BY_* |
2100 | * Regulatory hints come on a first come first serve basis and we | 2133 | * Regulatory hints come on a first come first serve basis and we |
@@ -2126,6 +2159,11 @@ static void reg_process_pending_hints(void) | |||
2126 | 2159 | ||
2127 | spin_unlock(®_requests_lock); | 2160 | spin_unlock(®_requests_lock); |
2128 | 2161 | ||
2162 | if (reg_only_self_managed_wiphys()) { | ||
2163 | reg_free_request(reg_request); | ||
2164 | return; | ||
2165 | } | ||
2166 | |||
2129 | reg_process_hint(reg_request); | 2167 | reg_process_hint(reg_request); |
2130 | } | 2168 | } |
2131 | 2169 | ||
@@ -2153,11 +2191,52 @@ static void reg_process_pending_beacon_hints(void) | |||
2153 | spin_unlock_bh(®_pending_beacons_lock); | 2191 | spin_unlock_bh(®_pending_beacons_lock); |
2154 | } | 2192 | } |
2155 | 2193 | ||
2194 | static void reg_process_self_managed_hints(void) | ||
2195 | { | ||
2196 | struct cfg80211_registered_device *rdev; | ||
2197 | struct wiphy *wiphy; | ||
2198 | const struct ieee80211_regdomain *tmp; | ||
2199 | const struct ieee80211_regdomain *regd; | ||
2200 | enum ieee80211_band band; | ||
2201 | struct regulatory_request request = {}; | ||
2202 | |||
2203 | list_for_each_entry(rdev, &cfg80211_rdev_list, list) { | ||
2204 | wiphy = &rdev->wiphy; | ||
2205 | |||
2206 | spin_lock(®_requests_lock); | ||
2207 | regd = rdev->requested_regd; | ||
2208 | rdev->requested_regd = NULL; | ||
2209 | spin_unlock(®_requests_lock); | ||
2210 | |||
2211 | if (regd == NULL) | ||
2212 | continue; | ||
2213 | |||
2214 | tmp = get_wiphy_regdom(wiphy); | ||
2215 | rcu_assign_pointer(wiphy->regd, regd); | ||
2216 | rcu_free_regdom(tmp); | ||
2217 | |||
2218 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) | ||
2219 | handle_band_custom(wiphy, wiphy->bands[band], regd); | ||
2220 | |||
2221 | reg_process_ht_flags(wiphy); | ||
2222 | |||
2223 | request.wiphy_idx = get_wiphy_idx(wiphy); | ||
2224 | request.alpha2[0] = regd->alpha2[0]; | ||
2225 | request.alpha2[1] = regd->alpha2[1]; | ||
2226 | request.initiator = NL80211_REGDOM_SET_BY_DRIVER; | ||
2227 | |||
2228 | nl80211_send_wiphy_reg_change_event(&request); | ||
2229 | } | ||
2230 | |||
2231 | reg_check_channels(); | ||
2232 | } | ||
2233 | |||
2156 | static void reg_todo(struct work_struct *work) | 2234 | static void reg_todo(struct work_struct *work) |
2157 | { | 2235 | { |
2158 | rtnl_lock(); | 2236 | rtnl_lock(); |
2159 | reg_process_pending_hints(); | 2237 | reg_process_pending_hints(); |
2160 | reg_process_pending_beacon_hints(); | 2238 | reg_process_pending_beacon_hints(); |
2239 | reg_process_self_managed_hints(); | ||
2161 | rtnl_unlock(); | 2240 | rtnl_unlock(); |
2162 | } | 2241 | } |
2163 | 2242 | ||
@@ -2438,6 +2517,8 @@ static void restore_regulatory_settings(bool reset_user) | |||
2438 | world_alpha2[1] = cfg80211_world_regdom->alpha2[1]; | 2517 | world_alpha2[1] = cfg80211_world_regdom->alpha2[1]; |
2439 | 2518 | ||
2440 | list_for_each_entry(rdev, &cfg80211_rdev_list, list) { | 2519 | list_for_each_entry(rdev, &cfg80211_rdev_list, list) { |
2520 | if (rdev->wiphy.regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED) | ||
2521 | continue; | ||
2441 | if (rdev->wiphy.regulatory_flags & REGULATORY_CUSTOM_REG) | 2522 | if (rdev->wiphy.regulatory_flags & REGULATORY_CUSTOM_REG) |
2442 | restore_custom_reg_settings(&rdev->wiphy); | 2523 | restore_custom_reg_settings(&rdev->wiphy); |
2443 | } | 2524 | } |
@@ -2841,10 +2922,79 @@ int set_regdom(const struct ieee80211_regdomain *rd) | |||
2841 | return 0; | 2922 | return 0; |
2842 | } | 2923 | } |
2843 | 2924 | ||
2925 | static int __regulatory_set_wiphy_regd(struct wiphy *wiphy, | ||
2926 | struct ieee80211_regdomain *rd) | ||
2927 | { | ||
2928 | const struct ieee80211_regdomain *regd; | ||
2929 | const struct ieee80211_regdomain *prev_regd; | ||
2930 | struct cfg80211_registered_device *rdev; | ||
2931 | |||
2932 | if (WARN_ON(!wiphy || !rd)) | ||
2933 | return -EINVAL; | ||
2934 | |||
2935 | if (WARN(!(wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED), | ||
2936 | "wiphy should have REGULATORY_WIPHY_SELF_MANAGED\n")) | ||
2937 | return -EPERM; | ||
2938 | |||
2939 | if (WARN(!is_valid_rd(rd), "Invalid regulatory domain detected\n")) { | ||
2940 | print_regdomain_info(rd); | ||
2941 | return -EINVAL; | ||
2942 | } | ||
2943 | |||
2944 | regd = reg_copy_regd(rd); | ||
2945 | if (IS_ERR(regd)) | ||
2946 | return PTR_ERR(regd); | ||
2947 | |||
2948 | rdev = wiphy_to_rdev(wiphy); | ||
2949 | |||
2950 | spin_lock(®_requests_lock); | ||
2951 | prev_regd = rdev->requested_regd; | ||
2952 | rdev->requested_regd = regd; | ||
2953 | spin_unlock(®_requests_lock); | ||
2954 | |||
2955 | kfree(prev_regd); | ||
2956 | return 0; | ||
2957 | } | ||
2958 | |||
2959 | int regulatory_set_wiphy_regd(struct wiphy *wiphy, | ||
2960 | struct ieee80211_regdomain *rd) | ||
2961 | { | ||
2962 | int ret = __regulatory_set_wiphy_regd(wiphy, rd); | ||
2963 | |||
2964 | if (ret) | ||
2965 | return ret; | ||
2966 | |||
2967 | schedule_work(®_work); | ||
2968 | return 0; | ||
2969 | } | ||
2970 | EXPORT_SYMBOL(regulatory_set_wiphy_regd); | ||
2971 | |||
2972 | int regulatory_set_wiphy_regd_sync_rtnl(struct wiphy *wiphy, | ||
2973 | struct ieee80211_regdomain *rd) | ||
2974 | { | ||
2975 | int ret; | ||
2976 | |||
2977 | ASSERT_RTNL(); | ||
2978 | |||
2979 | ret = __regulatory_set_wiphy_regd(wiphy, rd); | ||
2980 | if (ret) | ||
2981 | return ret; | ||
2982 | |||
2983 | /* process the request immediately */ | ||
2984 | reg_process_self_managed_hints(); | ||
2985 | return 0; | ||
2986 | } | ||
2987 | EXPORT_SYMBOL(regulatory_set_wiphy_regd_sync_rtnl); | ||
2988 | |||
2844 | void wiphy_regulatory_register(struct wiphy *wiphy) | 2989 | void wiphy_regulatory_register(struct wiphy *wiphy) |
2845 | { | 2990 | { |
2846 | struct regulatory_request *lr; | 2991 | struct regulatory_request *lr; |
2847 | 2992 | ||
2993 | /* self-managed devices ignore external hints */ | ||
2994 | if (wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED) | ||
2995 | wiphy->regulatory_flags |= REGULATORY_DISABLE_BEACON_HINTS | | ||
2996 | REGULATORY_COUNTRY_IE_IGNORE; | ||
2997 | |||
2848 | if (!reg_dev_ignore_cell_hint(wiphy)) | 2998 | if (!reg_dev_ignore_cell_hint(wiphy)) |
2849 | reg_num_devs_support_basehint++; | 2999 | reg_num_devs_support_basehint++; |
2850 | 3000 | ||
diff --git a/net/wireless/reg.h b/net/wireless/reg.h index 5e48031ccb9a..4b45d6e61d24 100644 --- a/net/wireless/reg.h +++ b/net/wireless/reg.h | |||
@@ -38,6 +38,7 @@ unsigned int reg_get_max_bandwidth(const struct ieee80211_regdomain *rd, | |||
38 | const struct ieee80211_reg_rule *rule); | 38 | const struct ieee80211_reg_rule *rule); |
39 | 39 | ||
40 | bool reg_last_request_cell_base(void); | 40 | bool reg_last_request_cell_base(void); |
41 | const struct ieee80211_regdomain *get_wiphy_regdom(struct wiphy *wiphy); | ||
41 | 42 | ||
42 | /** | 43 | /** |
43 | * regulatory_hint_found_beacon - hints a beacon was found on a channel | 44 | * regulatory_hint_found_beacon - hints a beacon was found on a channel |
diff --git a/net/wireless/scan.c b/net/wireless/scan.c index bda39f149810..c705c3e2b751 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c | |||
@@ -257,7 +257,7 @@ void __cfg80211_sched_scan_results(struct work_struct *wk) | |||
257 | 257 | ||
258 | rtnl_lock(); | 258 | rtnl_lock(); |
259 | 259 | ||
260 | request = rdev->sched_scan_req; | 260 | request = rtnl_dereference(rdev->sched_scan_req); |
261 | 261 | ||
262 | /* we don't have sched_scan_req anymore if the scan is stopping */ | 262 | /* we don't have sched_scan_req anymore if the scan is stopping */ |
263 | if (request) { | 263 | if (request) { |
@@ -279,7 +279,8 @@ void cfg80211_sched_scan_results(struct wiphy *wiphy) | |||
279 | { | 279 | { |
280 | trace_cfg80211_sched_scan_results(wiphy); | 280 | trace_cfg80211_sched_scan_results(wiphy); |
281 | /* ignore if we're not scanning */ | 281 | /* ignore if we're not scanning */ |
282 | if (wiphy_to_rdev(wiphy)->sched_scan_req) | 282 | |
283 | if (rcu_access_pointer(wiphy_to_rdev(wiphy)->sched_scan_req)) | ||
283 | queue_work(cfg80211_wq, | 284 | queue_work(cfg80211_wq, |
284 | &wiphy_to_rdev(wiphy)->sched_scan_results_wk); | 285 | &wiphy_to_rdev(wiphy)->sched_scan_results_wk); |
285 | } | 286 | } |
@@ -308,6 +309,7 @@ EXPORT_SYMBOL(cfg80211_sched_scan_stopped); | |||
308 | int __cfg80211_stop_sched_scan(struct cfg80211_registered_device *rdev, | 309 | int __cfg80211_stop_sched_scan(struct cfg80211_registered_device *rdev, |
309 | bool driver_initiated) | 310 | bool driver_initiated) |
310 | { | 311 | { |
312 | struct cfg80211_sched_scan_request *sched_scan_req; | ||
311 | struct net_device *dev; | 313 | struct net_device *dev; |
312 | 314 | ||
313 | ASSERT_RTNL(); | 315 | ASSERT_RTNL(); |
@@ -315,7 +317,8 @@ int __cfg80211_stop_sched_scan(struct cfg80211_registered_device *rdev, | |||
315 | if (!rdev->sched_scan_req) | 317 | if (!rdev->sched_scan_req) |
316 | return -ENOENT; | 318 | return -ENOENT; |
317 | 319 | ||
318 | dev = rdev->sched_scan_req->dev; | 320 | sched_scan_req = rtnl_dereference(rdev->sched_scan_req); |
321 | dev = sched_scan_req->dev; | ||
319 | 322 | ||
320 | if (!driver_initiated) { | 323 | if (!driver_initiated) { |
321 | int err = rdev_sched_scan_stop(rdev, dev); | 324 | int err = rdev_sched_scan_stop(rdev, dev); |
@@ -325,8 +328,8 @@ int __cfg80211_stop_sched_scan(struct cfg80211_registered_device *rdev, | |||
325 | 328 | ||
326 | nl80211_send_sched_scan(rdev, dev, NL80211_CMD_SCHED_SCAN_STOPPED); | 329 | nl80211_send_sched_scan(rdev, dev, NL80211_CMD_SCHED_SCAN_STOPPED); |
327 | 330 | ||
328 | kfree(rdev->sched_scan_req); | 331 | RCU_INIT_POINTER(rdev->sched_scan_req, NULL); |
329 | rdev->sched_scan_req = NULL; | 332 | kfree_rcu(sched_scan_req, rcu_head); |
330 | 333 | ||
331 | return 0; | 334 | return 0; |
332 | } | 335 | } |
diff --git a/net/wireless/trace.h b/net/wireless/trace.h index ad38910f7036..b17b3692f8c2 100644 --- a/net/wireless/trace.h +++ b/net/wireless/trace.h | |||
@@ -1604,11 +1604,12 @@ TRACE_EVENT(rdev_return_int_survey_info, | |||
1604 | WIPHY_ENTRY | 1604 | WIPHY_ENTRY |
1605 | CHAN_ENTRY | 1605 | CHAN_ENTRY |
1606 | __field(int, ret) | 1606 | __field(int, ret) |
1607 | __field(u64, channel_time) | 1607 | __field(u64, time) |
1608 | __field(u64, channel_time_busy) | 1608 | __field(u64, time_busy) |
1609 | __field(u64, channel_time_ext_busy) | 1609 | __field(u64, time_ext_busy) |
1610 | __field(u64, channel_time_rx) | 1610 | __field(u64, time_rx) |
1611 | __field(u64, channel_time_tx) | 1611 | __field(u64, time_tx) |
1612 | __field(u64, time_scan) | ||
1612 | __field(u32, filled) | 1613 | __field(u32, filled) |
1613 | __field(s8, noise) | 1614 | __field(s8, noise) |
1614 | ), | 1615 | ), |
@@ -1616,22 +1617,24 @@ TRACE_EVENT(rdev_return_int_survey_info, | |||
1616 | WIPHY_ASSIGN; | 1617 | WIPHY_ASSIGN; |
1617 | CHAN_ASSIGN(info->channel); | 1618 | CHAN_ASSIGN(info->channel); |
1618 | __entry->ret = ret; | 1619 | __entry->ret = ret; |
1619 | __entry->channel_time = info->channel_time; | 1620 | __entry->time = info->time; |
1620 | __entry->channel_time_busy = info->channel_time_busy; | 1621 | __entry->time_busy = info->time_busy; |
1621 | __entry->channel_time_ext_busy = info->channel_time_ext_busy; | 1622 | __entry->time_ext_busy = info->time_ext_busy; |
1622 | __entry->channel_time_rx = info->channel_time_rx; | 1623 | __entry->time_rx = info->time_rx; |
1623 | __entry->channel_time_tx = info->channel_time_tx; | 1624 | __entry->time_tx = info->time_tx; |
1625 | __entry->time_scan = info->time_scan; | ||
1624 | __entry->filled = info->filled; | 1626 | __entry->filled = info->filled; |
1625 | __entry->noise = info->noise; | 1627 | __entry->noise = info->noise; |
1626 | ), | 1628 | ), |
1627 | TP_printk(WIPHY_PR_FMT ", returned: %d, " CHAN_PR_FMT | 1629 | TP_printk(WIPHY_PR_FMT ", returned: %d, " CHAN_PR_FMT |
1628 | ", channel time: %llu, channel time busy: %llu, " | 1630 | ", channel time: %llu, channel time busy: %llu, " |
1629 | "channel time extension busy: %llu, channel time rx: %llu, " | 1631 | "channel time extension busy: %llu, channel time rx: %llu, " |
1630 | "channel time tx: %llu, filled: %u, noise: %d", | 1632 | "channel time tx: %llu, scan time: %llu, filled: %u, noise: %d", |
1631 | WIPHY_PR_ARG, __entry->ret, CHAN_PR_ARG, | 1633 | WIPHY_PR_ARG, __entry->ret, CHAN_PR_ARG, |
1632 | __entry->channel_time, __entry->channel_time_busy, | 1634 | __entry->time, __entry->time_busy, |
1633 | __entry->channel_time_ext_busy, __entry->channel_time_rx, | 1635 | __entry->time_ext_busy, __entry->time_rx, |
1634 | __entry->channel_time_tx, __entry->filled, __entry->noise) | 1636 | __entry->time_tx, __entry->time_scan, |
1637 | __entry->filled, __entry->noise) | ||
1635 | ); | 1638 | ); |
1636 | 1639 | ||
1637 | TRACE_EVENT(rdev_tdls_oper, | 1640 | TRACE_EVENT(rdev_tdls_oper, |
diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c index 0f47948c572f..5b24d39d7903 100644 --- a/net/wireless/wext-compat.c +++ b/net/wireless/wext-compat.c | |||
@@ -1300,7 +1300,7 @@ static int cfg80211_wext_giwrate(struct net_device *dev, | |||
1300 | if (err) | 1300 | if (err) |
1301 | return err; | 1301 | return err; |
1302 | 1302 | ||
1303 | if (!(sinfo.filled & STATION_INFO_TX_BITRATE)) | 1303 | if (!(sinfo.filled & BIT(NL80211_STA_INFO_TX_BITRATE))) |
1304 | return -EOPNOTSUPP; | 1304 | return -EOPNOTSUPP; |
1305 | 1305 | ||
1306 | rate->value = 100000 * cfg80211_calculate_bitrate(&sinfo.txrate); | 1306 | rate->value = 100000 * cfg80211_calculate_bitrate(&sinfo.txrate); |
@@ -1340,7 +1340,7 @@ static struct iw_statistics *cfg80211_wireless_stats(struct net_device *dev) | |||
1340 | 1340 | ||
1341 | switch (rdev->wiphy.signal_type) { | 1341 | switch (rdev->wiphy.signal_type) { |
1342 | case CFG80211_SIGNAL_TYPE_MBM: | 1342 | case CFG80211_SIGNAL_TYPE_MBM: |
1343 | if (sinfo.filled & STATION_INFO_SIGNAL) { | 1343 | if (sinfo.filled & BIT(NL80211_STA_INFO_SIGNAL)) { |
1344 | int sig = sinfo.signal; | 1344 | int sig = sinfo.signal; |
1345 | wstats.qual.updated |= IW_QUAL_LEVEL_UPDATED; | 1345 | wstats.qual.updated |= IW_QUAL_LEVEL_UPDATED; |
1346 | wstats.qual.updated |= IW_QUAL_QUAL_UPDATED; | 1346 | wstats.qual.updated |= IW_QUAL_QUAL_UPDATED; |
@@ -1354,7 +1354,7 @@ static struct iw_statistics *cfg80211_wireless_stats(struct net_device *dev) | |||
1354 | break; | 1354 | break; |
1355 | } | 1355 | } |
1356 | case CFG80211_SIGNAL_TYPE_UNSPEC: | 1356 | case CFG80211_SIGNAL_TYPE_UNSPEC: |
1357 | if (sinfo.filled & STATION_INFO_SIGNAL) { | 1357 | if (sinfo.filled & BIT(NL80211_STA_INFO_SIGNAL)) { |
1358 | wstats.qual.updated |= IW_QUAL_LEVEL_UPDATED; | 1358 | wstats.qual.updated |= IW_QUAL_LEVEL_UPDATED; |
1359 | wstats.qual.updated |= IW_QUAL_QUAL_UPDATED; | 1359 | wstats.qual.updated |= IW_QUAL_QUAL_UPDATED; |
1360 | wstats.qual.level = sinfo.signal; | 1360 | wstats.qual.level = sinfo.signal; |
@@ -1367,9 +1367,9 @@ static struct iw_statistics *cfg80211_wireless_stats(struct net_device *dev) | |||
1367 | } | 1367 | } |
1368 | 1368 | ||
1369 | wstats.qual.updated |= IW_QUAL_NOISE_INVALID; | 1369 | wstats.qual.updated |= IW_QUAL_NOISE_INVALID; |
1370 | if (sinfo.filled & STATION_INFO_RX_DROP_MISC) | 1370 | if (sinfo.filled & BIT(NL80211_STA_INFO_RX_DROP_MISC)) |
1371 | wstats.discard.misc = sinfo.rx_dropped_misc; | 1371 | wstats.discard.misc = sinfo.rx_dropped_misc; |
1372 | if (sinfo.filled & STATION_INFO_TX_FAILED) | 1372 | if (sinfo.filled & BIT(NL80211_STA_INFO_TX_FAILED)) |
1373 | wstats.discard.retries = sinfo.tx_failed; | 1373 | wstats.discard.retries = sinfo.tx_failed; |
1374 | 1374 | ||
1375 | return &wstats; | 1375 | return &wstats; |