diff options
author | David S. Miller <davem@davemloft.net> | 2018-12-19 11:36:18 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2018-12-19 11:36:18 -0500 |
commit | 5a862f86b8e86562fc8532160c5530a13e1e944b (patch) | |
tree | 0fa13538752825a01dc98c34dc175271c9341815 /net/wireless | |
parent | 33f18c96afdf4da20014f834874e2820ee880cde (diff) | |
parent | d359bbce0601c6a19203a4b813a7e3910fcba282 (diff) |
Merge tag 'mac80211-next-for-davem-2018-12-19' of git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next
Johannes Berg says:
====================
This time we have too many changes to list, highlights:
* virt_wifi - wireless control simulation on top of
another network interface
* hwsim configurability to test capabilities similar
to real hardware
* various mesh improvements
* various radiotap vendor data fixes in mac80211
* finally the nl_set_extack_cookie_u64() we talked
about previously, used for
* peer measurement APIs, right now only with FTM
(flight time measurement) for location
* made nl80211 radio/interface announcements more complete
* various new HE (802.11ax) things:
updates, TWT support, ...
====================
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/wireless')
-rw-r--r-- | net/wireless/Makefile | 1 | ||||
-rw-r--r-- | net/wireless/chan.c | 3 | ||||
-rw-r--r-- | net/wireless/core.c | 48 | ||||
-rw-r--r-- | net/wireless/core.h | 5 | ||||
-rw-r--r-- | net/wireless/nl80211.c | 307 | ||||
-rw-r--r-- | net/wireless/nl80211.h | 32 | ||||
-rw-r--r-- | net/wireless/pmsr.c | 590 | ||||
-rw-r--r-- | net/wireless/rdev-ops.h | 25 | ||||
-rw-r--r-- | net/wireless/scan.c | 2 | ||||
-rw-r--r-- | net/wireless/trace.h | 92 | ||||
-rw-r--r-- | net/wireless/util.c | 15 |
11 files changed, 1065 insertions, 55 deletions
diff --git a/net/wireless/Makefile b/net/wireless/Makefile index 1d84f91bbfb0..72a224ce8e0a 100644 --- a/net/wireless/Makefile +++ b/net/wireless/Makefile | |||
@@ -12,6 +12,7 @@ obj-$(CONFIG_WEXT_PRIV) += wext-priv.o | |||
12 | 12 | ||
13 | cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o scan.o nl80211.o | 13 | cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o scan.o nl80211.o |
14 | cfg80211-y += mlme.o ibss.o sme.o chan.o ethtool.o mesh.o ap.o trace.o ocb.o | 14 | cfg80211-y += mlme.o ibss.o sme.o chan.o ethtool.o mesh.o ap.o trace.o ocb.o |
15 | cfg80211-y += pmsr.o | ||
15 | cfg80211-$(CONFIG_OF) += of.o | 16 | cfg80211-$(CONFIG_OF) += of.o |
16 | cfg80211-$(CONFIG_CFG80211_DEBUGFS) += debugfs.o | 17 | cfg80211-$(CONFIG_CFG80211_DEBUGFS) += debugfs.o |
17 | cfg80211-$(CONFIG_CFG80211_WEXT) += wext-compat.o wext-sme.o | 18 | cfg80211-$(CONFIG_CFG80211_WEXT) += wext-compat.o wext-sme.o |
diff --git a/net/wireless/chan.c b/net/wireless/chan.c index 2db713d18f71..7dc1bbd0888f 100644 --- a/net/wireless/chan.c +++ b/net/wireless/chan.c | |||
@@ -6,6 +6,7 @@ | |||
6 | * | 6 | * |
7 | * Copyright 2009 Johannes Berg <johannes@sipsolutions.net> | 7 | * Copyright 2009 Johannes Berg <johannes@sipsolutions.net> |
8 | * Copyright 2013-2014 Intel Mobile Communications GmbH | 8 | * Copyright 2013-2014 Intel Mobile Communications GmbH |
9 | * Copyright 2018 Intel Corporation | ||
9 | */ | 10 | */ |
10 | 11 | ||
11 | #include <linux/export.h> | 12 | #include <linux/export.h> |
@@ -747,6 +748,7 @@ bool cfg80211_chandef_usable(struct wiphy *wiphy, | |||
747 | case NL80211_CHAN_WIDTH_20: | 748 | case NL80211_CHAN_WIDTH_20: |
748 | if (!ht_cap->ht_supported) | 749 | if (!ht_cap->ht_supported) |
749 | return false; | 750 | return false; |
751 | /* fall through */ | ||
750 | case NL80211_CHAN_WIDTH_20_NOHT: | 752 | case NL80211_CHAN_WIDTH_20_NOHT: |
751 | prohibited_flags |= IEEE80211_CHAN_NO_20MHZ; | 753 | prohibited_flags |= IEEE80211_CHAN_NO_20MHZ; |
752 | width = 20; | 754 | width = 20; |
@@ -769,6 +771,7 @@ bool cfg80211_chandef_usable(struct wiphy *wiphy, | |||
769 | cap = vht_cap->cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK; | 771 | cap = vht_cap->cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK; |
770 | if (cap != IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ) | 772 | if (cap != IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ) |
771 | return false; | 773 | return false; |
774 | /* fall through */ | ||
772 | case NL80211_CHAN_WIDTH_80: | 775 | case NL80211_CHAN_WIDTH_80: |
773 | if (!vht_cap->vht_supported) | 776 | if (!vht_cap->vht_supported) |
774 | return false; | 777 | return false; |
diff --git a/net/wireless/core.c b/net/wireless/core.c index 5bd01058b9e6..623dfe5e211c 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c | |||
@@ -4,6 +4,7 @@ | |||
4 | * Copyright 2006-2010 Johannes Berg <johannes@sipsolutions.net> | 4 | * Copyright 2006-2010 Johannes Berg <johannes@sipsolutions.net> |
5 | * Copyright 2013-2014 Intel Mobile Communications GmbH | 5 | * Copyright 2013-2014 Intel Mobile Communications GmbH |
6 | * Copyright 2015-2017 Intel Deutschland GmbH | 6 | * Copyright 2015-2017 Intel Deutschland GmbH |
7 | * Copyright (C) 2018 Intel Corporation | ||
7 | */ | 8 | */ |
8 | 9 | ||
9 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | 10 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
@@ -190,11 +191,25 @@ int cfg80211_switch_netns(struct cfg80211_registered_device *rdev, | |||
190 | return err; | 191 | return err; |
191 | } | 192 | } |
192 | 193 | ||
194 | list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) { | ||
195 | if (!wdev->netdev) | ||
196 | continue; | ||
197 | nl80211_notify_iface(rdev, wdev, NL80211_CMD_DEL_INTERFACE); | ||
198 | } | ||
199 | nl80211_notify_wiphy(rdev, NL80211_CMD_DEL_WIPHY); | ||
200 | |||
193 | wiphy_net_set(&rdev->wiphy, net); | 201 | wiphy_net_set(&rdev->wiphy, net); |
194 | 202 | ||
195 | err = device_rename(&rdev->wiphy.dev, dev_name(&rdev->wiphy.dev)); | 203 | err = device_rename(&rdev->wiphy.dev, dev_name(&rdev->wiphy.dev)); |
196 | WARN_ON(err); | 204 | WARN_ON(err); |
197 | 205 | ||
206 | nl80211_notify_wiphy(rdev, NL80211_CMD_NEW_WIPHY); | ||
207 | list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) { | ||
208 | if (!wdev->netdev) | ||
209 | continue; | ||
210 | nl80211_notify_iface(rdev, wdev, NL80211_CMD_NEW_INTERFACE); | ||
211 | } | ||
212 | |||
198 | return 0; | 213 | return 0; |
199 | } | 214 | } |
200 | 215 | ||
@@ -664,6 +679,34 @@ int wiphy_register(struct wiphy *wiphy) | |||
664 | return -EINVAL; | 679 | return -EINVAL; |
665 | #endif | 680 | #endif |
666 | 681 | ||
682 | if (WARN_ON(wiphy->pmsr_capa && !wiphy->pmsr_capa->ftm.supported)) | ||
683 | return -EINVAL; | ||
684 | |||
685 | if (wiphy->pmsr_capa && wiphy->pmsr_capa->ftm.supported) { | ||
686 | if (WARN_ON(!wiphy->pmsr_capa->ftm.asap && | ||
687 | !wiphy->pmsr_capa->ftm.non_asap)) | ||
688 | return -EINVAL; | ||
689 | if (WARN_ON(!wiphy->pmsr_capa->ftm.preambles || | ||
690 | !wiphy->pmsr_capa->ftm.bandwidths)) | ||
691 | return -EINVAL; | ||
692 | if (WARN_ON(wiphy->pmsr_capa->ftm.preambles & | ||
693 | ~(BIT(NL80211_PREAMBLE_LEGACY) | | ||
694 | BIT(NL80211_PREAMBLE_HT) | | ||
695 | BIT(NL80211_PREAMBLE_VHT) | | ||
696 | BIT(NL80211_PREAMBLE_DMG)))) | ||
697 | return -EINVAL; | ||
698 | if (WARN_ON(wiphy->pmsr_capa->ftm.bandwidths & | ||
699 | ~(BIT(NL80211_CHAN_WIDTH_20_NOHT) | | ||
700 | BIT(NL80211_CHAN_WIDTH_20) | | ||
701 | BIT(NL80211_CHAN_WIDTH_40) | | ||
702 | BIT(NL80211_CHAN_WIDTH_80) | | ||
703 | BIT(NL80211_CHAN_WIDTH_80P80) | | ||
704 | BIT(NL80211_CHAN_WIDTH_160) | | ||
705 | BIT(NL80211_CHAN_WIDTH_5) | | ||
706 | BIT(NL80211_CHAN_WIDTH_10)))) | ||
707 | return -EINVAL; | ||
708 | } | ||
709 | |||
667 | /* | 710 | /* |
668 | * if a wiphy has unsupported modes for regulatory channel enforcement, | 711 | * if a wiphy has unsupported modes for regulatory channel enforcement, |
669 | * opt-out of enforcement checking | 712 | * opt-out of enforcement checking |
@@ -1087,6 +1130,8 @@ void __cfg80211_leave(struct cfg80211_registered_device *rdev, | |||
1087 | ASSERT_RTNL(); | 1130 | ASSERT_RTNL(); |
1088 | ASSERT_WDEV_LOCK(wdev); | 1131 | ASSERT_WDEV_LOCK(wdev); |
1089 | 1132 | ||
1133 | cfg80211_pmsr_wdev_down(wdev); | ||
1134 | |||
1090 | switch (wdev->iftype) { | 1135 | switch (wdev->iftype) { |
1091 | case NL80211_IFTYPE_ADHOC: | 1136 | case NL80211_IFTYPE_ADHOC: |
1092 | __cfg80211_leave_ibss(rdev, dev, true); | 1137 | __cfg80211_leave_ibss(rdev, dev, true); |
@@ -1174,6 +1219,9 @@ void cfg80211_init_wdev(struct cfg80211_registered_device *rdev, | |||
1174 | spin_lock_init(&wdev->event_lock); | 1219 | spin_lock_init(&wdev->event_lock); |
1175 | INIT_LIST_HEAD(&wdev->mgmt_registrations); | 1220 | INIT_LIST_HEAD(&wdev->mgmt_registrations); |
1176 | spin_lock_init(&wdev->mgmt_registrations_lock); | 1221 | spin_lock_init(&wdev->mgmt_registrations_lock); |
1222 | INIT_LIST_HEAD(&wdev->pmsr_list); | ||
1223 | spin_lock_init(&wdev->pmsr_lock); | ||
1224 | INIT_WORK(&wdev->pmsr_free_wk, cfg80211_pmsr_free_wk); | ||
1177 | 1225 | ||
1178 | /* | 1226 | /* |
1179 | * We get here also when the interface changes network namespaces, | 1227 | * We get here also when the interface changes network namespaces, |
diff --git a/net/wireless/core.h b/net/wireless/core.h index c61dbba8bf47..c5d6f3418601 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h | |||
@@ -3,6 +3,7 @@ | |||
3 | * Wireless configuration interface internals. | 3 | * Wireless configuration interface internals. |
4 | * | 4 | * |
5 | * Copyright 2006-2010 Johannes Berg <johannes@sipsolutions.net> | 5 | * Copyright 2006-2010 Johannes Berg <johannes@sipsolutions.net> |
6 | * Copyright (C) 2018 Intel Corporation | ||
6 | */ | 7 | */ |
7 | #ifndef __NET_WIRELESS_CORE_H | 8 | #ifndef __NET_WIRELESS_CORE_H |
8 | #define __NET_WIRELESS_CORE_H | 9 | #define __NET_WIRELESS_CORE_H |
@@ -530,4 +531,8 @@ void cfg80211_stop_nan(struct cfg80211_registered_device *rdev, | |||
530 | 531 | ||
531 | void cfg80211_cqm_config_free(struct wireless_dev *wdev); | 532 | void cfg80211_cqm_config_free(struct wireless_dev *wdev); |
532 | 533 | ||
534 | void cfg80211_release_pmsr(struct wireless_dev *wdev, u32 portid); | ||
535 | void cfg80211_pmsr_wdev_down(struct wireless_dev *wdev); | ||
536 | void cfg80211_pmsr_free_wk(struct work_struct *work); | ||
537 | |||
533 | #endif /* __NET_WIRELESS_CORE_H */ | 538 | #endif /* __NET_WIRELESS_CORE_H */ |
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 8d763725498c..10ec05589795 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -240,7 +240,63 @@ nl80211_ftm_responder_policy[NL80211_FTM_RESP_ATTR_MAX + 1] = { | |||
240 | .len = U8_MAX }, | 240 | .len = U8_MAX }, |
241 | }; | 241 | }; |
242 | 242 | ||
243 | static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = { | 243 | static const struct nla_policy |
244 | nl80211_pmsr_ftm_req_attr_policy[NL80211_PMSR_FTM_REQ_ATTR_MAX + 1] = { | ||
245 | [NL80211_PMSR_FTM_REQ_ATTR_ASAP] = { .type = NLA_FLAG }, | ||
246 | [NL80211_PMSR_FTM_REQ_ATTR_PREAMBLE] = { .type = NLA_U32 }, | ||
247 | [NL80211_PMSR_FTM_REQ_ATTR_NUM_BURSTS_EXP] = | ||
248 | NLA_POLICY_MAX(NLA_U8, 15), | ||
249 | [NL80211_PMSR_FTM_REQ_ATTR_BURST_PERIOD] = { .type = NLA_U16 }, | ||
250 | [NL80211_PMSR_FTM_REQ_ATTR_BURST_DURATION] = | ||
251 | NLA_POLICY_MAX(NLA_U8, 15), | ||
252 | [NL80211_PMSR_FTM_REQ_ATTR_FTMS_PER_BURST] = | ||
253 | NLA_POLICY_MAX(NLA_U8, 15), | ||
254 | [NL80211_PMSR_FTM_REQ_ATTR_NUM_FTMR_RETRIES] = { .type = NLA_U8 }, | ||
255 | [NL80211_PMSR_FTM_REQ_ATTR_REQUEST_LCI] = { .type = NLA_FLAG }, | ||
256 | [NL80211_PMSR_FTM_REQ_ATTR_REQUEST_CIVICLOC] = { .type = NLA_FLAG }, | ||
257 | }; | ||
258 | |||
259 | static const struct nla_policy | ||
260 | nl80211_pmsr_req_data_policy[NL80211_PMSR_TYPE_MAX + 1] = { | ||
261 | [NL80211_PMSR_TYPE_FTM] = | ||
262 | NLA_POLICY_NESTED(NL80211_PMSR_FTM_REQ_ATTR_MAX, | ||
263 | nl80211_pmsr_ftm_req_attr_policy), | ||
264 | }; | ||
265 | |||
266 | static const struct nla_policy | ||
267 | nl80211_pmsr_req_attr_policy[NL80211_PMSR_REQ_ATTR_MAX + 1] = { | ||
268 | [NL80211_PMSR_REQ_ATTR_DATA] = | ||
269 | NLA_POLICY_NESTED(NL80211_PMSR_TYPE_MAX, | ||
270 | nl80211_pmsr_req_data_policy), | ||
271 | [NL80211_PMSR_REQ_ATTR_GET_AP_TSF] = { .type = NLA_FLAG }, | ||
272 | }; | ||
273 | |||
274 | static const struct nla_policy | ||
275 | nl80211_psmr_peer_attr_policy[NL80211_PMSR_PEER_ATTR_MAX + 1] = { | ||
276 | [NL80211_PMSR_PEER_ATTR_ADDR] = NLA_POLICY_ETH_ADDR, | ||
277 | /* | ||
278 | * we could specify this again to be the top-level policy, | ||
279 | * but that would open us up to recursion problems ... | ||
280 | */ | ||
281 | [NL80211_PMSR_PEER_ATTR_CHAN] = { .type = NLA_NESTED }, | ||
282 | [NL80211_PMSR_PEER_ATTR_REQ] = | ||
283 | NLA_POLICY_NESTED(NL80211_PMSR_REQ_ATTR_MAX, | ||
284 | nl80211_pmsr_req_attr_policy), | ||
285 | [NL80211_PMSR_PEER_ATTR_RESP] = { .type = NLA_REJECT }, | ||
286 | }; | ||
287 | |||
288 | static const struct nla_policy | ||
289 | nl80211_pmsr_attr_policy[NL80211_PMSR_ATTR_MAX + 1] = { | ||
290 | [NL80211_PMSR_ATTR_MAX_PEERS] = { .type = NLA_REJECT }, | ||
291 | [NL80211_PMSR_ATTR_REPORT_AP_TSF] = { .type = NLA_REJECT }, | ||
292 | [NL80211_PMSR_ATTR_RANDOMIZE_MAC_ADDR] = { .type = NLA_REJECT }, | ||
293 | [NL80211_PMSR_ATTR_TYPE_CAPA] = { .type = NLA_REJECT }, | ||
294 | [NL80211_PMSR_ATTR_PEERS] = | ||
295 | NLA_POLICY_NESTED_ARRAY(NL80211_PMSR_PEER_ATTR_MAX, | ||
296 | nl80211_psmr_peer_attr_policy), | ||
297 | }; | ||
298 | |||
299 | const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = { | ||
244 | [NL80211_ATTR_WIPHY] = { .type = NLA_U32 }, | 300 | [NL80211_ATTR_WIPHY] = { .type = NLA_U32 }, |
245 | [NL80211_ATTR_WIPHY_NAME] = { .type = NLA_NUL_STRING, | 301 | [NL80211_ATTR_WIPHY_NAME] = { .type = NLA_NUL_STRING, |
246 | .len = 20-1 }, | 302 | .len = 20-1 }, |
@@ -497,6 +553,10 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = { | |||
497 | .type = NLA_NESTED, | 553 | .type = NLA_NESTED, |
498 | .validation_data = nl80211_ftm_responder_policy, | 554 | .validation_data = nl80211_ftm_responder_policy, |
499 | }, | 555 | }, |
556 | [NL80211_ATTR_TIMEOUT] = NLA_POLICY_MIN(NLA_U32, 1), | ||
557 | [NL80211_ATTR_PEER_MEASUREMENTS] = | ||
558 | NLA_POLICY_NESTED(NL80211_PMSR_FTM_REQ_ATTR_MAX, | ||
559 | nl80211_pmsr_attr_policy), | ||
500 | }; | 560 | }; |
501 | 561 | ||
502 | /* policy for the key attributes */ | 562 | /* policy for the key attributes */ |
@@ -637,9 +697,9 @@ nl80211_packet_pattern_policy[MAX_NL80211_PKTPAT + 1] = { | |||
637 | [NL80211_PKTPAT_OFFSET] = { .type = NLA_U32 }, | 697 | [NL80211_PKTPAT_OFFSET] = { .type = NLA_U32 }, |
638 | }; | 698 | }; |
639 | 699 | ||
640 | static int nl80211_prepare_wdev_dump(struct netlink_callback *cb, | 700 | int nl80211_prepare_wdev_dump(struct netlink_callback *cb, |
641 | struct cfg80211_registered_device **rdev, | 701 | struct cfg80211_registered_device **rdev, |
642 | struct wireless_dev **wdev) | 702 | struct wireless_dev **wdev) |
643 | { | 703 | { |
644 | int err; | 704 | int err; |
645 | 705 | ||
@@ -684,8 +744,8 @@ static int nl80211_prepare_wdev_dump(struct netlink_callback *cb, | |||
684 | } | 744 | } |
685 | 745 | ||
686 | /* message building helper */ | 746 | /* message building helper */ |
687 | static inline void *nl80211hdr_put(struct sk_buff *skb, u32 portid, u32 seq, | 747 | void *nl80211hdr_put(struct sk_buff *skb, u32 portid, u32 seq, |
688 | int flags, u8 cmd) | 748 | int flags, u8 cmd) |
689 | { | 749 | { |
690 | /* since there is no private header just add the generic one */ | 750 | /* since there is no private header just add the generic one */ |
691 | return genlmsg_put(skb, portid, seq, &nl80211_fam, flags, cmd); | 751 | return genlmsg_put(skb, portid, seq, &nl80211_fam, flags, cmd); |
@@ -1615,6 +1675,91 @@ static int nl80211_add_commands_unsplit(struct cfg80211_registered_device *rdev, | |||
1615 | return -ENOBUFS; | 1675 | return -ENOBUFS; |
1616 | } | 1676 | } |
1617 | 1677 | ||
1678 | static int | ||
1679 | nl80211_send_pmsr_ftm_capa(const struct cfg80211_pmsr_capabilities *cap, | ||
1680 | struct sk_buff *msg) | ||
1681 | { | ||
1682 | struct nlattr *ftm; | ||
1683 | |||
1684 | if (!cap->ftm.supported) | ||
1685 | return 0; | ||
1686 | |||
1687 | ftm = nla_nest_start(msg, NL80211_PMSR_TYPE_FTM); | ||
1688 | if (!ftm) | ||
1689 | return -ENOBUFS; | ||
1690 | |||
1691 | if (cap->ftm.asap && nla_put_flag(msg, NL80211_PMSR_FTM_CAPA_ATTR_ASAP)) | ||
1692 | return -ENOBUFS; | ||
1693 | if (cap->ftm.non_asap && | ||
1694 | nla_put_flag(msg, NL80211_PMSR_FTM_CAPA_ATTR_NON_ASAP)) | ||
1695 | return -ENOBUFS; | ||
1696 | if (cap->ftm.request_lci && | ||
1697 | nla_put_flag(msg, NL80211_PMSR_FTM_CAPA_ATTR_REQ_LCI)) | ||
1698 | return -ENOBUFS; | ||
1699 | if (cap->ftm.request_civicloc && | ||
1700 | nla_put_flag(msg, NL80211_PMSR_FTM_CAPA_ATTR_REQ_CIVICLOC)) | ||
1701 | return -ENOBUFS; | ||
1702 | if (nla_put_u32(msg, NL80211_PMSR_FTM_CAPA_ATTR_PREAMBLES, | ||
1703 | cap->ftm.preambles)) | ||
1704 | return -ENOBUFS; | ||
1705 | if (nla_put_u32(msg, NL80211_PMSR_FTM_CAPA_ATTR_BANDWIDTHS, | ||
1706 | cap->ftm.bandwidths)) | ||
1707 | return -ENOBUFS; | ||
1708 | if (cap->ftm.max_bursts_exponent >= 0 && | ||
1709 | nla_put_u32(msg, NL80211_PMSR_FTM_CAPA_ATTR_MAX_BURSTS_EXPONENT, | ||
1710 | cap->ftm.max_bursts_exponent)) | ||
1711 | return -ENOBUFS; | ||
1712 | if (cap->ftm.max_ftms_per_burst && | ||
1713 | nla_put_u32(msg, NL80211_PMSR_FTM_CAPA_ATTR_MAX_FTMS_PER_BURST, | ||
1714 | cap->ftm.max_ftms_per_burst)) | ||
1715 | return -ENOBUFS; | ||
1716 | |||
1717 | nla_nest_end(msg, ftm); | ||
1718 | return 0; | ||
1719 | } | ||
1720 | |||
1721 | static int nl80211_send_pmsr_capa(struct cfg80211_registered_device *rdev, | ||
1722 | struct sk_buff *msg) | ||
1723 | { | ||
1724 | const struct cfg80211_pmsr_capabilities *cap = rdev->wiphy.pmsr_capa; | ||
1725 | struct nlattr *pmsr, *caps; | ||
1726 | |||
1727 | if (!cap) | ||
1728 | return 0; | ||
1729 | |||
1730 | /* | ||
1731 | * we don't need to clean up anything here since the caller | ||
1732 | * will genlmsg_cancel() if we fail | ||
1733 | */ | ||
1734 | |||
1735 | pmsr = nla_nest_start(msg, NL80211_ATTR_PEER_MEASUREMENTS); | ||
1736 | if (!pmsr) | ||
1737 | return -ENOBUFS; | ||
1738 | |||
1739 | if (nla_put_u32(msg, NL80211_PMSR_ATTR_MAX_PEERS, cap->max_peers)) | ||
1740 | return -ENOBUFS; | ||
1741 | |||
1742 | if (cap->report_ap_tsf && | ||
1743 | nla_put_flag(msg, NL80211_PMSR_ATTR_REPORT_AP_TSF)) | ||
1744 | return -ENOBUFS; | ||
1745 | |||
1746 | if (cap->randomize_mac_addr && | ||
1747 | nla_put_flag(msg, NL80211_PMSR_ATTR_RANDOMIZE_MAC_ADDR)) | ||
1748 | return -ENOBUFS; | ||
1749 | |||
1750 | caps = nla_nest_start(msg, NL80211_PMSR_ATTR_TYPE_CAPA); | ||
1751 | if (!caps) | ||
1752 | return -ENOBUFS; | ||
1753 | |||
1754 | if (nl80211_send_pmsr_ftm_capa(cap, msg)) | ||
1755 | return -ENOBUFS; | ||
1756 | |||
1757 | nla_nest_end(msg, caps); | ||
1758 | nla_nest_end(msg, pmsr); | ||
1759 | |||
1760 | return 0; | ||
1761 | } | ||
1762 | |||
1618 | struct nl80211_dump_wiphy_state { | 1763 | struct nl80211_dump_wiphy_state { |
1619 | s64 filter_wiphy; | 1764 | s64 filter_wiphy; |
1620 | long start; | 1765 | long start; |
@@ -1706,6 +1851,7 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev, | |||
1706 | state->split_start++; | 1851 | state->split_start++; |
1707 | if (state->split) | 1852 | if (state->split) |
1708 | break; | 1853 | break; |
1854 | /* fall through */ | ||
1709 | case 1: | 1855 | case 1: |
1710 | if (nla_put(msg, NL80211_ATTR_CIPHER_SUITES, | 1856 | if (nla_put(msg, NL80211_ATTR_CIPHER_SUITES, |
1711 | sizeof(u32) * rdev->wiphy.n_cipher_suites, | 1857 | sizeof(u32) * rdev->wiphy.n_cipher_suites, |
@@ -1752,6 +1898,7 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev, | |||
1752 | state->split_start++; | 1898 | state->split_start++; |
1753 | if (state->split) | 1899 | if (state->split) |
1754 | break; | 1900 | break; |
1901 | /* fall through */ | ||
1755 | case 2: | 1902 | case 2: |
1756 | if (nl80211_put_iftypes(msg, NL80211_ATTR_SUPPORTED_IFTYPES, | 1903 | if (nl80211_put_iftypes(msg, NL80211_ATTR_SUPPORTED_IFTYPES, |
1757 | rdev->wiphy.interface_modes)) | 1904 | rdev->wiphy.interface_modes)) |
@@ -1759,6 +1906,7 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev, | |||
1759 | state->split_start++; | 1906 | state->split_start++; |
1760 | if (state->split) | 1907 | if (state->split) |
1761 | break; | 1908 | break; |
1909 | /* fall through */ | ||
1762 | case 3: | 1910 | case 3: |
1763 | nl_bands = nla_nest_start(msg, NL80211_ATTR_WIPHY_BANDS); | 1911 | nl_bands = nla_nest_start(msg, NL80211_ATTR_WIPHY_BANDS); |
1764 | if (!nl_bands) | 1912 | if (!nl_bands) |
@@ -1784,6 +1932,7 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev, | |||
1784 | state->chan_start++; | 1932 | state->chan_start++; |
1785 | if (state->split) | 1933 | if (state->split) |
1786 | break; | 1934 | break; |
1935 | /* fall through */ | ||
1787 | default: | 1936 | default: |
1788 | /* add frequencies */ | 1937 | /* add frequencies */ |
1789 | nl_freqs = nla_nest_start( | 1938 | nl_freqs = nla_nest_start( |
@@ -1837,6 +1986,7 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev, | |||
1837 | state->split_start++; | 1986 | state->split_start++; |
1838 | if (state->split) | 1987 | if (state->split) |
1839 | break; | 1988 | break; |
1989 | /* fall through */ | ||
1840 | case 4: | 1990 | case 4: |
1841 | nl_cmds = nla_nest_start(msg, NL80211_ATTR_SUPPORTED_COMMANDS); | 1991 | nl_cmds = nla_nest_start(msg, NL80211_ATTR_SUPPORTED_COMMANDS); |
1842 | if (!nl_cmds) | 1992 | if (!nl_cmds) |
@@ -1863,6 +2013,7 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev, | |||
1863 | state->split_start++; | 2013 | state->split_start++; |
1864 | if (state->split) | 2014 | if (state->split) |
1865 | break; | 2015 | break; |
2016 | /* fall through */ | ||
1866 | case 5: | 2017 | case 5: |
1867 | if (rdev->ops->remain_on_channel && | 2018 | if (rdev->ops->remain_on_channel && |
1868 | (rdev->wiphy.flags & WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL) && | 2019 | (rdev->wiphy.flags & WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL) && |
@@ -1880,6 +2031,7 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev, | |||
1880 | state->split_start++; | 2031 | state->split_start++; |
1881 | if (state->split) | 2032 | if (state->split) |
1882 | break; | 2033 | break; |
2034 | /* fall through */ | ||
1883 | case 6: | 2035 | case 6: |
1884 | #ifdef CONFIG_PM | 2036 | #ifdef CONFIG_PM |
1885 | if (nl80211_send_wowlan(msg, rdev, state->split)) | 2037 | if (nl80211_send_wowlan(msg, rdev, state->split)) |
@@ -1890,6 +2042,7 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev, | |||
1890 | #else | 2042 | #else |
1891 | state->split_start++; | 2043 | state->split_start++; |
1892 | #endif | 2044 | #endif |
2045 | /* fall through */ | ||
1893 | case 7: | 2046 | case 7: |
1894 | if (nl80211_put_iftypes(msg, NL80211_ATTR_SOFTWARE_IFTYPES, | 2047 | if (nl80211_put_iftypes(msg, NL80211_ATTR_SOFTWARE_IFTYPES, |
1895 | rdev->wiphy.software_iftypes)) | 2048 | rdev->wiphy.software_iftypes)) |
@@ -1902,6 +2055,7 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev, | |||
1902 | state->split_start++; | 2055 | state->split_start++; |
1903 | if (state->split) | 2056 | if (state->split) |
1904 | break; | 2057 | break; |
2058 | /* fall through */ | ||
1905 | case 8: | 2059 | case 8: |
1906 | if ((rdev->wiphy.flags & WIPHY_FLAG_HAVE_AP_SME) && | 2060 | if ((rdev->wiphy.flags & WIPHY_FLAG_HAVE_AP_SME) && |
1907 | nla_put_u32(msg, NL80211_ATTR_DEVICE_AP_SME, | 2061 | nla_put_u32(msg, NL80211_ATTR_DEVICE_AP_SME, |
@@ -2118,6 +2272,12 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev, | |||
2118 | goto nla_put_failure; | 2272 | goto nla_put_failure; |
2119 | } | 2273 | } |
2120 | 2274 | ||
2275 | state->split_start++; | ||
2276 | break; | ||
2277 | case 14: | ||
2278 | if (nl80211_send_pmsr_capa(rdev, msg)) | ||
2279 | goto nla_put_failure; | ||
2280 | |||
2121 | /* done */ | 2281 | /* done */ |
2122 | state->split_start = 0; | 2282 | state->split_start = 0; |
2123 | break; | 2283 | break; |
@@ -2318,9 +2478,9 @@ static bool nl80211_can_set_dev_channel(struct wireless_dev *wdev) | |||
2318 | wdev->iftype == NL80211_IFTYPE_P2P_GO; | 2478 | wdev->iftype == NL80211_IFTYPE_P2P_GO; |
2319 | } | 2479 | } |
2320 | 2480 | ||
2321 | static int nl80211_parse_chandef(struct cfg80211_registered_device *rdev, | 2481 | int nl80211_parse_chandef(struct cfg80211_registered_device *rdev, |
2322 | struct genl_info *info, | 2482 | struct genl_info *info, |
2323 | struct cfg80211_chan_def *chandef) | 2483 | struct cfg80211_chan_def *chandef) |
2324 | { | 2484 | { |
2325 | struct netlink_ext_ack *extack = info->extack; | 2485 | struct netlink_ext_ack *extack = info->extack; |
2326 | struct nlattr **attrs = info->attrs; | 2486 | struct nlattr **attrs = info->attrs; |
@@ -2794,12 +2954,6 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) | |||
2794 | return 0; | 2954 | return 0; |
2795 | } | 2955 | } |
2796 | 2956 | ||
2797 | static inline u64 wdev_id(struct wireless_dev *wdev) | ||
2798 | { | ||
2799 | return (u64)wdev->identifier | | ||
2800 | ((u64)wiphy_to_rdev(wdev->wiphy)->wiphy_idx << 32); | ||
2801 | } | ||
2802 | |||
2803 | static int nl80211_send_chandef(struct sk_buff *msg, | 2957 | static int nl80211_send_chandef(struct sk_buff *msg, |
2804 | const struct cfg80211_chan_def *chandef) | 2958 | const struct cfg80211_chan_def *chandef) |
2805 | { | 2959 | { |
@@ -2832,14 +2986,15 @@ static int nl80211_send_chandef(struct sk_buff *msg, | |||
2832 | 2986 | ||
2833 | static int nl80211_send_iface(struct sk_buff *msg, u32 portid, u32 seq, int flags, | 2987 | static int nl80211_send_iface(struct sk_buff *msg, u32 portid, u32 seq, int flags, |
2834 | struct cfg80211_registered_device *rdev, | 2988 | struct cfg80211_registered_device *rdev, |
2835 | struct wireless_dev *wdev, bool removal) | 2989 | struct wireless_dev *wdev, |
2990 | enum nl80211_commands cmd) | ||
2836 | { | 2991 | { |
2837 | struct net_device *dev = wdev->netdev; | 2992 | struct net_device *dev = wdev->netdev; |
2838 | u8 cmd = NL80211_CMD_NEW_INTERFACE; | ||
2839 | void *hdr; | 2993 | void *hdr; |
2840 | 2994 | ||
2841 | if (removal) | 2995 | WARN_ON(cmd != NL80211_CMD_NEW_INTERFACE && |
2842 | cmd = NL80211_CMD_DEL_INTERFACE; | 2996 | cmd != NL80211_CMD_DEL_INTERFACE && |
2997 | cmd != NL80211_CMD_SET_INTERFACE); | ||
2843 | 2998 | ||
2844 | hdr = nl80211hdr_put(msg, portid, seq, flags, cmd); | 2999 | hdr = nl80211hdr_put(msg, portid, seq, flags, cmd); |
2845 | if (!hdr) | 3000 | if (!hdr) |
@@ -2987,7 +3142,8 @@ static int nl80211_dump_interface(struct sk_buff *skb, struct netlink_callback * | |||
2987 | } | 3142 | } |
2988 | if (nl80211_send_iface(skb, NETLINK_CB(cb->skb).portid, | 3143 | if (nl80211_send_iface(skb, NETLINK_CB(cb->skb).portid, |
2989 | cb->nlh->nlmsg_seq, NLM_F_MULTI, | 3144 | cb->nlh->nlmsg_seq, NLM_F_MULTI, |
2990 | rdev, wdev, false) < 0) { | 3145 | rdev, wdev, |
3146 | NL80211_CMD_NEW_INTERFACE) < 0) { | ||
2991 | goto out; | 3147 | goto out; |
2992 | } | 3148 | } |
2993 | if_idx++; | 3149 | if_idx++; |
@@ -3017,7 +3173,7 @@ static int nl80211_get_interface(struct sk_buff *skb, struct genl_info *info) | |||
3017 | return -ENOMEM; | 3173 | return -ENOMEM; |
3018 | 3174 | ||
3019 | if (nl80211_send_iface(msg, info->snd_portid, info->snd_seq, 0, | 3175 | if (nl80211_send_iface(msg, info->snd_portid, info->snd_seq, 0, |
3020 | rdev, wdev, false) < 0) { | 3176 | rdev, wdev, NL80211_CMD_NEW_INTERFACE) < 0) { |
3021 | nlmsg_free(msg); | 3177 | nlmsg_free(msg); |
3022 | return -ENOBUFS; | 3178 | return -ENOBUFS; |
3023 | } | 3179 | } |
@@ -3207,6 +3363,12 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) | |||
3207 | if (!err && params.use_4addr != -1) | 3363 | if (!err && params.use_4addr != -1) |
3208 | dev->ieee80211_ptr->use_4addr = params.use_4addr; | 3364 | dev->ieee80211_ptr->use_4addr = params.use_4addr; |
3209 | 3365 | ||
3366 | if (change && !err) { | ||
3367 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
3368 | |||
3369 | nl80211_notify_iface(rdev, wdev, NL80211_CMD_SET_INTERFACE); | ||
3370 | } | ||
3371 | |||
3210 | return err; | 3372 | return err; |
3211 | } | 3373 | } |
3212 | 3374 | ||
@@ -3298,7 +3460,7 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) | |||
3298 | } | 3460 | } |
3299 | 3461 | ||
3300 | if (nl80211_send_iface(msg, info->snd_portid, info->snd_seq, 0, | 3462 | if (nl80211_send_iface(msg, info->snd_portid, info->snd_seq, 0, |
3301 | rdev, wdev, false) < 0) { | 3463 | rdev, wdev, NL80211_CMD_NEW_INTERFACE) < 0) { |
3302 | nlmsg_free(msg); | 3464 | nlmsg_free(msg); |
3303 | return -ENOBUFS; | 3465 | return -ENOBUFS; |
3304 | } | 3466 | } |
@@ -4521,8 +4683,7 @@ static int parse_station_flags(struct genl_info *info, | |||
4521 | return 0; | 4683 | return 0; |
4522 | } | 4684 | } |
4523 | 4685 | ||
4524 | static bool nl80211_put_sta_rate(struct sk_buff *msg, struct rate_info *info, | 4686 | bool nl80211_put_sta_rate(struct sk_buff *msg, struct rate_info *info, int attr) |
4525 | int attr) | ||
4526 | { | 4687 | { |
4527 | struct nlattr *rate; | 4688 | struct nlattr *rate; |
4528 | u32 bitrate; | 4689 | u32 bitrate; |
@@ -4731,6 +4892,7 @@ static int nl80211_send_station(struct sk_buff *msg, u32 cmd, u32 portid, | |||
4731 | PUT_SINFO(LOCAL_PM, local_pm, u32); | 4892 | PUT_SINFO(LOCAL_PM, local_pm, u32); |
4732 | PUT_SINFO(PEER_PM, peer_pm, u32); | 4893 | PUT_SINFO(PEER_PM, peer_pm, u32); |
4733 | PUT_SINFO(NONPEER_PM, nonpeer_pm, u32); | 4894 | PUT_SINFO(NONPEER_PM, nonpeer_pm, u32); |
4895 | PUT_SINFO(CONNECTED_TO_GATE, connected_to_gate, u8); | ||
4734 | 4896 | ||
4735 | if (sinfo->filled & BIT_ULL(NL80211_STA_INFO_BSS_PARAM)) { | 4897 | if (sinfo->filled & BIT_ULL(NL80211_STA_INFO_BSS_PARAM)) { |
4736 | bss_param = nla_nest_start(msg, NL80211_STA_INFO_BSS_PARAM); | 4898 | bss_param = nla_nest_start(msg, NL80211_STA_INFO_BSS_PARAM); |
@@ -6122,7 +6284,9 @@ static int nl80211_get_mesh_config(struct sk_buff *skb, | |||
6122 | nla_put_u16(msg, NL80211_MESHCONF_AWAKE_WINDOW, | 6284 | nla_put_u16(msg, NL80211_MESHCONF_AWAKE_WINDOW, |
6123 | cur_params.dot11MeshAwakeWindowDuration) || | 6285 | cur_params.dot11MeshAwakeWindowDuration) || |
6124 | nla_put_u32(msg, NL80211_MESHCONF_PLINK_TIMEOUT, | 6286 | nla_put_u32(msg, NL80211_MESHCONF_PLINK_TIMEOUT, |
6125 | cur_params.plink_timeout)) | 6287 | cur_params.plink_timeout) || |
6288 | nla_put_u8(msg, NL80211_MESHCONF_CONNECTED_TO_GATE, | ||
6289 | cur_params.dot11MeshConnectedToMeshGate)) | ||
6126 | goto nla_put_failure; | 6290 | goto nla_put_failure; |
6127 | nla_nest_end(msg, pinfoattr); | 6291 | nla_nest_end(msg, pinfoattr); |
6128 | genlmsg_end(msg, hdr); | 6292 | genlmsg_end(msg, hdr); |
@@ -6179,6 +6343,7 @@ nl80211_meshconf_params_policy[NL80211_MESHCONF_ATTR_MAX+1] = { | |||
6179 | NL80211_MESH_POWER_MAX), | 6343 | NL80211_MESH_POWER_MAX), |
6180 | [NL80211_MESHCONF_AWAKE_WINDOW] = { .type = NLA_U16 }, | 6344 | [NL80211_MESHCONF_AWAKE_WINDOW] = { .type = NLA_U16 }, |
6181 | [NL80211_MESHCONF_PLINK_TIMEOUT] = { .type = NLA_U32 }, | 6345 | [NL80211_MESHCONF_PLINK_TIMEOUT] = { .type = NLA_U32 }, |
6346 | [NL80211_MESHCONF_CONNECTED_TO_GATE] = NLA_POLICY_RANGE(NLA_U8, 0, 1), | ||
6182 | }; | 6347 | }; |
6183 | 6348 | ||
6184 | static const struct nla_policy | 6349 | static const struct nla_policy |
@@ -6290,6 +6455,9 @@ do { \ | |||
6290 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, rssi_threshold, mask, | 6455 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, rssi_threshold, mask, |
6291 | NL80211_MESHCONF_RSSI_THRESHOLD, | 6456 | NL80211_MESHCONF_RSSI_THRESHOLD, |
6292 | nla_get_s32); | 6457 | nla_get_s32); |
6458 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshConnectedToMeshGate, mask, | ||
6459 | NL80211_MESHCONF_CONNECTED_TO_GATE, | ||
6460 | nla_get_u8); | ||
6293 | /* | 6461 | /* |
6294 | * Check HT operation mode based on | 6462 | * Check HT operation mode based on |
6295 | * IEEE 802.11-2016 9.4.2.57 HT Operation element. | 6463 | * IEEE 802.11-2016 9.4.2.57 HT Operation element. |
@@ -6855,8 +7023,8 @@ static int parse_bss_select(struct nlattr *nla, struct wiphy *wiphy, | |||
6855 | return 0; | 7023 | return 0; |
6856 | } | 7024 | } |
6857 | 7025 | ||
6858 | static int nl80211_parse_random_mac(struct nlattr **attrs, | 7026 | int nl80211_parse_random_mac(struct nlattr **attrs, |
6859 | u8 *mac_addr, u8 *mac_addr_mask) | 7027 | u8 *mac_addr, u8 *mac_addr_mask) |
6860 | { | 7028 | { |
6861 | int i; | 7029 | int i; |
6862 | 7030 | ||
@@ -7822,6 +7990,60 @@ static int nl80211_start_radar_detection(struct sk_buff *skb, | |||
7822 | return err; | 7990 | return err; |
7823 | } | 7991 | } |
7824 | 7992 | ||
7993 | static int nl80211_notify_radar_detection(struct sk_buff *skb, | ||
7994 | struct genl_info *info) | ||
7995 | { | ||
7996 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | ||
7997 | struct net_device *dev = info->user_ptr[1]; | ||
7998 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
7999 | struct wiphy *wiphy = wdev->wiphy; | ||
8000 | struct cfg80211_chan_def chandef; | ||
8001 | enum nl80211_dfs_regions dfs_region; | ||
8002 | int err; | ||
8003 | |||
8004 | dfs_region = reg_get_dfs_region(wiphy); | ||
8005 | if (dfs_region == NL80211_DFS_UNSET) { | ||
8006 | GENL_SET_ERR_MSG(info, | ||
8007 | "DFS Region is not set. Unexpected Radar indication"); | ||
8008 | return -EINVAL; | ||
8009 | } | ||
8010 | |||
8011 | err = nl80211_parse_chandef(rdev, info, &chandef); | ||
8012 | if (err) { | ||
8013 | GENL_SET_ERR_MSG(info, "Unable to extract chandef info"); | ||
8014 | return err; | ||
8015 | } | ||
8016 | |||
8017 | err = cfg80211_chandef_dfs_required(wiphy, &chandef, wdev->iftype); | ||
8018 | if (err < 0) { | ||
8019 | GENL_SET_ERR_MSG(info, "chandef is invalid"); | ||
8020 | return err; | ||
8021 | } | ||
8022 | |||
8023 | if (err == 0) { | ||
8024 | GENL_SET_ERR_MSG(info, | ||
8025 | "Unexpected Radar indication for chandef/iftype"); | ||
8026 | return -EINVAL; | ||
8027 | } | ||
8028 | |||
8029 | /* Do not process this notification if radar is already detected | ||
8030 | * by kernel on this channel, and return success. | ||
8031 | */ | ||
8032 | if (chandef.chan->dfs_state == NL80211_DFS_UNAVAILABLE) | ||
8033 | return 0; | ||
8034 | |||
8035 | cfg80211_set_dfs_state(wiphy, &chandef, NL80211_DFS_UNAVAILABLE); | ||
8036 | |||
8037 | cfg80211_sched_dfs_chan_update(rdev); | ||
8038 | |||
8039 | memcpy(&rdev->radar_chandef, &chandef, sizeof(chandef)); | ||
8040 | |||
8041 | /* Propagate this notification to other radios as well */ | ||
8042 | queue_work(cfg80211_wq, &rdev->propagate_radar_detect_wk); | ||
8043 | |||
8044 | return 0; | ||
8045 | } | ||
8046 | |||
7825 | static int nl80211_channel_switch(struct sk_buff *skb, struct genl_info *info) | 8047 | static int nl80211_channel_switch(struct sk_buff *skb, struct genl_info *info) |
7826 | { | 8048 | { |
7827 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 8049 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
@@ -13899,6 +14121,22 @@ static const struct genl_ops nl80211_ops[] = { | |||
13899 | .internal_flags = NL80211_FLAG_NEED_NETDEV | | 14121 | .internal_flags = NL80211_FLAG_NEED_NETDEV | |
13900 | NL80211_FLAG_NEED_RTNL, | 14122 | NL80211_FLAG_NEED_RTNL, |
13901 | }, | 14123 | }, |
14124 | { | ||
14125 | .cmd = NL80211_CMD_PEER_MEASUREMENT_START, | ||
14126 | .doit = nl80211_pmsr_start, | ||
14127 | .policy = nl80211_policy, | ||
14128 | .flags = GENL_UNS_ADMIN_PERM, | ||
14129 | .internal_flags = NL80211_FLAG_NEED_WDEV_UP | | ||
14130 | NL80211_FLAG_NEED_RTNL, | ||
14131 | }, | ||
14132 | { | ||
14133 | .cmd = NL80211_CMD_NOTIFY_RADAR, | ||
14134 | .doit = nl80211_notify_radar_detection, | ||
14135 | .policy = nl80211_policy, | ||
14136 | .flags = GENL_UNS_ADMIN_PERM, | ||
14137 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | ||
14138 | NL80211_FLAG_NEED_RTNL, | ||
14139 | }, | ||
13902 | }; | 14140 | }; |
13903 | 14141 | ||
13904 | static struct genl_family nl80211_fam __ro_after_init = { | 14142 | static struct genl_family nl80211_fam __ro_after_init = { |
@@ -13946,15 +14184,11 @@ void nl80211_notify_iface(struct cfg80211_registered_device *rdev, | |||
13946 | { | 14184 | { |
13947 | struct sk_buff *msg; | 14185 | struct sk_buff *msg; |
13948 | 14186 | ||
13949 | WARN_ON(cmd != NL80211_CMD_NEW_INTERFACE && | ||
13950 | cmd != NL80211_CMD_DEL_INTERFACE); | ||
13951 | |||
13952 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | 14187 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); |
13953 | if (!msg) | 14188 | if (!msg) |
13954 | return; | 14189 | return; |
13955 | 14190 | ||
13956 | if (nl80211_send_iface(msg, 0, 0, 0, rdev, wdev, | 14191 | if (nl80211_send_iface(msg, 0, 0, 0, rdev, wdev, cmd) < 0) { |
13957 | cmd == NL80211_CMD_DEL_INTERFACE) < 0) { | ||
13958 | nlmsg_free(msg); | 14192 | nlmsg_free(msg); |
13959 | return; | 14193 | return; |
13960 | } | 14194 | } |
@@ -14573,7 +14807,8 @@ void nl80211_send_ibss_bssid(struct cfg80211_registered_device *rdev, | |||
14573 | } | 14807 | } |
14574 | 14808 | ||
14575 | void cfg80211_notify_new_peer_candidate(struct net_device *dev, const u8 *addr, | 14809 | void cfg80211_notify_new_peer_candidate(struct net_device *dev, const u8 *addr, |
14576 | const u8* ie, u8 ie_len, gfp_t gfp) | 14810 | const u8 *ie, u8 ie_len, |
14811 | int sig_dbm, gfp_t gfp) | ||
14577 | { | 14812 | { |
14578 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 14813 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
14579 | struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); | 14814 | struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); |
@@ -14599,7 +14834,9 @@ void cfg80211_notify_new_peer_candidate(struct net_device *dev, const u8 *addr, | |||
14599 | nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) || | 14834 | nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) || |
14600 | nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) || | 14835 | nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) || |
14601 | (ie_len && ie && | 14836 | (ie_len && ie && |
14602 | nla_put(msg, NL80211_ATTR_IE, ie_len , ie))) | 14837 | nla_put(msg, NL80211_ATTR_IE, ie_len, ie)) || |
14838 | (sig_dbm && | ||
14839 | nla_put_u32(msg, NL80211_ATTR_RX_SIGNAL_DBM, sig_dbm))) | ||
14603 | goto nla_put_failure; | 14840 | goto nla_put_failure; |
14604 | 14841 | ||
14605 | genlmsg_end(msg, hdr); | 14842 | genlmsg_end(msg, hdr); |
@@ -15882,6 +16119,8 @@ static int nl80211_netlink_notify(struct notifier_block * nb, | |||
15882 | } else if (wdev->conn_owner_nlportid == notify->portid) { | 16119 | } else if (wdev->conn_owner_nlportid == notify->portid) { |
15883 | schedule_work(&wdev->disconnect_wk); | 16120 | schedule_work(&wdev->disconnect_wk); |
15884 | } | 16121 | } |
16122 | |||
16123 | cfg80211_release_pmsr(wdev, notify->portid); | ||
15885 | } | 16124 | } |
15886 | 16125 | ||
15887 | spin_lock_bh(&rdev->beacon_registrations_lock); | 16126 | spin_lock_bh(&rdev->beacon_registrations_lock); |
diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h index 79e47fe60c35..531c82dcba6b 100644 --- a/net/wireless/nl80211.h +++ b/net/wireless/nl80211.h | |||
@@ -1,4 +1,8 @@ | |||
1 | /* SPDX-License-Identifier: GPL-2.0 */ | 1 | /* SPDX-License-Identifier: GPL-2.0 */ |
2 | /* | ||
3 | * Portions of this file | ||
4 | * Copyright (C) 2018 Intel Corporation | ||
5 | */ | ||
2 | #ifndef __NET_WIRELESS_NL80211_H | 6 | #ifndef __NET_WIRELESS_NL80211_H |
3 | #define __NET_WIRELESS_NL80211_H | 7 | #define __NET_WIRELESS_NL80211_H |
4 | 8 | ||
@@ -6,6 +10,30 @@ | |||
6 | 10 | ||
7 | int nl80211_init(void); | 11 | int nl80211_init(void); |
8 | void nl80211_exit(void); | 12 | void nl80211_exit(void); |
13 | |||
14 | extern const struct nla_policy nl80211_policy[NUM_NL80211_ATTR]; | ||
15 | |||
16 | void *nl80211hdr_put(struct sk_buff *skb, u32 portid, u32 seq, | ||
17 | int flags, u8 cmd); | ||
18 | bool nl80211_put_sta_rate(struct sk_buff *msg, struct rate_info *info, | ||
19 | int attr); | ||
20 | |||
21 | static inline u64 wdev_id(struct wireless_dev *wdev) | ||
22 | { | ||
23 | return (u64)wdev->identifier | | ||
24 | ((u64)wiphy_to_rdev(wdev->wiphy)->wiphy_idx << 32); | ||
25 | } | ||
26 | |||
27 | int nl80211_prepare_wdev_dump(struct netlink_callback *cb, | ||
28 | struct cfg80211_registered_device **rdev, | ||
29 | struct wireless_dev **wdev); | ||
30 | |||
31 | int nl80211_parse_chandef(struct cfg80211_registered_device *rdev, | ||
32 | struct genl_info *info, | ||
33 | struct cfg80211_chan_def *chandef); | ||
34 | int nl80211_parse_random_mac(struct nlattr **attrs, | ||
35 | u8 *mac_addr, u8 *mac_addr_mask); | ||
36 | |||
9 | void nl80211_notify_wiphy(struct cfg80211_registered_device *rdev, | 37 | void nl80211_notify_wiphy(struct cfg80211_registered_device *rdev, |
10 | enum nl80211_commands cmd); | 38 | enum nl80211_commands cmd); |
11 | void nl80211_notify_iface(struct cfg80211_registered_device *rdev, | 39 | void nl80211_notify_iface(struct cfg80211_registered_device *rdev, |
@@ -95,4 +123,8 @@ void nl80211_send_ap_stopped(struct wireless_dev *wdev); | |||
95 | 123 | ||
96 | void cfg80211_rdev_free_coalesce(struct cfg80211_registered_device *rdev); | 124 | void cfg80211_rdev_free_coalesce(struct cfg80211_registered_device *rdev); |
97 | 125 | ||
126 | /* peer measurement */ | ||
127 | int nl80211_pmsr_start(struct sk_buff *skb, struct genl_info *info); | ||
128 | int nl80211_pmsr_dump_results(struct sk_buff *skb, struct netlink_callback *cb); | ||
129 | |||
98 | #endif /* __NET_WIRELESS_NL80211_H */ | 130 | #endif /* __NET_WIRELESS_NL80211_H */ |
diff --git a/net/wireless/pmsr.c b/net/wireless/pmsr.c new file mode 100644 index 000000000000..de9286703280 --- /dev/null +++ b/net/wireless/pmsr.c | |||
@@ -0,0 +1,590 @@ | |||
1 | /* SPDX-License-Identifier: GPL-2.0 */ | ||
2 | /* | ||
3 | * Copyright (C) 2018 Intel Corporation | ||
4 | */ | ||
5 | #ifndef __PMSR_H | ||
6 | #define __PMSR_H | ||
7 | #include <net/cfg80211.h> | ||
8 | #include "core.h" | ||
9 | #include "nl80211.h" | ||
10 | #include "rdev-ops.h" | ||
11 | |||
12 | static int pmsr_parse_ftm(struct cfg80211_registered_device *rdev, | ||
13 | struct nlattr *ftmreq, | ||
14 | struct cfg80211_pmsr_request_peer *out, | ||
15 | struct genl_info *info) | ||
16 | { | ||
17 | const struct cfg80211_pmsr_capabilities *capa = rdev->wiphy.pmsr_capa; | ||
18 | struct nlattr *tb[NL80211_PMSR_FTM_REQ_ATTR_MAX + 1]; | ||
19 | u32 preamble = NL80211_PREAMBLE_DMG; /* only optional in DMG */ | ||
20 | |||
21 | /* validate existing data */ | ||
22 | if (!(rdev->wiphy.pmsr_capa->ftm.bandwidths & BIT(out->chandef.width))) { | ||
23 | NL_SET_ERR_MSG(info->extack, "FTM: unsupported bandwidth"); | ||
24 | return -EINVAL; | ||
25 | } | ||
26 | |||
27 | /* no validation needed - was already done via nested policy */ | ||
28 | nla_parse_nested(tb, NL80211_PMSR_FTM_REQ_ATTR_MAX, ftmreq, NULL, NULL); | ||
29 | |||
30 | if (tb[NL80211_PMSR_FTM_REQ_ATTR_PREAMBLE]) | ||
31 | preamble = nla_get_u32(tb[NL80211_PMSR_FTM_REQ_ATTR_PREAMBLE]); | ||
32 | |||
33 | /* set up values - struct is 0-initialized */ | ||
34 | out->ftm.requested = true; | ||
35 | |||
36 | switch (out->chandef.chan->band) { | ||
37 | case NL80211_BAND_60GHZ: | ||
38 | /* optional */ | ||
39 | break; | ||
40 | default: | ||
41 | if (!tb[NL80211_PMSR_FTM_REQ_ATTR_PREAMBLE]) { | ||
42 | NL_SET_ERR_MSG(info->extack, | ||
43 | "FTM: must specify preamble"); | ||
44 | return -EINVAL; | ||
45 | } | ||
46 | } | ||
47 | |||
48 | if (!(capa->ftm.preambles & BIT(preamble))) { | ||
49 | NL_SET_ERR_MSG_ATTR(info->extack, | ||
50 | tb[NL80211_PMSR_FTM_REQ_ATTR_PREAMBLE], | ||
51 | "FTM: invalid preamble"); | ||
52 | return -EINVAL; | ||
53 | } | ||
54 | |||
55 | out->ftm.preamble = preamble; | ||
56 | |||
57 | out->ftm.burst_period = 0; | ||
58 | if (tb[NL80211_PMSR_FTM_REQ_ATTR_BURST_PERIOD]) | ||
59 | out->ftm.burst_period = | ||
60 | nla_get_u32(tb[NL80211_PMSR_FTM_REQ_ATTR_BURST_PERIOD]); | ||
61 | |||
62 | out->ftm.asap = !!tb[NL80211_PMSR_FTM_REQ_ATTR_ASAP]; | ||
63 | if (out->ftm.asap && !capa->ftm.asap) { | ||
64 | NL_SET_ERR_MSG_ATTR(info->extack, | ||
65 | tb[NL80211_PMSR_FTM_REQ_ATTR_ASAP], | ||
66 | "FTM: ASAP mode not supported"); | ||
67 | return -EINVAL; | ||
68 | } | ||
69 | |||
70 | if (!out->ftm.asap && !capa->ftm.non_asap) { | ||
71 | NL_SET_ERR_MSG(info->extack, | ||
72 | "FTM: non-ASAP mode not supported"); | ||
73 | return -EINVAL; | ||
74 | } | ||
75 | |||
76 | out->ftm.num_bursts_exp = 0; | ||
77 | if (tb[NL80211_PMSR_FTM_REQ_ATTR_NUM_BURSTS_EXP]) | ||
78 | out->ftm.num_bursts_exp = | ||
79 | nla_get_u32(tb[NL80211_PMSR_FTM_REQ_ATTR_NUM_BURSTS_EXP]); | ||
80 | |||
81 | if (capa->ftm.max_bursts_exponent >= 0 && | ||
82 | out->ftm.num_bursts_exp > capa->ftm.max_bursts_exponent) { | ||
83 | NL_SET_ERR_MSG_ATTR(info->extack, | ||
84 | tb[NL80211_PMSR_FTM_REQ_ATTR_NUM_BURSTS_EXP], | ||
85 | "FTM: max NUM_BURSTS_EXP must be set lower than the device limit"); | ||
86 | return -EINVAL; | ||
87 | } | ||
88 | |||
89 | out->ftm.burst_duration = 15; | ||
90 | if (tb[NL80211_PMSR_FTM_REQ_ATTR_BURST_DURATION]) | ||
91 | out->ftm.burst_duration = | ||
92 | nla_get_u32(tb[NL80211_PMSR_FTM_REQ_ATTR_BURST_DURATION]); | ||
93 | |||
94 | out->ftm.ftms_per_burst = 0; | ||
95 | if (tb[NL80211_PMSR_FTM_REQ_ATTR_FTMS_PER_BURST]) | ||
96 | out->ftm.ftms_per_burst = | ||
97 | nla_get_u32(tb[NL80211_PMSR_FTM_REQ_ATTR_FTMS_PER_BURST]); | ||
98 | |||
99 | if (capa->ftm.max_ftms_per_burst && | ||
100 | (out->ftm.ftms_per_burst > capa->ftm.max_ftms_per_burst || | ||
101 | out->ftm.ftms_per_burst == 0)) { | ||
102 | NL_SET_ERR_MSG_ATTR(info->extack, | ||
103 | tb[NL80211_PMSR_FTM_REQ_ATTR_FTMS_PER_BURST], | ||
104 | "FTM: FTMs per burst must be set lower than the device limit but non-zero"); | ||
105 | return -EINVAL; | ||
106 | } | ||
107 | |||
108 | out->ftm.ftmr_retries = 3; | ||
109 | if (tb[NL80211_PMSR_FTM_REQ_ATTR_NUM_FTMR_RETRIES]) | ||
110 | out->ftm.ftmr_retries = | ||
111 | nla_get_u32(tb[NL80211_PMSR_FTM_REQ_ATTR_NUM_FTMR_RETRIES]); | ||
112 | |||
113 | out->ftm.request_lci = !!tb[NL80211_PMSR_FTM_REQ_ATTR_REQUEST_LCI]; | ||
114 | if (out->ftm.request_lci && !capa->ftm.request_lci) { | ||
115 | NL_SET_ERR_MSG_ATTR(info->extack, | ||
116 | tb[NL80211_PMSR_FTM_REQ_ATTR_REQUEST_LCI], | ||
117 | "FTM: LCI request not supported"); | ||
118 | } | ||
119 | |||
120 | out->ftm.request_civicloc = | ||
121 | !!tb[NL80211_PMSR_FTM_REQ_ATTR_REQUEST_CIVICLOC]; | ||
122 | if (out->ftm.request_civicloc && !capa->ftm.request_civicloc) { | ||
123 | NL_SET_ERR_MSG_ATTR(info->extack, | ||
124 | tb[NL80211_PMSR_FTM_REQ_ATTR_REQUEST_CIVICLOC], | ||
125 | "FTM: civic location request not supported"); | ||
126 | } | ||
127 | |||
128 | return 0; | ||
129 | } | ||
130 | |||
131 | static int pmsr_parse_peer(struct cfg80211_registered_device *rdev, | ||
132 | struct nlattr *peer, | ||
133 | struct cfg80211_pmsr_request_peer *out, | ||
134 | struct genl_info *info) | ||
135 | { | ||
136 | struct nlattr *tb[NL80211_PMSR_PEER_ATTR_MAX + 1]; | ||
137 | struct nlattr *req[NL80211_PMSR_REQ_ATTR_MAX + 1]; | ||
138 | struct nlattr *treq; | ||
139 | int err, rem; | ||
140 | |||
141 | /* no validation needed - was already done via nested policy */ | ||
142 | nla_parse_nested(tb, NL80211_PMSR_PEER_ATTR_MAX, peer, NULL, NULL); | ||
143 | |||
144 | if (!tb[NL80211_PMSR_PEER_ATTR_ADDR] || | ||
145 | !tb[NL80211_PMSR_PEER_ATTR_CHAN] || | ||
146 | !tb[NL80211_PMSR_PEER_ATTR_REQ]) { | ||
147 | NL_SET_ERR_MSG_ATTR(info->extack, peer, | ||
148 | "insufficient peer data"); | ||
149 | return -EINVAL; | ||
150 | } | ||
151 | |||
152 | memcpy(out->addr, nla_data(tb[NL80211_PMSR_PEER_ATTR_ADDR]), ETH_ALEN); | ||
153 | |||
154 | /* reuse info->attrs */ | ||
155 | memset(info->attrs, 0, sizeof(*info->attrs) * (NL80211_ATTR_MAX + 1)); | ||
156 | /* need to validate here, we don't want to have validation recursion */ | ||
157 | err = nla_parse_nested(info->attrs, NL80211_ATTR_MAX, | ||
158 | tb[NL80211_PMSR_PEER_ATTR_CHAN], | ||
159 | nl80211_policy, info->extack); | ||
160 | if (err) | ||
161 | return err; | ||
162 | |||
163 | err = nl80211_parse_chandef(rdev, info, &out->chandef); | ||
164 | if (err) | ||
165 | return err; | ||
166 | |||
167 | /* no validation needed - was already done via nested policy */ | ||
168 | nla_parse_nested(req, NL80211_PMSR_REQ_ATTR_MAX, | ||
169 | tb[NL80211_PMSR_PEER_ATTR_REQ], | ||
170 | NULL, NULL); | ||
171 | |||
172 | if (!req[NL80211_PMSR_REQ_ATTR_DATA]) { | ||
173 | NL_SET_ERR_MSG_ATTR(info->extack, | ||
174 | tb[NL80211_PMSR_PEER_ATTR_REQ], | ||
175 | "missing request type/data"); | ||
176 | return -EINVAL; | ||
177 | } | ||
178 | |||
179 | if (req[NL80211_PMSR_REQ_ATTR_GET_AP_TSF]) | ||
180 | out->report_ap_tsf = true; | ||
181 | |||
182 | if (out->report_ap_tsf && !rdev->wiphy.pmsr_capa->report_ap_tsf) { | ||
183 | NL_SET_ERR_MSG_ATTR(info->extack, | ||
184 | req[NL80211_PMSR_REQ_ATTR_GET_AP_TSF], | ||
185 | "reporting AP TSF is not supported"); | ||
186 | return -EINVAL; | ||
187 | } | ||
188 | |||
189 | nla_for_each_nested(treq, req[NL80211_PMSR_REQ_ATTR_DATA], rem) { | ||
190 | switch (nla_type(treq)) { | ||
191 | case NL80211_PMSR_TYPE_FTM: | ||
192 | err = pmsr_parse_ftm(rdev, treq, out, info); | ||
193 | break; | ||
194 | default: | ||
195 | NL_SET_ERR_MSG_ATTR(info->extack, treq, | ||
196 | "unsupported measurement type"); | ||
197 | err = -EINVAL; | ||
198 | } | ||
199 | } | ||
200 | |||
201 | if (err) | ||
202 | return err; | ||
203 | |||
204 | return 0; | ||
205 | } | ||
206 | |||
207 | int nl80211_pmsr_start(struct sk_buff *skb, struct genl_info *info) | ||
208 | { | ||
209 | struct nlattr *reqattr = info->attrs[NL80211_ATTR_PEER_MEASUREMENTS]; | ||
210 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | ||
211 | struct wireless_dev *wdev = info->user_ptr[1]; | ||
212 | struct cfg80211_pmsr_request *req; | ||
213 | struct nlattr *peers, *peer; | ||
214 | int count, rem, err, idx; | ||
215 | |||
216 | if (!rdev->wiphy.pmsr_capa) | ||
217 | return -EOPNOTSUPP; | ||
218 | |||
219 | if (!reqattr) | ||
220 | return -EINVAL; | ||
221 | |||
222 | peers = nla_find(nla_data(reqattr), nla_len(reqattr), | ||
223 | NL80211_PMSR_ATTR_PEERS); | ||
224 | if (!peers) | ||
225 | return -EINVAL; | ||
226 | |||
227 | count = 0; | ||
228 | nla_for_each_nested(peer, peers, rem) { | ||
229 | count++; | ||
230 | |||
231 | if (count > rdev->wiphy.pmsr_capa->max_peers) { | ||
232 | NL_SET_ERR_MSG_ATTR(info->extack, peer, | ||
233 | "Too many peers used"); | ||
234 | return -EINVAL; | ||
235 | } | ||
236 | } | ||
237 | |||
238 | req = kzalloc(struct_size(req, peers, count), GFP_KERNEL); | ||
239 | if (!req) | ||
240 | return -ENOMEM; | ||
241 | |||
242 | if (info->attrs[NL80211_ATTR_TIMEOUT]) | ||
243 | req->timeout = nla_get_u32(info->attrs[NL80211_ATTR_TIMEOUT]); | ||
244 | |||
245 | if (info->attrs[NL80211_ATTR_MAC]) { | ||
246 | if (!rdev->wiphy.pmsr_capa->randomize_mac_addr) { | ||
247 | NL_SET_ERR_MSG_ATTR(info->extack, | ||
248 | info->attrs[NL80211_ATTR_MAC], | ||
249 | "device cannot randomize MAC address"); | ||
250 | err = -EINVAL; | ||
251 | goto out_err; | ||
252 | } | ||
253 | |||
254 | err = nl80211_parse_random_mac(info->attrs, req->mac_addr, | ||
255 | req->mac_addr_mask); | ||
256 | if (err) | ||
257 | goto out_err; | ||
258 | } else { | ||
259 | memcpy(req->mac_addr, nla_data(info->attrs[NL80211_ATTR_MAC]), | ||
260 | ETH_ALEN); | ||
261 | memset(req->mac_addr_mask, 0xff, ETH_ALEN); | ||
262 | } | ||
263 | |||
264 | idx = 0; | ||
265 | nla_for_each_nested(peer, peers, rem) { | ||
266 | /* NB: this reuses info->attrs, but we no longer need it */ | ||
267 | err = pmsr_parse_peer(rdev, peer, &req->peers[idx], info); | ||
268 | if (err) | ||
269 | goto out_err; | ||
270 | idx++; | ||
271 | } | ||
272 | |||
273 | req->n_peers = count; | ||
274 | req->cookie = cfg80211_assign_cookie(rdev); | ||
275 | |||
276 | err = rdev_start_pmsr(rdev, wdev, req); | ||
277 | if (err) | ||
278 | goto out_err; | ||
279 | |||
280 | list_add_tail(&req->list, &wdev->pmsr_list); | ||
281 | |||
282 | nl_set_extack_cookie_u64(info->extack, req->cookie); | ||
283 | return 0; | ||
284 | out_err: | ||
285 | kfree(req); | ||
286 | return err; | ||
287 | } | ||
288 | |||
289 | void cfg80211_pmsr_complete(struct wireless_dev *wdev, | ||
290 | struct cfg80211_pmsr_request *req, | ||
291 | gfp_t gfp) | ||
292 | { | ||
293 | struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); | ||
294 | struct sk_buff *msg; | ||
295 | void *hdr; | ||
296 | |||
297 | trace_cfg80211_pmsr_complete(wdev->wiphy, wdev, req->cookie); | ||
298 | |||
299 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); | ||
300 | if (!msg) | ||
301 | goto free_request; | ||
302 | |||
303 | hdr = nl80211hdr_put(msg, 0, 0, 0, | ||
304 | NL80211_CMD_PEER_MEASUREMENT_COMPLETE); | ||
305 | if (!hdr) | ||
306 | goto free_msg; | ||
307 | |||
308 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || | ||
309 | nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev), | ||
310 | NL80211_ATTR_PAD)) | ||
311 | goto free_msg; | ||
312 | |||
313 | if (nla_put_u64_64bit(msg, NL80211_ATTR_COOKIE, req->cookie, | ||
314 | NL80211_ATTR_PAD)) | ||
315 | goto free_msg; | ||
316 | |||
317 | genlmsg_end(msg, hdr); | ||
318 | genlmsg_unicast(wiphy_net(wdev->wiphy), msg, req->nl_portid); | ||
319 | goto free_request; | ||
320 | free_msg: | ||
321 | nlmsg_free(msg); | ||
322 | free_request: | ||
323 | spin_lock_bh(&wdev->pmsr_lock); | ||
324 | list_del(&req->list); | ||
325 | spin_unlock_bh(&wdev->pmsr_lock); | ||
326 | kfree(req); | ||
327 | } | ||
328 | EXPORT_SYMBOL_GPL(cfg80211_pmsr_complete); | ||
329 | |||
330 | static int nl80211_pmsr_send_ftm_res(struct sk_buff *msg, | ||
331 | struct cfg80211_pmsr_result *res) | ||
332 | { | ||
333 | if (res->status == NL80211_PMSR_STATUS_FAILURE) { | ||
334 | if (nla_put_u32(msg, NL80211_PMSR_FTM_RESP_ATTR_FAIL_REASON, | ||
335 | res->ftm.failure_reason)) | ||
336 | goto error; | ||
337 | |||
338 | if (res->ftm.failure_reason == | ||
339 | NL80211_PMSR_FTM_FAILURE_PEER_BUSY && | ||
340 | res->ftm.busy_retry_time && | ||
341 | nla_put_u32(msg, NL80211_PMSR_FTM_RESP_ATTR_BUSY_RETRY_TIME, | ||
342 | res->ftm.busy_retry_time)) | ||
343 | goto error; | ||
344 | |||
345 | return 0; | ||
346 | } | ||
347 | |||
348 | #define PUT(tp, attr, val) \ | ||
349 | do { \ | ||
350 | if (nla_put_##tp(msg, \ | ||
351 | NL80211_PMSR_FTM_RESP_ATTR_##attr, \ | ||
352 | res->ftm.val)) \ | ||
353 | goto error; \ | ||
354 | } while (0) | ||
355 | |||
356 | #define PUTOPT(tp, attr, val) \ | ||
357 | do { \ | ||
358 | if (res->ftm.val##_valid) \ | ||
359 | PUT(tp, attr, val); \ | ||
360 | } while (0) | ||
361 | |||
362 | #define PUT_U64(attr, val) \ | ||
363 | do { \ | ||
364 | if (nla_put_u64_64bit(msg, \ | ||
365 | NL80211_PMSR_FTM_RESP_ATTR_##attr,\ | ||
366 | res->ftm.val, \ | ||
367 | NL80211_PMSR_FTM_RESP_ATTR_PAD)) \ | ||
368 | goto error; \ | ||
369 | } while (0) | ||
370 | |||
371 | #define PUTOPT_U64(attr, val) \ | ||
372 | do { \ | ||
373 | if (res->ftm.val##_valid) \ | ||
374 | PUT_U64(attr, val); \ | ||
375 | } while (0) | ||
376 | |||
377 | if (res->ftm.burst_index >= 0) | ||
378 | PUT(u32, BURST_INDEX, burst_index); | ||
379 | PUTOPT(u32, NUM_FTMR_ATTEMPTS, num_ftmr_attempts); | ||
380 | PUTOPT(u32, NUM_FTMR_SUCCESSES, num_ftmr_successes); | ||
381 | PUT(u8, NUM_BURSTS_EXP, num_bursts_exp); | ||
382 | PUT(u8, BURST_DURATION, burst_duration); | ||
383 | PUT(u8, FTMS_PER_BURST, ftms_per_burst); | ||
384 | PUTOPT(s32, RSSI_AVG, rssi_avg); | ||
385 | PUTOPT(s32, RSSI_SPREAD, rssi_spread); | ||
386 | if (res->ftm.tx_rate_valid && | ||
387 | !nl80211_put_sta_rate(msg, &res->ftm.tx_rate, | ||
388 | NL80211_PMSR_FTM_RESP_ATTR_TX_RATE)) | ||
389 | goto error; | ||
390 | if (res->ftm.rx_rate_valid && | ||
391 | !nl80211_put_sta_rate(msg, &res->ftm.rx_rate, | ||
392 | NL80211_PMSR_FTM_RESP_ATTR_RX_RATE)) | ||
393 | goto error; | ||
394 | PUTOPT_U64(RTT_AVG, rtt_avg); | ||
395 | PUTOPT_U64(RTT_VARIANCE, rtt_variance); | ||
396 | PUTOPT_U64(RTT_SPREAD, rtt_spread); | ||
397 | PUTOPT_U64(DIST_AVG, dist_avg); | ||
398 | PUTOPT_U64(DIST_VARIANCE, dist_variance); | ||
399 | PUTOPT_U64(DIST_SPREAD, dist_spread); | ||
400 | if (res->ftm.lci && res->ftm.lci_len && | ||
401 | nla_put(msg, NL80211_PMSR_FTM_RESP_ATTR_LCI, | ||
402 | res->ftm.lci_len, res->ftm.lci)) | ||
403 | goto error; | ||
404 | if (res->ftm.civicloc && res->ftm.civicloc_len && | ||
405 | nla_put(msg, NL80211_PMSR_FTM_RESP_ATTR_CIVICLOC, | ||
406 | res->ftm.civicloc_len, res->ftm.civicloc)) | ||
407 | goto error; | ||
408 | #undef PUT | ||
409 | #undef PUTOPT | ||
410 | #undef PUT_U64 | ||
411 | #undef PUTOPT_U64 | ||
412 | |||
413 | return 0; | ||
414 | error: | ||
415 | return -ENOSPC; | ||
416 | } | ||
417 | |||
418 | static int nl80211_pmsr_send_result(struct sk_buff *msg, | ||
419 | struct cfg80211_pmsr_result *res) | ||
420 | { | ||
421 | struct nlattr *pmsr, *peers, *peer, *resp, *data, *typedata; | ||
422 | |||
423 | pmsr = nla_nest_start(msg, NL80211_ATTR_PEER_MEASUREMENTS); | ||
424 | if (!pmsr) | ||
425 | goto error; | ||
426 | |||
427 | peers = nla_nest_start(msg, NL80211_PMSR_ATTR_PEERS); | ||
428 | if (!peers) | ||
429 | goto error; | ||
430 | |||
431 | peer = nla_nest_start(msg, 1); | ||
432 | if (!peer) | ||
433 | goto error; | ||
434 | |||
435 | if (nla_put(msg, NL80211_PMSR_PEER_ATTR_ADDR, ETH_ALEN, res->addr)) | ||
436 | goto error; | ||
437 | |||
438 | resp = nla_nest_start(msg, NL80211_PMSR_PEER_ATTR_RESP); | ||
439 | if (!resp) | ||
440 | goto error; | ||
441 | |||
442 | if (nla_put_u32(msg, NL80211_PMSR_RESP_ATTR_STATUS, res->status) || | ||
443 | nla_put_u64_64bit(msg, NL80211_PMSR_RESP_ATTR_HOST_TIME, | ||
444 | res->host_time, NL80211_PMSR_RESP_ATTR_PAD)) | ||
445 | goto error; | ||
446 | |||
447 | if (res->ap_tsf_valid && | ||
448 | nla_put_u64_64bit(msg, NL80211_PMSR_RESP_ATTR_AP_TSF, | ||
449 | res->host_time, NL80211_PMSR_RESP_ATTR_PAD)) | ||
450 | goto error; | ||
451 | |||
452 | if (res->final && nla_put_flag(msg, NL80211_PMSR_RESP_ATTR_FINAL)) | ||
453 | goto error; | ||
454 | |||
455 | data = nla_nest_start(msg, NL80211_PMSR_RESP_ATTR_DATA); | ||
456 | if (!data) | ||
457 | goto error; | ||
458 | |||
459 | typedata = nla_nest_start(msg, res->type); | ||
460 | if (!typedata) | ||
461 | goto error; | ||
462 | |||
463 | switch (res->type) { | ||
464 | case NL80211_PMSR_TYPE_FTM: | ||
465 | if (nl80211_pmsr_send_ftm_res(msg, res)) | ||
466 | goto error; | ||
467 | break; | ||
468 | default: | ||
469 | WARN_ON(1); | ||
470 | } | ||
471 | |||
472 | nla_nest_end(msg, typedata); | ||
473 | nla_nest_end(msg, data); | ||
474 | nla_nest_end(msg, resp); | ||
475 | nla_nest_end(msg, peer); | ||
476 | nla_nest_end(msg, peers); | ||
477 | nla_nest_end(msg, pmsr); | ||
478 | |||
479 | return 0; | ||
480 | error: | ||
481 | return -ENOSPC; | ||
482 | } | ||
483 | |||
484 | void cfg80211_pmsr_report(struct wireless_dev *wdev, | ||
485 | struct cfg80211_pmsr_request *req, | ||
486 | struct cfg80211_pmsr_result *result, | ||
487 | gfp_t gfp) | ||
488 | { | ||
489 | struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); | ||
490 | struct sk_buff *msg; | ||
491 | void *hdr; | ||
492 | int err; | ||
493 | |||
494 | trace_cfg80211_pmsr_report(wdev->wiphy, wdev, req->cookie, | ||
495 | result->addr); | ||
496 | |||
497 | /* | ||
498 | * Currently, only variable items are LCI and civic location, | ||
499 | * both of which are reasonably short so we don't need to | ||
500 | * worry about them here for the allocation. | ||
501 | */ | ||
502 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); | ||
503 | if (!msg) | ||
504 | return; | ||
505 | |||
506 | hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_PEER_MEASUREMENT_RESULT); | ||
507 | if (!hdr) | ||
508 | goto free; | ||
509 | |||
510 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || | ||
511 | nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev), | ||
512 | NL80211_ATTR_PAD)) | ||
513 | goto free; | ||
514 | |||
515 | if (nla_put_u64_64bit(msg, NL80211_ATTR_COOKIE, req->cookie, | ||
516 | NL80211_ATTR_PAD)) | ||
517 | goto free; | ||
518 | |||
519 | err = nl80211_pmsr_send_result(msg, result); | ||
520 | if (err) { | ||
521 | pr_err_ratelimited("peer measurement result: message didn't fit!"); | ||
522 | goto free; | ||
523 | } | ||
524 | |||
525 | genlmsg_end(msg, hdr); | ||
526 | genlmsg_unicast(wiphy_net(wdev->wiphy), msg, req->nl_portid); | ||
527 | return; | ||
528 | free: | ||
529 | nlmsg_free(msg); | ||
530 | } | ||
531 | EXPORT_SYMBOL_GPL(cfg80211_pmsr_report); | ||
532 | |||
533 | void cfg80211_pmsr_free_wk(struct work_struct *work) | ||
534 | { | ||
535 | struct wireless_dev *wdev = container_of(work, struct wireless_dev, | ||
536 | pmsr_free_wk); | ||
537 | struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); | ||
538 | struct cfg80211_pmsr_request *req, *tmp; | ||
539 | LIST_HEAD(free_list); | ||
540 | |||
541 | spin_lock_bh(&wdev->pmsr_lock); | ||
542 | list_for_each_entry_safe(req, tmp, &wdev->pmsr_list, list) { | ||
543 | if (req->nl_portid) | ||
544 | continue; | ||
545 | list_move_tail(&req->list, &free_list); | ||
546 | } | ||
547 | spin_unlock_bh(&wdev->pmsr_lock); | ||
548 | |||
549 | list_for_each_entry_safe(req, tmp, &free_list, list) { | ||
550 | wdev_lock(wdev); | ||
551 | rdev_abort_pmsr(rdev, wdev, req); | ||
552 | wdev_unlock(wdev); | ||
553 | |||
554 | kfree(req); | ||
555 | } | ||
556 | } | ||
557 | |||
558 | void cfg80211_pmsr_wdev_down(struct wireless_dev *wdev) | ||
559 | { | ||
560 | struct cfg80211_pmsr_request *req; | ||
561 | bool found = false; | ||
562 | |||
563 | spin_lock_bh(&wdev->pmsr_lock); | ||
564 | list_for_each_entry(req, &wdev->pmsr_list, list) { | ||
565 | found = true; | ||
566 | req->nl_portid = 0; | ||
567 | } | ||
568 | spin_unlock_bh(&wdev->pmsr_lock); | ||
569 | |||
570 | if (found) | ||
571 | schedule_work(&wdev->pmsr_free_wk); | ||
572 | flush_work(&wdev->pmsr_free_wk); | ||
573 | WARN_ON(!list_empty(&wdev->pmsr_list)); | ||
574 | } | ||
575 | |||
576 | void cfg80211_release_pmsr(struct wireless_dev *wdev, u32 portid) | ||
577 | { | ||
578 | struct cfg80211_pmsr_request *req; | ||
579 | |||
580 | spin_lock_bh(&wdev->pmsr_lock); | ||
581 | list_for_each_entry(req, &wdev->pmsr_list, list) { | ||
582 | if (req->nl_portid == portid) { | ||
583 | req->nl_portid = 0; | ||
584 | schedule_work(&wdev->pmsr_free_wk); | ||
585 | } | ||
586 | } | ||
587 | spin_unlock_bh(&wdev->pmsr_lock); | ||
588 | } | ||
589 | |||
590 | #endif /* __PMSR_H */ | ||
diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h index 51380b5c32f2..5cb48d135fab 100644 --- a/net/wireless/rdev-ops.h +++ b/net/wireless/rdev-ops.h | |||
@@ -1247,4 +1247,29 @@ rdev_get_ftm_responder_stats(struct cfg80211_registered_device *rdev, | |||
1247 | return ret; | 1247 | return ret; |
1248 | } | 1248 | } |
1249 | 1249 | ||
1250 | static inline int | ||
1251 | rdev_start_pmsr(struct cfg80211_registered_device *rdev, | ||
1252 | struct wireless_dev *wdev, | ||
1253 | struct cfg80211_pmsr_request *request) | ||
1254 | { | ||
1255 | int ret = -EOPNOTSUPP; | ||
1256 | |||
1257 | trace_rdev_start_pmsr(&rdev->wiphy, wdev, request->cookie); | ||
1258 | if (rdev->ops->start_pmsr) | ||
1259 | ret = rdev->ops->start_pmsr(&rdev->wiphy, wdev, request); | ||
1260 | trace_rdev_return_int(&rdev->wiphy, ret); | ||
1261 | return ret; | ||
1262 | } | ||
1263 | |||
1264 | static inline void | ||
1265 | rdev_abort_pmsr(struct cfg80211_registered_device *rdev, | ||
1266 | struct wireless_dev *wdev, | ||
1267 | struct cfg80211_pmsr_request *request) | ||
1268 | { | ||
1269 | trace_rdev_abort_pmsr(&rdev->wiphy, wdev, request->cookie); | ||
1270 | if (rdev->ops->abort_pmsr) | ||
1271 | rdev->ops->abort_pmsr(&rdev->wiphy, wdev, request); | ||
1272 | trace_rdev_return_void(&rdev->wiphy); | ||
1273 | } | ||
1274 | |||
1250 | #endif /* __CFG80211_RDEV_OPS */ | 1275 | #endif /* __CFG80211_RDEV_OPS */ |
diff --git a/net/wireless/scan.c b/net/wireless/scan.c index d0e7472dd9fd..5123667f4569 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c | |||
@@ -1183,7 +1183,7 @@ cfg80211_inform_bss_data(struct wiphy *wiphy, | |||
1183 | switch (ftype) { | 1183 | switch (ftype) { |
1184 | case CFG80211_BSS_FTYPE_BEACON: | 1184 | case CFG80211_BSS_FTYPE_BEACON: |
1185 | ies->from_beacon = true; | 1185 | ies->from_beacon = true; |
1186 | /* fall through to assign */ | 1186 | /* fall through */ |
1187 | case CFG80211_BSS_FTYPE_UNKNOWN: | 1187 | case CFG80211_BSS_FTYPE_UNKNOWN: |
1188 | rcu_assign_pointer(tmp.pub.beacon_ies, ies); | 1188 | rcu_assign_pointer(tmp.pub.beacon_ies, ies); |
1189 | break; | 1189 | break; |
diff --git a/net/wireless/trace.h b/net/wireless/trace.h index c6a9446b4e6b..44b2ce1bb13a 100644 --- a/net/wireless/trace.h +++ b/net/wireless/trace.h | |||
@@ -361,6 +361,24 @@ DECLARE_EVENT_CLASS(wiphy_wdev_evt, | |||
361 | TP_printk(WIPHY_PR_FMT ", " WDEV_PR_FMT, WIPHY_PR_ARG, WDEV_PR_ARG) | 361 | TP_printk(WIPHY_PR_FMT ", " WDEV_PR_FMT, WIPHY_PR_ARG, WDEV_PR_ARG) |
362 | ); | 362 | ); |
363 | 363 | ||
364 | DECLARE_EVENT_CLASS(wiphy_wdev_cookie_evt, | ||
365 | TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev, u64 cookie), | ||
366 | TP_ARGS(wiphy, wdev, cookie), | ||
367 | TP_STRUCT__entry( | ||
368 | WIPHY_ENTRY | ||
369 | WDEV_ENTRY | ||
370 | __field(u64, cookie) | ||
371 | ), | ||
372 | TP_fast_assign( | ||
373 | WIPHY_ASSIGN; | ||
374 | WDEV_ASSIGN; | ||
375 | __entry->cookie = cookie; | ||
376 | ), | ||
377 | TP_printk(WIPHY_PR_FMT ", " WDEV_PR_FMT ", cookie: %lld", | ||
378 | WIPHY_PR_ARG, WDEV_PR_ARG, | ||
379 | (unsigned long long)__entry->cookie) | ||
380 | ); | ||
381 | |||
364 | DEFINE_EVENT(wiphy_wdev_evt, rdev_return_wdev, | 382 | DEFINE_EVENT(wiphy_wdev_evt, rdev_return_wdev, |
365 | TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev), | 383 | TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev), |
366 | TP_ARGS(wiphy, wdev) | 384 | TP_ARGS(wiphy, wdev) |
@@ -770,9 +788,9 @@ DEFINE_EVENT(wiphy_netdev_mac_evt, rdev_set_wds_peer, | |||
770 | ); | 788 | ); |
771 | 789 | ||
772 | TRACE_EVENT(rdev_dump_station, | 790 | TRACE_EVENT(rdev_dump_station, |
773 | TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, int idx, | 791 | TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, int _idx, |
774 | u8 *mac), | 792 | u8 *mac), |
775 | TP_ARGS(wiphy, netdev, idx, mac), | 793 | TP_ARGS(wiphy, netdev, _idx, mac), |
776 | TP_STRUCT__entry( | 794 | TP_STRUCT__entry( |
777 | WIPHY_ENTRY | 795 | WIPHY_ENTRY |
778 | NETDEV_ENTRY | 796 | NETDEV_ENTRY |
@@ -783,7 +801,7 @@ TRACE_EVENT(rdev_dump_station, | |||
783 | WIPHY_ASSIGN; | 801 | WIPHY_ASSIGN; |
784 | NETDEV_ASSIGN; | 802 | NETDEV_ASSIGN; |
785 | MAC_ASSIGN(sta_mac, mac); | 803 | MAC_ASSIGN(sta_mac, mac); |
786 | __entry->idx = idx; | 804 | __entry->idx = _idx; |
787 | ), | 805 | ), |
788 | TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", station mac: " MAC_PR_FMT ", idx: %d", | 806 | TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", station mac: " MAC_PR_FMT ", idx: %d", |
789 | WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(sta_mac), | 807 | WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(sta_mac), |
@@ -847,9 +865,9 @@ DEFINE_EVENT(mpath_evt, rdev_get_mpath, | |||
847 | ); | 865 | ); |
848 | 866 | ||
849 | TRACE_EVENT(rdev_dump_mpath, | 867 | TRACE_EVENT(rdev_dump_mpath, |
850 | TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, int idx, | 868 | TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, int _idx, |
851 | u8 *dst, u8 *next_hop), | 869 | u8 *dst, u8 *next_hop), |
852 | TP_ARGS(wiphy, netdev, idx, dst, next_hop), | 870 | TP_ARGS(wiphy, netdev, _idx, dst, next_hop), |
853 | TP_STRUCT__entry( | 871 | TP_STRUCT__entry( |
854 | WIPHY_ENTRY | 872 | WIPHY_ENTRY |
855 | NETDEV_ENTRY | 873 | NETDEV_ENTRY |
@@ -862,7 +880,7 @@ TRACE_EVENT(rdev_dump_mpath, | |||
862 | NETDEV_ASSIGN; | 880 | NETDEV_ASSIGN; |
863 | MAC_ASSIGN(dst, dst); | 881 | MAC_ASSIGN(dst, dst); |
864 | MAC_ASSIGN(next_hop, next_hop); | 882 | MAC_ASSIGN(next_hop, next_hop); |
865 | __entry->idx = idx; | 883 | __entry->idx = _idx; |
866 | ), | 884 | ), |
867 | TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", index: %d, destination: " | 885 | TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", index: %d, destination: " |
868 | MAC_PR_FMT ", next hop: " MAC_PR_FMT, | 886 | MAC_PR_FMT ", next hop: " MAC_PR_FMT, |
@@ -892,9 +910,9 @@ TRACE_EVENT(rdev_get_mpp, | |||
892 | ); | 910 | ); |
893 | 911 | ||
894 | TRACE_EVENT(rdev_dump_mpp, | 912 | TRACE_EVENT(rdev_dump_mpp, |
895 | TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, int idx, | 913 | TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, int _idx, |
896 | u8 *dst, u8 *mpp), | 914 | u8 *dst, u8 *mpp), |
897 | TP_ARGS(wiphy, netdev, idx, mpp, dst), | 915 | TP_ARGS(wiphy, netdev, _idx, mpp, dst), |
898 | TP_STRUCT__entry( | 916 | TP_STRUCT__entry( |
899 | WIPHY_ENTRY | 917 | WIPHY_ENTRY |
900 | NETDEV_ENTRY | 918 | NETDEV_ENTRY |
@@ -907,7 +925,7 @@ TRACE_EVENT(rdev_dump_mpp, | |||
907 | NETDEV_ASSIGN; | 925 | NETDEV_ASSIGN; |
908 | MAC_ASSIGN(dst, dst); | 926 | MAC_ASSIGN(dst, dst); |
909 | MAC_ASSIGN(mpp, mpp); | 927 | MAC_ASSIGN(mpp, mpp); |
910 | __entry->idx = idx; | 928 | __entry->idx = _idx; |
911 | ), | 929 | ), |
912 | TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", index: %d, destination: " | 930 | TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", index: %d, destination: " |
913 | MAC_PR_FMT ", mpp: " MAC_PR_FMT, | 931 | MAC_PR_FMT ", mpp: " MAC_PR_FMT, |
@@ -1673,8 +1691,8 @@ TRACE_EVENT(rdev_tdls_mgmt, | |||
1673 | ); | 1691 | ); |
1674 | 1692 | ||
1675 | TRACE_EVENT(rdev_dump_survey, | 1693 | TRACE_EVENT(rdev_dump_survey, |
1676 | TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, int idx), | 1694 | TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, int _idx), |
1677 | TP_ARGS(wiphy, netdev, idx), | 1695 | TP_ARGS(wiphy, netdev, _idx), |
1678 | TP_STRUCT__entry( | 1696 | TP_STRUCT__entry( |
1679 | WIPHY_ENTRY | 1697 | WIPHY_ENTRY |
1680 | NETDEV_ENTRY | 1698 | NETDEV_ENTRY |
@@ -1683,7 +1701,7 @@ TRACE_EVENT(rdev_dump_survey, | |||
1683 | TP_fast_assign( | 1701 | TP_fast_assign( |
1684 | WIPHY_ASSIGN; | 1702 | WIPHY_ASSIGN; |
1685 | NETDEV_ASSIGN; | 1703 | NETDEV_ASSIGN; |
1686 | __entry->idx = idx; | 1704 | __entry->idx = _idx; |
1687 | ), | 1705 | ), |
1688 | TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", index: %d", | 1706 | TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", index: %d", |
1689 | WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->idx) | 1707 | WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->idx) |
@@ -2502,6 +2520,16 @@ TRACE_EVENT(rdev_get_ftm_responder_stats, | |||
2502 | __entry->out_of_window) | 2520 | __entry->out_of_window) |
2503 | ); | 2521 | ); |
2504 | 2522 | ||
2523 | DEFINE_EVENT(wiphy_wdev_cookie_evt, rdev_start_pmsr, | ||
2524 | TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev, u64 cookie), | ||
2525 | TP_ARGS(wiphy, wdev, cookie) | ||
2526 | ); | ||
2527 | |||
2528 | DEFINE_EVENT(wiphy_wdev_cookie_evt, rdev_abort_pmsr, | ||
2529 | TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev, u64 cookie), | ||
2530 | TP_ARGS(wiphy, wdev, cookie) | ||
2531 | ); | ||
2532 | |||
2505 | /************************************************************* | 2533 | /************************************************************* |
2506 | * cfg80211 exported functions traces * | 2534 | * cfg80211 exported functions traces * |
2507 | *************************************************************/ | 2535 | *************************************************************/ |
@@ -3294,6 +3322,46 @@ TRACE_EVENT(cfg80211_stop_iface, | |||
3294 | TP_printk(WIPHY_PR_FMT ", " WDEV_PR_FMT, | 3322 | TP_printk(WIPHY_PR_FMT ", " WDEV_PR_FMT, |
3295 | WIPHY_PR_ARG, WDEV_PR_ARG) | 3323 | WIPHY_PR_ARG, WDEV_PR_ARG) |
3296 | ); | 3324 | ); |
3325 | |||
3326 | TRACE_EVENT(cfg80211_pmsr_report, | ||
3327 | TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev, | ||
3328 | u64 cookie, const u8 *addr), | ||
3329 | TP_ARGS(wiphy, wdev, cookie, addr), | ||
3330 | TP_STRUCT__entry( | ||
3331 | WIPHY_ENTRY | ||
3332 | WDEV_ENTRY | ||
3333 | __field(u64, cookie) | ||
3334 | MAC_ENTRY(addr) | ||
3335 | ), | ||
3336 | TP_fast_assign( | ||
3337 | WIPHY_ASSIGN; | ||
3338 | WDEV_ASSIGN; | ||
3339 | __entry->cookie = cookie; | ||
3340 | MAC_ASSIGN(addr, addr); | ||
3341 | ), | ||
3342 | TP_printk(WIPHY_PR_FMT ", " WDEV_PR_FMT ", cookie:%lld, " MAC_PR_FMT, | ||
3343 | WIPHY_PR_ARG, WDEV_PR_ARG, | ||
3344 | (unsigned long long)__entry->cookie, | ||
3345 | MAC_PR_ARG(addr)) | ||
3346 | ); | ||
3347 | |||
3348 | TRACE_EVENT(cfg80211_pmsr_complete, | ||
3349 | TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev, u64 cookie), | ||
3350 | TP_ARGS(wiphy, wdev, cookie), | ||
3351 | TP_STRUCT__entry( | ||
3352 | WIPHY_ENTRY | ||
3353 | WDEV_ENTRY | ||
3354 | __field(u64, cookie) | ||
3355 | ), | ||
3356 | TP_fast_assign( | ||
3357 | WIPHY_ASSIGN; | ||
3358 | WDEV_ASSIGN; | ||
3359 | __entry->cookie = cookie; | ||
3360 | ), | ||
3361 | TP_printk(WIPHY_PR_FMT ", " WDEV_PR_FMT ", cookie:%lld", | ||
3362 | WIPHY_PR_ARG, WDEV_PR_ARG, | ||
3363 | (unsigned long long)__entry->cookie) | ||
3364 | ); | ||
3297 | #endif /* !__RDEV_OPS_TRACE || TRACE_HEADER_MULTI_READ */ | 3365 | #endif /* !__RDEV_OPS_TRACE || TRACE_HEADER_MULTI_READ */ |
3298 | 3366 | ||
3299 | #undef TRACE_INCLUDE_PATH | 3367 | #undef TRACE_INCLUDE_PATH |
diff --git a/net/wireless/util.c b/net/wireless/util.c index d473bd135da8..cd48cdd582c0 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c | |||
@@ -2015,33 +2015,32 @@ int ieee80211_get_vht_max_nss(struct ieee80211_vht_cap *cap, | |||
2015 | case IEEE80211_VHT_CHANWIDTH_160MHZ: | 2015 | case IEEE80211_VHT_CHANWIDTH_160MHZ: |
2016 | if (supp_width == 0 && | 2016 | if (supp_width == 0 && |
2017 | (ext_nss_bw == 1 || ext_nss_bw == 2)) | 2017 | (ext_nss_bw == 1 || ext_nss_bw == 2)) |
2018 | return DIV_ROUND_UP(max_vht_nss, 2); | 2018 | return max_vht_nss / 2; |
2019 | if (supp_width == 0 && | 2019 | if (supp_width == 0 && |
2020 | ext_nss_bw == 3) | 2020 | ext_nss_bw == 3) |
2021 | return DIV_ROUND_UP(3 * max_vht_nss, 4); | 2021 | return (3 * max_vht_nss) / 4; |
2022 | if (supp_width == 1 && | 2022 | if (supp_width == 1 && |
2023 | ext_nss_bw == 3) | 2023 | ext_nss_bw == 3) |
2024 | return 2 * max_vht_nss; | 2024 | return 2 * max_vht_nss; |
2025 | break; | 2025 | break; |
2026 | case IEEE80211_VHT_CHANWIDTH_80P80MHZ: | 2026 | case IEEE80211_VHT_CHANWIDTH_80P80MHZ: |
2027 | if (supp_width == 0 && | 2027 | if (supp_width == 0 && ext_nss_bw == 1) |
2028 | (ext_nss_bw == 1 || ext_nss_bw == 2)) | ||
2029 | return 0; /* not possible */ | 2028 | return 0; /* not possible */ |
2030 | if (supp_width == 0 && | 2029 | if (supp_width == 0 && |
2031 | ext_nss_bw == 2) | 2030 | ext_nss_bw == 2) |
2032 | return DIV_ROUND_UP(max_vht_nss, 2); | 2031 | return max_vht_nss / 2; |
2033 | if (supp_width == 0 && | 2032 | if (supp_width == 0 && |
2034 | ext_nss_bw == 3) | 2033 | ext_nss_bw == 3) |
2035 | return DIV_ROUND_UP(3 * max_vht_nss, 4); | 2034 | return (3 * max_vht_nss) / 4; |
2036 | if (supp_width == 1 && | 2035 | if (supp_width == 1 && |
2037 | ext_nss_bw == 0) | 2036 | ext_nss_bw == 0) |
2038 | return 0; /* not possible */ | 2037 | return 0; /* not possible */ |
2039 | if (supp_width == 1 && | 2038 | if (supp_width == 1 && |
2040 | ext_nss_bw == 1) | 2039 | ext_nss_bw == 1) |
2041 | return DIV_ROUND_UP(max_vht_nss, 2); | 2040 | return max_vht_nss / 2; |
2042 | if (supp_width == 1 && | 2041 | if (supp_width == 1 && |
2043 | ext_nss_bw == 2) | 2042 | ext_nss_bw == 2) |
2044 | return DIV_ROUND_UP(3 * max_vht_nss, 4); | 2043 | return (3 * max_vht_nss) / 4; |
2045 | break; | 2044 | break; |
2046 | } | 2045 | } |
2047 | 2046 | ||