diff options
author | Johannes Berg <johannes.berg@intel.com> | 2018-09-10 07:29:12 -0400 |
---|---|---|
committer | Johannes Berg <johannes.berg@intel.com> | 2018-11-09 05:20:13 -0500 |
commit | 9bb7e0f24e7e7d00daa1219b14539e2e602649b2 (patch) | |
tree | ba16695740cec99cd4a4af3198cf791b7ca81b70 | |
parent | 801f87469ee8d97af5997ef52188bb0e1908b110 (diff) |
cfg80211: add peer measurement with FTM initiator API
Add a new "peer measurement" API, that can be used to measure
certain things related to a peer. Right now, only implement
FTM (flight time measurement) over it, but the idea is that
it'll be extensible to also support measuring the necessary
things to calculate e.g. angle-of-arrival for WiGig.
The API is structured to have a generic list of peers and
channels to measure with/on, and then for each of those a
set of measurements (again, only FTM right now) to perform.
Results are sent to the requesting socket, including a final
complete message.
Closing the controlling netlink socket will abort a running
measurement.
v3:
- add a bit to report "final" for partial results
- remove list keeping etc. and just unicast out the results
to the requester (big code reduction ...)
- also send complete message unicast, and as a result
remove the multicast group
- separate out struct cfg80211_pmsr_ftm_request_peer
from struct cfg80211_pmsr_request_peer
- document timeout == 0 if no timeout
- disallow setting timeout nl80211 attribute to 0,
must not include attribute for no timeout
- make MAC address randomization optional
- change num bursts exponent default to 0 (1 burst, rather
rather than the old default of 15==don't care)
v4:
- clarify NL80211_ATTR_TIMEOUT documentation
v5:
- remove unnecessary nl80211 multicast/family changes
- remove partial results bit/flag, final is sufficient
- add max_bursts_exponent, max_ftms_per_burst to capability
- rename "frames per burst" -> "FTMs per burst"
v6:
- rename cfg80211_pmsr_free_wdev() to cfg80211_pmsr_wdev_down()
and call it in leave, so the device can't go down with any
pending measurements
v7:
- wording fixes (Lior)
- fix ftm.max_bursts_exponent to allow having the limit of 0 (Lior)
v8:
- copyright statements
- minor coding style fixes
- fix error path leak
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
-rw-r--r-- | include/net/cfg80211.h | 263 | ||||
-rw-r--r-- | include/uapi/linux/nl80211.h | 418 | ||||
-rw-r--r-- | net/wireless/Makefile | 1 | ||||
-rw-r--r-- | net/wireless/core.c | 34 | ||||
-rw-r--r-- | net/wireless/core.h | 5 | ||||
-rw-r--r-- | net/wireless/nl80211.c | 192 | ||||
-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/trace.h | 68 |
10 files changed, 1609 insertions, 19 deletions
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 1fa41b7a1be3..c21c5c70a2fd 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h | |||
@@ -2849,6 +2849,190 @@ struct cfg80211_ftm_responder_stats { | |||
2849 | }; | 2849 | }; |
2850 | 2850 | ||
2851 | /** | 2851 | /** |
2852 | * struct cfg80211_pmsr_ftm_result - FTM result | ||
2853 | * @failure_reason: if this measurement failed (PMSR status is | ||
2854 | * %NL80211_PMSR_STATUS_FAILURE), this gives a more precise | ||
2855 | * reason than just "failure" | ||
2856 | * @burst_index: if reporting partial results, this is the index | ||
2857 | * in [0 .. num_bursts-1] of the burst that's being reported | ||
2858 | * @num_ftmr_attempts: number of FTM request frames transmitted | ||
2859 | * @num_ftmr_successes: number of FTM request frames acked | ||
2860 | * @busy_retry_time: if failure_reason is %NL80211_PMSR_FTM_FAILURE_PEER_BUSY, | ||
2861 | * fill this to indicate in how many seconds a retry is deemed possible | ||
2862 | * by the responder | ||
2863 | * @num_bursts_exp: actual number of bursts exponent negotiated | ||
2864 | * @burst_duration: actual burst duration negotiated | ||
2865 | * @ftms_per_burst: actual FTMs per burst negotiated | ||
2866 | * @lci_len: length of LCI information (if present) | ||
2867 | * @civicloc_len: length of civic location information (if present) | ||
2868 | * @lci: LCI data (may be %NULL) | ||
2869 | * @civicloc: civic location data (may be %NULL) | ||
2870 | * @rssi_avg: average RSSI over FTM action frames reported | ||
2871 | * @rssi_spread: spread of the RSSI over FTM action frames reported | ||
2872 | * @tx_rate: bitrate for transmitted FTM action frame response | ||
2873 | * @rx_rate: bitrate of received FTM action frame | ||
2874 | * @rtt_avg: average of RTTs measured (must have either this or @dist_avg) | ||
2875 | * @rtt_variance: variance of RTTs measured (note that standard deviation is | ||
2876 | * the square root of the variance) | ||
2877 | * @rtt_spread: spread of the RTTs measured | ||
2878 | * @dist_avg: average of distances (mm) measured | ||
2879 | * (must have either this or @rtt_avg) | ||
2880 | * @dist_variance: variance of distances measured (see also @rtt_variance) | ||
2881 | * @dist_spread: spread of distances measured (see also @rtt_spread) | ||
2882 | * @num_ftmr_attempts_valid: @num_ftmr_attempts is valid | ||
2883 | * @num_ftmr_successes_valid: @num_ftmr_successes is valid | ||
2884 | * @rssi_avg_valid: @rssi_avg is valid | ||
2885 | * @rssi_spread_valid: @rssi_spread is valid | ||
2886 | * @tx_rate_valid: @tx_rate is valid | ||
2887 | * @rx_rate_valid: @rx_rate is valid | ||
2888 | * @rtt_avg_valid: @rtt_avg is valid | ||
2889 | * @rtt_variance_valid: @rtt_variance is valid | ||
2890 | * @rtt_spread_valid: @rtt_spread is valid | ||
2891 | * @dist_avg_valid: @dist_avg is valid | ||
2892 | * @dist_variance_valid: @dist_variance is valid | ||
2893 | * @dist_spread_valid: @dist_spread is valid | ||
2894 | */ | ||
2895 | struct cfg80211_pmsr_ftm_result { | ||
2896 | const u8 *lci; | ||
2897 | const u8 *civicloc; | ||
2898 | unsigned int lci_len; | ||
2899 | unsigned int civicloc_len; | ||
2900 | enum nl80211_peer_measurement_ftm_failure_reasons failure_reason; | ||
2901 | u32 num_ftmr_attempts, num_ftmr_successes; | ||
2902 | s16 burst_index; | ||
2903 | u8 busy_retry_time; | ||
2904 | u8 num_bursts_exp; | ||
2905 | u8 burst_duration; | ||
2906 | u8 ftms_per_burst; | ||
2907 | s32 rssi_avg; | ||
2908 | s32 rssi_spread; | ||
2909 | struct rate_info tx_rate, rx_rate; | ||
2910 | s64 rtt_avg; | ||
2911 | s64 rtt_variance; | ||
2912 | s64 rtt_spread; | ||
2913 | s64 dist_avg; | ||
2914 | s64 dist_variance; | ||
2915 | s64 dist_spread; | ||
2916 | |||
2917 | u16 num_ftmr_attempts_valid:1, | ||
2918 | num_ftmr_successes_valid:1, | ||
2919 | rssi_avg_valid:1, | ||
2920 | rssi_spread_valid:1, | ||
2921 | tx_rate_valid:1, | ||
2922 | rx_rate_valid:1, | ||
2923 | rtt_avg_valid:1, | ||
2924 | rtt_variance_valid:1, | ||
2925 | rtt_spread_valid:1, | ||
2926 | dist_avg_valid:1, | ||
2927 | dist_variance_valid:1, | ||
2928 | dist_spread_valid:1; | ||
2929 | }; | ||
2930 | |||
2931 | /** | ||
2932 | * struct cfg80211_pmsr_result - peer measurement result | ||
2933 | * @addr: address of the peer | ||
2934 | * @host_time: host time (use ktime_get_boottime() adjust to the time when the | ||
2935 | * measurement was made) | ||
2936 | * @ap_tsf: AP's TSF at measurement time | ||
2937 | * @status: status of the measurement | ||
2938 | * @final: if reporting partial results, mark this as the last one; if not | ||
2939 | * reporting partial results always set this flag | ||
2940 | * @ap_tsf_valid: indicates the @ap_tsf value is valid | ||
2941 | * @type: type of the measurement reported, note that we only support reporting | ||
2942 | * one type at a time, but you can report multiple results separately and | ||
2943 | * they're all aggregated for userspace. | ||
2944 | */ | ||
2945 | struct cfg80211_pmsr_result { | ||
2946 | u64 host_time, ap_tsf; | ||
2947 | enum nl80211_peer_measurement_status status; | ||
2948 | |||
2949 | u8 addr[ETH_ALEN]; | ||
2950 | |||
2951 | u8 final:1, | ||
2952 | ap_tsf_valid:1; | ||
2953 | |||
2954 | enum nl80211_peer_measurement_type type; | ||
2955 | |||
2956 | union { | ||
2957 | struct cfg80211_pmsr_ftm_result ftm; | ||
2958 | }; | ||
2959 | }; | ||
2960 | |||
2961 | /** | ||
2962 | * struct cfg80211_pmsr_ftm_request_peer - FTM request data | ||
2963 | * @requested: indicates FTM is requested | ||
2964 | * @preamble: frame preamble to use | ||
2965 | * @burst_period: burst period to use | ||
2966 | * @asap: indicates to use ASAP mode | ||
2967 | * @num_bursts_exp: number of bursts exponent | ||
2968 | * @burst_duration: burst duration | ||
2969 | * @ftms_per_burst: number of FTMs per burst | ||
2970 | * @ftmr_retries: number of retries for FTM request | ||
2971 | * @request_lci: request LCI information | ||
2972 | * @request_civicloc: request civic location information | ||
2973 | * | ||
2974 | * See also nl80211 for the respective attribute documentation. | ||
2975 | */ | ||
2976 | struct cfg80211_pmsr_ftm_request_peer { | ||
2977 | enum nl80211_preamble preamble; | ||
2978 | u16 burst_period; | ||
2979 | u8 requested:1, | ||
2980 | asap:1, | ||
2981 | request_lci:1, | ||
2982 | request_civicloc:1; | ||
2983 | u8 num_bursts_exp; | ||
2984 | u8 burst_duration; | ||
2985 | u8 ftms_per_burst; | ||
2986 | u8 ftmr_retries; | ||
2987 | }; | ||
2988 | |||
2989 | /** | ||
2990 | * struct cfg80211_pmsr_request_peer - peer data for a peer measurement request | ||
2991 | * @addr: MAC address | ||
2992 | * @chandef: channel to use | ||
2993 | * @report_ap_tsf: report the associated AP's TSF | ||
2994 | * @ftm: FTM data, see &struct cfg80211_pmsr_ftm_request_peer | ||
2995 | */ | ||
2996 | struct cfg80211_pmsr_request_peer { | ||
2997 | u8 addr[ETH_ALEN]; | ||
2998 | struct cfg80211_chan_def chandef; | ||
2999 | u8 report_ap_tsf:1; | ||
3000 | struct cfg80211_pmsr_ftm_request_peer ftm; | ||
3001 | }; | ||
3002 | |||
3003 | /** | ||
3004 | * struct cfg80211_pmsr_request - peer measurement request | ||
3005 | * @cookie: cookie, set by cfg80211 | ||
3006 | * @nl_portid: netlink portid - used by cfg80211 | ||
3007 | * @drv_data: driver data for this request, if required for aborting, | ||
3008 | * not otherwise freed or anything by cfg80211 | ||
3009 | * @mac_addr: MAC address used for (randomised) request | ||
3010 | * @mac_addr_mask: MAC address mask used for randomisation, bits that | ||
3011 | * are 0 in the mask should be randomised, bits that are 1 should | ||
3012 | * be taken from the @mac_addr | ||
3013 | * @list: used by cfg80211 to hold on to the request | ||
3014 | * @timeout: timeout (in milliseconds) for the whole operation, if | ||
3015 | * zero it means there's no timeout | ||
3016 | * @n_peers: number of peers to do measurements with | ||
3017 | * @peers: per-peer measurement request data | ||
3018 | */ | ||
3019 | struct cfg80211_pmsr_request { | ||
3020 | u64 cookie; | ||
3021 | void *drv_data; | ||
3022 | u32 n_peers; | ||
3023 | u32 nl_portid; | ||
3024 | |||
3025 | u32 timeout; | ||
3026 | |||
3027 | u8 mac_addr[ETH_ALEN] __aligned(2); | ||
3028 | u8 mac_addr_mask[ETH_ALEN] __aligned(2); | ||
3029 | |||
3030 | struct list_head list; | ||
3031 | |||
3032 | struct cfg80211_pmsr_request_peer peers[]; | ||
3033 | }; | ||
3034 | |||
3035 | /** | ||
2852 | * struct cfg80211_ops - backend description for wireless configuration | 3036 | * struct cfg80211_ops - backend description for wireless configuration |
2853 | * | 3037 | * |
2854 | * This struct is registered by fullmac card drivers and/or wireless stacks | 3038 | * This struct is registered by fullmac card drivers and/or wireless stacks |
@@ -3183,6 +3367,8 @@ struct cfg80211_ftm_responder_stats { | |||
3183 | * | 3367 | * |
3184 | * @get_ftm_responder_stats: Retrieve FTM responder statistics, if available. | 3368 | * @get_ftm_responder_stats: Retrieve FTM responder statistics, if available. |
3185 | * Statistics should be cumulative, currently no way to reset is provided. | 3369 | * Statistics should be cumulative, currently no way to reset is provided. |
3370 | * @start_pmsr: start peer measurement (e.g. FTM) | ||
3371 | * @abort_pmsr: abort peer measurement | ||
3186 | */ | 3372 | */ |
3187 | struct cfg80211_ops { | 3373 | struct cfg80211_ops { |
3188 | int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow); | 3374 | int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow); |
@@ -3492,6 +3678,11 @@ struct cfg80211_ops { | |||
3492 | int (*get_ftm_responder_stats)(struct wiphy *wiphy, | 3678 | int (*get_ftm_responder_stats)(struct wiphy *wiphy, |
3493 | struct net_device *dev, | 3679 | struct net_device *dev, |
3494 | struct cfg80211_ftm_responder_stats *ftm_stats); | 3680 | struct cfg80211_ftm_responder_stats *ftm_stats); |
3681 | |||
3682 | int (*start_pmsr)(struct wiphy *wiphy, struct wireless_dev *wdev, | ||
3683 | struct cfg80211_pmsr_request *request); | ||
3684 | void (*abort_pmsr)(struct wiphy *wiphy, struct wireless_dev *wdev, | ||
3685 | struct cfg80211_pmsr_request *request); | ||
3495 | }; | 3686 | }; |
3496 | 3687 | ||
3497 | /* | 3688 | /* |
@@ -3864,6 +4055,42 @@ struct wiphy_iftype_ext_capab { | |||
3864 | }; | 4055 | }; |
3865 | 4056 | ||
3866 | /** | 4057 | /** |
4058 | * struct cfg80211_pmsr_capabilities - cfg80211 peer measurement capabilities | ||
4059 | * @max_peers: maximum number of peers in a single measurement | ||
4060 | * @report_ap_tsf: can report assoc AP's TSF for radio resource measurement | ||
4061 | * @randomize_mac_addr: can randomize MAC address for measurement | ||
4062 | * @ftm.supported: FTM measurement is supported | ||
4063 | * @ftm.asap: ASAP-mode is supported | ||
4064 | * @ftm.non_asap: non-ASAP-mode is supported | ||
4065 | * @ftm.request_lci: can request LCI data | ||
4066 | * @ftm.request_civicloc: can request civic location data | ||
4067 | * @ftm.preambles: bitmap of preambles supported (&enum nl80211_preamble) | ||
4068 | * @ftm.bandwidths: bitmap of bandwidths supported (&enum nl80211_chan_width) | ||
4069 | * @ftm.max_bursts_exponent: maximum burst exponent supported | ||
4070 | * (set to -1 if not limited; note that setting this will necessarily | ||
4071 | * forbid using the value 15 to let the responder pick) | ||
4072 | * @ftm.max_ftms_per_burst: maximum FTMs per burst supported (set to 0 if | ||
4073 | * not limited) | ||
4074 | */ | ||
4075 | struct cfg80211_pmsr_capabilities { | ||
4076 | unsigned int max_peers; | ||
4077 | u8 report_ap_tsf:1, | ||
4078 | randomize_mac_addr:1; | ||
4079 | |||
4080 | struct { | ||
4081 | u32 preambles; | ||
4082 | u32 bandwidths; | ||
4083 | s8 max_bursts_exponent; | ||
4084 | u8 max_ftms_per_burst; | ||
4085 | u8 supported:1, | ||
4086 | asap:1, | ||
4087 | non_asap:1, | ||
4088 | request_lci:1, | ||
4089 | request_civicloc:1; | ||
4090 | } ftm; | ||
4091 | }; | ||
4092 | |||
4093 | /** | ||
3867 | * struct wiphy - wireless hardware description | 4094 | * struct wiphy - wireless hardware description |
3868 | * @reg_notifier: the driver's regulatory notification callback, | 4095 | * @reg_notifier: the driver's regulatory notification callback, |
3869 | * note that if your driver uses wiphy_apply_custom_regulatory() | 4096 | * note that if your driver uses wiphy_apply_custom_regulatory() |
@@ -4027,6 +4254,8 @@ struct wiphy_iftype_ext_capab { | |||
4027 | * @txq_limit: configuration of internal TX queue frame limit | 4254 | * @txq_limit: configuration of internal TX queue frame limit |
4028 | * @txq_memory_limit: configuration internal TX queue memory limit | 4255 | * @txq_memory_limit: configuration internal TX queue memory limit |
4029 | * @txq_quantum: configuration of internal TX queue scheduler quantum | 4256 | * @txq_quantum: configuration of internal TX queue scheduler quantum |
4257 | * | ||
4258 | * @pmsr_capa: peer measurement capabilities | ||
4030 | */ | 4259 | */ |
4031 | struct wiphy { | 4260 | struct wiphy { |
4032 | /* assign these fields before you register the wiphy */ | 4261 | /* assign these fields before you register the wiphy */ |
@@ -4163,6 +4392,8 @@ struct wiphy { | |||
4163 | u32 txq_memory_limit; | 4392 | u32 txq_memory_limit; |
4164 | u32 txq_quantum; | 4393 | u32 txq_quantum; |
4165 | 4394 | ||
4395 | const struct cfg80211_pmsr_capabilities *pmsr_capa; | ||
4396 | |||
4166 | char priv[0] __aligned(NETDEV_ALIGN); | 4397 | char priv[0] __aligned(NETDEV_ALIGN); |
4167 | }; | 4398 | }; |
4168 | 4399 | ||
@@ -4365,6 +4596,9 @@ struct cfg80211_cqm_config; | |||
4365 | * @owner_nlportid: (private) owner socket port ID | 4596 | * @owner_nlportid: (private) owner socket port ID |
4366 | * @nl_owner_dead: (private) owner socket went away | 4597 | * @nl_owner_dead: (private) owner socket went away |
4367 | * @cqm_config: (private) nl80211 RSSI monitor state | 4598 | * @cqm_config: (private) nl80211 RSSI monitor state |
4599 | * @pmsr_list: (private) peer measurement requests | ||
4600 | * @pmsr_lock: (private) peer measurements requests/results lock | ||
4601 | * @pmsr_free_wk: (private) peer measurements cleanup work | ||
4368 | */ | 4602 | */ |
4369 | struct wireless_dev { | 4603 | struct wireless_dev { |
4370 | struct wiphy *wiphy; | 4604 | struct wiphy *wiphy; |
@@ -4436,6 +4670,10 @@ struct wireless_dev { | |||
4436 | #endif | 4670 | #endif |
4437 | 4671 | ||
4438 | struct cfg80211_cqm_config *cqm_config; | 4672 | struct cfg80211_cqm_config *cqm_config; |
4673 | |||
4674 | struct list_head pmsr_list; | ||
4675 | spinlock_t pmsr_lock; | ||
4676 | struct work_struct pmsr_free_wk; | ||
4439 | }; | 4677 | }; |
4440 | 4678 | ||
4441 | static inline u8 *wdev_address(struct wireless_dev *wdev) | 4679 | static inline u8 *wdev_address(struct wireless_dev *wdev) |
@@ -6630,6 +6868,31 @@ int cfg80211_external_auth_request(struct net_device *netdev, | |||
6630 | struct cfg80211_external_auth_params *params, | 6868 | struct cfg80211_external_auth_params *params, |
6631 | gfp_t gfp); | 6869 | gfp_t gfp); |
6632 | 6870 | ||
6871 | /** | ||
6872 | * cfg80211_pmsr_report - report peer measurement result data | ||
6873 | * @wdev: the wireless device reporting the measurement | ||
6874 | * @req: the original measurement request | ||
6875 | * @result: the result data | ||
6876 | * @gfp: allocation flags | ||
6877 | */ | ||
6878 | void cfg80211_pmsr_report(struct wireless_dev *wdev, | ||
6879 | struct cfg80211_pmsr_request *req, | ||
6880 | struct cfg80211_pmsr_result *result, | ||
6881 | gfp_t gfp); | ||
6882 | |||
6883 | /** | ||
6884 | * cfg80211_pmsr_complete - report peer measurement completed | ||
6885 | * @wdev: the wireless device reporting the measurement | ||
6886 | * @req: the original measurement request | ||
6887 | * @gfp: allocation flags | ||
6888 | * | ||
6889 | * Report that the entire measurement completed, after this | ||
6890 | * the request pointer will no longer be valid. | ||
6891 | */ | ||
6892 | void cfg80211_pmsr_complete(struct wireless_dev *wdev, | ||
6893 | struct cfg80211_pmsr_request *req, | ||
6894 | gfp_t gfp); | ||
6895 | |||
6633 | /* Logging, debugging and troubleshooting/diagnostic helpers. */ | 6896 | /* Logging, debugging and troubleshooting/diagnostic helpers. */ |
6634 | 6897 | ||
6635 | /* wiphy_printk helpers, similar to dev_printk */ | 6898 | /* wiphy_printk helpers, similar to dev_printk */ |
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index 6d610bae30a9..e45b88925783 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h | |||
@@ -1036,6 +1036,30 @@ | |||
1036 | * @NL80211_CMD_GET_FTM_RESPONDER_STATS: Retrieve FTM responder statistics, in | 1036 | * @NL80211_CMD_GET_FTM_RESPONDER_STATS: Retrieve FTM responder statistics, in |
1037 | * the %NL80211_ATTR_FTM_RESPONDER_STATS attribute. | 1037 | * the %NL80211_ATTR_FTM_RESPONDER_STATS attribute. |
1038 | * | 1038 | * |
1039 | * @NL80211_CMD_PEER_MEASUREMENT_START: start a (set of) peer measurement(s) | ||
1040 | * with the given parameters, which are encapsulated in the nested | ||
1041 | * %NL80211_ATTR_PEER_MEASUREMENTS attribute. Optionally, MAC address | ||
1042 | * randomization may be enabled and configured by specifying the | ||
1043 | * %NL80211_ATTR_MAC and %NL80211_ATTR_MAC_MASK attributes. | ||
1044 | * If a timeout is requested, use the %NL80211_ATTR_TIMEOUT attribute. | ||
1045 | * A u64 cookie for further %NL80211_ATTR_COOKIE use is is returned in | ||
1046 | * the netlink extended ack message. | ||
1047 | * | ||
1048 | * To cancel a measurement, close the socket that requested it. | ||
1049 | * | ||
1050 | * Measurement results are reported to the socket that requested the | ||
1051 | * measurement using @NL80211_CMD_PEER_MEASUREMENT_RESULT when they | ||
1052 | * become available, so applications must ensure a large enough socket | ||
1053 | * buffer size. | ||
1054 | * | ||
1055 | * Depending on driver support it may or may not be possible to start | ||
1056 | * multiple concurrent measurements. | ||
1057 | * @NL80211_CMD_PEER_MEASUREMENT_RESULT: This command number is used for the | ||
1058 | * result notification from the driver to the requesting socket. | ||
1059 | * @NL80211_CMD_PEER_MEASUREMENT_COMPLETE: Notification only, indicating that | ||
1060 | * the measurement completed, using the measurement cookie | ||
1061 | * (%NL80211_ATTR_COOKIE). | ||
1062 | * | ||
1039 | * @NL80211_CMD_MAX: highest used command number | 1063 | * @NL80211_CMD_MAX: highest used command number |
1040 | * @__NL80211_CMD_AFTER_LAST: internal use | 1064 | * @__NL80211_CMD_AFTER_LAST: internal use |
1041 | */ | 1065 | */ |
@@ -1250,6 +1274,10 @@ enum nl80211_commands { | |||
1250 | 1274 | ||
1251 | NL80211_CMD_GET_FTM_RESPONDER_STATS, | 1275 | NL80211_CMD_GET_FTM_RESPONDER_STATS, |
1252 | 1276 | ||
1277 | NL80211_CMD_PEER_MEASUREMENT_START, | ||
1278 | NL80211_CMD_PEER_MEASUREMENT_RESULT, | ||
1279 | NL80211_CMD_PEER_MEASUREMENT_COMPLETE, | ||
1280 | |||
1253 | /* add new commands above here */ | 1281 | /* add new commands above here */ |
1254 | 1282 | ||
1255 | /* used to define NL80211_CMD_MAX below */ | 1283 | /* used to define NL80211_CMD_MAX below */ |
@@ -2254,6 +2282,16 @@ enum nl80211_commands { | |||
2254 | * @NL80211_ATTR_FTM_RESPONDER_STATS: Nested attribute with FTM responder | 2282 | * @NL80211_ATTR_FTM_RESPONDER_STATS: Nested attribute with FTM responder |
2255 | * statistics, see &enum nl80211_ftm_responder_stats. | 2283 | * statistics, see &enum nl80211_ftm_responder_stats. |
2256 | * | 2284 | * |
2285 | * @NL80211_ATTR_TIMEOUT: Timeout for the given operation in milliseconds (u32), | ||
2286 | * if the attribute is not given no timeout is requested. Note that 0 is an | ||
2287 | * invalid value. | ||
2288 | * | ||
2289 | * @NL80211_ATTR_PEER_MEASUREMENTS: peer measurements request (and result) | ||
2290 | * data, uses nested attributes specified in | ||
2291 | * &enum nl80211_peer_measurement_attrs. | ||
2292 | * This is also used for capability advertisement in the wiphy information, | ||
2293 | * with the appropriate sub-attributes. | ||
2294 | * | ||
2257 | * @NUM_NL80211_ATTR: total number of nl80211_attrs available | 2295 | * @NUM_NL80211_ATTR: total number of nl80211_attrs available |
2258 | * @NL80211_ATTR_MAX: highest attribute number currently defined | 2296 | * @NL80211_ATTR_MAX: highest attribute number currently defined |
2259 | * @__NL80211_ATTR_AFTER_LAST: internal use | 2297 | * @__NL80211_ATTR_AFTER_LAST: internal use |
@@ -2699,6 +2737,10 @@ enum nl80211_attrs { | |||
2699 | 2737 | ||
2700 | NL80211_ATTR_FTM_RESPONDER_STATS, | 2738 | NL80211_ATTR_FTM_RESPONDER_STATS, |
2701 | 2739 | ||
2740 | NL80211_ATTR_TIMEOUT, | ||
2741 | |||
2742 | NL80211_ATTR_PEER_MEASUREMENTS, | ||
2743 | |||
2702 | /* add attributes here, update the policy in nl80211.c */ | 2744 | /* add attributes here, update the policy in nl80211.c */ |
2703 | 2745 | ||
2704 | __NL80211_ATTR_AFTER_LAST, | 2746 | __NL80211_ATTR_AFTER_LAST, |
@@ -5906,4 +5948,380 @@ enum nl80211_ftm_responder_stats { | |||
5906 | NL80211_FTM_STATS_MAX = __NL80211_FTM_STATS_AFTER_LAST - 1 | 5948 | NL80211_FTM_STATS_MAX = __NL80211_FTM_STATS_AFTER_LAST - 1 |
5907 | }; | 5949 | }; |
5908 | 5950 | ||
5951 | /** | ||
5952 | * enum nl80211_preamble - frame preamble types | ||
5953 | * @NL80211_PREAMBLE_LEGACY: legacy (HR/DSSS, OFDM, ERP PHY) preamble | ||
5954 | * @NL80211_PREAMBLE_HT: HT preamble | ||
5955 | * @NL80211_PREAMBLE_VHT: VHT preamble | ||
5956 | * @NL80211_PREAMBLE_DMG: DMG preamble | ||
5957 | */ | ||
5958 | enum nl80211_preamble { | ||
5959 | NL80211_PREAMBLE_LEGACY, | ||
5960 | NL80211_PREAMBLE_HT, | ||
5961 | NL80211_PREAMBLE_VHT, | ||
5962 | NL80211_PREAMBLE_DMG, | ||
5963 | }; | ||
5964 | |||
5965 | /** | ||
5966 | * enum nl80211_peer_measurement_type - peer measurement types | ||
5967 | * @NL80211_PMSR_TYPE_INVALID: invalid/unused, needed as we use | ||
5968 | * these numbers also for attributes | ||
5969 | * | ||
5970 | * @NL80211_PMSR_TYPE_FTM: flight time measurement | ||
5971 | * | ||
5972 | * @NUM_NL80211_PMSR_TYPES: internal | ||
5973 | * @NL80211_PMSR_TYPE_MAX: highest type number | ||
5974 | */ | ||
5975 | enum nl80211_peer_measurement_type { | ||
5976 | NL80211_PMSR_TYPE_INVALID, | ||
5977 | |||
5978 | NL80211_PMSR_TYPE_FTM, | ||
5979 | |||
5980 | NUM_NL80211_PMSR_TYPES, | ||
5981 | NL80211_PMSR_TYPE_MAX = NUM_NL80211_PMSR_TYPES - 1 | ||
5982 | }; | ||
5983 | |||
5984 | /** | ||
5985 | * enum nl80211_peer_measurement_status - peer measurement status | ||
5986 | * @NL80211_PMSR_STATUS_SUCCESS: measurement completed successfully | ||
5987 | * @NL80211_PMSR_STATUS_REFUSED: measurement was locally refused | ||
5988 | * @NL80211_PMSR_STATUS_TIMEOUT: measurement timed out | ||
5989 | * @NL80211_PMSR_STATUS_FAILURE: measurement failed, a type-dependent | ||
5990 | * reason may be available in the response data | ||
5991 | */ | ||
5992 | enum nl80211_peer_measurement_status { | ||
5993 | NL80211_PMSR_STATUS_SUCCESS, | ||
5994 | NL80211_PMSR_STATUS_REFUSED, | ||
5995 | NL80211_PMSR_STATUS_TIMEOUT, | ||
5996 | NL80211_PMSR_STATUS_FAILURE, | ||
5997 | }; | ||
5998 | |||
5999 | /** | ||
6000 | * enum nl80211_peer_measurement_req - peer measurement request attributes | ||
6001 | * @__NL80211_PMSR_REQ_ATTR_INVALID: invalid | ||
6002 | * | ||
6003 | * @NL80211_PMSR_REQ_ATTR_DATA: This is a nested attribute with measurement | ||
6004 | * type-specific request data inside. The attributes used are from the | ||
6005 | * enums named nl80211_peer_measurement_<type>_req. | ||
6006 | * @NL80211_PMSR_REQ_ATTR_GET_AP_TSF: include AP TSF timestamp, if supported | ||
6007 | * (flag attribute) | ||
6008 | * | ||
6009 | * @NUM_NL80211_PMSR_REQ_ATTRS: internal | ||
6010 | * @NL80211_PMSR_REQ_ATTR_MAX: highest attribute number | ||
6011 | */ | ||
6012 | enum nl80211_peer_measurement_req { | ||
6013 | __NL80211_PMSR_REQ_ATTR_INVALID, | ||
6014 | |||
6015 | NL80211_PMSR_REQ_ATTR_DATA, | ||
6016 | NL80211_PMSR_REQ_ATTR_GET_AP_TSF, | ||
6017 | |||
6018 | /* keep last */ | ||
6019 | NUM_NL80211_PMSR_REQ_ATTRS, | ||
6020 | NL80211_PMSR_REQ_ATTR_MAX = NUM_NL80211_PMSR_REQ_ATTRS - 1 | ||
6021 | }; | ||
6022 | |||
6023 | /** | ||
6024 | * enum nl80211_peer_measurement_resp - peer measurement response attributes | ||
6025 | * @__NL80211_PMSR_RESP_ATTR_INVALID: invalid | ||
6026 | * | ||
6027 | * @NL80211_PMSR_RESP_ATTR_DATA: This is a nested attribute with measurement | ||
6028 | * type-specific results inside. The attributes used are from the enums | ||
6029 | * named nl80211_peer_measurement_<type>_resp. | ||
6030 | * @NL80211_PMSR_RESP_ATTR_STATUS: u32 value with the measurement status | ||
6031 | * (using values from &enum nl80211_peer_measurement_status.) | ||
6032 | * @NL80211_PMSR_RESP_ATTR_HOST_TIME: host time (%CLOCK_BOOTTIME) when the | ||
6033 | * result was measured; this value is not expected to be accurate to | ||
6034 | * more than 20ms. (u64, nanoseconds) | ||
6035 | * @NL80211_PMSR_RESP_ATTR_AP_TSF: TSF of the AP that the interface | ||
6036 | * doing the measurement is connected to when the result was measured. | ||
6037 | * This shall be accurately reported if supported and requested | ||
6038 | * (u64, usec) | ||
6039 | * @NL80211_PMSR_RESP_ATTR_FINAL: If results are sent to the host partially | ||
6040 | * (*e.g. with FTM per-burst data) this flag will be cleared on all but | ||
6041 | * the last result; if all results are combined it's set on the single | ||
6042 | * result. | ||
6043 | * @NL80211_PMSR_RESP_ATTR_PAD: padding for 64-bit attributes, ignore | ||
6044 | * | ||
6045 | * @NUM_NL80211_PMSR_RESP_ATTRS: internal | ||
6046 | * @NL80211_PMSR_RESP_ATTR_MAX: highest attribute number | ||
6047 | */ | ||
6048 | enum nl80211_peer_measurement_resp { | ||
6049 | __NL80211_PMSR_RESP_ATTR_INVALID, | ||
6050 | |||
6051 | NL80211_PMSR_RESP_ATTR_DATA, | ||
6052 | NL80211_PMSR_RESP_ATTR_STATUS, | ||
6053 | NL80211_PMSR_RESP_ATTR_HOST_TIME, | ||
6054 | NL80211_PMSR_RESP_ATTR_AP_TSF, | ||
6055 | NL80211_PMSR_RESP_ATTR_FINAL, | ||
6056 | NL80211_PMSR_RESP_ATTR_PAD, | ||
6057 | |||
6058 | /* keep last */ | ||
6059 | NUM_NL80211_PMSR_RESP_ATTRS, | ||
6060 | NL80211_PMSR_RESP_ATTR_MAX = NUM_NL80211_PMSR_RESP_ATTRS - 1 | ||
6061 | }; | ||
6062 | |||
6063 | /** | ||
6064 | * enum nl80211_peer_measurement_peer_attrs - peer attributes for measurement | ||
6065 | * @__NL80211_PMSR_PEER_ATTR_INVALID: invalid | ||
6066 | * | ||
6067 | * @NL80211_PMSR_PEER_ATTR_ADDR: peer's MAC address | ||
6068 | * @NL80211_PMSR_PEER_ATTR_CHAN: channel definition, nested, using top-level | ||
6069 | * attributes like %NL80211_ATTR_WIPHY_FREQ etc. | ||
6070 | * @NL80211_PMSR_PEER_ATTR_REQ: This is a nested attribute indexed by | ||
6071 | * measurement type, with attributes from the | ||
6072 | * &enum nl80211_peer_measurement_req inside. | ||
6073 | * @NL80211_PMSR_PEER_ATTR_RESP: This is a nested attribute indexed by | ||
6074 | * measurement type, with attributes from the | ||
6075 | * &enum nl80211_peer_measurement_resp inside. | ||
6076 | * | ||
6077 | * @NUM_NL80211_PMSR_PEER_ATTRS: internal | ||
6078 | * @NL80211_PMSR_PEER_ATTR_MAX: highest attribute number | ||
6079 | */ | ||
6080 | enum nl80211_peer_measurement_peer_attrs { | ||
6081 | __NL80211_PMSR_PEER_ATTR_INVALID, | ||
6082 | |||
6083 | NL80211_PMSR_PEER_ATTR_ADDR, | ||
6084 | NL80211_PMSR_PEER_ATTR_CHAN, | ||
6085 | NL80211_PMSR_PEER_ATTR_REQ, | ||
6086 | NL80211_PMSR_PEER_ATTR_RESP, | ||
6087 | |||
6088 | /* keep last */ | ||
6089 | NUM_NL80211_PMSR_PEER_ATTRS, | ||
6090 | NL80211_PMSR_PEER_ATTR_MAX = NUM_NL80211_PMSR_PEER_ATTRS - 1, | ||
6091 | }; | ||
6092 | |||
6093 | /** | ||
6094 | * enum nl80211_peer_measurement_attrs - peer measurement attributes | ||
6095 | * @__NL80211_PMSR_ATTR_INVALID: invalid | ||
6096 | * | ||
6097 | * @NL80211_PMSR_ATTR_MAX_PEERS: u32 attribute used for capability | ||
6098 | * advertisement only, indicates the maximum number of peers | ||
6099 | * measurements can be done with in a single request | ||
6100 | * @NL80211_PMSR_ATTR_REPORT_AP_TSF: flag attribute in capability | ||
6101 | * indicating that the connected AP's TSF can be reported in | ||
6102 | * measurement results | ||
6103 | * @NL80211_PMSR_ATTR_RANDOMIZE_MAC_ADDR: flag attribute in capability | ||
6104 | * indicating that MAC address randomization is supported. | ||
6105 | * @NL80211_PMSR_ATTR_TYPE_CAPA: capabilities reported by the device, | ||
6106 | * this contains a nesting indexed by measurement type, and | ||
6107 | * type-specific capabilities inside, which are from the enums | ||
6108 | * named nl80211_peer_measurement_<type>_capa. | ||
6109 | * @NL80211_PMSR_ATTR_PEERS: nested attribute, the nesting index is | ||
6110 | * meaningless, just a list of peers to measure with, with the | ||
6111 | * sub-attributes taken from | ||
6112 | * &enum nl80211_peer_measurement_peer_attrs. | ||
6113 | * | ||
6114 | * @NUM_NL80211_PMSR_ATTR: internal | ||
6115 | * @NL80211_PMSR_ATTR_MAX: highest attribute number | ||
6116 | */ | ||
6117 | enum nl80211_peer_measurement_attrs { | ||
6118 | __NL80211_PMSR_ATTR_INVALID, | ||
6119 | |||
6120 | NL80211_PMSR_ATTR_MAX_PEERS, | ||
6121 | NL80211_PMSR_ATTR_REPORT_AP_TSF, | ||
6122 | NL80211_PMSR_ATTR_RANDOMIZE_MAC_ADDR, | ||
6123 | NL80211_PMSR_ATTR_TYPE_CAPA, | ||
6124 | NL80211_PMSR_ATTR_PEERS, | ||
6125 | |||
6126 | /* keep last */ | ||
6127 | NUM_NL80211_PMSR_ATTR, | ||
6128 | NL80211_PMSR_ATTR_MAX = NUM_NL80211_PMSR_ATTR - 1 | ||
6129 | }; | ||
6130 | |||
6131 | /** | ||
6132 | * enum nl80211_peer_measurement_ftm_capa - FTM capabilities | ||
6133 | * @__NL80211_PMSR_FTM_CAPA_ATTR_INVALID: invalid | ||
6134 | * | ||
6135 | * @NL80211_PMSR_FTM_CAPA_ATTR_ASAP: flag attribute indicating ASAP mode | ||
6136 | * is supported | ||
6137 | * @NL80211_PMSR_FTM_CAPA_ATTR_NON_ASAP: flag attribute indicating non-ASAP | ||
6138 | * mode is supported | ||
6139 | * @NL80211_PMSR_FTM_CAPA_ATTR_REQ_LCI: flag attribute indicating if LCI | ||
6140 | * data can be requested during the measurement | ||
6141 | * @NL80211_PMSR_FTM_CAPA_ATTR_REQ_CIVICLOC: flag attribute indicating if civic | ||
6142 | * location data can be requested during the measurement | ||
6143 | * @NL80211_PMSR_FTM_CAPA_ATTR_PREAMBLES: u32 bitmap attribute of bits | ||
6144 | * from &enum nl80211_preamble. | ||
6145 | * @NL80211_PMSR_FTM_CAPA_ATTR_BANDWIDTHS: bitmap of values from | ||
6146 | * &enum nl80211_chan_width indicating the supported channel | ||
6147 | * bandwidths for FTM. Note that a higher channel bandwidth may be | ||
6148 | * configured to allow for other measurements types with different | ||
6149 | * bandwidth requirement in the same measurement. | ||
6150 | * @NL80211_PMSR_FTM_CAPA_ATTR_MAX_BURSTS_EXPONENT: u32 attribute indicating | ||
6151 | * the maximum bursts exponent that can be used (if not present anything | ||
6152 | * is valid) | ||
6153 | * @NL80211_PMSR_FTM_CAPA_ATTR_MAX_FTMS_PER_BURST: u32 attribute indicating | ||
6154 | * the maximum FTMs per burst (if not present anything is valid) | ||
6155 | * | ||
6156 | * @NUM_NL80211_PMSR_FTM_CAPA_ATTR: internal | ||
6157 | * @NL80211_PMSR_FTM_CAPA_ATTR_MAX: highest attribute number | ||
6158 | */ | ||
6159 | enum nl80211_peer_measurement_ftm_capa { | ||
6160 | __NL80211_PMSR_FTM_CAPA_ATTR_INVALID, | ||
6161 | |||
6162 | NL80211_PMSR_FTM_CAPA_ATTR_ASAP, | ||
6163 | NL80211_PMSR_FTM_CAPA_ATTR_NON_ASAP, | ||
6164 | NL80211_PMSR_FTM_CAPA_ATTR_REQ_LCI, | ||
6165 | NL80211_PMSR_FTM_CAPA_ATTR_REQ_CIVICLOC, | ||
6166 | NL80211_PMSR_FTM_CAPA_ATTR_PREAMBLES, | ||
6167 | NL80211_PMSR_FTM_CAPA_ATTR_BANDWIDTHS, | ||
6168 | NL80211_PMSR_FTM_CAPA_ATTR_MAX_BURSTS_EXPONENT, | ||
6169 | NL80211_PMSR_FTM_CAPA_ATTR_MAX_FTMS_PER_BURST, | ||
6170 | |||
6171 | /* keep last */ | ||
6172 | NUM_NL80211_PMSR_FTM_CAPA_ATTR, | ||
6173 | NL80211_PMSR_FTM_CAPA_ATTR_MAX = NUM_NL80211_PMSR_FTM_CAPA_ATTR - 1 | ||
6174 | }; | ||
6175 | |||
6176 | /** | ||
6177 | * enum nl80211_peer_measurement_ftm_req - FTM request attributes | ||
6178 | * @__NL80211_PMSR_FTM_REQ_ATTR_INVALID: invalid | ||
6179 | * | ||
6180 | * @NL80211_PMSR_FTM_REQ_ATTR_ASAP: ASAP mode requested (flag) | ||
6181 | * @NL80211_PMSR_FTM_REQ_ATTR_PREAMBLE: preamble type (see | ||
6182 | * &enum nl80211_preamble), optional for DMG (u32) | ||
6183 | * @NL80211_PMSR_FTM_REQ_ATTR_NUM_BURSTS_EXP: number of bursts exponent as in | ||
6184 | * 802.11-2016 9.4.2.168 "Fine Timing Measurement Parameters element" | ||
6185 | * (u8, 0-15, optional with default 15 i.e. "no preference") | ||
6186 | * @NL80211_PMSR_FTM_REQ_ATTR_BURST_PERIOD: interval between bursts in units | ||
6187 | * of 100ms (u16, optional with default 0) | ||
6188 | * @NL80211_PMSR_FTM_REQ_ATTR_BURST_DURATION: burst duration, as in 802.11-2016 | ||
6189 | * Table 9-257 "Burst Duration field encoding" (u8, 0-15, optional with | ||
6190 | * default 15 i.e. "no preference") | ||
6191 | * @NL80211_PMSR_FTM_REQ_ATTR_FTMS_PER_BURST: number of successful FTM frames | ||
6192 | * requested per burst | ||
6193 | * (u8, 0-31, optional with default 0 i.e. "no preference") | ||
6194 | * @NL80211_PMSR_FTM_REQ_ATTR_NUM_FTMR_RETRIES: number of FTMR frame retries | ||
6195 | * (u8, default 3) | ||
6196 | * @NL80211_PMSR_FTM_REQ_ATTR_REQUEST_LCI: request LCI data (flag) | ||
6197 | * @NL80211_PMSR_FTM_REQ_ATTR_REQUEST_CIVICLOC: request civic location data | ||
6198 | * (flag) | ||
6199 | * | ||
6200 | * @NUM_NL80211_PMSR_FTM_REQ_ATTR: internal | ||
6201 | * @NL80211_PMSR_FTM_REQ_ATTR_MAX: highest attribute number | ||
6202 | */ | ||
6203 | enum nl80211_peer_measurement_ftm_req { | ||
6204 | __NL80211_PMSR_FTM_REQ_ATTR_INVALID, | ||
6205 | |||
6206 | NL80211_PMSR_FTM_REQ_ATTR_ASAP, | ||
6207 | NL80211_PMSR_FTM_REQ_ATTR_PREAMBLE, | ||
6208 | NL80211_PMSR_FTM_REQ_ATTR_NUM_BURSTS_EXP, | ||
6209 | NL80211_PMSR_FTM_REQ_ATTR_BURST_PERIOD, | ||
6210 | NL80211_PMSR_FTM_REQ_ATTR_BURST_DURATION, | ||
6211 | NL80211_PMSR_FTM_REQ_ATTR_FTMS_PER_BURST, | ||
6212 | NL80211_PMSR_FTM_REQ_ATTR_NUM_FTMR_RETRIES, | ||
6213 | NL80211_PMSR_FTM_REQ_ATTR_REQUEST_LCI, | ||
6214 | NL80211_PMSR_FTM_REQ_ATTR_REQUEST_CIVICLOC, | ||
6215 | |||
6216 | /* keep last */ | ||
6217 | NUM_NL80211_PMSR_FTM_REQ_ATTR, | ||
6218 | NL80211_PMSR_FTM_REQ_ATTR_MAX = NUM_NL80211_PMSR_FTM_REQ_ATTR - 1 | ||
6219 | }; | ||
6220 | |||
6221 | /** | ||
6222 | * enum nl80211_peer_measurement_ftm_failure_reasons - FTM failure reasons | ||
6223 | * @NL80211_PMSR_FTM_FAILURE_UNSPECIFIED: unspecified failure, not used | ||
6224 | * @NL80211_PMSR_FTM_FAILURE_NO_RESPONSE: no response from the FTM responder | ||
6225 | * @NL80211_PMSR_FTM_FAILURE_REJECTED: FTM responder rejected measurement | ||
6226 | * @NL80211_PMSR_FTM_FAILURE_WRONG_CHANNEL: we already know the peer is | ||
6227 | * on a different channel, so can't measure (if we didn't know, we'd | ||
6228 | * try and get no response) | ||
6229 | * @NL80211_PMSR_FTM_FAILURE_PEER_NOT_CAPABLE: peer can't actually do FTM | ||
6230 | * @NL80211_PMSR_FTM_FAILURE_INVALID_TIMESTAMP: invalid T1/T4 timestamps | ||
6231 | * received | ||
6232 | * @NL80211_PMSR_FTM_FAILURE_PEER_BUSY: peer reports busy, you may retry | ||
6233 | * later (see %NL80211_PMSR_FTM_RESP_ATTR_BUSY_RETRY_TIME) | ||
6234 | * @NL80211_PMSR_FTM_FAILURE_BAD_CHANGED_PARAMS: parameters were changed | ||
6235 | * by the peer and are no longer supported | ||
6236 | */ | ||
6237 | enum nl80211_peer_measurement_ftm_failure_reasons { | ||
6238 | NL80211_PMSR_FTM_FAILURE_UNSPECIFIED, | ||
6239 | NL80211_PMSR_FTM_FAILURE_NO_RESPONSE, | ||
6240 | NL80211_PMSR_FTM_FAILURE_REJECTED, | ||
6241 | NL80211_PMSR_FTM_FAILURE_WRONG_CHANNEL, | ||
6242 | NL80211_PMSR_FTM_FAILURE_PEER_NOT_CAPABLE, | ||
6243 | NL80211_PMSR_FTM_FAILURE_INVALID_TIMESTAMP, | ||
6244 | NL80211_PMSR_FTM_FAILURE_PEER_BUSY, | ||
6245 | NL80211_PMSR_FTM_FAILURE_BAD_CHANGED_PARAMS, | ||
6246 | }; | ||
6247 | |||
6248 | /** | ||
6249 | * enum nl80211_peer_measurement_ftm_resp - FTM response attributes | ||
6250 | * @__NL80211_PMSR_FTM_RESP_ATTR_INVALID: invalid | ||
6251 | * | ||
6252 | * @NL80211_PMSR_FTM_RESP_ATTR_FAIL_REASON: FTM-specific failure reason | ||
6253 | * (u32, optional) | ||
6254 | * @NL80211_PMSR_FTM_RESP_ATTR_BURST_INDEX: optional, if bursts are reported | ||
6255 | * as separate results then it will be the burst index 0...(N-1) and | ||
6256 | * the top level will indicate partial results (u32) | ||
6257 | * @NL80211_PMSR_FTM_RESP_ATTR_NUM_FTMR_ATTEMPTS: number of FTM Request frames | ||
6258 | * transmitted (u32, optional) | ||
6259 | * @NL80211_PMSR_FTM_RESP_ATTR_NUM_FTMR_SUCCESSES: number of FTM Request frames | ||
6260 | * that were acknowleged (u32, optional) | ||
6261 | * @NL80211_PMSR_FTM_RESP_ATTR_BUSY_RETRY_TIME: retry time received from the | ||
6262 | * busy peer (u32, seconds) | ||
6263 | * @NL80211_PMSR_FTM_RESP_ATTR_NUM_BURSTS_EXP: actual number of bursts exponent | ||
6264 | * used by the responder (similar to request, u8) | ||
6265 | * @NL80211_PMSR_FTM_RESP_ATTR_BURST_DURATION: actual burst duration used by | ||
6266 | * the responder (similar to request, u8) | ||
6267 | * @NL80211_PMSR_FTM_RESP_ATTR_FTMS_PER_BURST: actual FTMs per burst used | ||
6268 | * by the responder (similar to request, u8) | ||
6269 | * @NL80211_PMSR_FTM_RESP_ATTR_RSSI_AVG: average RSSI across all FTM action | ||
6270 | * frames (optional, s32, 1/2 dBm) | ||
6271 | * @NL80211_PMSR_FTM_RESP_ATTR_RSSI_SPREAD: RSSI spread across all FTM action | ||
6272 | * frames (optional, s32, 1/2 dBm) | ||
6273 | * @NL80211_PMSR_FTM_RESP_ATTR_TX_RATE: bitrate we used for the response to the | ||
6274 | * FTM action frame (optional, nested, using &enum nl80211_rate_info | ||
6275 | * attributes) | ||
6276 | * @NL80211_PMSR_FTM_RESP_ATTR_RX_RATE: bitrate the responder used for the FTM | ||
6277 | * action frame (optional, nested, using &enum nl80211_rate_info attrs) | ||
6278 | * @NL80211_PMSR_FTM_RESP_ATTR_RTT_AVG: average RTT (s64, picoseconds, optional | ||
6279 | * but one of RTT/DIST must be present) | ||
6280 | * @NL80211_PMSR_FTM_RESP_ATTR_RTT_VARIANCE: RTT variance (u64, ps^2, note that | ||
6281 | * standard deviation is the square root of variance, optional) | ||
6282 | * @NL80211_PMSR_FTM_RESP_ATTR_RTT_SPREAD: RTT spread (u64, picoseconds, | ||
6283 | * optional) | ||
6284 | * @NL80211_PMSR_FTM_RESP_ATTR_DIST_AVG: average distance (s64, mm, optional | ||
6285 | * but one of RTT/DIST must be present) | ||
6286 | * @NL80211_PMSR_FTM_RESP_ATTR_DIST_VARIANCE: distance variance (u64, mm^2, note | ||
6287 | * that standard deviation is the square root of variance, optional) | ||
6288 | * @NL80211_PMSR_FTM_RESP_ATTR_DIST_SPREAD: distance spread (u64, mm, optional) | ||
6289 | * @NL80211_PMSR_FTM_RESP_ATTR_LCI: LCI data from peer (binary, optional) | ||
6290 | * @NL80211_PMSR_FTM_RESP_ATTR_CIVICLOC: civic location data from peer | ||
6291 | * (binary, optional) | ||
6292 | * @NL80211_PMSR_FTM_RESP_ATTR_PAD: ignore, for u64/s64 padding only | ||
6293 | * | ||
6294 | * @NUM_NL80211_PMSR_FTM_RESP_ATTR: internal | ||
6295 | * @NL80211_PMSR_FTM_RESP_ATTR_MAX: highest attribute number | ||
6296 | */ | ||
6297 | enum nl80211_peer_measurement_ftm_resp { | ||
6298 | __NL80211_PMSR_FTM_RESP_ATTR_INVALID, | ||
6299 | |||
6300 | NL80211_PMSR_FTM_RESP_ATTR_FAIL_REASON, | ||
6301 | NL80211_PMSR_FTM_RESP_ATTR_BURST_INDEX, | ||
6302 | NL80211_PMSR_FTM_RESP_ATTR_NUM_FTMR_ATTEMPTS, | ||
6303 | NL80211_PMSR_FTM_RESP_ATTR_NUM_FTMR_SUCCESSES, | ||
6304 | NL80211_PMSR_FTM_RESP_ATTR_BUSY_RETRY_TIME, | ||
6305 | NL80211_PMSR_FTM_RESP_ATTR_NUM_BURSTS_EXP, | ||
6306 | NL80211_PMSR_FTM_RESP_ATTR_BURST_DURATION, | ||
6307 | NL80211_PMSR_FTM_RESP_ATTR_FTMS_PER_BURST, | ||
6308 | NL80211_PMSR_FTM_RESP_ATTR_RSSI_AVG, | ||
6309 | NL80211_PMSR_FTM_RESP_ATTR_RSSI_SPREAD, | ||
6310 | NL80211_PMSR_FTM_RESP_ATTR_TX_RATE, | ||
6311 | NL80211_PMSR_FTM_RESP_ATTR_RX_RATE, | ||
6312 | NL80211_PMSR_FTM_RESP_ATTR_RTT_AVG, | ||
6313 | NL80211_PMSR_FTM_RESP_ATTR_RTT_VARIANCE, | ||
6314 | NL80211_PMSR_FTM_RESP_ATTR_RTT_SPREAD, | ||
6315 | NL80211_PMSR_FTM_RESP_ATTR_DIST_AVG, | ||
6316 | NL80211_PMSR_FTM_RESP_ATTR_DIST_VARIANCE, | ||
6317 | NL80211_PMSR_FTM_RESP_ATTR_DIST_SPREAD, | ||
6318 | NL80211_PMSR_FTM_RESP_ATTR_LCI, | ||
6319 | NL80211_PMSR_FTM_RESP_ATTR_CIVICLOC, | ||
6320 | NL80211_PMSR_FTM_RESP_ATTR_PAD, | ||
6321 | |||
6322 | /* keep last */ | ||
6323 | NUM_NL80211_PMSR_FTM_RESP_ATTR, | ||
6324 | NL80211_PMSR_FTM_RESP_ATTR_MAX = NUM_NL80211_PMSR_FTM_RESP_ATTR - 1 | ||
6325 | }; | ||
6326 | |||
5909 | #endif /* __LINUX_NL80211_H */ | 6327 | #endif /* __LINUX_NL80211_H */ |
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/core.c b/net/wireless/core.c index 5bd01058b9e6..0a3092c56b3e 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 |
@@ -664,6 +665,34 @@ int wiphy_register(struct wiphy *wiphy) | |||
664 | return -EINVAL; | 665 | return -EINVAL; |
665 | #endif | 666 | #endif |
666 | 667 | ||
668 | if (WARN_ON(wiphy->pmsr_capa && !wiphy->pmsr_capa->ftm.supported)) | ||
669 | return -EINVAL; | ||
670 | |||
671 | if (wiphy->pmsr_capa && wiphy->pmsr_capa->ftm.supported) { | ||
672 | if (WARN_ON(!wiphy->pmsr_capa->ftm.asap && | ||
673 | !wiphy->pmsr_capa->ftm.non_asap)) | ||
674 | return -EINVAL; | ||
675 | if (WARN_ON(!wiphy->pmsr_capa->ftm.preambles || | ||
676 | !wiphy->pmsr_capa->ftm.bandwidths)) | ||
677 | return -EINVAL; | ||
678 | if (WARN_ON(wiphy->pmsr_capa->ftm.preambles & | ||
679 | ~(BIT(NL80211_PREAMBLE_LEGACY) | | ||
680 | BIT(NL80211_PREAMBLE_HT) | | ||
681 | BIT(NL80211_PREAMBLE_VHT) | | ||
682 | BIT(NL80211_PREAMBLE_DMG)))) | ||
683 | return -EINVAL; | ||
684 | if (WARN_ON(wiphy->pmsr_capa->ftm.bandwidths & | ||
685 | ~(BIT(NL80211_CHAN_WIDTH_20_NOHT) | | ||
686 | BIT(NL80211_CHAN_WIDTH_20) | | ||
687 | BIT(NL80211_CHAN_WIDTH_40) | | ||
688 | BIT(NL80211_CHAN_WIDTH_80) | | ||
689 | BIT(NL80211_CHAN_WIDTH_80P80) | | ||
690 | BIT(NL80211_CHAN_WIDTH_160) | | ||
691 | BIT(NL80211_CHAN_WIDTH_5) | | ||
692 | BIT(NL80211_CHAN_WIDTH_10)))) | ||
693 | return -EINVAL; | ||
694 | } | ||
695 | |||
667 | /* | 696 | /* |
668 | * if a wiphy has unsupported modes for regulatory channel enforcement, | 697 | * if a wiphy has unsupported modes for regulatory channel enforcement, |
669 | * opt-out of enforcement checking | 698 | * opt-out of enforcement checking |
@@ -1087,6 +1116,8 @@ void __cfg80211_leave(struct cfg80211_registered_device *rdev, | |||
1087 | ASSERT_RTNL(); | 1116 | ASSERT_RTNL(); |
1088 | ASSERT_WDEV_LOCK(wdev); | 1117 | ASSERT_WDEV_LOCK(wdev); |
1089 | 1118 | ||
1119 | cfg80211_pmsr_wdev_down(wdev); | ||
1120 | |||
1090 | switch (wdev->iftype) { | 1121 | switch (wdev->iftype) { |
1091 | case NL80211_IFTYPE_ADHOC: | 1122 | case NL80211_IFTYPE_ADHOC: |
1092 | __cfg80211_leave_ibss(rdev, dev, true); | 1123 | __cfg80211_leave_ibss(rdev, dev, true); |
@@ -1174,6 +1205,9 @@ void cfg80211_init_wdev(struct cfg80211_registered_device *rdev, | |||
1174 | spin_lock_init(&wdev->event_lock); | 1205 | spin_lock_init(&wdev->event_lock); |
1175 | INIT_LIST_HEAD(&wdev->mgmt_registrations); | 1206 | INIT_LIST_HEAD(&wdev->mgmt_registrations); |
1176 | spin_lock_init(&wdev->mgmt_registrations_lock); | 1207 | spin_lock_init(&wdev->mgmt_registrations_lock); |
1208 | INIT_LIST_HEAD(&wdev->pmsr_list); | ||
1209 | spin_lock_init(&wdev->pmsr_lock); | ||
1210 | INIT_WORK(&wdev->pmsr_free_wk, cfg80211_pmsr_free_wk); | ||
1177 | 1211 | ||
1178 | /* | 1212 | /* |
1179 | * We get here also when the interface changes network namespaces, | 1213 | * 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 744b5851bbf9..6fd93eb0df6d 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; |
@@ -2118,6 +2263,12 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev, | |||
2118 | goto nla_put_failure; | 2263 | goto nla_put_failure; |
2119 | } | 2264 | } |
2120 | 2265 | ||
2266 | state->split_start++; | ||
2267 | break; | ||
2268 | case 14: | ||
2269 | if (nl80211_send_pmsr_capa(rdev, msg)) | ||
2270 | goto nla_put_failure; | ||
2271 | |||
2121 | /* done */ | 2272 | /* done */ |
2122 | state->split_start = 0; | 2273 | state->split_start = 0; |
2123 | break; | 2274 | break; |
@@ -2318,9 +2469,9 @@ static bool nl80211_can_set_dev_channel(struct wireless_dev *wdev) | |||
2318 | wdev->iftype == NL80211_IFTYPE_P2P_GO; | 2469 | wdev->iftype == NL80211_IFTYPE_P2P_GO; |
2319 | } | 2470 | } |
2320 | 2471 | ||
2321 | static int nl80211_parse_chandef(struct cfg80211_registered_device *rdev, | 2472 | int nl80211_parse_chandef(struct cfg80211_registered_device *rdev, |
2322 | struct genl_info *info, | 2473 | struct genl_info *info, |
2323 | struct cfg80211_chan_def *chandef) | 2474 | struct cfg80211_chan_def *chandef) |
2324 | { | 2475 | { |
2325 | struct netlink_ext_ack *extack = info->extack; | 2476 | struct netlink_ext_ack *extack = info->extack; |
2326 | struct nlattr **attrs = info->attrs; | 2477 | struct nlattr **attrs = info->attrs; |
@@ -2794,12 +2945,6 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) | |||
2794 | return 0; | 2945 | return 0; |
2795 | } | 2946 | } |
2796 | 2947 | ||
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, | 2948 | static int nl80211_send_chandef(struct sk_buff *msg, |
2804 | const struct cfg80211_chan_def *chandef) | 2949 | const struct cfg80211_chan_def *chandef) |
2805 | { | 2950 | { |
@@ -4521,8 +4666,7 @@ static int parse_station_flags(struct genl_info *info, | |||
4521 | return 0; | 4666 | return 0; |
4522 | } | 4667 | } |
4523 | 4668 | ||
4524 | static bool nl80211_put_sta_rate(struct sk_buff *msg, struct rate_info *info, | 4669 | bool nl80211_put_sta_rate(struct sk_buff *msg, struct rate_info *info, int attr) |
4525 | int attr) | ||
4526 | { | 4670 | { |
4527 | struct nlattr *rate; | 4671 | struct nlattr *rate; |
4528 | u32 bitrate; | 4672 | u32 bitrate; |
@@ -6855,8 +6999,8 @@ static int parse_bss_select(struct nlattr *nla, struct wiphy *wiphy, | |||
6855 | return 0; | 6999 | return 0; |
6856 | } | 7000 | } |
6857 | 7001 | ||
6858 | static int nl80211_parse_random_mac(struct nlattr **attrs, | 7002 | int nl80211_parse_random_mac(struct nlattr **attrs, |
6859 | u8 *mac_addr, u8 *mac_addr_mask) | 7003 | u8 *mac_addr, u8 *mac_addr_mask) |
6860 | { | 7004 | { |
6861 | int i; | 7005 | int i; |
6862 | 7006 | ||
@@ -13898,6 +14042,14 @@ static const struct genl_ops nl80211_ops[] = { | |||
13898 | .internal_flags = NL80211_FLAG_NEED_NETDEV | | 14042 | .internal_flags = NL80211_FLAG_NEED_NETDEV | |
13899 | NL80211_FLAG_NEED_RTNL, | 14043 | NL80211_FLAG_NEED_RTNL, |
13900 | }, | 14044 | }, |
14045 | { | ||
14046 | .cmd = NL80211_CMD_PEER_MEASUREMENT_START, | ||
14047 | .doit = nl80211_pmsr_start, | ||
14048 | .policy = nl80211_policy, | ||
14049 | .flags = GENL_UNS_ADMIN_PERM, | ||
14050 | .internal_flags = NL80211_FLAG_NEED_WDEV_UP | | ||
14051 | NL80211_FLAG_NEED_RTNL, | ||
14052 | }, | ||
13901 | }; | 14053 | }; |
13902 | 14054 | ||
13903 | static struct genl_family nl80211_fam __ro_after_init = { | 14055 | static struct genl_family nl80211_fam __ro_after_init = { |
@@ -15881,6 +16033,8 @@ static int nl80211_netlink_notify(struct notifier_block * nb, | |||
15881 | } else if (wdev->conn_owner_nlportid == notify->portid) { | 16033 | } else if (wdev->conn_owner_nlportid == notify->portid) { |
15882 | schedule_work(&wdev->disconnect_wk); | 16034 | schedule_work(&wdev->disconnect_wk); |
15883 | } | 16035 | } |
16036 | |||
16037 | cfg80211_release_pmsr(wdev, notify->portid); | ||
15884 | } | 16038 | } |
15885 | 16039 | ||
15886 | spin_lock_bh(&rdev->beacon_registrations_lock); | 16040 | 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/trace.h b/net/wireless/trace.h index f7909867d8fb..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) |
@@ -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 |