1*71e72c9eSCy Schubert /*
2*71e72c9eSCy Schubert * Proxmity Ranging
3*71e72c9eSCy Schubert * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
4*71e72c9eSCy Schubert *
5*71e72c9eSCy Schubert * This software may be distributed under the terms of the BSD license.
6*71e72c9eSCy Schubert * See README for more details.
7*71e72c9eSCy Schubert */
8*71e72c9eSCy Schubert
9*71e72c9eSCy Schubert #include "includes.h"
10*71e72c9eSCy Schubert
11*71e72c9eSCy Schubert #include "utils/common.h"
12*71e72c9eSCy Schubert #include "common/ieee802_11_defs.h"
13*71e72c9eSCy Schubert #include "common/ieee802_11_common.h"
14*71e72c9eSCy Schubert #include "crypto/sha256.h"
15*71e72c9eSCy Schubert #include "pasn/pasn_common.h"
16*71e72c9eSCy Schubert #include "proximity_ranging.h"
17*71e72c9eSCy Schubert
18*71e72c9eSCy Schubert
valid_country_ch(char c)19*71e72c9eSCy Schubert static bool valid_country_ch(char c)
20*71e72c9eSCy Schubert {
21*71e72c9eSCy Schubert return c >= 'A' && c <= 'Z';
22*71e72c9eSCy Schubert }
23*71e72c9eSCy Schubert
24*71e72c9eSCy Schubert
pr_device_free(struct pr_data * pr,struct pr_device * dev)25*71e72c9eSCy Schubert static void pr_device_free(struct pr_data *pr, struct pr_device *dev)
26*71e72c9eSCy Schubert {
27*71e72c9eSCy Schubert #ifdef CONFIG_PASN
28*71e72c9eSCy Schubert wpabuf_free(dev->ranging_wrapper);
29*71e72c9eSCy Schubert if (dev->pasn) {
30*71e72c9eSCy Schubert wpa_pasn_reset(dev->pasn);
31*71e72c9eSCy Schubert pasn_data_deinit(dev->pasn);
32*71e72c9eSCy Schubert }
33*71e72c9eSCy Schubert #endif /* CONFIG_PASN */
34*71e72c9eSCy Schubert os_free(dev);
35*71e72c9eSCy Schubert }
36*71e72c9eSCy Schubert
37*71e72c9eSCy Schubert
pr_get_device(struct pr_data * pr,const u8 * addr)38*71e72c9eSCy Schubert static struct pr_device * pr_get_device(struct pr_data *pr, const u8 *addr)
39*71e72c9eSCy Schubert {
40*71e72c9eSCy Schubert struct pr_device *dev;
41*71e72c9eSCy Schubert
42*71e72c9eSCy Schubert dl_list_for_each(dev, &pr->devices, struct pr_device, list) {
43*71e72c9eSCy Schubert if (ether_addr_equal(dev->pr_device_addr, addr))
44*71e72c9eSCy Schubert return dev;
45*71e72c9eSCy Schubert }
46*71e72c9eSCy Schubert return NULL;
47*71e72c9eSCy Schubert }
48*71e72c9eSCy Schubert
49*71e72c9eSCy Schubert
pr_create_device(struct pr_data * pr,const u8 * addr)50*71e72c9eSCy Schubert static struct pr_device * pr_create_device(struct pr_data *pr, const u8 *addr)
51*71e72c9eSCy Schubert {
52*71e72c9eSCy Schubert struct pr_device *dev, *oldest = NULL;
53*71e72c9eSCy Schubert size_t count = 0;
54*71e72c9eSCy Schubert
55*71e72c9eSCy Schubert dev = pr_get_device(pr, addr);
56*71e72c9eSCy Schubert if (dev)
57*71e72c9eSCy Schubert return dev;
58*71e72c9eSCy Schubert
59*71e72c9eSCy Schubert dl_list_for_each(dev, &pr->devices, struct pr_device, list) {
60*71e72c9eSCy Schubert count++;
61*71e72c9eSCy Schubert if (!oldest ||
62*71e72c9eSCy Schubert os_reltime_before(&dev->last_seen, &oldest->last_seen))
63*71e72c9eSCy Schubert oldest = dev;
64*71e72c9eSCy Schubert }
65*71e72c9eSCy Schubert if (count + 1 > PR_MAX_PEER && oldest) {
66*71e72c9eSCy Schubert wpa_printf(MSG_DEBUG,
67*71e72c9eSCy Schubert "PR: Remove oldest peer entry to make room for a new peer "
68*71e72c9eSCy Schubert MACSTR, MAC2STR(oldest->pr_device_addr));
69*71e72c9eSCy Schubert dl_list_del(&oldest->list);
70*71e72c9eSCy Schubert pr_device_free(pr, oldest);
71*71e72c9eSCy Schubert }
72*71e72c9eSCy Schubert
73*71e72c9eSCy Schubert dev = os_zalloc(sizeof(*dev));
74*71e72c9eSCy Schubert if (!dev)
75*71e72c9eSCy Schubert return NULL;
76*71e72c9eSCy Schubert
77*71e72c9eSCy Schubert dl_list_add(&pr->devices, &dev->list);
78*71e72c9eSCy Schubert os_memcpy(dev->pr_device_addr, addr, ETH_ALEN);
79*71e72c9eSCy Schubert wpa_printf(MSG_DEBUG, "PR: New Proximity Ranging device " MACSTR
80*71e72c9eSCy Schubert " added to list", MAC2STR(addr));
81*71e72c9eSCy Schubert
82*71e72c9eSCy Schubert return dev;
83*71e72c9eSCy Schubert }
84*71e72c9eSCy Schubert
85*71e72c9eSCy Schubert
pr_init(const struct pr_config * cfg)86*71e72c9eSCy Schubert struct pr_data * pr_init(const struct pr_config *cfg)
87*71e72c9eSCy Schubert {
88*71e72c9eSCy Schubert struct pr_data *pr;
89*71e72c9eSCy Schubert
90*71e72c9eSCy Schubert pr = os_zalloc(sizeof(*pr) + sizeof(*cfg));
91*71e72c9eSCy Schubert if (!pr)
92*71e72c9eSCy Schubert return NULL;
93*71e72c9eSCy Schubert
94*71e72c9eSCy Schubert pr->cfg = (struct pr_config *) (pr + 1);
95*71e72c9eSCy Schubert os_memcpy(pr->cfg, cfg, sizeof(*cfg));
96*71e72c9eSCy Schubert if (cfg->dev_name)
97*71e72c9eSCy Schubert pr->cfg->dev_name = os_strdup(cfg->dev_name);
98*71e72c9eSCy Schubert else
99*71e72c9eSCy Schubert pr->cfg->dev_name = NULL;
100*71e72c9eSCy Schubert
101*71e72c9eSCy Schubert dl_list_init(&pr->devices);
102*71e72c9eSCy Schubert dl_list_init(&pr->dev_iks);
103*71e72c9eSCy Schubert
104*71e72c9eSCy Schubert #ifdef CONFIG_PASN
105*71e72c9eSCy Schubert pr->initiator_pmksa = pasn_initiator_pmksa_cache_init();
106*71e72c9eSCy Schubert pr->responder_pmksa = pasn_responder_pmksa_cache_init();
107*71e72c9eSCy Schubert #endif /* CONFIG_PASN */
108*71e72c9eSCy Schubert
109*71e72c9eSCy Schubert return pr;
110*71e72c9eSCy Schubert }
111*71e72c9eSCy Schubert
112*71e72c9eSCy Schubert
pr_deinit_dev_iks(struct pr_data * pr)113*71e72c9eSCy Schubert static void pr_deinit_dev_iks(struct pr_data *pr)
114*71e72c9eSCy Schubert {
115*71e72c9eSCy Schubert struct pr_dev_ik *dev_ik, *prev_dev_ik;
116*71e72c9eSCy Schubert
117*71e72c9eSCy Schubert dl_list_for_each_safe(dev_ik, prev_dev_ik, &pr->dev_iks,
118*71e72c9eSCy Schubert struct pr_dev_ik, list) {
119*71e72c9eSCy Schubert dl_list_del(&dev_ik->list);
120*71e72c9eSCy Schubert os_free(dev_ik);
121*71e72c9eSCy Schubert }
122*71e72c9eSCy Schubert }
123*71e72c9eSCy Schubert
124*71e72c9eSCy Schubert
pr_flush(struct pr_data * pr)125*71e72c9eSCy Schubert void pr_flush(struct pr_data *pr)
126*71e72c9eSCy Schubert {
127*71e72c9eSCy Schubert #ifdef CONFIG_PASN
128*71e72c9eSCy Schubert if (pr->initiator_pmksa)
129*71e72c9eSCy Schubert pasn_initiator_pmksa_cache_flush(pr->initiator_pmksa);
130*71e72c9eSCy Schubert if (pr->responder_pmksa)
131*71e72c9eSCy Schubert pasn_responder_pmksa_cache_flush(pr->responder_pmksa);
132*71e72c9eSCy Schubert #endif /* CONFIG_PASN */
133*71e72c9eSCy Schubert }
134*71e72c9eSCy Schubert
pr_deinit(struct pr_data * pr)135*71e72c9eSCy Schubert void pr_deinit(struct pr_data *pr)
136*71e72c9eSCy Schubert {
137*71e72c9eSCy Schubert struct pr_device *dev, *prev;
138*71e72c9eSCy Schubert
139*71e72c9eSCy Schubert if (!pr)
140*71e72c9eSCy Schubert return;
141*71e72c9eSCy Schubert
142*71e72c9eSCy Schubert os_free(pr->cfg->dev_name);
143*71e72c9eSCy Schubert
144*71e72c9eSCy Schubert dl_list_for_each_safe(dev, prev, &pr->devices, struct pr_device, list) {
145*71e72c9eSCy Schubert dl_list_del(&dev->list);
146*71e72c9eSCy Schubert pr_device_free(pr, dev);
147*71e72c9eSCy Schubert }
148*71e72c9eSCy Schubert
149*71e72c9eSCy Schubert pr_deinit_dev_iks(pr);
150*71e72c9eSCy Schubert
151*71e72c9eSCy Schubert #ifdef CONFIG_PASN
152*71e72c9eSCy Schubert os_free(pr->pr_pasn_params);
153*71e72c9eSCy Schubert pr->pr_pasn_params = NULL;
154*71e72c9eSCy Schubert pr->ranging_final_received = false;
155*71e72c9eSCy Schubert
156*71e72c9eSCy Schubert pasn_initiator_pmksa_cache_deinit(pr->initiator_pmksa);
157*71e72c9eSCy Schubert pasn_responder_pmksa_cache_deinit(pr->responder_pmksa);
158*71e72c9eSCy Schubert #endif /* CONFIG_PASN */
159*71e72c9eSCy Schubert
160*71e72c9eSCy Schubert os_free(pr);
161*71e72c9eSCy Schubert wpa_printf(MSG_DEBUG, "PR: Deinit done");
162*71e72c9eSCy Schubert }
163*71e72c9eSCy Schubert
164*71e72c9eSCy Schubert
pr_set_dev_addr(struct pr_data * pr,const u8 * addr)165*71e72c9eSCy Schubert void pr_set_dev_addr(struct pr_data *pr, const u8 *addr)
166*71e72c9eSCy Schubert {
167*71e72c9eSCy Schubert if (pr && addr)
168*71e72c9eSCy Schubert os_memcpy(pr->cfg->dev_addr, addr, ETH_ALEN);
169*71e72c9eSCy Schubert }
170*71e72c9eSCy Schubert
171*71e72c9eSCy Schubert
pr_clear_dev_iks(struct pr_data * pr)172*71e72c9eSCy Schubert void pr_clear_dev_iks(struct pr_data *pr)
173*71e72c9eSCy Schubert {
174*71e72c9eSCy Schubert struct pr_device *dev;
175*71e72c9eSCy Schubert
176*71e72c9eSCy Schubert pr->cfg->dik_len = 0;
177*71e72c9eSCy Schubert os_memset(pr->cfg->dik_data, 0, DEVICE_IDENTITY_KEY_LEN);
178*71e72c9eSCy Schubert pr->cfg->global_password_valid = false;
179*71e72c9eSCy Schubert os_memset(pr->cfg->global_password, 0,
180*71e72c9eSCy Schubert sizeof(pr->cfg->global_password));
181*71e72c9eSCy Schubert
182*71e72c9eSCy Schubert dl_list_for_each(dev, &pr->devices, struct pr_device, list) {
183*71e72c9eSCy Schubert dev->password_valid = false;
184*71e72c9eSCy Schubert os_memset(dev->password, 0, sizeof(dev->password));
185*71e72c9eSCy Schubert dev->dik_valid = false;
186*71e72c9eSCy Schubert os_memset(dev->dik, 0, DEVICE_IDENTITY_KEY_LEN);
187*71e72c9eSCy Schubert }
188*71e72c9eSCy Schubert
189*71e72c9eSCy Schubert pr_deinit_dev_iks(pr);
190*71e72c9eSCy Schubert }
191*71e72c9eSCy Schubert
192*71e72c9eSCy Schubert
pr_add_dev_ik(struct pr_data * pr,const u8 * dik,const char * password,const u8 * pmk,size_t pmk_len,bool own)193*71e72c9eSCy Schubert void pr_add_dev_ik(struct pr_data *pr, const u8 *dik, const char *password,
194*71e72c9eSCy Schubert const u8 *pmk, size_t pmk_len, bool own)
195*71e72c9eSCy Schubert {
196*71e72c9eSCy Schubert struct pr_dev_ik *dev_ik;
197*71e72c9eSCy Schubert
198*71e72c9eSCy Schubert if (own) {
199*71e72c9eSCy Schubert os_memcpy(pr->cfg->dik_data, dik, DEVICE_IDENTITY_KEY_LEN);
200*71e72c9eSCy Schubert pr->cfg->dik_len = DEVICE_IDENTITY_KEY_LEN;
201*71e72c9eSCy Schubert if (password) {
202*71e72c9eSCy Schubert os_strlcpy(pr->cfg->global_password, password,
203*71e72c9eSCy Schubert sizeof(pr->cfg->global_password));
204*71e72c9eSCy Schubert pr->cfg->global_password_valid = true;
205*71e72c9eSCy Schubert }
206*71e72c9eSCy Schubert return;
207*71e72c9eSCy Schubert }
208*71e72c9eSCy Schubert
209*71e72c9eSCy Schubert if (pmk && (pmk_len != 32 && pmk_len != 48 && pmk_len != 64)) {
210*71e72c9eSCy Schubert wpa_printf(MSG_INFO, "PR: Unexpected PMK length %zu", pmk_len);
211*71e72c9eSCy Schubert return;
212*71e72c9eSCy Schubert }
213*71e72c9eSCy Schubert
214*71e72c9eSCy Schubert dl_list_for_each(dev_ik, &pr->dev_iks, struct pr_dev_ik, list) {
215*71e72c9eSCy Schubert if (os_memcmp(dik, dev_ik->dik, DEVICE_IDENTITY_KEY_LEN) == 0) {
216*71e72c9eSCy Schubert dl_list_del(&dev_ik->list);
217*71e72c9eSCy Schubert os_free(dev_ik);
218*71e72c9eSCy Schubert break;
219*71e72c9eSCy Schubert }
220*71e72c9eSCy Schubert }
221*71e72c9eSCy Schubert
222*71e72c9eSCy Schubert dev_ik = os_zalloc(sizeof(*dev_ik));
223*71e72c9eSCy Schubert if (!dev_ik)
224*71e72c9eSCy Schubert return;
225*71e72c9eSCy Schubert
226*71e72c9eSCy Schubert dl_list_add(&pr->dev_iks, &dev_ik->list);
227*71e72c9eSCy Schubert os_memcpy(dev_ik->dik, dik, DEVICE_IDENTITY_KEY_LEN);
228*71e72c9eSCy Schubert if (password) {
229*71e72c9eSCy Schubert os_strlcpy(dev_ik->password, password,
230*71e72c9eSCy Schubert sizeof(dev_ik->password));
231*71e72c9eSCy Schubert dev_ik->password_valid = true;
232*71e72c9eSCy Schubert }
233*71e72c9eSCy Schubert if (pmk) {
234*71e72c9eSCy Schubert os_memcpy(dev_ik->pmk, pmk, pmk_len);
235*71e72c9eSCy Schubert dev_ik->pmk_len = pmk_len;
236*71e72c9eSCy Schubert dev_ik->pmk_valid = true;
237*71e72c9eSCy Schubert }
238*71e72c9eSCy Schubert
239*71e72c9eSCy Schubert wpa_printf(MSG_DEBUG, "PR: New Device Identity added to list");
240*71e72c9eSCy Schubert }
241*71e72c9eSCy Schubert
242*71e72c9eSCy Schubert
pr_set_peer_credentials(struct pr_data * pr,const u8 * addr,const u8 * pmk,size_t pmk_len,const char * password)243*71e72c9eSCy Schubert int pr_set_peer_credentials(struct pr_data *pr, const u8 *addr,
244*71e72c9eSCy Schubert const u8 *pmk, size_t pmk_len,
245*71e72c9eSCy Schubert const char *password)
246*71e72c9eSCy Schubert {
247*71e72c9eSCy Schubert struct pr_device *dev;
248*71e72c9eSCy Schubert
249*71e72c9eSCy Schubert if (!pr || !addr)
250*71e72c9eSCy Schubert return -1;
251*71e72c9eSCy Schubert
252*71e72c9eSCy Schubert dev = pr_get_device(pr, addr);
253*71e72c9eSCy Schubert if (!dev) {
254*71e72c9eSCy Schubert wpa_printf(MSG_DEBUG, "PR: set_peer_credentials: " MACSTR
255*71e72c9eSCy Schubert " not found", MAC2STR(addr));
256*71e72c9eSCy Schubert return -1;
257*71e72c9eSCy Schubert }
258*71e72c9eSCy Schubert
259*71e72c9eSCy Schubert if (pmk && pmk_len) {
260*71e72c9eSCy Schubert if (pmk_len > PMK_LEN_MAX)
261*71e72c9eSCy Schubert return -1;
262*71e72c9eSCy Schubert os_memcpy(dev->pmk, pmk, pmk_len);
263*71e72c9eSCy Schubert dev->pmk_len = pmk_len;
264*71e72c9eSCy Schubert dev->pmk_valid = true;
265*71e72c9eSCy Schubert wpa_printf(MSG_DEBUG, "PR: PMK set for " MACSTR, MAC2STR(addr));
266*71e72c9eSCy Schubert }
267*71e72c9eSCy Schubert
268*71e72c9eSCy Schubert if (password) {
269*71e72c9eSCy Schubert if (os_strlen(password) >= sizeof(dev->password))
270*71e72c9eSCy Schubert return -1;
271*71e72c9eSCy Schubert os_strlcpy(dev->password, password, sizeof(dev->password));
272*71e72c9eSCy Schubert dev->password_valid = true;
273*71e72c9eSCy Schubert wpa_printf(MSG_DEBUG, "PR: password set for " MACSTR,
274*71e72c9eSCy Schubert MAC2STR(addr));
275*71e72c9eSCy Schubert }
276*71e72c9eSCy Schubert
277*71e72c9eSCy Schubert return 0;
278*71e72c9eSCy Schubert }
279*71e72c9eSCy Schubert
280*71e72c9eSCy Schubert
pr_encaps_elem(const struct wpabuf * subelems,u32 ie_type)281*71e72c9eSCy Schubert static struct wpabuf * pr_encaps_elem(const struct wpabuf *subelems,
282*71e72c9eSCy Schubert u32 ie_type)
283*71e72c9eSCy Schubert {
284*71e72c9eSCy Schubert struct wpabuf *ie = NULL;
285*71e72c9eSCy Schubert const u8 *pos, *end;
286*71e72c9eSCy Schubert size_t len = 0;
287*71e72c9eSCy Schubert
288*71e72c9eSCy Schubert if (!subelems)
289*71e72c9eSCy Schubert return NULL;
290*71e72c9eSCy Schubert
291*71e72c9eSCy Schubert len = wpabuf_len(subelems) + 1000;
292*71e72c9eSCy Schubert ie = wpabuf_alloc(len);
293*71e72c9eSCy Schubert if (!ie)
294*71e72c9eSCy Schubert return NULL;
295*71e72c9eSCy Schubert
296*71e72c9eSCy Schubert pos = wpabuf_head(subelems);
297*71e72c9eSCy Schubert end = pos + wpabuf_len(subelems);
298*71e72c9eSCy Schubert
299*71e72c9eSCy Schubert while (end > pos) {
300*71e72c9eSCy Schubert size_t frag_len = end - pos;
301*71e72c9eSCy Schubert
302*71e72c9eSCy Schubert if (frag_len > 251)
303*71e72c9eSCy Schubert frag_len = 251;
304*71e72c9eSCy Schubert wpabuf_put_u8(ie, WLAN_EID_VENDOR_SPECIFIC);
305*71e72c9eSCy Schubert wpabuf_put_u8(ie, 4 + frag_len);
306*71e72c9eSCy Schubert wpabuf_put_be32(ie, ie_type);
307*71e72c9eSCy Schubert wpabuf_put_data(ie, pos, frag_len);
308*71e72c9eSCy Schubert pos += frag_len;
309*71e72c9eSCy Schubert }
310*71e72c9eSCy Schubert return ie;
311*71e72c9eSCy Schubert }
312*71e72c9eSCy Schubert
313*71e72c9eSCy Schubert
pr_get_ranging_capabilities(struct pr_data * pr,struct pr_capabilities * capab)314*71e72c9eSCy Schubert static void pr_get_ranging_capabilities(struct pr_data *pr,
315*71e72c9eSCy Schubert struct pr_capabilities *capab)
316*71e72c9eSCy Schubert {
317*71e72c9eSCy Schubert os_memset(capab, 0, sizeof(struct pr_capabilities));
318*71e72c9eSCy Schubert
319*71e72c9eSCy Schubert if (pr->cfg->dev_name)
320*71e72c9eSCy Schubert os_strlcpy(capab->device_name, pr->cfg->dev_name,
321*71e72c9eSCy Schubert sizeof(capab->device_name));
322*71e72c9eSCy Schubert
323*71e72c9eSCy Schubert if (pr->cfg->edca_ista_support || pr->cfg->edca_rsta_support)
324*71e72c9eSCy Schubert capab->edca_support = true;
325*71e72c9eSCy Schubert
326*71e72c9eSCy Schubert if (pr->cfg->ntb_ista_support || pr->cfg->ntb_rsta_support)
327*71e72c9eSCy Schubert capab->ntb_support = true;
328*71e72c9eSCy Schubert
329*71e72c9eSCy Schubert capab->secure_he_ltf = pr->cfg->secure_he_ltf;
330*71e72c9eSCy Schubert capab->pasn_type = pr->cfg->pasn_type;
331*71e72c9eSCy Schubert capab->support_6ghz = pr->cfg->support_6ghz;
332*71e72c9eSCy Schubert }
333*71e72c9eSCy Schubert
334*71e72c9eSCy Schubert
pr_get_edca_capabilities(struct pr_data * pr,struct edca_capabilities * capab)335*71e72c9eSCy Schubert static void pr_get_edca_capabilities(struct pr_data *pr,
336*71e72c9eSCy Schubert struct edca_capabilities *capab)
337*71e72c9eSCy Schubert {
338*71e72c9eSCy Schubert u16 edca_hw_caps = 0;
339*71e72c9eSCy Schubert
340*71e72c9eSCy Schubert os_memset(capab, 0, sizeof(struct edca_capabilities));
341*71e72c9eSCy Schubert capab->ista_support = pr->cfg->edca_ista_support;
342*71e72c9eSCy Schubert capab->rsta_support = pr->cfg->edca_rsta_support;
343*71e72c9eSCy Schubert os_memcpy(capab->country, pr->cfg->country, 3);
344*71e72c9eSCy Schubert
345*71e72c9eSCy Schubert edca_hw_caps |= (pr->cfg->edca_format_and_bw & EDCA_FORMAT_AND_BW_MASK)
346*71e72c9eSCy Schubert << EDCA_FORMAT_AND_BW;
347*71e72c9eSCy Schubert edca_hw_caps |= (pr->cfg->max_tx_antenna & EDCA_MAX_TX_ANTENNA_MASK) <<
348*71e72c9eSCy Schubert EDCA_MAX_TX_ANTENNA;
349*71e72c9eSCy Schubert edca_hw_caps |= (pr->cfg->max_rx_antenna & EDCA_MAX_RX_ANTENNA_MASK) <<
350*71e72c9eSCy Schubert EDCA_MAX_RX_ANTENNA;
351*71e72c9eSCy Schubert
352*71e72c9eSCy Schubert capab->edca_hw_caps = edca_hw_caps;
353*71e72c9eSCy Schubert os_memcpy(&capab->channels, &pr->cfg->edca_channels,
354*71e72c9eSCy Schubert sizeof(struct pr_channels));
355*71e72c9eSCy Schubert }
356*71e72c9eSCy Schubert
357*71e72c9eSCy Schubert
pr_get_ntb_capabilities(struct pr_data * pr,struct ntb_capabilities * capab)358*71e72c9eSCy Schubert static void pr_get_ntb_capabilities(struct pr_data *pr,
359*71e72c9eSCy Schubert struct ntb_capabilities *capab)
360*71e72c9eSCy Schubert {
361*71e72c9eSCy Schubert u32 ntb_hw_caps = 0;
362*71e72c9eSCy Schubert
363*71e72c9eSCy Schubert os_memset(capab, 0, sizeof(struct ntb_capabilities));
364*71e72c9eSCy Schubert capab->ista_support = pr->cfg->ntb_ista_support;
365*71e72c9eSCy Schubert capab->rsta_support = pr->cfg->ntb_rsta_support;
366*71e72c9eSCy Schubert os_memcpy(capab->country, pr->cfg->country, 3);
367*71e72c9eSCy Schubert capab->secure_he_ltf = pr->cfg->secure_he_ltf;
368*71e72c9eSCy Schubert
369*71e72c9eSCy Schubert ntb_hw_caps |= (pr->cfg->ntb_format_and_bw & NTB_FORMAT_AND_BW_MASK) <<
370*71e72c9eSCy Schubert NTB_FORMAT_AND_BW;
371*71e72c9eSCy Schubert ntb_hw_caps |= (pr->cfg->max_tx_ltf_repetations &
372*71e72c9eSCy Schubert MAX_TX_LTF_REPETATIONS_MASK) << MAX_TX_LTF_REPETATIONS;
373*71e72c9eSCy Schubert ntb_hw_caps |= (pr->cfg->max_rx_ltf_repetations &
374*71e72c9eSCy Schubert MAX_RX_LTF_REPETATIONS_MASK) << MAX_RX_LTF_REPETATIONS;
375*71e72c9eSCy Schubert
376*71e72c9eSCy Schubert ntb_hw_caps |= (pr->cfg->max_rx_ltf_total & MAX_RX_LTF_TOTAL_MASK) <<
377*71e72c9eSCy Schubert MAX_RX_LTF_TOTAL;
378*71e72c9eSCy Schubert ntb_hw_caps |= (pr->cfg->max_tx_ltf_total & MAX_TX_LTF_TOTAL_MASK) <<
379*71e72c9eSCy Schubert MAX_TX_LTF_TOTAL;
380*71e72c9eSCy Schubert
381*71e72c9eSCy Schubert ntb_hw_caps |= (pr->cfg->max_rx_sts_le_80 & MAX_RX_STS_LE_80_MASK) <<
382*71e72c9eSCy Schubert MAX_RX_STS_LE_80;
383*71e72c9eSCy Schubert ntb_hw_caps |= (pr->cfg->max_rx_sts_gt_80 & MAX_RX_STS_GT_80_MASK) <<
384*71e72c9eSCy Schubert MAX_RX_STS_GT_80;
385*71e72c9eSCy Schubert
386*71e72c9eSCy Schubert ntb_hw_caps |= (pr->cfg->max_tx_sts_le_80 & MAX_TX_STS_LE_80_MASK) <<
387*71e72c9eSCy Schubert MAX_TX_STS_LE_80;
388*71e72c9eSCy Schubert ntb_hw_caps |= (pr->cfg->max_tx_sts_gt_80 & MAX_TX_STS_GT_80_MASK) <<
389*71e72c9eSCy Schubert MAX_TX_STS_GT_80;
390*71e72c9eSCy Schubert
391*71e72c9eSCy Schubert capab->ntb_hw_caps = ntb_hw_caps;
392*71e72c9eSCy Schubert os_memcpy(&capab->channels, &pr->cfg->ntb_channels,
393*71e72c9eSCy Schubert sizeof(struct pr_channels));
394*71e72c9eSCy Schubert }
395*71e72c9eSCy Schubert
396*71e72c9eSCy Schubert
pr_derive_dira(struct pr_data * pr,const u8 * src_addr,struct pr_dira * dira)397*71e72c9eSCy Schubert static int pr_derive_dira(struct pr_data *pr, const u8 *src_addr,
398*71e72c9eSCy Schubert struct pr_dira *dira)
399*71e72c9eSCy Schubert {
400*71e72c9eSCy Schubert u8 nonce[DEVICE_IDENTITY_NONCE_LEN];
401*71e72c9eSCy Schubert u8 tag[DEVICE_MAX_HASH_LEN];
402*71e72c9eSCy Schubert u8 data[DIR_STR_LEN + ETH_ALEN + DEVICE_IDENTITY_NONCE_LEN];
403*71e72c9eSCy Schubert
404*71e72c9eSCy Schubert if (pr->cfg->dik_cipher != DIRA_CIPHER_VERSION_128) {
405*71e72c9eSCy Schubert wpa_printf(MSG_INFO, "PR: Unsupported DIRA Cipher version %d",
406*71e72c9eSCy Schubert pr->cfg->dik_cipher);
407*71e72c9eSCy Schubert return -1;
408*71e72c9eSCy Schubert }
409*71e72c9eSCy Schubert
410*71e72c9eSCy Schubert if (pr->cfg->dik_len != DEVICE_IDENTITY_KEY_LEN) {
411*71e72c9eSCy Schubert wpa_printf(MSG_INFO, "PR: Invalid DIK length %zu",
412*71e72c9eSCy Schubert pr->cfg->dik_len);
413*71e72c9eSCy Schubert return -1;
414*71e72c9eSCy Schubert }
415*71e72c9eSCy Schubert
416*71e72c9eSCy Schubert os_memset(data, 0, sizeof(data));
417*71e72c9eSCy Schubert
418*71e72c9eSCy Schubert if (os_get_random(nonce, DEVICE_IDENTITY_NONCE_LEN) < 0) {
419*71e72c9eSCy Schubert wpa_printf(MSG_INFO, "PR: Failed to generate DIRA nonce");
420*71e72c9eSCy Schubert return -1;
421*71e72c9eSCy Schubert }
422*71e72c9eSCy Schubert
423*71e72c9eSCy Schubert /* Tag = Truncate-64(HMAC-SHA-256(DevIK, "DIR" || PR Device Address ||
424*71e72c9eSCy Schubert * Nonce))
425*71e72c9eSCy Schubert */
426*71e72c9eSCy Schubert os_memcpy(data, "DIR", DIR_STR_LEN);
427*71e72c9eSCy Schubert os_memcpy(&data[DIR_STR_LEN], src_addr, ETH_ALEN);
428*71e72c9eSCy Schubert os_memcpy(&data[DIR_STR_LEN + ETH_ALEN], nonce,
429*71e72c9eSCy Schubert DEVICE_IDENTITY_NONCE_LEN);
430*71e72c9eSCy Schubert
431*71e72c9eSCy Schubert if (hmac_sha256(pr->cfg->dik_data, pr->cfg->dik_len, data, sizeof(data),
432*71e72c9eSCy Schubert tag) < 0) {
433*71e72c9eSCy Schubert wpa_printf(MSG_ERROR, "PR: Could not derive DIRA tag");
434*71e72c9eSCy Schubert return -1;
435*71e72c9eSCy Schubert }
436*71e72c9eSCy Schubert
437*71e72c9eSCy Schubert os_memset(dira, 0, sizeof(struct pr_dira));
438*71e72c9eSCy Schubert dira->cipher_version = pr->cfg->dik_cipher;
439*71e72c9eSCy Schubert dira->nonce_len = DEVICE_IDENTITY_NONCE_LEN;
440*71e72c9eSCy Schubert os_memcpy(dira->nonce, nonce, DEVICE_IDENTITY_NONCE_LEN);
441*71e72c9eSCy Schubert dira->tag_len = DEVICE_IDENTITY_TAG_LEN;
442*71e72c9eSCy Schubert os_memcpy(dira->tag, tag, DEVICE_IDENTITY_TAG_LEN);
443*71e72c9eSCy Schubert
444*71e72c9eSCy Schubert wpa_hexdump_key(MSG_DEBUG, "PR: DIK", pr->cfg->dik_data,
445*71e72c9eSCy Schubert pr->cfg->dik_len);
446*71e72c9eSCy Schubert wpa_hexdump(MSG_DEBUG, "PR: DIRA-NONCE", dira->nonce, dira->nonce_len);
447*71e72c9eSCy Schubert wpa_hexdump(MSG_DEBUG, "PR: DIRA-TAG", dira->tag, dira->tag_len);
448*71e72c9eSCy Schubert
449*71e72c9eSCy Schubert return 0;
450*71e72c9eSCy Schubert }
451*71e72c9eSCy Schubert
452*71e72c9eSCy Schubert
pr_validate_dira(struct pr_data * pr,struct pr_device * dev,const u8 * dira,u16 dira_len)453*71e72c9eSCy Schubert static int pr_validate_dira(struct pr_data *pr, struct pr_device *dev,
454*71e72c9eSCy Schubert const u8 *dira, u16 dira_len)
455*71e72c9eSCy Schubert {
456*71e72c9eSCy Schubert int ret;
457*71e72c9eSCy Schubert size_t len[3];
458*71e72c9eSCy Schubert const u8 *addr[3];
459*71e72c9eSCy Schubert struct pr_dev_ik *dev_ik;
460*71e72c9eSCy Schubert u8 tag[DEVICE_MAX_HASH_LEN];
461*71e72c9eSCy Schubert const char *label = "DIR";
462*71e72c9eSCy Schubert const u8 *dira_nonce, *dira_tag;
463*71e72c9eSCy Schubert
464*71e72c9eSCy Schubert /* Reset DevIK state - set only if DIRA verification succeeds */
465*71e72c9eSCy Schubert os_memset(dev->dik, 0, DEVICE_IDENTITY_KEY_LEN);
466*71e72c9eSCy Schubert dev->dik_valid = false;
467*71e72c9eSCy Schubert
468*71e72c9eSCy Schubert if (dira_len < 1 + DEVICE_IDENTITY_NONCE_LEN + DEVICE_IDENTITY_TAG_LEN)
469*71e72c9eSCy Schubert {
470*71e72c9eSCy Schubert wpa_printf(MSG_DEBUG, "PR: Truncated DIRA (length %u)",
471*71e72c9eSCy Schubert dira_len);
472*71e72c9eSCy Schubert return -1;
473*71e72c9eSCy Schubert }
474*71e72c9eSCy Schubert
475*71e72c9eSCy Schubert /* Cipher Version */
476*71e72c9eSCy Schubert if (dira[0] != DIRA_CIPHER_VERSION_128) {
477*71e72c9eSCy Schubert wpa_printf(MSG_DEBUG, "PR: Unsupported DIRA cipher version %d",
478*71e72c9eSCy Schubert dira[0]);
479*71e72c9eSCy Schubert return -1;
480*71e72c9eSCy Schubert }
481*71e72c9eSCy Schubert
482*71e72c9eSCy Schubert /* Nonce */
483*71e72c9eSCy Schubert dira_nonce = &dira[1];
484*71e72c9eSCy Schubert
485*71e72c9eSCy Schubert /* Tag */
486*71e72c9eSCy Schubert dira_tag = &dira[1 + DEVICE_IDENTITY_NONCE_LEN];
487*71e72c9eSCy Schubert
488*71e72c9eSCy Schubert /* Tag = Truncate-64(HMAC-SHA-256(DevIK, "DIR" || Device Address ||
489*71e72c9eSCy Schubert * Nonce)) */
490*71e72c9eSCy Schubert addr[0] = (const u8 *) label;
491*71e72c9eSCy Schubert len[0] = DIR_STR_LEN;
492*71e72c9eSCy Schubert addr[1] = dev->pr_device_addr;
493*71e72c9eSCy Schubert len[1] = ETH_ALEN;
494*71e72c9eSCy Schubert addr[2] = dira_nonce;
495*71e72c9eSCy Schubert len[2] = DEVICE_IDENTITY_NONCE_LEN;
496*71e72c9eSCy Schubert
497*71e72c9eSCy Schubert dl_list_for_each(dev_ik, &pr->dev_iks, struct pr_dev_ik, list) {
498*71e72c9eSCy Schubert ret = hmac_sha256_vector(dev_ik->dik, DEVICE_IDENTITY_KEY_LEN,
499*71e72c9eSCy Schubert 3, addr, len, tag);
500*71e72c9eSCy Schubert if (ret < 0) {
501*71e72c9eSCy Schubert wpa_printf(MSG_INFO,
502*71e72c9eSCy Schubert "PR: Failed to derive DIRA Tag");
503*71e72c9eSCy Schubert return -1;
504*71e72c9eSCy Schubert }
505*71e72c9eSCy Schubert
506*71e72c9eSCy Schubert if (os_memcmp(tag, dira_tag, DEVICE_IDENTITY_TAG_LEN) == 0) {
507*71e72c9eSCy Schubert wpa_printf(MSG_DEBUG, "PR: DIRA Tag matched");
508*71e72c9eSCy Schubert if (dev_ik->password_valid) {
509*71e72c9eSCy Schubert os_strlcpy(dev->password, dev_ik->password,
510*71e72c9eSCy Schubert sizeof(dev->password));
511*71e72c9eSCy Schubert dev->password_valid = true;
512*71e72c9eSCy Schubert }
513*71e72c9eSCy Schubert if (dev_ik->pmk_valid) {
514*71e72c9eSCy Schubert os_memcpy(dev->pmk, dev_ik->pmk,
515*71e72c9eSCy Schubert dev_ik->pmk_len);
516*71e72c9eSCy Schubert dev->pmk_len = dev_ik->pmk_len;
517*71e72c9eSCy Schubert dev->pmk_valid = true;
518*71e72c9eSCy Schubert }
519*71e72c9eSCy Schubert os_memcpy(dev->dik, dev_ik->dik,
520*71e72c9eSCy Schubert DEVICE_IDENTITY_KEY_LEN);
521*71e72c9eSCy Schubert dev->dik_valid = true;
522*71e72c9eSCy Schubert return 0;
523*71e72c9eSCy Schubert }
524*71e72c9eSCy Schubert }
525*71e72c9eSCy Schubert
526*71e72c9eSCy Schubert return -1;
527*71e72c9eSCy Schubert }
528*71e72c9eSCy Schubert
529*71e72c9eSCy Schubert
530*71e72c9eSCy Schubert #ifdef CONFIG_PASN
531*71e72c9eSCy Schubert
pr_copy_channels(struct pr_channels * dst,const struct pr_channels * src,bool allow_6ghz)532*71e72c9eSCy Schubert static void pr_copy_channels(struct pr_channels *dst,
533*71e72c9eSCy Schubert const struct pr_channels *src, bool allow_6ghz)
534*71e72c9eSCy Schubert {
535*71e72c9eSCy Schubert size_t i, j;
536*71e72c9eSCy Schubert
537*71e72c9eSCy Schubert if (allow_6ghz) {
538*71e72c9eSCy Schubert os_memcpy(dst, src, sizeof(struct pr_channels));
539*71e72c9eSCy Schubert return;
540*71e72c9eSCy Schubert }
541*71e72c9eSCy Schubert
542*71e72c9eSCy Schubert for (i = 0, j = 0; i < src->op_classes; i++) {
543*71e72c9eSCy Schubert if (is_6ghz_op_class(src->op_class[i].op_class))
544*71e72c9eSCy Schubert continue;
545*71e72c9eSCy Schubert os_memcpy(&dst->op_class[j], &src->op_class[i],
546*71e72c9eSCy Schubert sizeof(struct pr_op_class));
547*71e72c9eSCy Schubert j++;
548*71e72c9eSCy Schubert }
549*71e72c9eSCy Schubert dst->op_classes = j;
550*71e72c9eSCy Schubert }
551*71e72c9eSCy Schubert
552*71e72c9eSCy Schubert
pr_op_class_intersect(const struct pr_op_class * a,const struct pr_op_class * b,struct pr_op_class * res)553*71e72c9eSCy Schubert static void pr_op_class_intersect(const struct pr_op_class *a,
554*71e72c9eSCy Schubert const struct pr_op_class *b,
555*71e72c9eSCy Schubert struct pr_op_class *res)
556*71e72c9eSCy Schubert {
557*71e72c9eSCy Schubert size_t i, j;
558*71e72c9eSCy Schubert
559*71e72c9eSCy Schubert res->op_class = a->op_class;
560*71e72c9eSCy Schubert for (i = 0; i < a->channels; i++) {
561*71e72c9eSCy Schubert for (j = 0; j < b->channels; j++) {
562*71e72c9eSCy Schubert if (a->channel[i] != b->channel[j])
563*71e72c9eSCy Schubert continue;
564*71e72c9eSCy Schubert res->channel[res->channels] = a->channel[i];
565*71e72c9eSCy Schubert res->channels++;
566*71e72c9eSCy Schubert if (res->channels == PR_MAX_OP_CLASS_CHANNELS)
567*71e72c9eSCy Schubert return;
568*71e72c9eSCy Schubert }
569*71e72c9eSCy Schubert }
570*71e72c9eSCy Schubert }
571*71e72c9eSCy Schubert
572*71e72c9eSCy Schubert
573*71e72c9eSCy Schubert /**
574*71e72c9eSCy Schubert * pr_channels_intersect - Intersection of supported channel lists
575*71e72c9eSCy Schubert * @a: First set of supported channels
576*71e72c9eSCy Schubert * @b: Second set of supported channels
577*71e72c9eSCy Schubert * @res: Data structure for returning the intersection of supported channels
578*71e72c9eSCy Schubert *
579*71e72c9eSCy Schubert * This function can be used to find a common set of supported channels. Both
580*71e72c9eSCy Schubert * input channel sets are assumed to use the global operating classes or the
581*71e72c9eSCy Schubert * same country code. If different country codes are used without using the
582*71e72c9eSCy Schubert * global operating classes, the operating class numbers may not be matched
583*71e72c9eSCy Schubert * correctly and results are undefined.
584*71e72c9eSCy Schubert */
pr_channels_intersect(const struct pr_channels * a,const struct pr_channels * b,struct pr_channels * res)585*71e72c9eSCy Schubert static void pr_channels_intersect(const struct pr_channels *a,
586*71e72c9eSCy Schubert const struct pr_channels *b,
587*71e72c9eSCy Schubert struct pr_channels *res)
588*71e72c9eSCy Schubert {
589*71e72c9eSCy Schubert size_t i, j;
590*71e72c9eSCy Schubert const struct pr_op_class *a_op;
591*71e72c9eSCy Schubert const struct pr_op_class *b_op;
592*71e72c9eSCy Schubert
593*71e72c9eSCy Schubert os_memset(res, 0, sizeof(*res));
594*71e72c9eSCy Schubert
595*71e72c9eSCy Schubert for (i = 0; i < a->op_classes; i++) {
596*71e72c9eSCy Schubert a_op = &a->op_class[i];
597*71e72c9eSCy Schubert for (j = 0; j < b->op_classes; j++) {
598*71e72c9eSCy Schubert b_op = &b->op_class[j];
599*71e72c9eSCy Schubert if (a_op->op_class != b_op->op_class)
600*71e72c9eSCy Schubert continue;
601*71e72c9eSCy Schubert pr_op_class_intersect(a_op, b_op,
602*71e72c9eSCy Schubert &res->op_class[res->op_classes]);
603*71e72c9eSCy Schubert if (res->op_class[res->op_classes].channels) {
604*71e72c9eSCy Schubert res->op_classes++;
605*71e72c9eSCy Schubert if (res->op_classes == PR_MAX_OP_CLASSES)
606*71e72c9eSCy Schubert return;
607*71e72c9eSCy Schubert }
608*71e72c9eSCy Schubert }
609*71e72c9eSCy Schubert }
610*71e72c9eSCy Schubert }
611*71e72c9eSCy Schubert
612*71e72c9eSCy Schubert #endif /* CONFIG_PASN */
613*71e72c9eSCy Schubert
614*71e72c9eSCy Schubert
pr_buf_add_channel_list(struct wpabuf * buf,const char * country,const struct pr_channels * chan)615*71e72c9eSCy Schubert static void pr_buf_add_channel_list(struct wpabuf *buf, const char *country,
616*71e72c9eSCy Schubert const struct pr_channels *chan)
617*71e72c9eSCy Schubert {
618*71e72c9eSCy Schubert size_t i;
619*71e72c9eSCy Schubert
620*71e72c9eSCy Schubert wpabuf_put_data(buf, country, 3); /* Country String */
621*71e72c9eSCy Schubert wpabuf_put_u8(buf, chan->op_classes); /* Number of Channel Entries */
622*71e72c9eSCy Schubert
623*71e72c9eSCy Schubert /* Channel Entry List */
624*71e72c9eSCy Schubert for (i = 0; i < chan->op_classes; i++) {
625*71e72c9eSCy Schubert const struct pr_op_class *c = &chan->op_class[i];
626*71e72c9eSCy Schubert
627*71e72c9eSCy Schubert wpabuf_put_u8(buf, c->op_class);
628*71e72c9eSCy Schubert wpabuf_put_u8(buf, c->channels);
629*71e72c9eSCy Schubert wpabuf_put_data(buf, c->channel, c->channels);
630*71e72c9eSCy Schubert }
631*71e72c9eSCy Schubert }
632*71e72c9eSCy Schubert
633*71e72c9eSCy Schubert
pr_buf_add_ranging_capa_info(struct wpabuf * buf,const struct pr_capabilities * capab)634*71e72c9eSCy Schubert static void pr_buf_add_ranging_capa_info(struct wpabuf *buf,
635*71e72c9eSCy Schubert const struct pr_capabilities *capab)
636*71e72c9eSCy Schubert {
637*71e72c9eSCy Schubert u8 *len;
638*71e72c9eSCy Schubert u8 capa_6g = 0;
639*71e72c9eSCy Schubert u8 protocol_type = 0;
640*71e72c9eSCy Schubert size_t _len;
641*71e72c9eSCy Schubert
642*71e72c9eSCy Schubert /* Proximity Ranging Capability Attribute */
643*71e72c9eSCy Schubert wpabuf_put_u8(buf, PR_ATTR_RANGING_CAPABILITY);
644*71e72c9eSCy Schubert len = wpabuf_put(buf, 2); /* Attribute length to be filled */
645*71e72c9eSCy Schubert
646*71e72c9eSCy Schubert /* Ranging Protocol Type */
647*71e72c9eSCy Schubert if (capab->edca_support)
648*71e72c9eSCy Schubert protocol_type |= PR_EDCA_BASED_RANGING;
649*71e72c9eSCy Schubert if (capab->ntb_support && capab->secure_he_ltf)
650*71e72c9eSCy Schubert protocol_type |= PR_NTB_SECURE_LTF_BASED_RANGING;
651*71e72c9eSCy Schubert if (capab->ntb_support)
652*71e72c9eSCy Schubert protocol_type |= PR_NTB_OPEN_BASED_RANGING;
653*71e72c9eSCy Schubert wpabuf_put_u8(buf, protocol_type);
654*71e72c9eSCy Schubert
655*71e72c9eSCy Schubert /* PASN Type */
656*71e72c9eSCy Schubert wpabuf_put_u8(buf, capab->pasn_type);
657*71e72c9eSCy Schubert
658*71e72c9eSCy Schubert /* 6GHz band */
659*71e72c9eSCy Schubert if (capab->support_6ghz)
660*71e72c9eSCy Schubert capa_6g |= BIT(0);
661*71e72c9eSCy Schubert
662*71e72c9eSCy Schubert wpabuf_put_u8(buf, capa_6g);
663*71e72c9eSCy Schubert
664*71e72c9eSCy Schubert /* Device Name */
665*71e72c9eSCy Schubert wpabuf_put_data(buf, capab->device_name, WPS_DEV_NAME_MAX_LEN);
666*71e72c9eSCy Schubert wpa_printf(MSG_DEBUG, "PR: Device name: %s", capab->device_name);
667*71e72c9eSCy Schubert
668*71e72c9eSCy Schubert _len = (u8 *) wpabuf_put(buf, 0) - len - 2;
669*71e72c9eSCy Schubert WPA_PUT_LE16(len, _len);
670*71e72c9eSCy Schubert wpa_hexdump(MSG_DEBUG, "PR: * Capability Attribute", len + 2, _len);
671*71e72c9eSCy Schubert }
672*71e72c9eSCy Schubert
673*71e72c9eSCy Schubert
pr_buf_add_edca_capa_info(struct wpabuf * buf,const struct edca_capabilities * edca_data)674*71e72c9eSCy Schubert static void pr_buf_add_edca_capa_info(struct wpabuf *buf,
675*71e72c9eSCy Schubert const struct edca_capabilities *edca_data)
676*71e72c9eSCy Schubert {
677*71e72c9eSCy Schubert u8 *len;
678*71e72c9eSCy Schubert u8 ranging_role = 0;
679*71e72c9eSCy Schubert size_t _len;
680*71e72c9eSCy Schubert
681*71e72c9eSCy Schubert /* Proximity Ranging EDCA Capability Attribute */
682*71e72c9eSCy Schubert wpabuf_put_u8(buf, PR_ATTR_EDCA_CAPABILITY);
683*71e72c9eSCy Schubert len = wpabuf_put(buf, 2); /* Attribute length to be filled */
684*71e72c9eSCy Schubert
685*71e72c9eSCy Schubert /* Ranging Role */
686*71e72c9eSCy Schubert if (edca_data->ista_support)
687*71e72c9eSCy Schubert ranging_role |= PR_ISTA_SUPPORT;
688*71e72c9eSCy Schubert if (edca_data->rsta_support)
689*71e72c9eSCy Schubert ranging_role |= PR_RSTA_SUPPORT;
690*71e72c9eSCy Schubert wpabuf_put_u8(buf, ranging_role);
691*71e72c9eSCy Schubert
692*71e72c9eSCy Schubert /* Ranging Parameters */
693*71e72c9eSCy Schubert wpabuf_put_le16(buf, edca_data->edca_hw_caps);
694*71e72c9eSCy Schubert
695*71e72c9eSCy Schubert pr_buf_add_channel_list(buf, edca_data->country, &edca_data->channels);
696*71e72c9eSCy Schubert
697*71e72c9eSCy Schubert _len = (u8 *) wpabuf_put(buf, 0) - len - 2;
698*71e72c9eSCy Schubert WPA_PUT_LE16(len, _len);
699*71e72c9eSCy Schubert wpa_hexdump(MSG_DEBUG, "PR: * EDCA Capability Attribute",
700*71e72c9eSCy Schubert len + 2, _len);
701*71e72c9eSCy Schubert }
702*71e72c9eSCy Schubert
703*71e72c9eSCy Schubert
pr_buf_add_ntb_capa_info(struct wpabuf * buf,const struct ntb_capabilities * ntb_data)704*71e72c9eSCy Schubert static void pr_buf_add_ntb_capa_info(struct wpabuf *buf,
705*71e72c9eSCy Schubert const struct ntb_capabilities *ntb_data)
706*71e72c9eSCy Schubert {
707*71e72c9eSCy Schubert u8 *len;
708*71e72c9eSCy Schubert u8 ranging_role = 0;
709*71e72c9eSCy Schubert size_t _len;
710*71e72c9eSCy Schubert
711*71e72c9eSCy Schubert /* Proximity Ranging 11az NTB Capability Attribute */
712*71e72c9eSCy Schubert wpabuf_put_u8(buf, PR_ATTR_NTB_CAPABILITY);
713*71e72c9eSCy Schubert len = wpabuf_put(buf, 2);
714*71e72c9eSCy Schubert
715*71e72c9eSCy Schubert /* Ranging Role */
716*71e72c9eSCy Schubert if (ntb_data->ista_support)
717*71e72c9eSCy Schubert ranging_role |= PR_ISTA_SUPPORT;
718*71e72c9eSCy Schubert if (ntb_data->rsta_support)
719*71e72c9eSCy Schubert ranging_role |= PR_RSTA_SUPPORT;
720*71e72c9eSCy Schubert wpabuf_put_u8(buf, ranging_role);
721*71e72c9eSCy Schubert
722*71e72c9eSCy Schubert /* Ranging Parameter */
723*71e72c9eSCy Schubert wpabuf_put_le32(buf, ntb_data->ntb_hw_caps);
724*71e72c9eSCy Schubert
725*71e72c9eSCy Schubert pr_buf_add_channel_list(buf, ntb_data->country, &ntb_data->channels);
726*71e72c9eSCy Schubert
727*71e72c9eSCy Schubert _len = (u8 *) wpabuf_put(buf, 0) - len - 2;
728*71e72c9eSCy Schubert WPA_PUT_LE16(len, _len);
729*71e72c9eSCy Schubert wpa_hexdump(MSG_DEBUG, "PR: * NTB Capability Attribute", len + 2, _len);
730*71e72c9eSCy Schubert }
731*71e72c9eSCy Schubert
732*71e72c9eSCy Schubert
pr_buf_add_dira(struct wpabuf * buf,const struct pr_dira * dira)733*71e72c9eSCy Schubert static void pr_buf_add_dira(struct wpabuf *buf, const struct pr_dira *dira)
734*71e72c9eSCy Schubert {
735*71e72c9eSCy Schubert u8 *len;
736*71e72c9eSCy Schubert size_t _len;
737*71e72c9eSCy Schubert
738*71e72c9eSCy Schubert /* Proximity Ranging Device Identity Resolution attribute */
739*71e72c9eSCy Schubert wpabuf_put_u8(buf, PR_ATTR_DEVICE_IDENTITY_RESOLUTION);
740*71e72c9eSCy Schubert
741*71e72c9eSCy Schubert /* Length to be filled */
742*71e72c9eSCy Schubert len = wpabuf_put(buf, 2);
743*71e72c9eSCy Schubert
744*71e72c9eSCy Schubert wpabuf_put_u8(buf, dira->cipher_version);
745*71e72c9eSCy Schubert wpabuf_put_data(buf, dira->nonce, dira->nonce_len);
746*71e72c9eSCy Schubert wpabuf_put_data(buf, dira->tag, dira->tag_len);
747*71e72c9eSCy Schubert
748*71e72c9eSCy Schubert /* Update attribute length */
749*71e72c9eSCy Schubert _len = (u8 *) wpabuf_put(buf, 0) - len - 2;
750*71e72c9eSCy Schubert WPA_PUT_LE16(len, _len);
751*71e72c9eSCy Schubert
752*71e72c9eSCy Schubert wpa_printf(MSG_DEBUG, "PR: * DIRA");
753*71e72c9eSCy Schubert }
754*71e72c9eSCy Schubert
755*71e72c9eSCy Schubert
pr_prepare_usd_elems(struct pr_data * pr,const u8 * src_addr)756*71e72c9eSCy Schubert struct wpabuf * pr_prepare_usd_elems(struct pr_data *pr, const u8 *src_addr)
757*71e72c9eSCy Schubert {
758*71e72c9eSCy Schubert u32 ie_type;
759*71e72c9eSCy Schubert struct wpabuf *buf, *buf2;
760*71e72c9eSCy Schubert struct pr_capabilities pr_caps;
761*71e72c9eSCy Schubert struct pr_dira dira;
762*71e72c9eSCy Schubert
763*71e72c9eSCy Schubert buf = wpabuf_alloc(1000);
764*71e72c9eSCy Schubert if (!buf)
765*71e72c9eSCy Schubert return NULL;
766*71e72c9eSCy Schubert
767*71e72c9eSCy Schubert pr_get_ranging_capabilities(pr, &pr_caps);
768*71e72c9eSCy Schubert pr_buf_add_ranging_capa_info(buf, &pr_caps);
769*71e72c9eSCy Schubert
770*71e72c9eSCy Schubert if (pr->cfg->edca_ista_support || pr->cfg->edca_rsta_support) {
771*71e72c9eSCy Schubert struct edca_capabilities edca_caps;
772*71e72c9eSCy Schubert
773*71e72c9eSCy Schubert pr_get_edca_capabilities(pr, &edca_caps);
774*71e72c9eSCy Schubert pr_buf_add_edca_capa_info(buf, &edca_caps);
775*71e72c9eSCy Schubert }
776*71e72c9eSCy Schubert
777*71e72c9eSCy Schubert if (pr->cfg->ntb_ista_support || pr->cfg->ntb_rsta_support) {
778*71e72c9eSCy Schubert struct ntb_capabilities ntb_caps;
779*71e72c9eSCy Schubert
780*71e72c9eSCy Schubert pr_get_ntb_capabilities(pr, &ntb_caps);
781*71e72c9eSCy Schubert pr_buf_add_ntb_capa_info(buf, &ntb_caps);
782*71e72c9eSCy Schubert }
783*71e72c9eSCy Schubert
784*71e72c9eSCy Schubert if (!pr_derive_dira(pr, src_addr, &dira))
785*71e72c9eSCy Schubert pr_buf_add_dira(buf, &dira);
786*71e72c9eSCy Schubert
787*71e72c9eSCy Schubert ie_type = (OUI_WFA << 8) | PR_OUI_TYPE;
788*71e72c9eSCy Schubert buf2 = pr_encaps_elem(buf, ie_type);
789*71e72c9eSCy Schubert wpabuf_free(buf);
790*71e72c9eSCy Schubert
791*71e72c9eSCy Schubert return buf2;
792*71e72c9eSCy Schubert }
793*71e72c9eSCy Schubert
794*71e72c9eSCy Schubert
pr_parse_attribute(u8 id,const u8 * data,u16 len,struct pr_message * msg)795*71e72c9eSCy Schubert static int pr_parse_attribute(u8 id, const u8 *data, u16 len,
796*71e72c9eSCy Schubert struct pr_message *msg)
797*71e72c9eSCy Schubert {
798*71e72c9eSCy Schubert switch (id) {
799*71e72c9eSCy Schubert case PR_ATTR_STATUS:
800*71e72c9eSCy Schubert if (len < 1) {
801*71e72c9eSCy Schubert wpa_printf(MSG_INFO,
802*71e72c9eSCy Schubert "PR: Invalid Proximity Ranging Status Attribute (length %d)",
803*71e72c9eSCy Schubert len);
804*71e72c9eSCy Schubert return -1;
805*71e72c9eSCy Schubert }
806*71e72c9eSCy Schubert msg->status_ie = data;
807*71e72c9eSCy Schubert msg->status_ie_len = len;
808*71e72c9eSCy Schubert wpa_printf(MSG_DEBUG, "PR: Status Code %u", data[0]);
809*71e72c9eSCy Schubert break;
810*71e72c9eSCy Schubert case PR_ATTR_RANGING_CAPABILITY:
811*71e72c9eSCy Schubert if (len < 35) {
812*71e72c9eSCy Schubert wpa_printf(MSG_INFO,
813*71e72c9eSCy Schubert "PR: Too short Proximity Ranging Capability Attribute (length %d)",
814*71e72c9eSCy Schubert len);
815*71e72c9eSCy Schubert return -1;
816*71e72c9eSCy Schubert }
817*71e72c9eSCy Schubert msg->pr_capability = data;
818*71e72c9eSCy Schubert msg->pr_capability_len = len;
819*71e72c9eSCy Schubert wpa_printf(MSG_DEBUG,
820*71e72c9eSCy Schubert "PR: Ranging Protocol Type: %02x PASN Type: %02x",
821*71e72c9eSCy Schubert data[0], data[1]);
822*71e72c9eSCy Schubert break;
823*71e72c9eSCy Schubert case PR_ATTR_EDCA_CAPABILITY:
824*71e72c9eSCy Schubert if (len < 10) {
825*71e72c9eSCy Schubert wpa_printf(MSG_INFO,
826*71e72c9eSCy Schubert "PR: Too short Proximity Ranging EDCA Capability Attribute (length %d)",
827*71e72c9eSCy Schubert len);
828*71e72c9eSCy Schubert return -1;
829*71e72c9eSCy Schubert }
830*71e72c9eSCy Schubert msg->edca_capability = data;
831*71e72c9eSCy Schubert msg->edca_capability_len = len;
832*71e72c9eSCy Schubert wpa_printf(MSG_DEBUG,
833*71e72c9eSCy Schubert "PR: EDCA Ranging Role %02x, Ranging Parameters %04x",
834*71e72c9eSCy Schubert data[0], WPA_GET_LE16(data + 1));
835*71e72c9eSCy Schubert break;
836*71e72c9eSCy Schubert case PR_ATTR_NTB_CAPABILITY:
837*71e72c9eSCy Schubert if (len < 12) {
838*71e72c9eSCy Schubert wpa_printf(MSG_INFO,
839*71e72c9eSCy Schubert "PR: Too short Proximity Ranging 11az NTB Capability Attribute (length %d)",
840*71e72c9eSCy Schubert len);
841*71e72c9eSCy Schubert return -1;
842*71e72c9eSCy Schubert }
843*71e72c9eSCy Schubert msg->ntb_capability = data;
844*71e72c9eSCy Schubert msg->ntb_capability_len = len;
845*71e72c9eSCy Schubert wpa_printf(MSG_DEBUG,
846*71e72c9eSCy Schubert "PR: NTB Ranging Role %02x, Ranging Parameter %04x",
847*71e72c9eSCy Schubert data[0], WPA_GET_LE32(data + 1));
848*71e72c9eSCy Schubert break;
849*71e72c9eSCy Schubert case PR_ATTR_OPERATION_MODE:
850*71e72c9eSCy Schubert if (len < 9) {
851*71e72c9eSCy Schubert wpa_printf(MSG_INFO,
852*71e72c9eSCy Schubert "PR: Invalid Proximity Ranging Operation Mode Attribute (length %d)",
853*71e72c9eSCy Schubert len);
854*71e72c9eSCy Schubert return -1;
855*71e72c9eSCy Schubert }
856*71e72c9eSCy Schubert msg->op_mode = data;
857*71e72c9eSCy Schubert msg->op_mode_len = len;
858*71e72c9eSCy Schubert break;
859*71e72c9eSCy Schubert case PR_ATTR_DEVICE_IDENTITY_RESOLUTION:
860*71e72c9eSCy Schubert if (len < 1 + DEVICE_IDENTITY_NONCE_LEN +
861*71e72c9eSCy Schubert DEVICE_IDENTITY_TAG_LEN) {
862*71e72c9eSCy Schubert wpa_printf(MSG_INFO, "PR: Too short DIRA (length %d)",
863*71e72c9eSCy Schubert len);
864*71e72c9eSCy Schubert return -1;
865*71e72c9eSCy Schubert }
866*71e72c9eSCy Schubert msg->dira = data;
867*71e72c9eSCy Schubert msg->dira_len = len;
868*71e72c9eSCy Schubert wpa_printf(MSG_DEBUG, "PR: DIRA cipher version %u", data[0]);
869*71e72c9eSCy Schubert break;
870*71e72c9eSCy Schubert default:
871*71e72c9eSCy Schubert wpa_printf(MSG_DEBUG,
872*71e72c9eSCy Schubert "PR: Skipped unknown attribute %d (length %d)",
873*71e72c9eSCy Schubert id, len);
874*71e72c9eSCy Schubert break;
875*71e72c9eSCy Schubert }
876*71e72c9eSCy Schubert
877*71e72c9eSCy Schubert return 0;
878*71e72c9eSCy Schubert }
879*71e72c9eSCy Schubert
880*71e72c9eSCy Schubert
881*71e72c9eSCy Schubert /**
882*71e72c9eSCy Schubert * pr_parse_proximity_ranging_element - Parse Proximity Ranging element
883*71e72c9eSCy Schubert * @buf: Concatenated PR element(s) payload
884*71e72c9eSCy Schubert * @msg: Buffer for returning parsed attributes
885*71e72c9eSCy Schubert * Returns: 0 on success, -1 on failure
886*71e72c9eSCy Schubert *
887*71e72c9eSCy Schubert * Note: The caller is responsible for clearing the msg data structure before
888*71e72c9eSCy Schubert * calling this function.
889*71e72c9eSCy Schubert */
pr_parse_proximity_ranging_element(const struct wpabuf * buf,struct pr_message * msg)890*71e72c9eSCy Schubert static int pr_parse_proximity_ranging_element(const struct wpabuf *buf,
891*71e72c9eSCy Schubert struct pr_message *msg)
892*71e72c9eSCy Schubert {
893*71e72c9eSCy Schubert const u8 *pos = wpabuf_head_u8(buf);
894*71e72c9eSCy Schubert const u8 *end = pos + wpabuf_len(buf);
895*71e72c9eSCy Schubert
896*71e72c9eSCy Schubert wpa_printf(MSG_DEBUG, "PR: Parsing Proximity Ranging element");
897*71e72c9eSCy Schubert
898*71e72c9eSCy Schubert while (pos < end) {
899*71e72c9eSCy Schubert u16 attr_len;
900*71e72c9eSCy Schubert u8 id;
901*71e72c9eSCy Schubert
902*71e72c9eSCy Schubert if (end - pos < 3) {
903*71e72c9eSCy Schubert wpa_printf(MSG_DEBUG, "PR: Invalid PR attribute");
904*71e72c9eSCy Schubert return -1;
905*71e72c9eSCy Schubert }
906*71e72c9eSCy Schubert id = *pos++;
907*71e72c9eSCy Schubert attr_len = WPA_GET_LE16(pos);
908*71e72c9eSCy Schubert pos += 2;
909*71e72c9eSCy Schubert wpa_printf(MSG_DEBUG, "PR: Attribute %d length %u",
910*71e72c9eSCy Schubert id, attr_len);
911*71e72c9eSCy Schubert if (attr_len > end - pos) {
912*71e72c9eSCy Schubert wpa_printf(MSG_DEBUG,
913*71e72c9eSCy Schubert "PR: Attribute underflow (len=%u left=%d)",
914*71e72c9eSCy Schubert attr_len, (int) (end - pos));
915*71e72c9eSCy Schubert wpa_hexdump(MSG_MSGDUMP, "PR: Data", pos, end - pos);
916*71e72c9eSCy Schubert return -1;
917*71e72c9eSCy Schubert }
918*71e72c9eSCy Schubert if (pr_parse_attribute(id, pos, attr_len, msg))
919*71e72c9eSCy Schubert return -1;
920*71e72c9eSCy Schubert pos += attr_len;
921*71e72c9eSCy Schubert }
922*71e72c9eSCy Schubert
923*71e72c9eSCy Schubert return 0;
924*71e72c9eSCy Schubert }
925*71e72c9eSCy Schubert
926*71e72c9eSCy Schubert
pr_parse_free(struct pr_message * msg)927*71e72c9eSCy Schubert static void pr_parse_free(struct pr_message *msg)
928*71e72c9eSCy Schubert {
929*71e72c9eSCy Schubert wpabuf_free(msg->pr_attributes);
930*71e72c9eSCy Schubert msg->pr_attributes = NULL;
931*71e72c9eSCy Schubert }
932*71e72c9eSCy Schubert
933*71e72c9eSCy Schubert
934*71e72c9eSCy Schubert /**
935*71e72c9eSCy Schubert * pr_parse_elements - Parse Proximity Ranging element(s)
936*71e72c9eSCy Schubert * @data: Elements from the message
937*71e72c9eSCy Schubert * @len: Length of data buffer in octets
938*71e72c9eSCy Schubert * @msg: Buffer for returning parsed attributes
939*71e72c9eSCy Schubert * Returns: 0 on success, -1 on failure
940*71e72c9eSCy Schubert *
941*71e72c9eSCy Schubert * Note: The caller is responsible for clearing the msg data structure before
942*71e72c9eSCy Schubert * calling this function.
943*71e72c9eSCy Schubert *
944*71e72c9eSCy Schubert * Note: The caller must free temporary memory allocations by calling
945*71e72c9eSCy Schubert * pr_parse_free() when the parsed data is not needed anymore.
946*71e72c9eSCy Schubert */
pr_parse_elements(const u8 * data,size_t len,struct pr_message * msg)947*71e72c9eSCy Schubert static int pr_parse_elements(const u8 *data, size_t len, struct pr_message *msg)
948*71e72c9eSCy Schubert {
949*71e72c9eSCy Schubert struct ieee802_11_elems elems;
950*71e72c9eSCy Schubert
951*71e72c9eSCy Schubert if (ieee802_11_parse_elems(data, len, &elems, true) == ParseFailed)
952*71e72c9eSCy Schubert return -1;
953*71e72c9eSCy Schubert
954*71e72c9eSCy Schubert msg->pr_attributes = ieee802_11_vendor_ie_concat(data, len,
955*71e72c9eSCy Schubert PR_IE_VENDOR_TYPE);
956*71e72c9eSCy Schubert if (msg->pr_attributes &&
957*71e72c9eSCy Schubert pr_parse_proximity_ranging_element(msg->pr_attributes, msg)) {
958*71e72c9eSCy Schubert wpa_printf(MSG_INFO,
959*71e72c9eSCy Schubert "PR: Failed to parse Proximity Ranging element data");
960*71e72c9eSCy Schubert if (msg->pr_attributes)
961*71e72c9eSCy Schubert wpa_hexdump_buf(MSG_MSGDUMP,
962*71e72c9eSCy Schubert "PR: Proximity Ranging element payload",
963*71e72c9eSCy Schubert msg->pr_attributes);
964*71e72c9eSCy Schubert pr_parse_free(msg);
965*71e72c9eSCy Schubert return -1;
966*71e72c9eSCy Schubert }
967*71e72c9eSCy Schubert return 0;
968*71e72c9eSCy Schubert }
969*71e72c9eSCy Schubert
970*71e72c9eSCy Schubert
pr_process_channels(const u8 * channel_list,size_t channel_list_len,struct pr_channels * ch)971*71e72c9eSCy Schubert static int pr_process_channels(const u8 *channel_list, size_t channel_list_len,
972*71e72c9eSCy Schubert struct pr_channels *ch)
973*71e72c9eSCy Schubert {
974*71e72c9eSCy Schubert u8 channels;
975*71e72c9eSCy Schubert const u8 *pos, *end;
976*71e72c9eSCy Schubert u8 op_class_count;
977*71e72c9eSCy Schubert
978*71e72c9eSCy Schubert if (channel_list_len < 1)
979*71e72c9eSCy Schubert return -1;
980*71e72c9eSCy Schubert
981*71e72c9eSCy Schubert pos = channel_list;
982*71e72c9eSCy Schubert end = channel_list + channel_list_len;
983*71e72c9eSCy Schubert
984*71e72c9eSCy Schubert /* Number of Channel Entries */
985*71e72c9eSCy Schubert /* Get total count of the operational classes */
986*71e72c9eSCy Schubert op_class_count = pos[0];
987*71e72c9eSCy Schubert wpa_printf(MSG_DEBUG, "PR: Total operational classes: %u",
988*71e72c9eSCy Schubert op_class_count);
989*71e72c9eSCy Schubert pos++;
990*71e72c9eSCy Schubert
991*71e72c9eSCy Schubert /* Channel Entry List */
992*71e72c9eSCy Schubert ch->op_classes = 0;
993*71e72c9eSCy Schubert while (end - pos > 2 && (ch->op_classes <= op_class_count)) {
994*71e72c9eSCy Schubert struct pr_op_class *cl = &ch->op_class[ch->op_classes];
995*71e72c9eSCy Schubert
996*71e72c9eSCy Schubert cl->op_class = *pos++; /* Operating Class */
997*71e72c9eSCy Schubert channels = *pos++; /* Number of Channels */
998*71e72c9eSCy Schubert
999*71e72c9eSCy Schubert /* Channel List */
1000*71e72c9eSCy Schubert if (channels > end - pos) {
1001*71e72c9eSCy Schubert wpa_printf(MSG_INFO,
1002*71e72c9eSCy Schubert "PR: Invalid channel list channel %d, size: %ld",
1003*71e72c9eSCy Schubert channels, end - pos);
1004*71e72c9eSCy Schubert return -1;
1005*71e72c9eSCy Schubert }
1006*71e72c9eSCy Schubert cl->channels = channels > PR_MAX_OP_CLASS_CHANNELS ?
1007*71e72c9eSCy Schubert PR_MAX_OP_CLASS_CHANNELS : channels;
1008*71e72c9eSCy Schubert os_memcpy(cl->channel, pos, cl->channels);
1009*71e72c9eSCy Schubert pos += channels;
1010*71e72c9eSCy Schubert ch->op_classes++;
1011*71e72c9eSCy Schubert if (ch->op_classes == PR_MAX_OP_CLASSES)
1012*71e72c9eSCy Schubert break;
1013*71e72c9eSCy Schubert }
1014*71e72c9eSCy Schubert
1015*71e72c9eSCy Schubert if (ch->op_classes != op_class_count &&
1016*71e72c9eSCy Schubert ch->op_classes < PR_MAX_OP_CLASSES) {
1017*71e72c9eSCy Schubert wpa_printf(MSG_INFO,
1018*71e72c9eSCy Schubert "PR: Channel list count mismatch %lu != %d",
1019*71e72c9eSCy Schubert ch->op_classes, op_class_count);
1020*71e72c9eSCy Schubert return -1;
1021*71e72c9eSCy Schubert }
1022*71e72c9eSCy Schubert
1023*71e72c9eSCy Schubert return 0;
1024*71e72c9eSCy Schubert }
1025*71e72c9eSCy Schubert
1026*71e72c9eSCy Schubert
pr_process_ranging_capabilities(const u8 * caps,size_t caps_len,struct pr_capabilities * pr_caps)1027*71e72c9eSCy Schubert static void pr_process_ranging_capabilities(const u8 *caps, size_t caps_len,
1028*71e72c9eSCy Schubert struct pr_capabilities *pr_caps)
1029*71e72c9eSCy Schubert {
1030*71e72c9eSCy Schubert const u8 *pos;
1031*71e72c9eSCy Schubert
1032*71e72c9eSCy Schubert if (!caps || caps_len < 3 + WPS_DEV_NAME_MAX_LEN) {
1033*71e72c9eSCy Schubert wpa_printf(MSG_INFO,
1034*71e72c9eSCy Schubert "PR: Invalid Proximity Ranging Capability Attribute");
1035*71e72c9eSCy Schubert return;
1036*71e72c9eSCy Schubert }
1037*71e72c9eSCy Schubert
1038*71e72c9eSCy Schubert pos = caps;
1039*71e72c9eSCy Schubert
1040*71e72c9eSCy Schubert /* Ranging Protocol Type */
1041*71e72c9eSCy Schubert if (*pos & PR_EDCA_BASED_RANGING)
1042*71e72c9eSCy Schubert pr_caps->edca_support = true;
1043*71e72c9eSCy Schubert if (*pos & PR_NTB_SECURE_LTF_BASED_RANGING) {
1044*71e72c9eSCy Schubert pr_caps->secure_he_ltf = true;
1045*71e72c9eSCy Schubert pr_caps->ntb_support = true;
1046*71e72c9eSCy Schubert }
1047*71e72c9eSCy Schubert if (*pos & PR_NTB_OPEN_BASED_RANGING)
1048*71e72c9eSCy Schubert pr_caps->ntb_support = true;
1049*71e72c9eSCy Schubert
1050*71e72c9eSCy Schubert pos++;
1051*71e72c9eSCy Schubert /* PASN Type */
1052*71e72c9eSCy Schubert pr_caps->pasn_type = *pos;
1053*71e72c9eSCy Schubert
1054*71e72c9eSCy Schubert pos++;
1055*71e72c9eSCy Schubert /* 6GHz band */
1056*71e72c9eSCy Schubert pr_caps->support_6ghz = *pos & BIT(0);
1057*71e72c9eSCy Schubert
1058*71e72c9eSCy Schubert pos++;
1059*71e72c9eSCy Schubert /* Device Name */
1060*71e72c9eSCy Schubert os_memset(pr_caps->device_name, 0, WPS_DEV_NAME_MAX_LEN + 1);
1061*71e72c9eSCy Schubert os_memcpy(pr_caps->device_name, pos, WPS_DEV_NAME_MAX_LEN);
1062*71e72c9eSCy Schubert
1063*71e72c9eSCy Schubert wpa_printf(MSG_DEBUG,
1064*71e72c9eSCy Schubert "PR: Device name=%s, edca capability=%x, ntb capability=%x, secure LTF capability=%u, 6GHz=%u",
1065*71e72c9eSCy Schubert pr_caps->device_name, pr_caps->edca_support,
1066*71e72c9eSCy Schubert pr_caps->ntb_support, pr_caps->secure_he_ltf,
1067*71e72c9eSCy Schubert pr_caps->support_6ghz);
1068*71e72c9eSCy Schubert }
1069*71e72c9eSCy Schubert
1070*71e72c9eSCy Schubert
pr_process_edca_capabilities(const u8 * caps,size_t caps_len,struct edca_capabilities * edca_caps)1071*71e72c9eSCy Schubert static void pr_process_edca_capabilities(const u8 *caps, size_t caps_len,
1072*71e72c9eSCy Schubert struct edca_capabilities *edca_caps)
1073*71e72c9eSCy Schubert {
1074*71e72c9eSCy Schubert const u8 *pos, *end;
1075*71e72c9eSCy Schubert
1076*71e72c9eSCy Schubert if (caps_len < 7)
1077*71e72c9eSCy Schubert return;
1078*71e72c9eSCy Schubert
1079*71e72c9eSCy Schubert pos = caps;
1080*71e72c9eSCy Schubert end = caps + caps_len;
1081*71e72c9eSCy Schubert
1082*71e72c9eSCy Schubert /* Ranging Role */
1083*71e72c9eSCy Schubert if (*pos & PR_ISTA_SUPPORT)
1084*71e72c9eSCy Schubert edca_caps->ista_support = true;
1085*71e72c9eSCy Schubert if (*pos & PR_RSTA_SUPPORT)
1086*71e72c9eSCy Schubert edca_caps->rsta_support = true;
1087*71e72c9eSCy Schubert pos++;
1088*71e72c9eSCy Schubert
1089*71e72c9eSCy Schubert /* Ranging Parameters */
1090*71e72c9eSCy Schubert edca_caps->edca_hw_caps = WPA_GET_LE16(pos);
1091*71e72c9eSCy Schubert pos += 2;
1092*71e72c9eSCy Schubert
1093*71e72c9eSCy Schubert /* Country String */
1094*71e72c9eSCy Schubert os_memcpy(edca_caps->country, pos, 3);
1095*71e72c9eSCy Schubert pos += 3;
1096*71e72c9eSCy Schubert
1097*71e72c9eSCy Schubert pr_process_channels(pos, end - pos, &edca_caps->channels);
1098*71e72c9eSCy Schubert
1099*71e72c9eSCy Schubert wpa_printf(MSG_DEBUG,
1100*71e72c9eSCy Schubert "PR: EDCA ISTA support=%u, EDCA RSTA support=%u, op classes count=%lu, country=%c%c",
1101*71e72c9eSCy Schubert edca_caps->ista_support, edca_caps->rsta_support,
1102*71e72c9eSCy Schubert edca_caps->channels.op_classes,
1103*71e72c9eSCy Schubert valid_country_ch(edca_caps->country[0]) ?
1104*71e72c9eSCy Schubert edca_caps->country[0] : '_',
1105*71e72c9eSCy Schubert valid_country_ch(edca_caps->country[1]) ?
1106*71e72c9eSCy Schubert edca_caps->country[1] : '_');
1107*71e72c9eSCy Schubert }
1108*71e72c9eSCy Schubert
1109*71e72c9eSCy Schubert
pr_process_ntb_capabilities(const u8 * caps,size_t caps_len,struct ntb_capabilities * ntb_caps,bool secure_ltf)1110*71e72c9eSCy Schubert static void pr_process_ntb_capabilities(const u8 *caps, size_t caps_len,
1111*71e72c9eSCy Schubert struct ntb_capabilities *ntb_caps,
1112*71e72c9eSCy Schubert bool secure_ltf)
1113*71e72c9eSCy Schubert {
1114*71e72c9eSCy Schubert const u8 *pos, *end;
1115*71e72c9eSCy Schubert
1116*71e72c9eSCy Schubert if (caps_len < 9)
1117*71e72c9eSCy Schubert return;
1118*71e72c9eSCy Schubert
1119*71e72c9eSCy Schubert pos = caps;
1120*71e72c9eSCy Schubert end = caps + caps_len;
1121*71e72c9eSCy Schubert
1122*71e72c9eSCy Schubert /* Ranging Role */
1123*71e72c9eSCy Schubert if (*pos & PR_ISTA_SUPPORT)
1124*71e72c9eSCy Schubert ntb_caps->ista_support = true;
1125*71e72c9eSCy Schubert if (*pos & PR_RSTA_SUPPORT)
1126*71e72c9eSCy Schubert ntb_caps->rsta_support = true;
1127*71e72c9eSCy Schubert if (secure_ltf)
1128*71e72c9eSCy Schubert ntb_caps->secure_he_ltf = true;
1129*71e72c9eSCy Schubert pos++;
1130*71e72c9eSCy Schubert
1131*71e72c9eSCy Schubert /* Ranging Parameter */
1132*71e72c9eSCy Schubert ntb_caps->ntb_hw_caps = WPA_GET_LE32(pos);
1133*71e72c9eSCy Schubert pos += 4;
1134*71e72c9eSCy Schubert
1135*71e72c9eSCy Schubert /* Country String */
1136*71e72c9eSCy Schubert os_memcpy(ntb_caps->country, pos, 3);
1137*71e72c9eSCy Schubert pos += 3;
1138*71e72c9eSCy Schubert
1139*71e72c9eSCy Schubert pr_process_channels(pos, end - pos, &ntb_caps->channels);
1140*71e72c9eSCy Schubert
1141*71e72c9eSCy Schubert wpa_printf(MSG_DEBUG,
1142*71e72c9eSCy Schubert "PR: NTB ISTA support=%u, NTB RSTA support=%u, op classes count=%lu, secure HE-LTF=%u, country=%c%c",
1143*71e72c9eSCy Schubert ntb_caps->ista_support, ntb_caps->rsta_support,
1144*71e72c9eSCy Schubert ntb_caps->channels.op_classes,
1145*71e72c9eSCy Schubert ntb_caps->secure_he_ltf,
1146*71e72c9eSCy Schubert valid_country_ch(ntb_caps->country[0]) ?
1147*71e72c9eSCy Schubert ntb_caps->country[0] : '_',
1148*71e72c9eSCy Schubert valid_country_ch(ntb_caps->country[1]) ?
1149*71e72c9eSCy Schubert ntb_caps->country[1] : '_');
1150*71e72c9eSCy Schubert }
1151*71e72c9eSCy Schubert
1152*71e72c9eSCy Schubert
pr_process_usd_elems(struct pr_data * pr,const u8 * ies,u16 ies_len,const u8 * peer_addr,unsigned int freq)1153*71e72c9eSCy Schubert void pr_process_usd_elems(struct pr_data *pr, const u8 *ies, u16 ies_len,
1154*71e72c9eSCy Schubert const u8 *peer_addr, unsigned int freq)
1155*71e72c9eSCy Schubert {
1156*71e72c9eSCy Schubert struct pr_device *dev;
1157*71e72c9eSCy Schubert struct pr_message msg;
1158*71e72c9eSCy Schubert
1159*71e72c9eSCy Schubert os_memset(&msg, 0, sizeof(msg));
1160*71e72c9eSCy Schubert os_memcpy(msg.pr_device_addr, peer_addr, ETH_ALEN);
1161*71e72c9eSCy Schubert
1162*71e72c9eSCy Schubert if (pr_parse_elements(ies, ies_len, &msg)) {
1163*71e72c9eSCy Schubert wpa_printf(MSG_INFO,
1164*71e72c9eSCy Schubert "PR: Failed to parse Proximity Ranging element(s)");
1165*71e72c9eSCy Schubert pr_parse_free(&msg);
1166*71e72c9eSCy Schubert return;
1167*71e72c9eSCy Schubert }
1168*71e72c9eSCy Schubert
1169*71e72c9eSCy Schubert if (!msg.pr_capability) {
1170*71e72c9eSCy Schubert wpa_printf(MSG_DEBUG,
1171*71e72c9eSCy Schubert "PR: Ranging caps not present, ignoring proximity device "
1172*71e72c9eSCy Schubert MACSTR, MAC2STR(peer_addr));
1173*71e72c9eSCy Schubert pr_parse_free(&msg);
1174*71e72c9eSCy Schubert return;
1175*71e72c9eSCy Schubert }
1176*71e72c9eSCy Schubert
1177*71e72c9eSCy Schubert if (!msg.edca_capability && !msg.ntb_capability) {
1178*71e72c9eSCy Schubert wpa_printf(MSG_DEBUG,
1179*71e72c9eSCy Schubert "PR: Neither EDCA nor NTB capabilities are present, ignoring proximity device "
1180*71e72c9eSCy Schubert MACSTR, MAC2STR(peer_addr));
1181*71e72c9eSCy Schubert pr_parse_free(&msg);
1182*71e72c9eSCy Schubert return;
1183*71e72c9eSCy Schubert }
1184*71e72c9eSCy Schubert
1185*71e72c9eSCy Schubert dev = pr_create_device(pr, peer_addr);
1186*71e72c9eSCy Schubert if (!dev) {
1187*71e72c9eSCy Schubert pr_parse_free(&msg);
1188*71e72c9eSCy Schubert wpa_printf(MSG_INFO, "PR: Failed to create a device");
1189*71e72c9eSCy Schubert return;
1190*71e72c9eSCy Schubert }
1191*71e72c9eSCy Schubert
1192*71e72c9eSCy Schubert os_get_reltime(&dev->last_seen);
1193*71e72c9eSCy Schubert dev->listen_freq = freq;
1194*71e72c9eSCy Schubert dev->discovery_type = PR_DISCOVERY_TYPE_USD;
1195*71e72c9eSCy Schubert
1196*71e72c9eSCy Schubert pr_process_ranging_capabilities(msg.pr_capability,
1197*71e72c9eSCy Schubert msg.pr_capability_len, &dev->pr_caps);
1198*71e72c9eSCy Schubert
1199*71e72c9eSCy Schubert if (dev->pr_caps.edca_support && msg.edca_capability)
1200*71e72c9eSCy Schubert pr_process_edca_capabilities(msg.edca_capability,
1201*71e72c9eSCy Schubert msg.edca_capability_len,
1202*71e72c9eSCy Schubert &dev->edca_caps);
1203*71e72c9eSCy Schubert
1204*71e72c9eSCy Schubert if (dev->pr_caps.ntb_support && msg.ntb_capability)
1205*71e72c9eSCy Schubert pr_process_ntb_capabilities(msg.ntb_capability,
1206*71e72c9eSCy Schubert msg.ntb_capability_len,
1207*71e72c9eSCy Schubert &dev->ntb_caps,
1208*71e72c9eSCy Schubert dev->pr_caps.secure_he_ltf);
1209*71e72c9eSCy Schubert
1210*71e72c9eSCy Schubert if (msg.dira && msg.dira_len)
1211*71e72c9eSCy Schubert pr_validate_dira(pr, dev, msg.dira, msg.dira_len);
1212*71e72c9eSCy Schubert
1213*71e72c9eSCy Schubert if (pr->cfg->device_found)
1214*71e72c9eSCy Schubert pr->cfg->device_found(pr->cfg->cb_ctx, dev);
1215*71e72c9eSCy Schubert
1216*71e72c9eSCy Schubert pr_parse_free(&msg);
1217*71e72c9eSCy Schubert }
1218*71e72c9eSCy Schubert
1219*71e72c9eSCy Schubert
1220*71e72c9eSCy Schubert /**
1221*71e72c9eSCy Schubert * pr_ensure_oob_peer - Add a minimal OOB peer entry if not already present
1222*71e72c9eSCy Schubert */
pr_ensure_oob_peer(struct pr_data * pr,const u8 * addr,int freq)1223*71e72c9eSCy Schubert int pr_ensure_oob_peer(struct pr_data *pr, const u8 *addr, int freq)
1224*71e72c9eSCy Schubert {
1225*71e72c9eSCy Schubert struct pr_device *dev;
1226*71e72c9eSCy Schubert
1227*71e72c9eSCy Schubert if (!pr || !addr)
1228*71e72c9eSCy Schubert return -1;
1229*71e72c9eSCy Schubert
1230*71e72c9eSCy Schubert dev = pr_get_device(pr, addr);
1231*71e72c9eSCy Schubert if (dev)
1232*71e72c9eSCy Schubert return 0;
1233*71e72c9eSCy Schubert
1234*71e72c9eSCy Schubert dev = pr_create_device(pr, addr);
1235*71e72c9eSCy Schubert if (!dev) {
1236*71e72c9eSCy Schubert wpa_printf(MSG_INFO, "PR: Failed to create OOB peer " MACSTR,
1237*71e72c9eSCy Schubert MAC2STR(addr));
1238*71e72c9eSCy Schubert return -1;
1239*71e72c9eSCy Schubert }
1240*71e72c9eSCy Schubert
1241*71e72c9eSCy Schubert dev->discovery_type = PR_DISCOVERY_TYPE_OOB;
1242*71e72c9eSCy Schubert if (freq)
1243*71e72c9eSCy Schubert dev->listen_freq = freq;
1244*71e72c9eSCy Schubert
1245*71e72c9eSCy Schubert wpa_printf(MSG_DEBUG, "PR: OOB peer " MACSTR " created at PASN_START",
1246*71e72c9eSCy Schubert MAC2STR(addr));
1247*71e72c9eSCy Schubert return 0;
1248*71e72c9eSCy Schubert }
1249*71e72c9eSCy Schubert
1250*71e72c9eSCy Schubert
1251*71e72c9eSCy Schubert #ifdef CONFIG_PASN
1252*71e72c9eSCy Schubert
pr_eq_ranging_capa_params(const struct pr_device * dev,const struct pr_capabilities * caps)1253*71e72c9eSCy Schubert static bool pr_eq_ranging_capa_params(const struct pr_device *dev,
1254*71e72c9eSCy Schubert const struct pr_capabilities *caps)
1255*71e72c9eSCy Schubert {
1256*71e72c9eSCy Schubert if (dev->discovery_type == PR_DISCOVERY_TYPE_OOB)
1257*71e72c9eSCy Schubert return true;
1258*71e72c9eSCy Schubert
1259*71e72c9eSCy Schubert return dev->pr_caps.edca_support == caps->edca_support &&
1260*71e72c9eSCy Schubert dev->pr_caps.ntb_support == caps->ntb_support &&
1261*71e72c9eSCy Schubert dev->pr_caps.pasn_type == caps->pasn_type &&
1262*71e72c9eSCy Schubert dev->pr_caps.secure_he_ltf == caps->secure_he_ltf &&
1263*71e72c9eSCy Schubert dev->pr_caps.support_6ghz == caps->support_6ghz &&
1264*71e72c9eSCy Schubert os_strcmp(dev->pr_caps.device_name, caps->device_name) == 0;
1265*71e72c9eSCy Schubert }
1266*71e72c9eSCy Schubert
1267*71e72c9eSCy Schubert
pr_eq_edca_params(const struct pr_device * dev,const struct edca_capabilities * edca_caps)1268*71e72c9eSCy Schubert static bool pr_eq_edca_params(const struct pr_device *dev,
1269*71e72c9eSCy Schubert const struct edca_capabilities *edca_caps)
1270*71e72c9eSCy Schubert {
1271*71e72c9eSCy Schubert if (dev->discovery_type == PR_DISCOVERY_TYPE_OOB)
1272*71e72c9eSCy Schubert return true;
1273*71e72c9eSCy Schubert
1274*71e72c9eSCy Schubert return dev->edca_caps.ista_support == edca_caps->ista_support &&
1275*71e72c9eSCy Schubert dev->edca_caps.rsta_support == edca_caps->rsta_support &&
1276*71e72c9eSCy Schubert dev->edca_caps.edca_hw_caps == edca_caps->edca_hw_caps &&
1277*71e72c9eSCy Schubert os_memcmp(dev->edca_caps.country, edca_caps->country, 3) == 0;
1278*71e72c9eSCy Schubert }
1279*71e72c9eSCy Schubert
1280*71e72c9eSCy Schubert
pr_eq_ntb_params(const struct pr_device * dev,const struct ntb_capabilities * ntb_caps)1281*71e72c9eSCy Schubert static bool pr_eq_ntb_params(const struct pr_device *dev,
1282*71e72c9eSCy Schubert const struct ntb_capabilities *ntb_caps)
1283*71e72c9eSCy Schubert {
1284*71e72c9eSCy Schubert if (dev->discovery_type == PR_DISCOVERY_TYPE_OOB)
1285*71e72c9eSCy Schubert return true;
1286*71e72c9eSCy Schubert
1287*71e72c9eSCy Schubert return dev->ntb_caps.ista_support == ntb_caps->ista_support &&
1288*71e72c9eSCy Schubert dev->ntb_caps.rsta_support == ntb_caps->rsta_support &&
1289*71e72c9eSCy Schubert dev->ntb_caps.ntb_hw_caps == ntb_caps->ntb_hw_caps &&
1290*71e72c9eSCy Schubert os_memcmp(dev->ntb_caps.country, ntb_caps->country, 3) == 0;
1291*71e72c9eSCy Schubert }
1292*71e72c9eSCy Schubert
1293*71e72c9eSCy Schubert
pr_buf_add_operation_mode(struct wpabuf * buf,struct operation_mode * mode)1294*71e72c9eSCy Schubert static void pr_buf_add_operation_mode(struct wpabuf *buf,
1295*71e72c9eSCy Schubert struct operation_mode *mode)
1296*71e72c9eSCy Schubert {
1297*71e72c9eSCy Schubert u8 *len;
1298*71e72c9eSCy Schubert size_t _len;
1299*71e72c9eSCy Schubert
1300*71e72c9eSCy Schubert /* Proximity Ranging Operation Mode Attribute */
1301*71e72c9eSCy Schubert wpabuf_put_u8(buf, PR_ATTR_OPERATION_MODE);
1302*71e72c9eSCy Schubert /* Length to be filled */
1303*71e72c9eSCy Schubert len = wpabuf_put(buf, 2);
1304*71e72c9eSCy Schubert
1305*71e72c9eSCy Schubert /* Ranging Protocol Type */
1306*71e72c9eSCy Schubert wpabuf_put_u8(buf, mode->protocol_type);
1307*71e72c9eSCy Schubert
1308*71e72c9eSCy Schubert /* Ranging Role */
1309*71e72c9eSCy Schubert wpabuf_put_u8(buf, mode->role);
1310*71e72c9eSCy Schubert
1311*71e72c9eSCy Schubert pr_buf_add_channel_list(buf, mode->country, &mode->channels);
1312*71e72c9eSCy Schubert
1313*71e72c9eSCy Schubert /* Update attribute length */
1314*71e72c9eSCy Schubert _len = (u8 *) wpabuf_put(buf, 0) - len - 2;
1315*71e72c9eSCy Schubert WPA_PUT_LE16(len, _len);
1316*71e72c9eSCy Schubert wpa_hexdump(MSG_DEBUG, "PR: * Operation Mode", len + 2, _len);
1317*71e72c9eSCy Schubert }
1318*71e72c9eSCy Schubert
1319*71e72c9eSCy Schubert
pr_buf_add_ranging_neg_status(struct wpabuf * buf,u8 status)1320*71e72c9eSCy Schubert static void pr_buf_add_ranging_neg_status(struct wpabuf *buf, u8 status)
1321*71e72c9eSCy Schubert {
1322*71e72c9eSCy Schubert /* Proximity Ranging Status Attribute */
1323*71e72c9eSCy Schubert wpabuf_put_u8(buf, PR_ATTR_STATUS);
1324*71e72c9eSCy Schubert wpabuf_put_le16(buf, 1);
1325*71e72c9eSCy Schubert wpabuf_put_u8(buf, status);
1326*71e72c9eSCy Schubert wpa_printf(MSG_DEBUG, "PR: * Role negotiation status %u", status);
1327*71e72c9eSCy Schubert }
1328*71e72c9eSCy Schubert
1329*71e72c9eSCy Schubert
pr_process_op_mode(const u8 * caps,size_t caps_len,struct operation_mode * op_mode)1330*71e72c9eSCy Schubert static void pr_process_op_mode(const u8 *caps, size_t caps_len,
1331*71e72c9eSCy Schubert struct operation_mode *op_mode)
1332*71e72c9eSCy Schubert {
1333*71e72c9eSCy Schubert const u8 *pos, *end;
1334*71e72c9eSCy Schubert
1335*71e72c9eSCy Schubert if (!caps || caps_len < 6)
1336*71e72c9eSCy Schubert return;
1337*71e72c9eSCy Schubert
1338*71e72c9eSCy Schubert pos = caps;
1339*71e72c9eSCy Schubert end = caps + caps_len;
1340*71e72c9eSCy Schubert
1341*71e72c9eSCy Schubert /* Ranging Protocol Type */
1342*71e72c9eSCy Schubert op_mode->protocol_type = *pos;
1343*71e72c9eSCy Schubert pos++;
1344*71e72c9eSCy Schubert
1345*71e72c9eSCy Schubert /* Ranging Role */
1346*71e72c9eSCy Schubert op_mode->role = *pos;
1347*71e72c9eSCy Schubert pos++;
1348*71e72c9eSCy Schubert
1349*71e72c9eSCy Schubert /* Country String */
1350*71e72c9eSCy Schubert os_memcpy(op_mode->country, pos, 3);
1351*71e72c9eSCy Schubert pos += 3;
1352*71e72c9eSCy Schubert
1353*71e72c9eSCy Schubert pr_process_channels(pos, end - pos, &op_mode->channels);
1354*71e72c9eSCy Schubert
1355*71e72c9eSCy Schubert wpa_printf(MSG_DEBUG,
1356*71e72c9eSCy Schubert "PR: protocol type=%u, role type=%u, country=%c%c, channel size=%lu",
1357*71e72c9eSCy Schubert op_mode->protocol_type, op_mode->role,
1358*71e72c9eSCy Schubert valid_country_ch(op_mode->country[0]) ?
1359*71e72c9eSCy Schubert op_mode->country[0] : '_',
1360*71e72c9eSCy Schubert valid_country_ch(op_mode->country[1]) ?
1361*71e72c9eSCy Schubert op_mode->country[1] : '_',
1362*71e72c9eSCy Schubert op_mode->channels.op_classes);
1363*71e72c9eSCy Schubert }
1364*71e72c9eSCy Schubert
1365*71e72c9eSCy Schubert
pr_choose_best_channel(struct pr_channels * common_channel,u8 * op_class,u8 * op_channel)1366*71e72c9eSCy Schubert static void pr_choose_best_channel(struct pr_channels *common_channel,
1367*71e72c9eSCy Schubert u8 *op_class, u8 *op_channel)
1368*71e72c9eSCy Schubert {
1369*71e72c9eSCy Schubert int bw;
1370*71e72c9eSCy Schubert int max_bw = 0;
1371*71e72c9eSCy Schubert const struct oper_class_map *map;
1372*71e72c9eSCy Schubert size_t i;
1373*71e72c9eSCy Schubert
1374*71e72c9eSCy Schubert if (!common_channel || !common_channel->op_classes ||
1375*71e72c9eSCy Schubert !common_channel->op_class[0].channels) {
1376*71e72c9eSCy Schubert wpa_printf(MSG_INFO,
1377*71e72c9eSCy Schubert "PR: Empty channel list, cannot get best channel");
1378*71e72c9eSCy Schubert *op_class = 0;
1379*71e72c9eSCy Schubert *op_channel = 0;
1380*71e72c9eSCy Schubert return;
1381*71e72c9eSCy Schubert }
1382*71e72c9eSCy Schubert
1383*71e72c9eSCy Schubert for (i = 0; i < common_channel->op_classes; i++) {
1384*71e72c9eSCy Schubert map = get_oper_class(NULL,
1385*71e72c9eSCy Schubert common_channel->op_class[i].op_class);
1386*71e72c9eSCy Schubert if (!map)
1387*71e72c9eSCy Schubert continue;
1388*71e72c9eSCy Schubert bw = oper_class_bw_to_int(map);
1389*71e72c9eSCy Schubert if (bw > max_bw) {
1390*71e72c9eSCy Schubert *op_class = common_channel->op_class[i].op_class;
1391*71e72c9eSCy Schubert *op_channel = common_channel->op_class[i].channel[0];
1392*71e72c9eSCy Schubert max_bw = bw;
1393*71e72c9eSCy Schubert }
1394*71e72c9eSCy Schubert }
1395*71e72c9eSCy Schubert
1396*71e72c9eSCy Schubert wpa_printf(MSG_DEBUG,
1397*71e72c9eSCy Schubert "PR: Choose the operating class: %u, operating channel: %u",
1398*71e72c9eSCy Schubert *op_class, *op_channel);
1399*71e72c9eSCy Schubert }
1400*71e72c9eSCy Schubert
1401*71e72c9eSCy Schubert
pr_pasn_get_best_op_mode(struct pr_data * pr,u8 peer_supp_roles,struct operation_mode * op_mode,struct operation_mode * res_op_mode)1402*71e72c9eSCy Schubert static u8 pr_pasn_get_best_op_mode(struct pr_data *pr, u8 peer_supp_roles,
1403*71e72c9eSCy Schubert struct operation_mode *op_mode,
1404*71e72c9eSCy Schubert struct operation_mode *res_op_mode)
1405*71e72c9eSCy Schubert {
1406*71e72c9eSCy Schubert u8 ranging_type = 0;
1407*71e72c9eSCy Schubert struct pr_channels common_chan;
1408*71e72c9eSCy Schubert struct pr_channels *own_channels = NULL;
1409*71e72c9eSCy Schubert int status = PR_NEGOTIATION_FAIL;
1410*71e72c9eSCy Schubert u8 op_class = 0, op_channel = 0;
1411*71e72c9eSCy Schubert bool own_ista_support = false, own_rsta_support = false;
1412*71e72c9eSCy Schubert
1413*71e72c9eSCy Schubert if (op_mode->protocol_type &
1414*71e72c9eSCy Schubert (PR_NTB_SECURE_LTF_BASED_RANGING | PR_NTB_OPEN_BASED_RANGING)) {
1415*71e72c9eSCy Schubert if (op_mode->protocol_type == PR_NTB_SECURE_LTF_BASED_RANGING &&
1416*71e72c9eSCy Schubert !pr->cfg->secure_he_ltf) {
1417*71e72c9eSCy Schubert wpa_printf(MSG_INFO,
1418*71e72c9eSCy Schubert "PR PASN: Secure HE-LTF not supported");
1419*71e72c9eSCy Schubert return PR_NEGOTIATION_FAIL;
1420*71e72c9eSCy Schubert }
1421*71e72c9eSCy Schubert
1422*71e72c9eSCy Schubert if ((op_mode->protocol_type &
1423*71e72c9eSCy Schubert PR_NTB_SECURE_LTF_BASED_RANGING) && pr->cfg->secure_he_ltf)
1424*71e72c9eSCy Schubert ranging_type = PR_NTB_SECURE_LTF_BASED_RANGING;
1425*71e72c9eSCy Schubert else
1426*71e72c9eSCy Schubert ranging_type = PR_NTB_OPEN_BASED_RANGING;
1427*71e72c9eSCy Schubert
1428*71e72c9eSCy Schubert own_ista_support = pr->cfg->ntb_ista_support;
1429*71e72c9eSCy Schubert own_rsta_support = pr->cfg->ntb_rsta_support;
1430*71e72c9eSCy Schubert own_channels = &pr->cfg->ntb_channels;
1431*71e72c9eSCy Schubert wpa_printf(MSG_DEBUG, "PR PASN: Choose NTB Ranging Protocol");
1432*71e72c9eSCy Schubert } else if (op_mode->protocol_type & PR_EDCA_BASED_RANGING) {
1433*71e72c9eSCy Schubert ranging_type = PR_EDCA_BASED_RANGING;
1434*71e72c9eSCy Schubert
1435*71e72c9eSCy Schubert own_ista_support = pr->cfg->edca_ista_support;
1436*71e72c9eSCy Schubert own_rsta_support = pr->cfg->edca_rsta_support;
1437*71e72c9eSCy Schubert own_channels = &pr->cfg->edca_channels;
1438*71e72c9eSCy Schubert wpa_printf(MSG_DEBUG, "PR PASN: Choose EDCA Ranging Protocol");
1439*71e72c9eSCy Schubert } else {
1440*71e72c9eSCy Schubert wpa_printf(MSG_DEBUG,
1441*71e72c9eSCy Schubert "PR PASN: Invalid Ranging Protocol, proposed type 0x%x",
1442*71e72c9eSCy Schubert op_mode->protocol_type);
1443*71e72c9eSCy Schubert return PR_NEGOTIATION_FAIL;
1444*71e72c9eSCy Schubert }
1445*71e72c9eSCy Schubert
1446*71e72c9eSCy Schubert if (!own_ista_support && !own_rsta_support) {
1447*71e72c9eSCy Schubert wpa_printf(MSG_DEBUG,
1448*71e72c9eSCy Schubert "PR PASN: Device can't fulfill any requested Ranging Role");
1449*71e72c9eSCy Schubert return PR_NEGOTIATION_FAIL;
1450*71e72c9eSCy Schubert }
1451*71e72c9eSCy Schubert
1452*71e72c9eSCy Schubert if (own_channels == NULL || !own_channels->op_classes) {
1453*71e72c9eSCy Schubert wpa_printf(MSG_DEBUG,
1454*71e72c9eSCy Schubert "PR PASN: Invalid or empty channel list to negotiate");
1455*71e72c9eSCy Schubert return PR_NEGOTIATION_FAIL;
1456*71e72c9eSCy Schubert }
1457*71e72c9eSCy Schubert
1458*71e72c9eSCy Schubert pr_channels_intersect(own_channels, &op_mode->channels, &common_chan);
1459*71e72c9eSCy Schubert if (!common_chan.op_classes) {
1460*71e72c9eSCy Schubert wpa_printf(MSG_DEBUG,
1461*71e72c9eSCy Schubert "PR PASN: No common channels to perform ranging");
1462*71e72c9eSCy Schubert return PR_NEGOTIATION_FAIL;
1463*71e72c9eSCy Schubert }
1464*71e72c9eSCy Schubert
1465*71e72c9eSCy Schubert if (op_mode->role == PR_ISTA_SUPPORT && !own_rsta_support &&
1466*71e72c9eSCy Schubert !(peer_supp_roles & PR_RSTA_SUPPORT)) {
1467*71e72c9eSCy Schubert wpa_printf(MSG_DEBUG,
1468*71e72c9eSCy Schubert "PR PASN: Device cannot act as RSTA and cannot update role");
1469*71e72c9eSCy Schubert return PR_NEGOTIATION_FAIL;
1470*71e72c9eSCy Schubert }
1471*71e72c9eSCy Schubert
1472*71e72c9eSCy Schubert if (op_mode->role == PR_RSTA_SUPPORT && !own_ista_support &&
1473*71e72c9eSCy Schubert !(peer_supp_roles & PR_ISTA_SUPPORT)) {
1474*71e72c9eSCy Schubert wpa_printf(MSG_DEBUG,
1475*71e72c9eSCy Schubert "PR PASN: Device cannot act as ISTA and cannot update role");
1476*71e72c9eSCy Schubert return PR_NEGOTIATION_FAIL;
1477*71e72c9eSCy Schubert }
1478*71e72c9eSCy Schubert
1479*71e72c9eSCy Schubert if (op_mode->role == PR_ISTA_SUPPORT && own_rsta_support) {
1480*71e72c9eSCy Schubert res_op_mode->role = PR_RSTA_SUPPORT;
1481*71e72c9eSCy Schubert status = PR_NEGOTIATION_SUCCESS;
1482*71e72c9eSCy Schubert } else if (op_mode->role == PR_RSTA_SUPPORT && own_ista_support) {
1483*71e72c9eSCy Schubert res_op_mode->role = PR_ISTA_SUPPORT;
1484*71e72c9eSCy Schubert status = PR_NEGOTIATION_SUCCESS;
1485*71e72c9eSCy Schubert } else if ((op_mode->role == PR_ISTA_SUPPORT && !own_rsta_support) &&
1486*71e72c9eSCy Schubert ((peer_supp_roles & PR_RSTA_SUPPORT) && own_ista_support)) {
1487*71e72c9eSCy Schubert res_op_mode->role = PR_ISTA_SUPPORT;
1488*71e72c9eSCy Schubert status = PR_NEGOTIATION_UPDATE;
1489*71e72c9eSCy Schubert } else if ((op_mode->role == PR_RSTA_SUPPORT && !own_ista_support) &&
1490*71e72c9eSCy Schubert ((peer_supp_roles & PR_ISTA_SUPPORT) && own_rsta_support)) {
1491*71e72c9eSCy Schubert res_op_mode->role = PR_RSTA_SUPPORT;
1492*71e72c9eSCy Schubert status = PR_NEGOTIATION_UPDATE;
1493*71e72c9eSCy Schubert } else if (op_mode->role == (PR_RSTA_SUPPORT | PR_ISTA_SUPPORT)) {
1494*71e72c9eSCy Schubert if ((pr->cfg->preferred_ranging_role || !own_ista_support) &&
1495*71e72c9eSCy Schubert own_rsta_support) {
1496*71e72c9eSCy Schubert res_op_mode->role = PR_RSTA_SUPPORT;
1497*71e72c9eSCy Schubert status = PR_NEGOTIATION_SUCCESS;
1498*71e72c9eSCy Schubert wpa_printf(MSG_DEBUG, "PR PASN: Choose RSTA role");
1499*71e72c9eSCy Schubert } else if ((!pr->cfg->preferred_ranging_role ||
1500*71e72c9eSCy Schubert !own_rsta_support) && own_ista_support) {
1501*71e72c9eSCy Schubert res_op_mode->role = PR_ISTA_SUPPORT;
1502*71e72c9eSCy Schubert status = PR_NEGOTIATION_SUCCESS;
1503*71e72c9eSCy Schubert wpa_printf(MSG_DEBUG, "PR PASN: Choose ISTA role");
1504*71e72c9eSCy Schubert }
1505*71e72c9eSCy Schubert } else {
1506*71e72c9eSCy Schubert wpa_printf(MSG_DEBUG, "PR PASN: Failed to choose device role");
1507*71e72c9eSCy Schubert return PR_NEGOTIATION_FAIL;
1508*71e72c9eSCy Schubert }
1509*71e72c9eSCy Schubert
1510*71e72c9eSCy Schubert res_op_mode->protocol_type = ranging_type;
1511*71e72c9eSCy Schubert os_memcpy(res_op_mode->country, pr->cfg->country, 3);
1512*71e72c9eSCy Schubert
1513*71e72c9eSCy Schubert if (res_op_mode->role == PR_RSTA_SUPPORT) {
1514*71e72c9eSCy Schubert pr_copy_channels(&res_op_mode->channels, &common_chan,
1515*71e72c9eSCy Schubert pr->cfg->support_6ghz);
1516*71e72c9eSCy Schubert } else {
1517*71e72c9eSCy Schubert pr_choose_best_channel(&common_chan, &op_class, &op_channel);
1518*71e72c9eSCy Schubert if (!op_class || !op_channel) {
1519*71e72c9eSCy Schubert wpa_printf(MSG_DEBUG,
1520*71e72c9eSCy Schubert "PR: Couldn't choose a common channel for ranging in ISTA role");
1521*71e72c9eSCy Schubert return PR_NEGOTIATION_FAIL;
1522*71e72c9eSCy Schubert }
1523*71e72c9eSCy Schubert res_op_mode->channels.op_classes = 1;
1524*71e72c9eSCy Schubert res_op_mode->channels.op_class[0].channels = 1;
1525*71e72c9eSCy Schubert res_op_mode->channels.op_class[0].channel[0] = op_channel;
1526*71e72c9eSCy Schubert res_op_mode->channels.op_class[0].op_class = op_class;
1527*71e72c9eSCy Schubert wpa_printf(MSG_DEBUG,
1528*71e72c9eSCy Schubert "PR: Choose operating class %u, channel %u",
1529*71e72c9eSCy Schubert op_class, op_channel);
1530*71e72c9eSCy Schubert }
1531*71e72c9eSCy Schubert
1532*71e72c9eSCy Schubert wpa_printf(MSG_DEBUG,
1533*71e72c9eSCy Schubert "PR PASN: Ranging Protocol=%u, Role=%u, country=%c%c, status=%d, op class size=%lu",
1534*71e72c9eSCy Schubert res_op_mode->protocol_type, res_op_mode->role,
1535*71e72c9eSCy Schubert valid_country_ch(res_op_mode->country[0]) ?
1536*71e72c9eSCy Schubert res_op_mode->country[0] : '_',
1537*71e72c9eSCy Schubert valid_country_ch(res_op_mode->country[1]) ?
1538*71e72c9eSCy Schubert res_op_mode->country[1] : '_',
1539*71e72c9eSCy Schubert status, res_op_mode->channels.op_classes);
1540*71e72c9eSCy Schubert
1541*71e72c9eSCy Schubert return status;
1542*71e72c9eSCy Schubert }
1543*71e72c9eSCy Schubert
1544*71e72c9eSCy Schubert
pr_pasn_get_final_op_mode(struct pr_data * pr,u8 supp_roles,struct operation_mode * op_mode,struct operation_mode * res_op_mode)1545*71e72c9eSCy Schubert static u8 pr_pasn_get_final_op_mode(struct pr_data *pr, u8 supp_roles,
1546*71e72c9eSCy Schubert struct operation_mode *op_mode,
1547*71e72c9eSCy Schubert struct operation_mode *res_op_mode)
1548*71e72c9eSCy Schubert {
1549*71e72c9eSCy Schubert u8 ranging_type = 0;
1550*71e72c9eSCy Schubert struct pr_channels common_chan;
1551*71e72c9eSCy Schubert struct pr_channels *own_channels = NULL;
1552*71e72c9eSCy Schubert int status = PR_NEGOTIATION_FAIL;
1553*71e72c9eSCy Schubert u8 op_class = 0, op_channel = 0;
1554*71e72c9eSCy Schubert bool own_ista_support = false, own_rsta_support = false;
1555*71e72c9eSCy Schubert
1556*71e72c9eSCy Schubert if (op_mode->protocol_type &
1557*71e72c9eSCy Schubert (PR_NTB_SECURE_LTF_BASED_RANGING | PR_NTB_OPEN_BASED_RANGING)) {
1558*71e72c9eSCy Schubert if (op_mode->protocol_type == PR_NTB_SECURE_LTF_BASED_RANGING &&
1559*71e72c9eSCy Schubert !pr->cfg->secure_he_ltf) {
1560*71e72c9eSCy Schubert wpa_printf(MSG_INFO,
1561*71e72c9eSCy Schubert "PR PASN: Secure HE-LTF not supported");
1562*71e72c9eSCy Schubert return PR_NEGOTIATION_FAIL;
1563*71e72c9eSCy Schubert }
1564*71e72c9eSCy Schubert
1565*71e72c9eSCy Schubert if ((op_mode->protocol_type &
1566*71e72c9eSCy Schubert PR_NTB_SECURE_LTF_BASED_RANGING) && pr->cfg->secure_he_ltf)
1567*71e72c9eSCy Schubert ranging_type = PR_NTB_SECURE_LTF_BASED_RANGING;
1568*71e72c9eSCy Schubert else
1569*71e72c9eSCy Schubert ranging_type = PR_NTB_OPEN_BASED_RANGING;
1570*71e72c9eSCy Schubert
1571*71e72c9eSCy Schubert own_ista_support = pr->cfg->ntb_ista_support;
1572*71e72c9eSCy Schubert own_rsta_support = pr->cfg->ntb_rsta_support;
1573*71e72c9eSCy Schubert own_channels = &pr->cfg->ntb_channels;
1574*71e72c9eSCy Schubert wpa_printf(MSG_DEBUG, "PR PASN: Choose NTB Ranging Protocol");
1575*71e72c9eSCy Schubert } else if (op_mode->protocol_type & PR_EDCA_BASED_RANGING) {
1576*71e72c9eSCy Schubert ranging_type = PR_EDCA_BASED_RANGING;
1577*71e72c9eSCy Schubert
1578*71e72c9eSCy Schubert own_ista_support = pr->cfg->edca_ista_support;
1579*71e72c9eSCy Schubert own_rsta_support = pr->cfg->edca_rsta_support;
1580*71e72c9eSCy Schubert own_channels = &pr->cfg->edca_channels;
1581*71e72c9eSCy Schubert wpa_printf(MSG_DEBUG, "PR PASN: Choose EDCA Ranging Protocol");
1582*71e72c9eSCy Schubert } else {
1583*71e72c9eSCy Schubert wpa_printf(MSG_INFO,
1584*71e72c9eSCy Schubert "PR PASN: Invalid Ranging Protocol, proposed type 0x%x",
1585*71e72c9eSCy Schubert op_mode->protocol_type);
1586*71e72c9eSCy Schubert return PR_NEGOTIATION_FAIL;
1587*71e72c9eSCy Schubert }
1588*71e72c9eSCy Schubert
1589*71e72c9eSCy Schubert if (op_mode->role == PR_ISTA_SUPPORT && !own_rsta_support) {
1590*71e72c9eSCy Schubert wpa_printf(MSG_INFO, "PR: Device cannot act as RSTA");
1591*71e72c9eSCy Schubert return PR_NEGOTIATION_FAIL;
1592*71e72c9eSCy Schubert }
1593*71e72c9eSCy Schubert
1594*71e72c9eSCy Schubert if (op_mode->role == PR_RSTA_SUPPORT && !own_ista_support) {
1595*71e72c9eSCy Schubert wpa_printf(MSG_INFO, "PR: Device cannot act as ISTA");
1596*71e72c9eSCy Schubert return PR_NEGOTIATION_FAIL;
1597*71e72c9eSCy Schubert }
1598*71e72c9eSCy Schubert
1599*71e72c9eSCy Schubert if (op_mode->role == PR_ISTA_SUPPORT) {
1600*71e72c9eSCy Schubert res_op_mode->role = PR_RSTA_SUPPORT;
1601*71e72c9eSCy Schubert status = PR_NEGOTIATION_SUCCESS;
1602*71e72c9eSCy Schubert } else if (op_mode->role == PR_RSTA_SUPPORT) {
1603*71e72c9eSCy Schubert res_op_mode->role = PR_ISTA_SUPPORT;
1604*71e72c9eSCy Schubert status = PR_NEGOTIATION_SUCCESS;
1605*71e72c9eSCy Schubert } else {
1606*71e72c9eSCy Schubert wpa_printf(MSG_INFO, "PR: Invalid Ranging Role proposed");
1607*71e72c9eSCy Schubert return PR_NEGOTIATION_FAIL;
1608*71e72c9eSCy Schubert }
1609*71e72c9eSCy Schubert
1610*71e72c9eSCy Schubert pr_channels_intersect(own_channels, &op_mode->channels, &common_chan);
1611*71e72c9eSCy Schubert if (!common_chan.op_classes) {
1612*71e72c9eSCy Schubert wpa_printf(MSG_INFO,
1613*71e72c9eSCy Schubert "PR: No common channels to perform ranging");
1614*71e72c9eSCy Schubert return PR_NEGOTIATION_FAIL;
1615*71e72c9eSCy Schubert }
1616*71e72c9eSCy Schubert
1617*71e72c9eSCy Schubert pr_choose_best_channel(&common_chan, &op_class, &op_channel);
1618*71e72c9eSCy Schubert if (!op_class || !op_channel) {
1619*71e72c9eSCy Schubert wpa_printf(MSG_INFO,
1620*71e72c9eSCy Schubert "PR: Couldn't choose a common channel for ranging");
1621*71e72c9eSCy Schubert return PR_NEGOTIATION_FAIL;
1622*71e72c9eSCy Schubert }
1623*71e72c9eSCy Schubert
1624*71e72c9eSCy Schubert res_op_mode->protocol_type = ranging_type;
1625*71e72c9eSCy Schubert os_memcpy(res_op_mode->country, pr->cfg->country, 3);
1626*71e72c9eSCy Schubert res_op_mode->channels.op_classes = 1;
1627*71e72c9eSCy Schubert res_op_mode->channels.op_class[0].channels = 1;
1628*71e72c9eSCy Schubert res_op_mode->channels.op_class[0].channel[0] = op_channel;
1629*71e72c9eSCy Schubert res_op_mode->channels.op_class[0].op_class = op_class;
1630*71e72c9eSCy Schubert wpa_printf(MSG_DEBUG, "PR: Choose operating class %u, channel %u",
1631*71e72c9eSCy Schubert op_class, op_channel);
1632*71e72c9eSCy Schubert
1633*71e72c9eSCy Schubert return status;
1634*71e72c9eSCy Schubert }
1635*71e72c9eSCy Schubert
1636*71e72c9eSCy Schubert
pr_prepare_pasn_pr_elem(struct pr_data * pr,struct wpabuf * extra_ies,bool add_dira,u8 ranging_role,u8 ranging_type,int forced_pr_freq)1637*71e72c9eSCy Schubert static int pr_prepare_pasn_pr_elem(struct pr_data *pr, struct wpabuf *extra_ies,
1638*71e72c9eSCy Schubert bool add_dira, u8 ranging_role,
1639*71e72c9eSCy Schubert u8 ranging_type, int forced_pr_freq)
1640*71e72c9eSCy Schubert {
1641*71e72c9eSCy Schubert u32 ie_type;
1642*71e72c9eSCy Schubert struct wpabuf *buf, *buf2;
1643*71e72c9eSCy Schubert struct pr_dira dira;
1644*71e72c9eSCy Schubert struct pr_capabilities pr_caps;
1645*71e72c9eSCy Schubert struct edca_capabilities edca_caps;
1646*71e72c9eSCy Schubert struct ntb_capabilities ntb_caps;
1647*71e72c9eSCy Schubert struct operation_mode op_mode;
1648*71e72c9eSCy Schubert struct pr_channels op_channels;
1649*71e72c9eSCy Schubert u8 forced_op_class = 0, forced_op_channel = 0;
1650*71e72c9eSCy Schubert enum hostapd_hw_mode hw_mode;
1651*71e72c9eSCy Schubert
1652*71e72c9eSCy Schubert buf = wpabuf_alloc(1000);
1653*71e72c9eSCy Schubert if (!buf)
1654*71e72c9eSCy Schubert return -1;
1655*71e72c9eSCy Schubert
1656*71e72c9eSCy Schubert pr_get_ranging_capabilities(pr, &pr_caps);
1657*71e72c9eSCy Schubert pr_buf_add_ranging_capa_info(buf, &pr_caps);
1658*71e72c9eSCy Schubert
1659*71e72c9eSCy Schubert if (ranging_type & PR_EDCA_BASED_RANGING) {
1660*71e72c9eSCy Schubert pr_get_edca_capabilities(pr, &edca_caps);
1661*71e72c9eSCy Schubert pr_buf_add_edca_capa_info(buf, &edca_caps);
1662*71e72c9eSCy Schubert pr_copy_channels(&op_channels, &edca_caps.channels,
1663*71e72c9eSCy Schubert pr->cfg->support_6ghz);
1664*71e72c9eSCy Schubert } else if (ranging_type & PR_NTB_OPEN_BASED_RANGING ||
1665*71e72c9eSCy Schubert ranging_type & PR_NTB_SECURE_LTF_BASED_RANGING) {
1666*71e72c9eSCy Schubert pr_get_ntb_capabilities(pr, &ntb_caps);
1667*71e72c9eSCy Schubert pr_buf_add_ntb_capa_info(buf, &ntb_caps);
1668*71e72c9eSCy Schubert pr_copy_channels(&op_channels, &ntb_caps.channels,
1669*71e72c9eSCy Schubert pr->cfg->support_6ghz);
1670*71e72c9eSCy Schubert } else {
1671*71e72c9eSCy Schubert wpa_printf(MSG_INFO, "PR: Unsupported ranging_type 0x%x",
1672*71e72c9eSCy Schubert ranging_type);
1673*71e72c9eSCy Schubert wpabuf_free(buf);
1674*71e72c9eSCy Schubert return -1;
1675*71e72c9eSCy Schubert }
1676*71e72c9eSCy Schubert
1677*71e72c9eSCy Schubert os_memset(&op_mode, 0, sizeof(struct operation_mode));
1678*71e72c9eSCy Schubert op_mode.role = ranging_role;
1679*71e72c9eSCy Schubert op_mode.protocol_type = ranging_type;
1680*71e72c9eSCy Schubert os_memcpy(op_mode.country, pr->cfg->country, 3);
1681*71e72c9eSCy Schubert
1682*71e72c9eSCy Schubert if (forced_pr_freq) {
1683*71e72c9eSCy Schubert hw_mode = ieee80211_freq_to_channel_ext(forced_pr_freq, 0, 0,
1684*71e72c9eSCy Schubert &forced_op_class,
1685*71e72c9eSCy Schubert &forced_op_channel);
1686*71e72c9eSCy Schubert if (hw_mode == NUM_HOSTAPD_MODES) {
1687*71e72c9eSCy Schubert wpa_printf(MSG_INFO, "PR: Invalid forced_pr_freq");
1688*71e72c9eSCy Schubert wpabuf_free(buf);
1689*71e72c9eSCy Schubert return -1;
1690*71e72c9eSCy Schubert }
1691*71e72c9eSCy Schubert
1692*71e72c9eSCy Schubert op_mode.channels.op_classes = 1;
1693*71e72c9eSCy Schubert op_mode.channels.op_class[0].channels = 1;
1694*71e72c9eSCy Schubert op_mode.channels.op_class[0].channel[0] = forced_op_channel;
1695*71e72c9eSCy Schubert op_mode.channels.op_class[0].op_class = forced_op_class;
1696*71e72c9eSCy Schubert } else {
1697*71e72c9eSCy Schubert pr_copy_channels(&op_mode.channels, &op_channels,
1698*71e72c9eSCy Schubert pr->cfg->support_6ghz);
1699*71e72c9eSCy Schubert }
1700*71e72c9eSCy Schubert
1701*71e72c9eSCy Schubert pr_buf_add_operation_mode(buf, &op_mode);
1702*71e72c9eSCy Schubert
1703*71e72c9eSCy Schubert /* PR Device Identity Resolution attribute */
1704*71e72c9eSCy Schubert if (!pr_derive_dira(pr, pr->cfg->dev_addr, &dira))
1705*71e72c9eSCy Schubert pr_buf_add_dira(buf, &dira);
1706*71e72c9eSCy Schubert
1707*71e72c9eSCy Schubert ie_type = (OUI_WFA << 8) | PR_OUI_TYPE;
1708*71e72c9eSCy Schubert buf2 = pr_encaps_elem(buf, ie_type);
1709*71e72c9eSCy Schubert wpabuf_free(buf);
1710*71e72c9eSCy Schubert
1711*71e72c9eSCy Schubert if (wpabuf_tailroom(extra_ies) < wpabuf_len(buf2)) {
1712*71e72c9eSCy Schubert wpa_printf(MSG_INFO,
1713*71e72c9eSCy Schubert "PR: Not enough room for PR element in PASN Frame");
1714*71e72c9eSCy Schubert wpabuf_free(buf2);
1715*71e72c9eSCy Schubert return -1;
1716*71e72c9eSCy Schubert }
1717*71e72c9eSCy Schubert wpabuf_put_buf(extra_ies, buf2);
1718*71e72c9eSCy Schubert wpabuf_free(buf2);
1719*71e72c9eSCy Schubert
1720*71e72c9eSCy Schubert return 0;
1721*71e72c9eSCy Schubert }
1722*71e72c9eSCy Schubert
1723*71e72c9eSCy Schubert
pr_pasn_generate_rsnxe(struct pr_data * pr,int akmp)1724*71e72c9eSCy Schubert static struct wpabuf * pr_pasn_generate_rsnxe(struct pr_data *pr, int akmp)
1725*71e72c9eSCy Schubert {
1726*71e72c9eSCy Schubert u32 capab;
1727*71e72c9eSCy Schubert size_t flen = 0;
1728*71e72c9eSCy Schubert struct wpabuf *buf;
1729*71e72c9eSCy Schubert
1730*71e72c9eSCy Schubert capab = BIT(WLAN_RSNX_CAPAB_KEK_IN_PASN);
1731*71e72c9eSCy Schubert
1732*71e72c9eSCy Schubert if (wpa_key_mgmt_sae(akmp))
1733*71e72c9eSCy Schubert capab |= BIT(WLAN_RSNX_CAPAB_SAE_H2E);
1734*71e72c9eSCy Schubert if (pr->cfg->secure_he_ltf)
1735*71e72c9eSCy Schubert capab |= BIT(WLAN_RSNX_CAPAB_SECURE_LTF);
1736*71e72c9eSCy Schubert
1737*71e72c9eSCy Schubert while (capab >> flen * 8)
1738*71e72c9eSCy Schubert flen++;
1739*71e72c9eSCy Schubert
1740*71e72c9eSCy Schubert buf = wpabuf_alloc(2 + flen);
1741*71e72c9eSCy Schubert if (!buf)
1742*71e72c9eSCy Schubert return NULL;
1743*71e72c9eSCy Schubert
1744*71e72c9eSCy Schubert capab |= flen - 1; /* bit 0-3 = Field length (n - 1) */
1745*71e72c9eSCy Schubert
1746*71e72c9eSCy Schubert wpa_printf(MSG_DEBUG, "PR: RSNXE capabilities: %04x", capab);
1747*71e72c9eSCy Schubert wpabuf_put_u8(buf, WLAN_EID_RSNX);
1748*71e72c9eSCy Schubert wpabuf_put_u8(buf, flen);
1749*71e72c9eSCy Schubert while (flen--) {
1750*71e72c9eSCy Schubert wpabuf_put_u8(buf, capab & 0xff);
1751*71e72c9eSCy Schubert capab = capab >> 8;
1752*71e72c9eSCy Schubert }
1753*71e72c9eSCy Schubert
1754*71e72c9eSCy Schubert return buf;
1755*71e72c9eSCy Schubert }
1756*71e72c9eSCy Schubert
1757*71e72c9eSCy Schubert
1758*71e72c9eSCy Schubert /* SSID used for deriving SAE pt for PR security */
1759*71e72c9eSCy Schubert #define PR_PASN_SSID "516F9A010000"
1760*71e72c9eSCy Schubert
pr_pasn_set_password(struct pasn_data * pasn,u8 pasn_type,const char * passphrase)1761*71e72c9eSCy Schubert static void pr_pasn_set_password(struct pasn_data *pasn, u8 pasn_type,
1762*71e72c9eSCy Schubert const char *passphrase)
1763*71e72c9eSCy Schubert {
1764*71e72c9eSCy Schubert int pasn_groups[4] = { 0, 0, 0, 0 };
1765*71e72c9eSCy Schubert size_t len;
1766*71e72c9eSCy Schubert
1767*71e72c9eSCy Schubert if (!passphrase)
1768*71e72c9eSCy Schubert return;
1769*71e72c9eSCy Schubert
1770*71e72c9eSCy Schubert len = os_strlen(passphrase);
1771*71e72c9eSCy Schubert
1772*71e72c9eSCy Schubert if ((pasn_type & (PR_PASN_DH20_UNAUTH | PR_PASN_DH20_AUTH)) &&
1773*71e72c9eSCy Schubert (pasn_type & (PR_PASN_DH19_UNAUTH | PR_PASN_DH19_AUTH))) {
1774*71e72c9eSCy Schubert pasn_groups[0] = 20;
1775*71e72c9eSCy Schubert pasn_groups[1] = 19;
1776*71e72c9eSCy Schubert } else if (pasn_type & (PR_PASN_DH20_UNAUTH | PR_PASN_DH20_AUTH)) {
1777*71e72c9eSCy Schubert pasn_groups[0] = 20;
1778*71e72c9eSCy Schubert } else {
1779*71e72c9eSCy Schubert pasn_groups[0] = 19;
1780*71e72c9eSCy Schubert }
1781*71e72c9eSCy Schubert pasn->pt = sae_derive_pt(pasn_groups, (const u8 *) PR_PASN_SSID,
1782*71e72c9eSCy Schubert os_strlen(PR_PASN_SSID),
1783*71e72c9eSCy Schubert (const u8 *) passphrase, len, NULL, 0);
1784*71e72c9eSCy Schubert }
1785*71e72c9eSCy Schubert
1786*71e72c9eSCy Schubert
pr_pasn_initialize(struct pr_data * pr,struct pr_device * dev,const u8 * addr,u8 auth_mode,int freq,u8 ranging_type,const u8 * pmkid)1787*71e72c9eSCy Schubert static int pr_pasn_initialize(struct pr_data *pr, struct pr_device *dev,
1788*71e72c9eSCy Schubert const u8 *addr, u8 auth_mode, int freq,
1789*71e72c9eSCy Schubert u8 ranging_type, const u8 *pmkid)
1790*71e72c9eSCy Schubert {
1791*71e72c9eSCy Schubert struct wpabuf *rsnxe;
1792*71e72c9eSCy Schubert struct pasn_data *pasn;
1793*71e72c9eSCy Schubert
1794*71e72c9eSCy Schubert if (dev->pasn) {
1795*71e72c9eSCy Schubert wpa_pasn_reset(dev->pasn);
1796*71e72c9eSCy Schubert } else {
1797*71e72c9eSCy Schubert dev->pasn = pasn_data_init();
1798*71e72c9eSCy Schubert if (!dev->pasn)
1799*71e72c9eSCy Schubert return -1;
1800*71e72c9eSCy Schubert }
1801*71e72c9eSCy Schubert
1802*71e72c9eSCy Schubert pasn = dev->pasn;
1803*71e72c9eSCy Schubert os_memcpy(pasn->own_addr, pr->cfg->dev_addr, ETH_ALEN);
1804*71e72c9eSCy Schubert os_memcpy(pasn->peer_addr, addr, ETH_ALEN);
1805*71e72c9eSCy Schubert
1806*71e72c9eSCy Schubert if (dev->pasn_role == PR_ROLE_PASN_INITIATOR) {
1807*71e72c9eSCy Schubert pasn->pmksa = pr->initiator_pmksa;
1808*71e72c9eSCy Schubert os_memcpy(pasn->bssid, pasn->peer_addr, ETH_ALEN);
1809*71e72c9eSCy Schubert } else {
1810*71e72c9eSCy Schubert pasn->pmksa = pr->responder_pmksa;
1811*71e72c9eSCy Schubert os_memcpy(pasn->bssid, pasn->own_addr, ETH_ALEN);
1812*71e72c9eSCy Schubert }
1813*71e72c9eSCy Schubert
1814*71e72c9eSCy Schubert pasn->noauth = 1;
1815*71e72c9eSCy Schubert
1816*71e72c9eSCy Schubert /* As specified in Proximity Ranging Implementation Considerations for
1817*71e72c9eSCy Schubert * P2P Operation D1.8, unauthenticated mode PASN with DH group 19
1818*71e72c9eSCy Schubert * should be supported by all P2P proximity ranging devices. Skip
1819*71e72c9eSCy Schubert * this check for OOB peers whose capabilities are not known.
1820*71e72c9eSCy Schubert */
1821*71e72c9eSCy Schubert if (dev->discovery_type != PR_DISCOVERY_TYPE_OOB &&
1822*71e72c9eSCy Schubert (!(pr->cfg->pasn_type & BIT(0)) ||
1823*71e72c9eSCy Schubert !(dev->pr_caps.pasn_type & BIT(0)))) {
1824*71e72c9eSCy Schubert wpa_printf(MSG_DEBUG,
1825*71e72c9eSCy Schubert "PR PASN: Unauthenticated DH group 19 NOT supported, PASN type of self 0x%x, peer 0x%x",
1826*71e72c9eSCy Schubert pr->cfg->pasn_type, dev->pr_caps.pasn_type);
1827*71e72c9eSCy Schubert return -1;
1828*71e72c9eSCy Schubert }
1829*71e72c9eSCy Schubert
1830*71e72c9eSCy Schubert /* As specified in Proximity Ranging Implementation Considerations for
1831*71e72c9eSCy Schubert * P2P Operation D1.8, EDCA based ranging is only supported with
1832*71e72c9eSCy Schubert * unauthenticated mode PASN with DH group 19. */
1833*71e72c9eSCy Schubert if (((pr->cfg->pasn_type & 0xc) && (dev->pr_caps.pasn_type & 0xc)) &&
1834*71e72c9eSCy Schubert ranging_type != PR_EDCA_BASED_RANGING) {
1835*71e72c9eSCy Schubert pasn->group = 20;
1836*71e72c9eSCy Schubert pasn->cipher = WPA_CIPHER_GCMP_256;
1837*71e72c9eSCy Schubert } else {
1838*71e72c9eSCy Schubert pasn->group = 19;
1839*71e72c9eSCy Schubert pasn->cipher = WPA_CIPHER_CCMP;
1840*71e72c9eSCy Schubert }
1841*71e72c9eSCy Schubert
1842*71e72c9eSCy Schubert if (pr->cfg->secure_he_ltf &&
1843*71e72c9eSCy Schubert ranging_type == PR_NTB_SECURE_LTF_BASED_RANGING) {
1844*71e72c9eSCy Schubert pasn->secure_ltf = true;
1845*71e72c9eSCy Schubert pasn_enable_kdk_derivation(pasn);
1846*71e72c9eSCy Schubert } else {
1847*71e72c9eSCy Schubert pasn_disable_kdk_derivation(pasn);
1848*71e72c9eSCy Schubert }
1849*71e72c9eSCy Schubert wpa_printf(MSG_DEBUG, "PASN: kdk_len=%zu", pasn->kdk_len);
1850*71e72c9eSCy Schubert
1851*71e72c9eSCy Schubert if (auth_mode == PR_PASN_AUTH_MODE_SAE) {
1852*71e72c9eSCy Schubert pasn->akmp = WPA_KEY_MGMT_SAE;
1853*71e72c9eSCy Schubert if (dev->password_valid) {
1854*71e72c9eSCy Schubert pr_pasn_set_password(pasn, pr->cfg->pasn_type,
1855*71e72c9eSCy Schubert dev->password);
1856*71e72c9eSCy Schubert } else if (pr->cfg->global_password_valid) {
1857*71e72c9eSCy Schubert pr_pasn_set_password(pasn, pr->cfg->pasn_type,
1858*71e72c9eSCy Schubert pr->cfg->global_password);
1859*71e72c9eSCy Schubert } else {
1860*71e72c9eSCy Schubert wpa_printf(MSG_INFO, "PR PASN: Password not available");
1861*71e72c9eSCy Schubert return -1;
1862*71e72c9eSCy Schubert }
1863*71e72c9eSCy Schubert } else if (auth_mode == PR_PASN_AUTH_MODE_PMK && dev->pmk_valid) {
1864*71e72c9eSCy Schubert if (!dev->pmk_valid) {
1865*71e72c9eSCy Schubert wpa_printf(MSG_INFO, "PR PASN: PMK not available");
1866*71e72c9eSCy Schubert return -1;
1867*71e72c9eSCy Schubert }
1868*71e72c9eSCy Schubert if (dev->pasn_role == PR_ROLE_PASN_INITIATOR)
1869*71e72c9eSCy Schubert pasn_initiator_pmksa_cache_add(pr->initiator_pmksa,
1870*71e72c9eSCy Schubert pasn->own_addr,
1871*71e72c9eSCy Schubert pasn->peer_addr,
1872*71e72c9eSCy Schubert dev->pmk,
1873*71e72c9eSCy Schubert dev->pmk_len,
1874*71e72c9eSCy Schubert pmkid,
1875*71e72c9eSCy Schubert WPA_KEY_MGMT_SAE);
1876*71e72c9eSCy Schubert else
1877*71e72c9eSCy Schubert pasn_responder_pmksa_cache_add(pr->responder_pmksa,
1878*71e72c9eSCy Schubert pasn->own_addr,
1879*71e72c9eSCy Schubert pasn->peer_addr,
1880*71e72c9eSCy Schubert dev->pmk,
1881*71e72c9eSCy Schubert dev->pmk_len,
1882*71e72c9eSCy Schubert pmkid,
1883*71e72c9eSCy Schubert WPA_KEY_MGMT_SAE);
1884*71e72c9eSCy Schubert pasn->akmp = WPA_KEY_MGMT_SAE;
1885*71e72c9eSCy Schubert } else {
1886*71e72c9eSCy Schubert pasn->akmp = WPA_KEY_MGMT_PASN;
1887*71e72c9eSCy Schubert }
1888*71e72c9eSCy Schubert
1889*71e72c9eSCy Schubert pasn->rsn_pairwise = pasn->cipher;
1890*71e72c9eSCy Schubert pasn->wpa_key_mgmt = pasn->akmp;
1891*71e72c9eSCy Schubert
1892*71e72c9eSCy Schubert rsnxe = pr_pasn_generate_rsnxe(pr, pasn->akmp);
1893*71e72c9eSCy Schubert if (rsnxe) {
1894*71e72c9eSCy Schubert os_free(pasn->rsnxe_ie);
1895*71e72c9eSCy Schubert pasn->rsnxe_ie = os_memdup(wpabuf_head_u8(rsnxe),
1896*71e72c9eSCy Schubert wpabuf_len(rsnxe));
1897*71e72c9eSCy Schubert wpabuf_free(rsnxe);
1898*71e72c9eSCy Schubert if (!pasn->rsnxe_ie)
1899*71e72c9eSCy Schubert return -1;
1900*71e72c9eSCy Schubert }
1901*71e72c9eSCy Schubert
1902*71e72c9eSCy Schubert pasn->cb_ctx = pr->cfg->cb_ctx;
1903*71e72c9eSCy Schubert pasn->send_mgmt = pr->cfg->pasn_send_mgmt;
1904*71e72c9eSCy Schubert pasn->freq = freq;
1905*71e72c9eSCy Schubert return 0;
1906*71e72c9eSCy Schubert }
1907*71e72c9eSCy Schubert
1908*71e72c9eSCy Schubert
pr_validate_pasn_request(struct pr_data * pr,struct pr_device * dev,u8 auth_mode,u8 ranging_role,u8 ranging_type)1909*71e72c9eSCy Schubert static int pr_validate_pasn_request(struct pr_data *pr, struct pr_device *dev,
1910*71e72c9eSCy Schubert u8 auth_mode, u8 ranging_role,
1911*71e72c9eSCy Schubert u8 ranging_type)
1912*71e72c9eSCy Schubert {
1913*71e72c9eSCy Schubert if (!ranging_role || !ranging_type)
1914*71e72c9eSCy Schubert return -1;
1915*71e72c9eSCy Schubert
1916*71e72c9eSCy Schubert if (auth_mode == PR_PASN_AUTH_MODE_PASN) {
1917*71e72c9eSCy Schubert if (!(pr->cfg->pasn_type &
1918*71e72c9eSCy Schubert (PR_PASN_DH19_UNAUTH | PR_PASN_DH20_UNAUTH)) ||
1919*71e72c9eSCy Schubert !(dev->pr_caps.pasn_type &
1920*71e72c9eSCy Schubert (PR_PASN_DH19_UNAUTH | PR_PASN_DH20_UNAUTH))) {
1921*71e72c9eSCy Schubert wpa_printf(MSG_INFO,
1922*71e72c9eSCy Schubert "PR: Dev/Peer doesn't support PASN-UNAUTH");
1923*71e72c9eSCy Schubert return -1;
1924*71e72c9eSCy Schubert }
1925*71e72c9eSCy Schubert } else if (auth_mode == PR_PASN_AUTH_MODE_PMK ||
1926*71e72c9eSCy Schubert auth_mode == PR_PASN_AUTH_MODE_SAE) {
1927*71e72c9eSCy Schubert if (!(pr->cfg->pasn_type &
1928*71e72c9eSCy Schubert (PR_PASN_DH19_AUTH | PR_PASN_DH20_AUTH)) ||
1929*71e72c9eSCy Schubert !(dev->pr_caps.pasn_type &
1930*71e72c9eSCy Schubert (PR_PASN_DH19_AUTH | PR_PASN_DH20_AUTH))) {
1931*71e72c9eSCy Schubert wpa_printf(MSG_INFO, "PR: Dev/Peer doesn't support PASN-SAE/PMK");
1932*71e72c9eSCy Schubert return -1;
1933*71e72c9eSCy Schubert }
1934*71e72c9eSCy Schubert }
1935*71e72c9eSCy Schubert
1936*71e72c9eSCy Schubert if (ranging_type == PR_NTB_SECURE_LTF_BASED_RANGING ||
1937*71e72c9eSCy Schubert ranging_type == PR_NTB_OPEN_BASED_RANGING) {
1938*71e72c9eSCy Schubert if (ranging_type == PR_NTB_SECURE_LTF_BASED_RANGING &&
1939*71e72c9eSCy Schubert (!pr->cfg->secure_he_ltf || !dev->ntb_caps.secure_he_ltf)) {
1940*71e72c9eSCy Schubert wpa_printf(MSG_INFO,
1941*71e72c9eSCy Schubert "PR: Dev/Peer doesn't support HE-LTF");
1942*71e72c9eSCy Schubert return -1;
1943*71e72c9eSCy Schubert }
1944*71e72c9eSCy Schubert
1945*71e72c9eSCy Schubert if (ranging_role == PR_ISTA_SUPPORT &&
1946*71e72c9eSCy Schubert !pr->cfg->ntb_ista_support) {
1947*71e72c9eSCy Schubert wpa_printf(MSG_INFO,
1948*71e72c9eSCy Schubert "PR: Device doesn't support NTB ISTA role");
1949*71e72c9eSCy Schubert return -1;
1950*71e72c9eSCy Schubert }
1951*71e72c9eSCy Schubert
1952*71e72c9eSCy Schubert if (ranging_role == PR_RSTA_SUPPORT &&
1953*71e72c9eSCy Schubert !pr->cfg->ntb_rsta_support) {
1954*71e72c9eSCy Schubert wpa_printf(MSG_INFO,
1955*71e72c9eSCy Schubert "PR: Device doesn't support NTB RSTA role");
1956*71e72c9eSCy Schubert return -1;
1957*71e72c9eSCy Schubert }
1958*71e72c9eSCy Schubert
1959*71e72c9eSCy Schubert if (ranging_role == PR_ISTA_SUPPORT &&
1960*71e72c9eSCy Schubert !dev->ntb_caps.rsta_support &&
1961*71e72c9eSCy Schubert !pr->cfg->ntb_rsta_support) {
1962*71e72c9eSCy Schubert wpa_printf(MSG_INFO,
1963*71e72c9eSCy Schubert "PR: Device and Peer doesn't support NTB RSTA role, no possiblity for negotiation update");
1964*71e72c9eSCy Schubert return -1;
1965*71e72c9eSCy Schubert }
1966*71e72c9eSCy Schubert
1967*71e72c9eSCy Schubert if (ranging_role == PR_RSTA_SUPPORT &&
1968*71e72c9eSCy Schubert !dev->ntb_caps.ista_support &&
1969*71e72c9eSCy Schubert !pr->cfg->ntb_ista_support) {
1970*71e72c9eSCy Schubert wpa_printf(MSG_INFO,
1971*71e72c9eSCy Schubert "PR: Device and Peer doesn't support NTB ISTA role, no possiblity for negotiation update");
1972*71e72c9eSCy Schubert return -1;
1973*71e72c9eSCy Schubert }
1974*71e72c9eSCy Schubert } else if (ranging_type == PR_EDCA_BASED_RANGING) {
1975*71e72c9eSCy Schubert if (ranging_role == PR_ISTA_SUPPORT &&
1976*71e72c9eSCy Schubert !pr->cfg->edca_ista_support) {
1977*71e72c9eSCy Schubert wpa_printf(MSG_INFO,
1978*71e72c9eSCy Schubert "PR: Device doesn't support EDCA ISTA role");
1979*71e72c9eSCy Schubert return -1;
1980*71e72c9eSCy Schubert }
1981*71e72c9eSCy Schubert
1982*71e72c9eSCy Schubert if (ranging_role == PR_RSTA_SUPPORT &&
1983*71e72c9eSCy Schubert !pr->cfg->edca_rsta_support) {
1984*71e72c9eSCy Schubert wpa_printf(MSG_INFO,
1985*71e72c9eSCy Schubert "PR: Device doesn't support EDCA RSTA role");
1986*71e72c9eSCy Schubert return -1;
1987*71e72c9eSCy Schubert }
1988*71e72c9eSCy Schubert
1989*71e72c9eSCy Schubert if (ranging_role == PR_ISTA_SUPPORT &&
1990*71e72c9eSCy Schubert !dev->edca_caps.rsta_support &&
1991*71e72c9eSCy Schubert !pr->cfg->edca_rsta_support) {
1992*71e72c9eSCy Schubert wpa_printf(MSG_INFO,
1993*71e72c9eSCy Schubert "PR: Device and Peer doesn't support EDCA RSTA role, no possiblity for negotiation update");
1994*71e72c9eSCy Schubert return -1;
1995*71e72c9eSCy Schubert }
1996*71e72c9eSCy Schubert
1997*71e72c9eSCy Schubert if (ranging_role == PR_RSTA_SUPPORT &&
1998*71e72c9eSCy Schubert !dev->edca_caps.ista_support &&
1999*71e72c9eSCy Schubert !pr->cfg->edca_ista_support) {
2000*71e72c9eSCy Schubert wpa_printf(MSG_INFO,
2001*71e72c9eSCy Schubert "PR: Device and Peer doesn't support EDCA ISTA role, no possiblity for negotiation update");
2002*71e72c9eSCy Schubert return -1;
2003*71e72c9eSCy Schubert }
2004*71e72c9eSCy Schubert }
2005*71e72c9eSCy Schubert
2006*71e72c9eSCy Schubert return 0;
2007*71e72c9eSCy Schubert }
2008*71e72c9eSCy Schubert
2009*71e72c9eSCy Schubert
pr_initiate_pasn_auth(struct pr_data * pr,const u8 * addr,int freq,u8 auth_mode,u8 ranging_role,u8 ranging_type,int forced_pr_freq)2010*71e72c9eSCy Schubert int pr_initiate_pasn_auth(struct pr_data *pr, const u8 *addr, int freq,
2011*71e72c9eSCy Schubert u8 auth_mode, u8 ranging_role, u8 ranging_type,
2012*71e72c9eSCy Schubert int forced_pr_freq)
2013*71e72c9eSCy Schubert {
2014*71e72c9eSCy Schubert int ret = 0;
2015*71e72c9eSCy Schubert struct pasn_data *pasn;
2016*71e72c9eSCy Schubert struct pr_device *dev;
2017*71e72c9eSCy Schubert u8 pmkid[PMKID_LEN];
2018*71e72c9eSCy Schubert struct wpabuf *extra_ies;
2019*71e72c9eSCy Schubert
2020*71e72c9eSCy Schubert if (!addr) {
2021*71e72c9eSCy Schubert wpa_printf(MSG_DEBUG, "PR PASN: Peer address NULL");
2022*71e72c9eSCy Schubert return -1;
2023*71e72c9eSCy Schubert }
2024*71e72c9eSCy Schubert
2025*71e72c9eSCy Schubert dev = pr_get_device(pr, addr);
2026*71e72c9eSCy Schubert if (!dev) {
2027*71e72c9eSCy Schubert wpa_printf(MSG_DEBUG, "PR PASN: Peer not known");
2028*71e72c9eSCy Schubert return -1;
2029*71e72c9eSCy Schubert }
2030*71e72c9eSCy Schubert
2031*71e72c9eSCy Schubert if (dev->discovery_type != PR_DISCOVERY_TYPE_OOB &&
2032*71e72c9eSCy Schubert pr_validate_pasn_request(pr, dev, auth_mode, ranging_role,
2033*71e72c9eSCy Schubert ranging_type) < 0) {
2034*71e72c9eSCy Schubert wpa_printf(MSG_INFO,
2035*71e72c9eSCy Schubert "PR PASN: Invalid parameters to initiate authentication");
2036*71e72c9eSCy Schubert return -1;
2037*71e72c9eSCy Schubert }
2038*71e72c9eSCy Schubert
2039*71e72c9eSCy Schubert if (freq == 0)
2040*71e72c9eSCy Schubert freq = dev->listen_freq;
2041*71e72c9eSCy Schubert
2042*71e72c9eSCy Schubert dev->pasn_role = PR_ROLE_PASN_INITIATOR;
2043*71e72c9eSCy Schubert
2044*71e72c9eSCy Schubert if (auth_mode == PR_PASN_AUTH_MODE_PMK && dev->pmk_valid &&
2045*71e72c9eSCy Schubert os_get_random(pmkid, PMKID_LEN) < 0)
2046*71e72c9eSCy Schubert return -1;
2047*71e72c9eSCy Schubert
2048*71e72c9eSCy Schubert if (pr_pasn_initialize(pr, dev, addr, auth_mode, freq, ranging_type,
2049*71e72c9eSCy Schubert pmkid)) {
2050*71e72c9eSCy Schubert wpa_printf(MSG_INFO, "PR PASN: Initialization failed");
2051*71e72c9eSCy Schubert return -1;
2052*71e72c9eSCy Schubert }
2053*71e72c9eSCy Schubert pasn = dev->pasn;
2054*71e72c9eSCy Schubert
2055*71e72c9eSCy Schubert extra_ies = wpabuf_alloc(1500);
2056*71e72c9eSCy Schubert if (!extra_ies)
2057*71e72c9eSCy Schubert return -1;
2058*71e72c9eSCy Schubert
2059*71e72c9eSCy Schubert if (pr_prepare_pasn_pr_elem(pr, extra_ies, false, ranging_role,
2060*71e72c9eSCy Schubert ranging_type, forced_pr_freq)) {
2061*71e72c9eSCy Schubert wpa_printf(MSG_INFO,
2062*71e72c9eSCy Schubert "PR PASN: Failed to prepare extra elements");
2063*71e72c9eSCy Schubert ret = -1;
2064*71e72c9eSCy Schubert goto out;
2065*71e72c9eSCy Schubert }
2066*71e72c9eSCy Schubert
2067*71e72c9eSCy Schubert pasn_set_extra_ies(dev->pasn, wpabuf_head_u8(extra_ies),
2068*71e72c9eSCy Schubert wpabuf_len(extra_ies));
2069*71e72c9eSCy Schubert
2070*71e72c9eSCy Schubert if (auth_mode == PR_PASN_AUTH_MODE_PMK) {
2071*71e72c9eSCy Schubert ret = wpa_pasn_verify(pasn, pasn->own_addr, pasn->peer_addr,
2072*71e72c9eSCy Schubert pasn->bssid, pasn->akmp, pasn->cipher,
2073*71e72c9eSCy Schubert pasn->group, pasn->freq, NULL, 0, NULL, 0,
2074*71e72c9eSCy Schubert NULL);
2075*71e72c9eSCy Schubert } else {
2076*71e72c9eSCy Schubert ret = wpas_pasn_start(pasn, pasn->own_addr, pasn->peer_addr,
2077*71e72c9eSCy Schubert pasn->bssid, pasn->akmp, pasn->cipher,
2078*71e72c9eSCy Schubert pasn->group, pasn->freq, NULL, 0, NULL, 0,
2079*71e72c9eSCy Schubert NULL);
2080*71e72c9eSCy Schubert }
2081*71e72c9eSCy Schubert if (ret) {
2082*71e72c9eSCy Schubert wpa_printf(MSG_INFO, "PR PASN: Failed to start PASN");
2083*71e72c9eSCy Schubert } else {
2084*71e72c9eSCy Schubert /* M1 sent successfully - notify that negotiation has started */
2085*71e72c9eSCy Schubert if (pr->cfg->negotiation_started)
2086*71e72c9eSCy Schubert pr->cfg->negotiation_started(pr->cfg->cb_ctx, addr,
2087*71e72c9eSCy Schubert ranging_role,
2088*71e72c9eSCy Schubert ranging_type);
2089*71e72c9eSCy Schubert }
2090*71e72c9eSCy Schubert
2091*71e72c9eSCy Schubert out:
2092*71e72c9eSCy Schubert wpabuf_free(extra_ies);
2093*71e72c9eSCy Schubert return ret;
2094*71e72c9eSCy Schubert }
2095*71e72c9eSCy Schubert
2096*71e72c9eSCy Schubert
pr_pasn_auth_tx_status(struct pr_data * pr,const u8 * data,size_t data_len,bool acked)2097*71e72c9eSCy Schubert int pr_pasn_auth_tx_status(struct pr_data *pr, const u8 *data, size_t data_len,
2098*71e72c9eSCy Schubert bool acked)
2099*71e72c9eSCy Schubert {
2100*71e72c9eSCy Schubert int ret = 0;
2101*71e72c9eSCy Schubert struct pr_device *dev;
2102*71e72c9eSCy Schubert struct pasn_data *pasn;
2103*71e72c9eSCy Schubert const struct ieee80211_mgmt *mgmt =
2104*71e72c9eSCy Schubert (const struct ieee80211_mgmt *) data;
2105*71e72c9eSCy Schubert u8 self_format_bw, peer_format_bw;
2106*71e72c9eSCy Schubert
2107*71e72c9eSCy Schubert if (!pr)
2108*71e72c9eSCy Schubert return -1;
2109*71e72c9eSCy Schubert
2110*71e72c9eSCy Schubert dev = pr_get_device(pr, mgmt->da);
2111*71e72c9eSCy Schubert if (!dev || !dev->pasn) {
2112*71e72c9eSCy Schubert wpa_printf(MSG_INFO, "PR PASN: Peer not found " MACSTR,
2113*71e72c9eSCy Schubert MAC2STR(mgmt->da));
2114*71e72c9eSCy Schubert return -1;
2115*71e72c9eSCy Schubert }
2116*71e72c9eSCy Schubert
2117*71e72c9eSCy Schubert pasn = dev->pasn;
2118*71e72c9eSCy Schubert wpa_printf(MSG_DEBUG, "PR PASN: TX status from " MACSTR " ack=%d",
2119*71e72c9eSCy Schubert MAC2STR(mgmt->da), acked);
2120*71e72c9eSCy Schubert
2121*71e72c9eSCy Schubert ret = wpa_pasn_auth_tx_status(pasn, data, data_len, acked);
2122*71e72c9eSCy Schubert
2123*71e72c9eSCy Schubert /*
2124*71e72c9eSCy Schubert * Authentication frame 1 was not acked; return to caller to schedule a
2125*71e72c9eSCy Schubert * retransmission. Preserve pasn->frame for the retry.
2126*71e72c9eSCy Schubert */
2127*71e72c9eSCy Schubert if (ret == 2)
2128*71e72c9eSCy Schubert return ret;
2129*71e72c9eSCy Schubert
2130*71e72c9eSCy Schubert if (ret == 1 && acked && pr->cfg->pasn_result)
2131*71e72c9eSCy Schubert pr->cfg->pasn_result(pr->cfg->cb_ctx, dev->ranging_role,
2132*71e72c9eSCy Schubert dev->protocol_type, dev->final_op_class,
2133*71e72c9eSCy Schubert dev->final_op_channel, pr->cfg->country);
2134*71e72c9eSCy Schubert
2135*71e72c9eSCy Schubert if (ret == 1 && acked && pr->cfg->get_ranging_params) {
2136*71e72c9eSCy Schubert if (dev->protocol_type & PR_EDCA_BASED_RANGING) {
2137*71e72c9eSCy Schubert self_format_bw = pr->cfg->edca_format_and_bw;
2138*71e72c9eSCy Schubert peer_format_bw = dev->edca_caps.edca_hw_caps &
2139*71e72c9eSCy Schubert EDCA_FORMAT_AND_BW_MASK;
2140*71e72c9eSCy Schubert } else if ((dev->protocol_type &
2141*71e72c9eSCy Schubert PR_NTB_SECURE_LTF_BASED_RANGING) ||
2142*71e72c9eSCy Schubert (dev->protocol_type & PR_NTB_OPEN_BASED_RANGING)) {
2143*71e72c9eSCy Schubert self_format_bw = pr->cfg->ntb_format_and_bw;
2144*71e72c9eSCy Schubert peer_format_bw = dev->ntb_caps.ntb_hw_caps &
2145*71e72c9eSCy Schubert NTB_FORMAT_AND_BW_MASK;
2146*71e72c9eSCy Schubert } else {
2147*71e72c9eSCy Schubert wpa_printf(MSG_INFO,
2148*71e72c9eSCy Schubert "PR PASN: Invalid protocol type: %u",
2149*71e72c9eSCy Schubert dev->protocol_type);
2150*71e72c9eSCy Schubert goto out;
2151*71e72c9eSCy Schubert }
2152*71e72c9eSCy Schubert
2153*71e72c9eSCy Schubert pr->cfg->get_ranging_params(pr->cfg->cb_ctx, pr->cfg->dev_addr,
2154*71e72c9eSCy Schubert dev->pr_device_addr,
2155*71e72c9eSCy Schubert dev->ranging_role,
2156*71e72c9eSCy Schubert dev->protocol_type,
2157*71e72c9eSCy Schubert dev->final_op_class,
2158*71e72c9eSCy Schubert dev->final_op_channel,
2159*71e72c9eSCy Schubert self_format_bw,
2160*71e72c9eSCy Schubert peer_format_bw);
2161*71e72c9eSCy Schubert pr_flush(pr);
2162*71e72c9eSCy Schubert }
2163*71e72c9eSCy Schubert
2164*71e72c9eSCy Schubert out:
2165*71e72c9eSCy Schubert wpabuf_free(pasn->frame);
2166*71e72c9eSCy Schubert pasn->frame = NULL;
2167*71e72c9eSCy Schubert
2168*71e72c9eSCy Schubert return ret;
2169*71e72c9eSCy Schubert }
2170*71e72c9eSCy Schubert
2171*71e72c9eSCy Schubert
pr_pasn_auth_retransmit(struct pr_data * pr,const u8 * addr)2172*71e72c9eSCy Schubert int pr_pasn_auth_retransmit(struct pr_data *pr, const u8 *addr)
2173*71e72c9eSCy Schubert {
2174*71e72c9eSCy Schubert struct pr_device *dev;
2175*71e72c9eSCy Schubert struct pasn_data *pasn;
2176*71e72c9eSCy Schubert
2177*71e72c9eSCy Schubert dev = pr_get_device(pr, addr);
2178*71e72c9eSCy Schubert if (!dev || !dev->pasn || !dev->pasn->frame)
2179*71e72c9eSCy Schubert return -1;
2180*71e72c9eSCy Schubert
2181*71e72c9eSCy Schubert pasn = dev->pasn;
2182*71e72c9eSCy Schubert wpa_printf(MSG_DEBUG, "PR PASN: retransmit Authentication frame 1 to "
2183*71e72c9eSCy Schubert MACSTR, MAC2STR(addr));
2184*71e72c9eSCy Schubert return pasn->send_mgmt(pasn->cb_ctx, wpabuf_head(pasn->frame),
2185*71e72c9eSCy Schubert wpabuf_len(pasn->frame), 0, pasn->freq, 1000);
2186*71e72c9eSCy Schubert }
2187*71e72c9eSCy Schubert
2188*71e72c9eSCy Schubert
pr_process_pasn_ranging_wrapper(struct pr_data * pr,struct pr_device * dev,const struct ieee80211_mgmt * mgmt,size_t len,int trans_seq)2189*71e72c9eSCy Schubert static int pr_process_pasn_ranging_wrapper(struct pr_data *pr,
2190*71e72c9eSCy Schubert struct pr_device *dev,
2191*71e72c9eSCy Schubert const struct ieee80211_mgmt *mgmt,
2192*71e72c9eSCy Schubert size_t len, int trans_seq)
2193*71e72c9eSCy Schubert {
2194*71e72c9eSCy Schubert u32 ie_type;
2195*71e72c9eSCy Schubert const u8 *ies;
2196*71e72c9eSCy Schubert size_t ies_len;
2197*71e72c9eSCy Schubert u8 status = PR_NEGOTIATION_FAIL;
2198*71e72c9eSCy Schubert bool success = false;
2199*71e72c9eSCy Schubert struct wpabuf *buf, *buf2;
2200*71e72c9eSCy Schubert struct pr_message msg;
2201*71e72c9eSCy Schubert struct pr_capabilities caps;
2202*71e72c9eSCy Schubert struct edca_capabilities edca;
2203*71e72c9eSCy Schubert struct ntb_capabilities ntb;
2204*71e72c9eSCy Schubert struct operation_mode op_mode;
2205*71e72c9eSCy Schubert u8 supp_ranging_role = 0;
2206*71e72c9eSCy Schubert struct operation_mode res_op_mode;
2207*71e72c9eSCy Schubert bool ntb_caps_valid = false, edca_caps_valid = false;
2208*71e72c9eSCy Schubert
2209*71e72c9eSCy Schubert buf = wpabuf_alloc(1000);
2210*71e72c9eSCy Schubert if (!buf) {
2211*71e72c9eSCy Schubert wpa_printf(MSG_INFO, "PR: Memory allocation failed");
2212*71e72c9eSCy Schubert return -1;
2213*71e72c9eSCy Schubert }
2214*71e72c9eSCy Schubert
2215*71e72c9eSCy Schubert os_memset(&msg, 0, sizeof(msg));
2216*71e72c9eSCy Schubert ies = mgmt->u.auth.variable;
2217*71e72c9eSCy Schubert if (offsetof(struct ieee80211_mgmt, u.auth.variable) > len)
2218*71e72c9eSCy Schubert return -1;
2219*71e72c9eSCy Schubert ies_len = len - offsetof(struct ieee80211_mgmt, u.auth.variable);
2220*71e72c9eSCy Schubert
2221*71e72c9eSCy Schubert if (pr_parse_elements(ies, ies_len, &msg) || !msg.op_mode) {
2222*71e72c9eSCy Schubert wpa_printf(MSG_INFO,
2223*71e72c9eSCy Schubert "PR PASN: Failed to parse PR element in Auth1");
2224*71e72c9eSCy Schubert goto end;
2225*71e72c9eSCy Schubert }
2226*71e72c9eSCy Schubert
2227*71e72c9eSCy Schubert if (trans_seq == WLAN_AUTH_TR_SEQ_PASN_AUTH2) {
2228*71e72c9eSCy Schubert if (!msg.status_ie || !msg.status_ie_len) {
2229*71e72c9eSCy Schubert wpa_printf(MSG_DEBUG, "PR INFO: * No status attribute");
2230*71e72c9eSCy Schubert wpabuf_free(buf);
2231*71e72c9eSCy Schubert pr_parse_free(&msg);
2232*71e72c9eSCy Schubert return -1;
2233*71e72c9eSCy Schubert }
2234*71e72c9eSCy Schubert if (*msg.status_ie == PR_NEGOTIATION_FAIL) {
2235*71e72c9eSCy Schubert wpa_printf(MSG_INFO,
2236*71e72c9eSCy Schubert "PR PASN: * Ranging Negotiation status fail");
2237*71e72c9eSCy Schubert wpabuf_free(buf);
2238*71e72c9eSCy Schubert pr_parse_free(&msg);
2239*71e72c9eSCy Schubert return -1;
2240*71e72c9eSCy Schubert }
2241*71e72c9eSCy Schubert }
2242*71e72c9eSCy Schubert
2243*71e72c9eSCy Schubert if (!msg.op_mode || !msg.op_mode_len ||
2244*71e72c9eSCy Schubert !msg.pr_capability || !msg.pr_capability_len ||
2245*71e72c9eSCy Schubert ((!msg.edca_capability || !msg.edca_capability_len) &&
2246*71e72c9eSCy Schubert (!msg.ntb_capability || !msg.ntb_capability_len)))
2247*71e72c9eSCy Schubert goto end;
2248*71e72c9eSCy Schubert
2249*71e72c9eSCy Schubert if (msg.dira && msg.dira_len)
2250*71e72c9eSCy Schubert pr_validate_dira(pr, dev, msg.dira, msg.dira_len);
2251*71e72c9eSCy Schubert
2252*71e72c9eSCy Schubert pr_process_op_mode(msg.op_mode, msg.op_mode_len, &op_mode);
2253*71e72c9eSCy Schubert if (!op_mode.channels.op_classes) {
2254*71e72c9eSCy Schubert wpa_printf(MSG_INFO, "PR: Received empty channel list");
2255*71e72c9eSCy Schubert goto end;
2256*71e72c9eSCy Schubert }
2257*71e72c9eSCy Schubert
2258*71e72c9eSCy Schubert os_memset(&caps, 0, sizeof(struct pr_capabilities));
2259*71e72c9eSCy Schubert pr_process_ranging_capabilities(msg.pr_capability,
2260*71e72c9eSCy Schubert msg.pr_capability_len, &caps);
2261*71e72c9eSCy Schubert if (!pr_eq_ranging_capa_params(dev, &caps)) {
2262*71e72c9eSCy Schubert wpa_printf(MSG_INFO, "PR: Ranging capabilities not matching");
2263*71e72c9eSCy Schubert goto end;
2264*71e72c9eSCy Schubert }
2265*71e72c9eSCy Schubert
2266*71e72c9eSCy Schubert pr_get_ranging_capabilities(pr, &caps);
2267*71e72c9eSCy Schubert
2268*71e72c9eSCy Schubert if ((op_mode.protocol_type & PR_EDCA_BASED_RANGING) &&
2269*71e72c9eSCy Schubert (!msg.edca_capability || !msg.edca_capability_len))
2270*71e72c9eSCy Schubert goto end;
2271*71e72c9eSCy Schubert if ((op_mode.protocol_type & PR_NTB_OPEN_BASED_RANGING) &&
2272*71e72c9eSCy Schubert (!msg.ntb_capability || !msg.ntb_capability_len))
2273*71e72c9eSCy Schubert goto end;
2274*71e72c9eSCy Schubert if ((op_mode.protocol_type & PR_NTB_SECURE_LTF_BASED_RANGING) &&
2275*71e72c9eSCy Schubert (!msg.ntb_capability || !msg.ntb_capability_len))
2276*71e72c9eSCy Schubert goto end;
2277*71e72c9eSCy Schubert
2278*71e72c9eSCy Schubert if (op_mode.protocol_type &
2279*71e72c9eSCy Schubert (PR_NTB_SECURE_LTF_BASED_RANGING | PR_NTB_OPEN_BASED_RANGING)) {
2280*71e72c9eSCy Schubert pr_process_ntb_capabilities(msg.ntb_capability,
2281*71e72c9eSCy Schubert msg.ntb_capability_len, &ntb,
2282*71e72c9eSCy Schubert caps.secure_he_ltf);
2283*71e72c9eSCy Schubert
2284*71e72c9eSCy Schubert if (!pr_eq_ntb_params(dev, &ntb)) {
2285*71e72c9eSCy Schubert wpa_printf(MSG_INFO,
2286*71e72c9eSCy Schubert "PR: NTB capabilities not matching");
2287*71e72c9eSCy Schubert goto end;
2288*71e72c9eSCy Schubert }
2289*71e72c9eSCy Schubert
2290*71e72c9eSCy Schubert if (dev->ntb_caps.ista_support)
2291*71e72c9eSCy Schubert supp_ranging_role |= PR_ISTA_SUPPORT;
2292*71e72c9eSCy Schubert if (dev->ntb_caps.rsta_support)
2293*71e72c9eSCy Schubert supp_ranging_role |= PR_RSTA_SUPPORT;
2294*71e72c9eSCy Schubert
2295*71e72c9eSCy Schubert pr_get_ntb_capabilities(pr, &ntb);
2296*71e72c9eSCy Schubert ntb_caps_valid = true;
2297*71e72c9eSCy Schubert } else if (op_mode.protocol_type & PR_EDCA_BASED_RANGING) {
2298*71e72c9eSCy Schubert pr_process_edca_capabilities(msg.edca_capability,
2299*71e72c9eSCy Schubert msg.edca_capability_len, &edca);
2300*71e72c9eSCy Schubert if (!pr_eq_edca_params(dev, &edca)) {
2301*71e72c9eSCy Schubert wpa_printf(MSG_INFO,
2302*71e72c9eSCy Schubert "PR: EDCA capabilities not matching");
2303*71e72c9eSCy Schubert goto end;
2304*71e72c9eSCy Schubert }
2305*71e72c9eSCy Schubert
2306*71e72c9eSCy Schubert if (dev->edca_caps.ista_support)
2307*71e72c9eSCy Schubert supp_ranging_role |= PR_ISTA_SUPPORT;
2308*71e72c9eSCy Schubert if (dev->edca_caps.rsta_support)
2309*71e72c9eSCy Schubert supp_ranging_role |= PR_RSTA_SUPPORT;
2310*71e72c9eSCy Schubert
2311*71e72c9eSCy Schubert pr_get_edca_capabilities(pr, &edca);
2312*71e72c9eSCy Schubert edca_caps_valid = true;
2313*71e72c9eSCy Schubert }
2314*71e72c9eSCy Schubert
2315*71e72c9eSCy Schubert if (trans_seq == WLAN_AUTH_TR_SEQ_PASN_AUTH1)
2316*71e72c9eSCy Schubert status = pr_pasn_get_best_op_mode(pr, supp_ranging_role,
2317*71e72c9eSCy Schubert &op_mode, &res_op_mode);
2318*71e72c9eSCy Schubert else if (trans_seq == WLAN_AUTH_TR_SEQ_PASN_AUTH2)
2319*71e72c9eSCy Schubert status = pr_pasn_get_final_op_mode(pr, supp_ranging_role,
2320*71e72c9eSCy Schubert &op_mode, &res_op_mode);
2321*71e72c9eSCy Schubert
2322*71e72c9eSCy Schubert if (status != PR_NEGOTIATION_SUCCESS &&
2323*71e72c9eSCy Schubert status != PR_NEGOTIATION_UPDATE) {
2324*71e72c9eSCy Schubert wpa_printf(MSG_DEBUG,
2325*71e72c9eSCy Schubert "PR: Couldn't derive suitable operation mode");
2326*71e72c9eSCy Schubert goto end;
2327*71e72c9eSCy Schubert }
2328*71e72c9eSCy Schubert
2329*71e72c9eSCy Schubert if (trans_seq == WLAN_AUTH_TR_SEQ_PASN_AUTH1) {
2330*71e72c9eSCy Schubert pr_buf_add_ranging_capa_info(buf, &caps);
2331*71e72c9eSCy Schubert if (edca_caps_valid)
2332*71e72c9eSCy Schubert pr_buf_add_edca_capa_info(buf, &edca);
2333*71e72c9eSCy Schubert if (ntb_caps_valid)
2334*71e72c9eSCy Schubert pr_buf_add_ntb_capa_info(buf, &ntb);
2335*71e72c9eSCy Schubert }
2336*71e72c9eSCy Schubert
2337*71e72c9eSCy Schubert pr_buf_add_ranging_neg_status(buf, status);
2338*71e72c9eSCy Schubert pr_buf_add_operation_mode(buf, &res_op_mode);
2339*71e72c9eSCy Schubert
2340*71e72c9eSCy Schubert dev->ranging_role = res_op_mode.role;
2341*71e72c9eSCy Schubert dev->protocol_type = res_op_mode.protocol_type;
2342*71e72c9eSCy Schubert
2343*71e72c9eSCy Schubert if (trans_seq == WLAN_AUTH_TR_SEQ_PASN_AUTH2) {
2344*71e72c9eSCy Schubert dev->final_op_channel =
2345*71e72c9eSCy Schubert res_op_mode.channels.op_class[0].channel[0];
2346*71e72c9eSCy Schubert dev->final_op_class = res_op_mode.channels.op_class[0].op_class;
2347*71e72c9eSCy Schubert }
2348*71e72c9eSCy Schubert
2349*71e72c9eSCy Schubert success = true;
2350*71e72c9eSCy Schubert end:
2351*71e72c9eSCy Schubert if (!success)
2352*71e72c9eSCy Schubert pr_buf_add_ranging_neg_status(buf, PR_NEGOTIATION_FAIL);
2353*71e72c9eSCy Schubert
2354*71e72c9eSCy Schubert ie_type = (OUI_WFA << 8) | PR_OUI_TYPE;
2355*71e72c9eSCy Schubert buf2 = pr_encaps_elem(buf, ie_type);
2356*71e72c9eSCy Schubert wpabuf_free(buf);
2357*71e72c9eSCy Schubert
2358*71e72c9eSCy Schubert wpabuf_free(dev->ranging_wrapper);
2359*71e72c9eSCy Schubert dev->ranging_wrapper = buf2;
2360*71e72c9eSCy Schubert pr_parse_free(&msg);
2361*71e72c9eSCy Schubert
2362*71e72c9eSCy Schubert return 0;
2363*71e72c9eSCy Schubert }
2364*71e72c9eSCy Schubert
2365*71e72c9eSCy Schubert
2366*71e72c9eSCy Schubert static int
pr_process_pasn_ranging_wrapper_result(struct pr_data * pr,struct pr_device * dev,const struct ieee80211_mgmt * mgmt,size_t len)2367*71e72c9eSCy Schubert pr_process_pasn_ranging_wrapper_result(struct pr_data *pr,
2368*71e72c9eSCy Schubert struct pr_device *dev,
2369*71e72c9eSCy Schubert const struct ieee80211_mgmt *mgmt,
2370*71e72c9eSCy Schubert size_t len)
2371*71e72c9eSCy Schubert {
2372*71e72c9eSCy Schubert int ret = -1;
2373*71e72c9eSCy Schubert const u8 *ies;
2374*71e72c9eSCy Schubert size_t ies_len;
2375*71e72c9eSCy Schubert struct pr_message msg;
2376*71e72c9eSCy Schubert struct operation_mode op_mode;
2377*71e72c9eSCy Schubert struct pr_channels common_chan;
2378*71e72c9eSCy Schubert
2379*71e72c9eSCy Schubert os_memset(&msg, 0, sizeof(msg));
2380*71e72c9eSCy Schubert ies = mgmt->u.auth.variable;
2381*71e72c9eSCy Schubert ies_len = len - offsetof(struct ieee80211_mgmt, u.auth.variable);
2382*71e72c9eSCy Schubert
2383*71e72c9eSCy Schubert if (pr_parse_elements(ies, ies_len, &msg) || !msg.op_mode) {
2384*71e72c9eSCy Schubert wpa_printf(MSG_INFO,
2385*71e72c9eSCy Schubert "PR PASN: Failed to parse PR element in Auth3");
2386*71e72c9eSCy Schubert goto fail;
2387*71e72c9eSCy Schubert }
2388*71e72c9eSCy Schubert
2389*71e72c9eSCy Schubert if (!msg.status_ie || !msg.status_ie_len) {
2390*71e72c9eSCy Schubert wpa_printf(MSG_INFO, "PR PASN: * No status attribute");
2391*71e72c9eSCy Schubert goto fail;
2392*71e72c9eSCy Schubert }
2393*71e72c9eSCy Schubert
2394*71e72c9eSCy Schubert if (*msg.status_ie == PR_NEGOTIATION_FAIL) {
2395*71e72c9eSCy Schubert wpa_printf(MSG_INFO,
2396*71e72c9eSCy Schubert "PR PASN: * Ranging Negotiation status fail");
2397*71e72c9eSCy Schubert goto fail;
2398*71e72c9eSCy Schubert }
2399*71e72c9eSCy Schubert
2400*71e72c9eSCy Schubert if (!msg.op_mode || !msg.op_mode_len)
2401*71e72c9eSCy Schubert goto fail;
2402*71e72c9eSCy Schubert
2403*71e72c9eSCy Schubert pr_process_op_mode(msg.op_mode, msg.op_mode_len, &op_mode);
2404*71e72c9eSCy Schubert if (op_mode.channels.op_classes != 1) {
2405*71e72c9eSCy Schubert wpa_printf(MSG_INFO, "PR: PASN received invalid channel list");
2406*71e72c9eSCy Schubert goto fail;
2407*71e72c9eSCy Schubert }
2408*71e72c9eSCy Schubert
2409*71e72c9eSCy Schubert wpa_printf(MSG_DEBUG,
2410*71e72c9eSCy Schubert "PR PASN: Frame 3: Operating mode data: Role=%u, protocol type=%u, operating class=%u, channel= %u",
2411*71e72c9eSCy Schubert op_mode.role, op_mode.protocol_type,
2412*71e72c9eSCy Schubert op_mode.channels.op_class[0].op_class,
2413*71e72c9eSCy Schubert op_mode.channels.op_class[0].channel[0]);
2414*71e72c9eSCy Schubert
2415*71e72c9eSCy Schubert if (op_mode.protocol_type &
2416*71e72c9eSCy Schubert (PR_NTB_SECURE_LTF_BASED_RANGING | PR_NTB_OPEN_BASED_RANGING)) {
2417*71e72c9eSCy Schubert if ((op_mode.role & PR_ISTA_SUPPORT) &&
2418*71e72c9eSCy Schubert !pr->cfg->ntb_rsta_support)
2419*71e72c9eSCy Schubert goto fail;
2420*71e72c9eSCy Schubert
2421*71e72c9eSCy Schubert if ((op_mode.role & PR_RSTA_SUPPORT) &&
2422*71e72c9eSCy Schubert !pr->cfg->ntb_ista_support)
2423*71e72c9eSCy Schubert goto fail;
2424*71e72c9eSCy Schubert
2425*71e72c9eSCy Schubert if ((op_mode.protocol_type & PR_NTB_SECURE_LTF_BASED_RANGING) &&
2426*71e72c9eSCy Schubert !pr->cfg->secure_he_ltf)
2427*71e72c9eSCy Schubert goto fail;
2428*71e72c9eSCy Schubert
2429*71e72c9eSCy Schubert pr_channels_intersect(&pr->cfg->ntb_channels, &op_mode.channels,
2430*71e72c9eSCy Schubert &common_chan);
2431*71e72c9eSCy Schubert if (common_chan.op_classes == 0) {
2432*71e72c9eSCy Schubert wpa_printf(MSG_INFO, "PR PASN: No common channel");
2433*71e72c9eSCy Schubert goto fail;
2434*71e72c9eSCy Schubert }
2435*71e72c9eSCy Schubert } else if (op_mode.protocol_type & PR_EDCA_BASED_RANGING) {
2436*71e72c9eSCy Schubert if ((op_mode.role & PR_ISTA_SUPPORT) &&
2437*71e72c9eSCy Schubert !pr->cfg->edca_rsta_support)
2438*71e72c9eSCy Schubert goto fail;
2439*71e72c9eSCy Schubert
2440*71e72c9eSCy Schubert if ((op_mode.role & PR_RSTA_SUPPORT) &&
2441*71e72c9eSCy Schubert !pr->cfg->edca_ista_support)
2442*71e72c9eSCy Schubert goto fail;
2443*71e72c9eSCy Schubert
2444*71e72c9eSCy Schubert pr_channels_intersect(&pr->cfg->edca_channels,
2445*71e72c9eSCy Schubert &op_mode.channels, &common_chan);
2446*71e72c9eSCy Schubert if (common_chan.op_classes == 0)
2447*71e72c9eSCy Schubert goto fail;
2448*71e72c9eSCy Schubert }
2449*71e72c9eSCy Schubert
2450*71e72c9eSCy Schubert if (op_mode.role & PR_RSTA_SUPPORT)
2451*71e72c9eSCy Schubert dev->ranging_role = PR_ISTA_SUPPORT;
2452*71e72c9eSCy Schubert else
2453*71e72c9eSCy Schubert dev->ranging_role = PR_RSTA_SUPPORT;
2454*71e72c9eSCy Schubert dev->protocol_type = op_mode.protocol_type;
2455*71e72c9eSCy Schubert dev->final_op_channel = op_mode.channels.op_class[0].channel[0];
2456*71e72c9eSCy Schubert dev->final_op_class = op_mode.channels.op_class[0].op_class;
2457*71e72c9eSCy Schubert ret = 0;
2458*71e72c9eSCy Schubert
2459*71e72c9eSCy Schubert fail:
2460*71e72c9eSCy Schubert pr_parse_free(&msg);
2461*71e72c9eSCy Schubert return ret;
2462*71e72c9eSCy Schubert }
2463*71e72c9eSCy Schubert
2464*71e72c9eSCy Schubert
pr_pasn_handle_auth_1(struct pr_data * pr,struct pr_device * dev,const struct ieee80211_mgmt * mgmt,size_t len,int freq)2465*71e72c9eSCy Schubert static int pr_pasn_handle_auth_1(struct pr_data *pr, struct pr_device *dev,
2466*71e72c9eSCy Schubert const struct ieee80211_mgmt *mgmt, size_t len,
2467*71e72c9eSCy Schubert int freq)
2468*71e72c9eSCy Schubert {
2469*71e72c9eSCy Schubert int ret = -1;
2470*71e72c9eSCy Schubert u8 pasn_type;
2471*71e72c9eSCy Schubert u8 auth_mode = 0;
2472*71e72c9eSCy Schubert int pasn_groups[4] = { 0 };
2473*71e72c9eSCy Schubert struct wpa_ie_data rsn_data;
2474*71e72c9eSCy Schubert struct ieee802_11_elems elems;
2475*71e72c9eSCy Schubert
2476*71e72c9eSCy Schubert pasn_type = pr->cfg->pasn_type;
2477*71e72c9eSCy Schubert if (pasn_type & (PR_PASN_DH20_UNAUTH | PR_PASN_DH20_AUTH) &&
2478*71e72c9eSCy Schubert pasn_type & (PR_PASN_DH19_UNAUTH | PR_PASN_DH19_AUTH)) {
2479*71e72c9eSCy Schubert pasn_groups[0] = 20;
2480*71e72c9eSCy Schubert pasn_groups[1] = 19;
2481*71e72c9eSCy Schubert } else if (pasn_type & (PR_PASN_DH20_UNAUTH | PR_PASN_DH20_AUTH)) {
2482*71e72c9eSCy Schubert pasn_groups[0] = 20;
2483*71e72c9eSCy Schubert } else {
2484*71e72c9eSCy Schubert pasn_groups[0] = 19;
2485*71e72c9eSCy Schubert }
2486*71e72c9eSCy Schubert
2487*71e72c9eSCy Schubert if (pr_process_pasn_ranging_wrapper(pr, dev, mgmt, len, 1)) {
2488*71e72c9eSCy Schubert wpa_printf(MSG_INFO,
2489*71e72c9eSCy Schubert "PR PASN: Failed to handle Auth1 action wrapper");
2490*71e72c9eSCy Schubert return -1;
2491*71e72c9eSCy Schubert }
2492*71e72c9eSCy Schubert
2493*71e72c9eSCy Schubert if (ieee802_11_parse_elems(mgmt->u.auth.variable,
2494*71e72c9eSCy Schubert len - offsetof(struct ieee80211_mgmt,
2495*71e72c9eSCy Schubert u.auth.variable),
2496*71e72c9eSCy Schubert &elems, 0) == ParseFailed) {
2497*71e72c9eSCy Schubert wpa_printf(MSG_DEBUG,
2498*71e72c9eSCy Schubert "PR PASN: Failed parsing elements in Auth1 frame");
2499*71e72c9eSCy Schubert goto fail;
2500*71e72c9eSCy Schubert }
2501*71e72c9eSCy Schubert
2502*71e72c9eSCy Schubert if (wpa_parse_wpa_ie_rsn(elems.rsn_ie - 2, elems.rsn_ie_len + 2,
2503*71e72c9eSCy Schubert &rsn_data) == 0) {
2504*71e72c9eSCy Schubert if (rsn_data.key_mgmt == WPA_KEY_MGMT_SAE && rsn_data.num_pmkid)
2505*71e72c9eSCy Schubert auth_mode = PR_PASN_AUTH_MODE_PMK;
2506*71e72c9eSCy Schubert else if (rsn_data.key_mgmt == WPA_KEY_MGMT_SAE)
2507*71e72c9eSCy Schubert auth_mode = PR_PASN_AUTH_MODE_SAE;
2508*71e72c9eSCy Schubert else
2509*71e72c9eSCy Schubert auth_mode = PR_PASN_AUTH_MODE_PASN;
2510*71e72c9eSCy Schubert }
2511*71e72c9eSCy Schubert
2512*71e72c9eSCy Schubert dev->pasn_role = PR_ROLE_PASN_RESPONDER;
2513*71e72c9eSCy Schubert if (pr_pasn_initialize(pr, dev, mgmt->sa, auth_mode, freq,
2514*71e72c9eSCy Schubert dev->protocol_type, rsn_data.pmkid)) {
2515*71e72c9eSCy Schubert wpa_printf(MSG_INFO, "PR PASN: Initialize failed");
2516*71e72c9eSCy Schubert goto fail;
2517*71e72c9eSCy Schubert }
2518*71e72c9eSCy Schubert
2519*71e72c9eSCy Schubert pasn_set_extra_ies(dev->pasn, wpabuf_head_u8(dev->ranging_wrapper),
2520*71e72c9eSCy Schubert wpabuf_len(dev->ranging_wrapper));
2521*71e72c9eSCy Schubert os_free(dev->pasn->pasn_groups);
2522*71e72c9eSCy Schubert dev->pasn->pasn_groups = int_array_dup(pasn_groups);
2523*71e72c9eSCy Schubert if (handle_auth_pasn_1(dev->pasn, pr->cfg->dev_addr, mgmt->sa, mgmt,
2524*71e72c9eSCy Schubert len, false) < 0) {
2525*71e72c9eSCy Schubert wpa_printf(MSG_INFO, "PR PASN: Handle Auth1 failed");
2526*71e72c9eSCy Schubert goto fail;
2527*71e72c9eSCy Schubert }
2528*71e72c9eSCy Schubert
2529*71e72c9eSCy Schubert if (!(dev->protocol_type & PR_EDCA_BASED_RANGING) &&
2530*71e72c9eSCy Schubert pr->cfg->set_keys &&
2531*71e72c9eSCy Schubert pr->cfg->set_keys(pr->cfg->cb_ctx, pr->cfg->dev_addr,
2532*71e72c9eSCy Schubert dev->pr_device_addr, dev->pasn->cipher,
2533*71e72c9eSCy Schubert dev->pasn->akmp, &dev->pasn->ptk) < 0) {
2534*71e72c9eSCy Schubert wpa_printf(MSG_INFO, "PR PASN: Key configuration failed");
2535*71e72c9eSCy Schubert goto fail;
2536*71e72c9eSCy Schubert }
2537*71e72c9eSCy Schubert
2538*71e72c9eSCy Schubert /* M1 received and M2 sent - notify that negotiation has started */
2539*71e72c9eSCy Schubert if (pr->cfg->negotiation_started)
2540*71e72c9eSCy Schubert pr->cfg->negotiation_started(pr->cfg->cb_ctx, mgmt->sa,
2541*71e72c9eSCy Schubert dev->ranging_role,
2542*71e72c9eSCy Schubert dev->protocol_type);
2543*71e72c9eSCy Schubert ret = 0;
2544*71e72c9eSCy Schubert
2545*71e72c9eSCy Schubert fail:
2546*71e72c9eSCy Schubert wpabuf_free(dev->ranging_wrapper);
2547*71e72c9eSCy Schubert dev->ranging_wrapper = NULL;
2548*71e72c9eSCy Schubert return ret;
2549*71e72c9eSCy Schubert }
2550*71e72c9eSCy Schubert
2551*71e72c9eSCy Schubert
pr_pasn_handle_auth_2(struct pr_data * pr,struct pr_device * dev,const struct ieee80211_mgmt * mgmt,size_t len)2552*71e72c9eSCy Schubert static int pr_pasn_handle_auth_2(struct pr_data *pr, struct pr_device *dev,
2553*71e72c9eSCy Schubert const struct ieee80211_mgmt *mgmt, size_t len)
2554*71e72c9eSCy Schubert {
2555*71e72c9eSCy Schubert int ret = -1;
2556*71e72c9eSCy Schubert struct wpa_pasn_params_data pasn_data;
2557*71e72c9eSCy Schubert
2558*71e72c9eSCy Schubert if (dev->pasn_role != PR_ROLE_PASN_INITIATOR) {
2559*71e72c9eSCy Schubert wpa_printf(MSG_INFO,
2560*71e72c9eSCy Schubert "PR PASN: Auth2 not expected on responder");
2561*71e72c9eSCy Schubert return -1;
2562*71e72c9eSCy Schubert }
2563*71e72c9eSCy Schubert
2564*71e72c9eSCy Schubert if (!dev->pasn)
2565*71e72c9eSCy Schubert return -1;
2566*71e72c9eSCy Schubert
2567*71e72c9eSCy Schubert if (pr_process_pasn_ranging_wrapper(pr, dev, mgmt, len, 2)) {
2568*71e72c9eSCy Schubert wpa_printf(MSG_INFO,
2569*71e72c9eSCy Schubert "PR PASN: Failed to handle Auth2 action wrapper");
2570*71e72c9eSCy Schubert return -1;
2571*71e72c9eSCy Schubert }
2572*71e72c9eSCy Schubert pasn_set_extra_ies(dev->pasn, wpabuf_head_u8(dev->ranging_wrapper),
2573*71e72c9eSCy Schubert wpabuf_len(dev->ranging_wrapper));
2574*71e72c9eSCy Schubert
2575*71e72c9eSCy Schubert if (wpa_pasn_auth_rx(dev->pasn, (const u8 *) mgmt, len,
2576*71e72c9eSCy Schubert &pasn_data) < 0) {
2577*71e72c9eSCy Schubert wpa_printf(MSG_INFO, "PR PASN: wpa_pasn_auth_rx() failed");
2578*71e72c9eSCy Schubert dev->pasn_role = PR_ROLE_IDLE;
2579*71e72c9eSCy Schubert goto fail;
2580*71e72c9eSCy Schubert }
2581*71e72c9eSCy Schubert
2582*71e72c9eSCy Schubert if (!(dev->protocol_type & PR_EDCA_BASED_RANGING) &&
2583*71e72c9eSCy Schubert pr->cfg->set_keys &&
2584*71e72c9eSCy Schubert pr->cfg->set_keys(pr->cfg->cb_ctx, pr->cfg->dev_addr,
2585*71e72c9eSCy Schubert dev->pr_device_addr, dev->pasn->cipher,
2586*71e72c9eSCy Schubert dev->pasn->akmp, &dev->pasn->ptk) < 0) {
2587*71e72c9eSCy Schubert wpa_printf(MSG_INFO, "PR PASN: Key configuration failed");
2588*71e72c9eSCy Schubert goto fail;
2589*71e72c9eSCy Schubert }
2590*71e72c9eSCy Schubert ret = 0;
2591*71e72c9eSCy Schubert
2592*71e72c9eSCy Schubert fail:
2593*71e72c9eSCy Schubert wpabuf_free(dev->ranging_wrapper);
2594*71e72c9eSCy Schubert dev->ranging_wrapper = NULL;
2595*71e72c9eSCy Schubert return ret;
2596*71e72c9eSCy Schubert }
2597*71e72c9eSCy Schubert
2598*71e72c9eSCy Schubert
pr_pasn_handle_auth_3(struct pr_data * pr,struct pr_device * dev,const struct ieee80211_mgmt * mgmt,size_t len)2599*71e72c9eSCy Schubert static int pr_pasn_handle_auth_3(struct pr_data *pr, struct pr_device *dev,
2600*71e72c9eSCy Schubert const struct ieee80211_mgmt *mgmt, size_t len)
2601*71e72c9eSCy Schubert {
2602*71e72c9eSCy Schubert u8 self_format_bw, peer_format_bw;
2603*71e72c9eSCy Schubert
2604*71e72c9eSCy Schubert if (dev->pasn_role != PR_ROLE_PASN_RESPONDER) {
2605*71e72c9eSCy Schubert wpa_printf(MSG_INFO,
2606*71e72c9eSCy Schubert "PR PASN: Auth3 not expected on initiator");
2607*71e72c9eSCy Schubert return -1;
2608*71e72c9eSCy Schubert }
2609*71e72c9eSCy Schubert
2610*71e72c9eSCy Schubert if (!dev->pasn)
2611*71e72c9eSCy Schubert return -1;
2612*71e72c9eSCy Schubert
2613*71e72c9eSCy Schubert if (pr_process_pasn_ranging_wrapper_result(pr, dev, mgmt, len)) {
2614*71e72c9eSCy Schubert wpa_printf(MSG_INFO,
2615*71e72c9eSCy Schubert "PR PASN: Failed to handle Auth3 action wrapper");
2616*71e72c9eSCy Schubert goto fail;
2617*71e72c9eSCy Schubert }
2618*71e72c9eSCy Schubert
2619*71e72c9eSCy Schubert if (handle_auth_pasn_3(dev->pasn, pr->cfg->dev_addr, mgmt->sa, mgmt,
2620*71e72c9eSCy Schubert len) < 0) {
2621*71e72c9eSCy Schubert wpa_printf(MSG_INFO, "PR PASN: Failed to handle Auth3");
2622*71e72c9eSCy Schubert goto fail;
2623*71e72c9eSCy Schubert }
2624*71e72c9eSCy Schubert
2625*71e72c9eSCy Schubert if (pr->cfg->pasn_result)
2626*71e72c9eSCy Schubert pr->cfg->pasn_result(pr->cfg->cb_ctx, dev->ranging_role,
2627*71e72c9eSCy Schubert dev->protocol_type, dev->final_op_class,
2628*71e72c9eSCy Schubert dev->final_op_channel, pr->cfg->country);
2629*71e72c9eSCy Schubert
2630*71e72c9eSCy Schubert if (dev->protocol_type & PR_EDCA_BASED_RANGING) {
2631*71e72c9eSCy Schubert self_format_bw = pr->cfg->edca_format_and_bw;
2632*71e72c9eSCy Schubert peer_format_bw = dev->edca_caps.edca_hw_caps &
2633*71e72c9eSCy Schubert EDCA_FORMAT_AND_BW_MASK;
2634*71e72c9eSCy Schubert
2635*71e72c9eSCy Schubert } else if ((dev->protocol_type & PR_NTB_SECURE_LTF_BASED_RANGING) ||
2636*71e72c9eSCy Schubert (dev->protocol_type & PR_NTB_OPEN_BASED_RANGING)) {
2637*71e72c9eSCy Schubert self_format_bw = pr->cfg->ntb_format_and_bw;
2638*71e72c9eSCy Schubert peer_format_bw = dev->ntb_caps.ntb_hw_caps &
2639*71e72c9eSCy Schubert NTB_FORMAT_AND_BW_MASK;
2640*71e72c9eSCy Schubert } else {
2641*71e72c9eSCy Schubert wpa_printf(MSG_INFO, "PR PASN: Invalid protocol type: %u",
2642*71e72c9eSCy Schubert dev->protocol_type);
2643*71e72c9eSCy Schubert goto fail;
2644*71e72c9eSCy Schubert }
2645*71e72c9eSCy Schubert
2646*71e72c9eSCy Schubert if (pr->cfg->get_ranging_params)
2647*71e72c9eSCy Schubert pr->cfg->get_ranging_params(pr->cfg->cb_ctx, pr->cfg->dev_addr,
2648*71e72c9eSCy Schubert dev->pr_device_addr,
2649*71e72c9eSCy Schubert dev->ranging_role,
2650*71e72c9eSCy Schubert dev->protocol_type,
2651*71e72c9eSCy Schubert dev->final_op_class,
2652*71e72c9eSCy Schubert dev->final_op_channel,
2653*71e72c9eSCy Schubert self_format_bw,
2654*71e72c9eSCy Schubert peer_format_bw);
2655*71e72c9eSCy Schubert pr_flush(pr);
2656*71e72c9eSCy Schubert return 0;
2657*71e72c9eSCy Schubert
2658*71e72c9eSCy Schubert fail:
2659*71e72c9eSCy Schubert /* Clear the keys as M3 processing failed */
2660*71e72c9eSCy Schubert if (pr->cfg->clear_keys)
2661*71e72c9eSCy Schubert pr->cfg->clear_keys(pr->cfg->cb_ctx, pr->cfg->dev_addr,
2662*71e72c9eSCy Schubert dev->pr_device_addr);
2663*71e72c9eSCy Schubert return -1;
2664*71e72c9eSCy Schubert }
2665*71e72c9eSCy Schubert
2666*71e72c9eSCy Schubert
pr_pasn_auth_rx(struct pr_data * pr,const struct ieee80211_mgmt * mgmt,size_t len,int freq)2667*71e72c9eSCy Schubert int pr_pasn_auth_rx(struct pr_data *pr, const struct ieee80211_mgmt *mgmt,
2668*71e72c9eSCy Schubert size_t len, int freq)
2669*71e72c9eSCy Schubert {
2670*71e72c9eSCy Schubert struct pr_device *dev;
2671*71e72c9eSCy Schubert u16 auth_alg, auth_transaction;
2672*71e72c9eSCy Schubert
2673*71e72c9eSCy Schubert dev = pr_get_device(pr, mgmt->sa);
2674*71e72c9eSCy Schubert if (!dev) {
2675*71e72c9eSCy Schubert wpa_printf(MSG_INFO, "PR: Peer not found " MACSTR,
2676*71e72c9eSCy Schubert MAC2STR(mgmt->sa));
2677*71e72c9eSCy Schubert return -1;
2678*71e72c9eSCy Schubert }
2679*71e72c9eSCy Schubert
2680*71e72c9eSCy Schubert if (!ether_addr_equal(mgmt->da, pr->cfg->dev_addr)) {
2681*71e72c9eSCy Schubert wpa_printf(MSG_INFO, "PR PASN: Not our frame");
2682*71e72c9eSCy Schubert return -1;
2683*71e72c9eSCy Schubert }
2684*71e72c9eSCy Schubert
2685*71e72c9eSCy Schubert if (len < offsetof(struct ieee80211_mgmt, u.auth.variable))
2686*71e72c9eSCy Schubert return -1;
2687*71e72c9eSCy Schubert
2688*71e72c9eSCy Schubert auth_alg = le_to_host16(mgmt->u.auth.auth_alg);
2689*71e72c9eSCy Schubert if (auth_alg != WLAN_AUTH_PASN) {
2690*71e72c9eSCy Schubert wpa_printf(MSG_INFO,
2691*71e72c9eSCy Schubert "PR: Unexpected Authentication frame, auth_alg=%d",
2692*71e72c9eSCy Schubert auth_alg);
2693*71e72c9eSCy Schubert return -1;
2694*71e72c9eSCy Schubert }
2695*71e72c9eSCy Schubert
2696*71e72c9eSCy Schubert auth_transaction = le_to_host16(mgmt->u.auth.auth_transaction);
2697*71e72c9eSCy Schubert if (auth_transaction == WLAN_AUTH_TR_SEQ_PASN_AUTH1)
2698*71e72c9eSCy Schubert return pr_pasn_handle_auth_1(pr, dev, mgmt, len, freq);
2699*71e72c9eSCy Schubert if (auth_transaction == WLAN_AUTH_TR_SEQ_PASN_AUTH2)
2700*71e72c9eSCy Schubert return pr_pasn_handle_auth_2(pr, dev, mgmt, len);
2701*71e72c9eSCy Schubert if (auth_transaction == WLAN_AUTH_TR_SEQ_PASN_AUTH3)
2702*71e72c9eSCy Schubert return pr_pasn_handle_auth_3(pr, dev, mgmt, len);
2703*71e72c9eSCy Schubert
2704*71e72c9eSCy Schubert return -1;
2705*71e72c9eSCy Schubert }
2706*71e72c9eSCy Schubert
2707*71e72c9eSCy Schubert #endif /* CONFIG_PASN */
2708