]> git.ipfire.org Git - thirdparty/hostap.git/blame - src/ap/ieee802_11_shared.c
SAE: Special test mode sae_pwe=3 for looping with password identifier
[thirdparty/hostap.git] / src / ap / ieee802_11_shared.c
CommitLineData
d4370eac
MP
1/*
2 * hostapd / IEEE 802.11 Management
b6668734 3 * Copyright (c) 2002-2012, Jouni Malinen <j@w1.fi>
d4370eac 4 *
0f3d578e
JM
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
d4370eac
MP
7 */
8
9#include "utils/includes.h"
10
11#include "utils/common.h"
12#include "common/ieee802_11_defs.h"
f9da7505 13#include "common/ocv.h"
d4370eac
MP
14#include "hostapd.h"
15#include "sta_info.h"
16#include "ap_config.h"
17#include "ap_drv_ops.h"
f9da7505 18#include "wpa_auth.h"
39b97072 19#include "ieee802_11.h"
d4370eac
MP
20
21
d4370eac
MP
22u8 * hostapd_eid_assoc_comeback_time(struct hostapd_data *hapd,
23 struct sta_info *sta, u8 *eid)
24{
25 u8 *pos = eid;
26 u32 timeout, tu;
10e694a6 27 struct os_reltime now, passed;
d4370eac
MP
28
29 *pos++ = WLAN_EID_TIMEOUT_INTERVAL;
30 *pos++ = 5;
31 *pos++ = WLAN_TIMEOUT_ASSOC_COMEBACK;
10e694a6
JB
32 os_get_reltime(&now);
33 os_reltime_sub(&now, &sta->sa_query_start, &passed);
d4370eac
MP
34 tu = (passed.sec * 1000000 + passed.usec) / 1024;
35 if (hapd->conf->assoc_sa_query_max_timeout > tu)
36 timeout = hapd->conf->assoc_sa_query_max_timeout - tu;
37 else
38 timeout = 0;
39 if (timeout < hapd->conf->assoc_sa_query_max_timeout)
40 timeout++; /* add some extra time for local timers */
41 WPA_PUT_LE32(pos, timeout);
42 pos += 4;
43
44 return pos;
45}
46
47
48/* MLME-SAQuery.request */
49void ieee802_11_send_sa_query_req(struct hostapd_data *hapd,
50 const u8 *addr, const u8 *trans_id)
51{
f9da7505
MV
52#ifdef CONFIG_OCV
53 struct sta_info *sta;
54#endif /* CONFIG_OCV */
55 struct ieee80211_mgmt *mgmt;
56 u8 *oci_ie = NULL;
57 u8 oci_ie_len = 0;
d4370eac
MP
58 u8 *end;
59
60 wpa_printf(MSG_DEBUG, "IEEE 802.11: Sending SA Query Request to "
61 MACSTR, MAC2STR(addr));
62 wpa_hexdump(MSG_DEBUG, "IEEE 802.11: SA Query Transaction ID",
63 trans_id, WLAN_SA_QUERY_TR_ID_LEN);
64
f9da7505
MV
65#ifdef CONFIG_OCV
66 sta = ap_get_sta(hapd, addr);
67 if (sta && wpa_auth_uses_ocv(sta->wpa_sm)) {
68 struct wpa_channel_info ci;
69
70 if (hostapd_drv_channel_info(hapd, &ci) != 0) {
71 wpa_printf(MSG_WARNING,
72 "Failed to get channel info for OCI element in SA Query Request");
73 return;
74 }
75
76 oci_ie_len = OCV_OCI_EXTENDED_LEN;
77 oci_ie = os_zalloc(oci_ie_len);
78 if (!oci_ie) {
79 wpa_printf(MSG_WARNING,
80 "Failed to allocate buffer for OCI element in SA Query Request");
81 return;
82 }
83
84 if (ocv_insert_extended_oci(&ci, oci_ie) < 0) {
85 os_free(oci_ie);
86 return;
87 }
88 }
89#endif /* CONFIG_OCV */
90
91 mgmt = os_zalloc(sizeof(*mgmt) + oci_ie_len);
92 if (!mgmt) {
93 wpa_printf(MSG_DEBUG,
94 "Failed to allocate buffer for SA Query Response frame");
95 os_free(oci_ie);
96 return;
97 }
98
99 mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
100 WLAN_FC_STYPE_ACTION);
101 os_memcpy(mgmt->da, addr, ETH_ALEN);
102 os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN);
103 os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN);
104 mgmt->u.action.category = WLAN_ACTION_SA_QUERY;
105 mgmt->u.action.u.sa_query_req.action = WLAN_SA_QUERY_REQUEST;
106 os_memcpy(mgmt->u.action.u.sa_query_req.trans_id, trans_id,
d4370eac 107 WLAN_SA_QUERY_TR_ID_LEN);
f9da7505
MV
108 end = mgmt->u.action.u.sa_query_req.variable;
109#ifdef CONFIG_OCV
110 if (oci_ie_len > 0) {
111 os_memcpy(end, oci_ie, oci_ie_len);
112 end += oci_ie_len;
113 }
114#endif /* CONFIG_OCV */
37100274
JM
115 if (hostapd_drv_send_mlme(hapd, mgmt, end - (u8 *) mgmt, 0, NULL, 0, 0)
116 < 0)
61323e70 117 wpa_printf(MSG_INFO, "ieee802_11_send_sa_query_req: send failed");
f9da7505
MV
118
119 os_free(mgmt);
120 os_free(oci_ie);
d4370eac
MP
121}
122
123
19df9b07
JM
124static void ieee802_11_send_sa_query_resp(struct hostapd_data *hapd,
125 const u8 *sa, const u8 *trans_id)
d4370eac
MP
126{
127 struct sta_info *sta;
f9da7505
MV
128 struct ieee80211_mgmt *resp;
129 u8 *oci_ie = NULL;
130 u8 oci_ie_len = 0;
d4370eac
MP
131 u8 *end;
132
133 wpa_printf(MSG_DEBUG, "IEEE 802.11: Received SA Query Request from "
134 MACSTR, MAC2STR(sa));
135 wpa_hexdump(MSG_DEBUG, "IEEE 802.11: SA Query Transaction ID",
136 trans_id, WLAN_SA_QUERY_TR_ID_LEN);
137
138 sta = ap_get_sta(hapd, sa);
139 if (sta == NULL || !(sta->flags & WLAN_STA_ASSOC)) {
140 wpa_printf(MSG_DEBUG, "IEEE 802.11: Ignore SA Query Request "
141 "from unassociated STA " MACSTR, MAC2STR(sa));
142 return;
143 }
144
f9da7505
MV
145#ifdef CONFIG_OCV
146 if (wpa_auth_uses_ocv(sta->wpa_sm)) {
147 struct wpa_channel_info ci;
148
149 if (hostapd_drv_channel_info(hapd, &ci) != 0) {
150 wpa_printf(MSG_WARNING,
151 "Failed to get channel info for OCI element in SA Query Response");
152 return;
153 }
154
155 oci_ie_len = OCV_OCI_EXTENDED_LEN;
156 oci_ie = os_zalloc(oci_ie_len);
157 if (!oci_ie) {
158 wpa_printf(MSG_WARNING,
159 "Failed to allocate buffer for for OCI element in SA Query Response");
160 return;
161 }
162
163 if (ocv_insert_extended_oci(&ci, oci_ie) < 0) {
164 os_free(oci_ie);
165 return;
166 }
167 }
168#endif /* CONFIG_OCV */
169
170 resp = os_zalloc(sizeof(*resp) + oci_ie_len);
171 if (!resp) {
172 wpa_printf(MSG_DEBUG,
173 "Failed to allocate buffer for SA Query Response frame");
174 os_free(oci_ie);
175 return;
176 }
177
d4370eac
MP
178 wpa_printf(MSG_DEBUG, "IEEE 802.11: Sending SA Query Response to "
179 MACSTR, MAC2STR(sa));
180
f9da7505
MV
181 resp->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
182 WLAN_FC_STYPE_ACTION);
183 os_memcpy(resp->da, sa, ETH_ALEN);
184 os_memcpy(resp->sa, hapd->own_addr, ETH_ALEN);
185 os_memcpy(resp->bssid, hapd->own_addr, ETH_ALEN);
186 resp->u.action.category = WLAN_ACTION_SA_QUERY;
187 resp->u.action.u.sa_query_req.action = WLAN_SA_QUERY_RESPONSE;
188 os_memcpy(resp->u.action.u.sa_query_req.trans_id, trans_id,
d4370eac 189 WLAN_SA_QUERY_TR_ID_LEN);
f9da7505
MV
190 end = resp->u.action.u.sa_query_req.variable;
191#ifdef CONFIG_OCV
192 if (oci_ie_len > 0) {
193 os_memcpy(end, oci_ie, oci_ie_len);
194 end += oci_ie_len;
195 }
196#endif /* CONFIG_OCV */
37100274
JM
197 if (hostapd_drv_send_mlme(hapd, resp, end - (u8 *) resp, 0, NULL, 0, 0)
198 < 0)
61323e70 199 wpa_printf(MSG_INFO, "ieee80211_mgmt_sa_query_request: send failed");
f9da7505
MV
200
201 os_free(resp);
202 os_free(oci_ie);
d4370eac
MP
203}
204
205
f9da7505
MV
206void ieee802_11_sa_query_action(struct hostapd_data *hapd,
207 const struct ieee80211_mgmt *mgmt,
208 size_t len)
d4370eac
MP
209{
210 struct sta_info *sta;
211 int i;
f9da7505
MV
212 const u8 *sa = mgmt->sa;
213 const u8 action_type = mgmt->u.action.u.sa_query_resp.action;
214 const u8 *trans_id = mgmt->u.action.u.sa_query_resp.trans_id;
215
700b3f39
JM
216 if (((const u8 *) mgmt) + len <
217 mgmt->u.action.u.sa_query_resp.variable) {
218 wpa_printf(MSG_DEBUG,
219 "IEEE 802.11: Too short SA Query Action frame (len=%lu)",
220 (unsigned long) len);
221 return;
222 }
223
f9da7505
MV
224 sta = ap_get_sta(hapd, sa);
225
226#ifdef CONFIG_OCV
227 if (sta && wpa_auth_uses_ocv(sta->wpa_sm)) {
228 struct ieee802_11_elems elems;
229 struct wpa_channel_info ci;
230 int tx_chanwidth;
231 int tx_seg1_idx;
232 size_t ies_len;
233 const u8 *ies;
234
235 ies = mgmt->u.action.u.sa_query_resp.variable;
236 ies_len = len - (ies - (u8 *) mgmt);
237 if (ieee802_11_parse_elems(ies, ies_len, &elems, 1) ==
238 ParseFailed) {
239 wpa_printf(MSG_DEBUG,
240 "SA Query: Failed to parse elements");
241 return;
242 }
243
244 if (hostapd_drv_channel_info(hapd, &ci) != 0) {
245 wpa_printf(MSG_WARNING,
246 "Failed to get channel info to validate received OCI in SA Query Action frame");
247 return;
248 }
249
250 if (get_sta_tx_parameters(sta->wpa_sm,
251 channel_width_to_int(ci.chanwidth),
252 ci.seg1_idx, &tx_chanwidth,
253 &tx_seg1_idx) < 0)
254 return;
255
256 if (ocv_verify_tx_params(elems.oci, elems.oci_len, &ci,
257 tx_chanwidth, tx_seg1_idx) != 0) {
258 wpa_printf(MSG_WARNING, "%s", ocv_errorstr);
259 return;
260 }
261 }
262#endif /* CONFIG_OCV */
d4370eac
MP
263
264 if (action_type == WLAN_SA_QUERY_REQUEST) {
265 ieee802_11_send_sa_query_resp(hapd, sa, trans_id);
266 return;
267 }
268
269 if (action_type != WLAN_SA_QUERY_RESPONSE) {
270 wpa_printf(MSG_DEBUG, "IEEE 802.11: Unexpected SA Query "
271 "Action %d", action_type);
272 return;
273 }
274
275 wpa_printf(MSG_DEBUG, "IEEE 802.11: Received SA Query Response from "
276 MACSTR, MAC2STR(sa));
277 wpa_hexdump(MSG_DEBUG, "IEEE 802.11: SA Query Transaction ID",
278 trans_id, WLAN_SA_QUERY_TR_ID_LEN);
279
280 /* MLME-SAQuery.confirm */
281
d4370eac
MP
282 if (sta == NULL || sta->sa_query_trans_id == NULL) {
283 wpa_printf(MSG_DEBUG, "IEEE 802.11: No matching STA with "
284 "pending SA Query request found");
285 return;
286 }
287
288 for (i = 0; i < sta->sa_query_count; i++) {
289 if (os_memcmp(sta->sa_query_trans_id +
290 i * WLAN_SA_QUERY_TR_ID_LEN,
291 trans_id, WLAN_SA_QUERY_TR_ID_LEN) == 0)
292 break;
293 }
294
295 if (i >= sta->sa_query_count) {
296 wpa_printf(MSG_DEBUG, "IEEE 802.11: No matching SA Query "
297 "transaction identifier found");
298 return;
299 }
300
301 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
302 HOSTAPD_LEVEL_DEBUG,
303 "Reply to pending SA Query received");
304 ap_sta_stop_sa_query(hapd, sta);
305}
306
06c4d247 307
8cd6b7bc
JB
308static void hostapd_ext_capab_byte(struct hostapd_data *hapd, u8 *pos, int idx)
309{
310 *pos = 0x00;
311
312 switch (idx) {
313 case 0: /* Bits 0-7 */
db63757d
PS
314 if (hapd->iconf->obss_interval)
315 *pos |= 0x01; /* Bit 0 - Coexistence management */
6315bfdb
AO
316 if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_AP_CSA)
317 *pos |= 0x04; /* Bit 2 - Extended Channel Switching */
8cd6b7bc
JB
318 break;
319 case 1: /* Bits 8-15 */
7d597d46
KP
320 if (hapd->conf->proxy_arp)
321 *pos |= 0x10; /* Bit 12 - Proxy ARP */
d514b502
JM
322 if (hapd->conf->coloc_intf_reporting) {
323 /* Bit 13 - Collocated Interference Reporting */
324 *pos |= 0x20;
325 }
8cd6b7bc
JB
326 break;
327 case 2: /* Bits 16-23 */
328 if (hapd->conf->wnm_sleep_mode)
329 *pos |= 0x02; /* Bit 17 - WNM-Sleep Mode */
330 if (hapd->conf->bss_transition)
331 *pos |= 0x08; /* Bit 19 - BSS Transition */
332 break;
333 case 3: /* Bits 24-31 */
b5bf84ba 334#ifdef CONFIG_WNM_AP
8cd6b7bc 335 *pos |= 0x02; /* Bit 25 - SSID List */
b5bf84ba 336#endif /* CONFIG_WNM_AP */
8cd6b7bc
JB
337 if (hapd->conf->time_advertisement == 2)
338 *pos |= 0x08; /* Bit 27 - UTC TSF Offset */
339 if (hapd->conf->interworking)
340 *pos |= 0x80; /* Bit 31 - Interworking */
341 break;
342 case 4: /* Bits 32-39 */
c551700f
KP
343 if (hapd->conf->qos_map_set_len)
344 *pos |= 0x01; /* Bit 32 - QoS Map */
8cd6b7bc
JB
345 if (hapd->conf->tdls & TDLS_PROHIBIT)
346 *pos |= 0x40; /* Bit 38 - TDLS Prohibited */
347 if (hapd->conf->tdls & TDLS_PROHIBIT_CHAN_SWITCH) {
348 /* Bit 39 - TDLS Channel Switching Prohibited */
349 *pos |= 0x80;
350 }
351 break;
352 case 5: /* Bits 40-47 */
3fb17a95
JM
353#ifdef CONFIG_HS20
354 if (hapd->conf->hs20)
355 *pos |= 0x40; /* Bit 46 - WNM-Notification */
356#endif /* CONFIG_HS20 */
e5783434
JM
357#ifdef CONFIG_MBO
358 if (hapd->conf->mbo_enabled)
359 *pos |= 0x40; /* Bit 46 - WNM-Notification */
360#endif /* CONFIG_MBO */
8cd6b7bc
JB
361 break;
362 case 6: /* Bits 48-55 */
363 if (hapd->conf->ssid.utf8_ssid)
364 *pos |= 0x01; /* Bit 48 - UTF-8 SSID */
365 break;
f55acd90
JM
366 case 7: /* Bits 56-63 */
367 break;
faecb392
LD
368 case 8: /* Bits 64-71 */
369 if (hapd->conf->ftm_responder)
370 *pos |= 0x40; /* Bit 70 - FTM responder */
371 if (hapd->conf->ftm_initiator)
372 *pos |= 0x80; /* Bit 71 - FTM initiator */
703470bf 373 break;
f55acd90
JM
374 case 9: /* Bits 72-79 */
375#ifdef CONFIG_FILS
376 if ((hapd->conf->wpa & WPA_PROTO_RSN) &&
377 wpa_key_mgmt_fils(hapd->conf->wpa_key_mgmt))
378 *pos |= 0x01;
379#endif /* CONFIG_FILS */
faecb392 380 break;
42d30863
JM
381 case 10: /* Bits 80-87 */
382#ifdef CONFIG_SAE
383 if (hapd->conf->wpa &&
384 wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt)) {
385 int in_use = hostapd_sae_pw_id_in_use(hapd->conf);
386
387 if (in_use)
388 *pos |= 0x02; /* Bit 81 - SAE Password
389 * Identifiers In Use */
390 if (in_use == 2)
391 *pos |= 0x04; /* Bit 82 - SAE Password
392 * Identifiers Used Exclusively */
393 }
394#endif /* CONFIG_SAE */
395 break;
8cd6b7bc
JB
396 }
397}
398
399
06c4d247
JM
400u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid)
401{
402 u8 *pos = eid;
8cd6b7bc 403 u8 len = 0, i;
06c4d247 404
d7678a08
JM
405 if (hapd->conf->qos_map_set_len ||
406 (hapd->conf->tdls & (TDLS_PROHIBIT | TDLS_PROHIBIT_CHAN_SWITCH)))
06c4d247 407 len = 5;
d7678a08
JM
408 if (len < 4 &&
409 (hapd->conf->time_advertisement == 2 || hapd->conf->interworking))
06c4d247 410 len = 4;
d7678a08
JM
411 if (len < 3 &&
412 (hapd->conf->wnm_sleep_mode || hapd->conf->bss_transition))
c79938a5 413 len = 3;
d7678a08
JM
414 if (len < 1 &&
415 (hapd->iconf->obss_interval ||
416 (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_AP_CSA)))
db63757d 417 len = 1;
d7678a08
JM
418 if (len < 2 &&
419 (hapd->conf->proxy_arp || hapd->conf->coloc_intf_reporting))
420 len = 2;
b93c8509
JM
421 if (len < 7 && hapd->conf->ssid.utf8_ssid)
422 len = 7;
faecb392
LD
423 if (len < 9 &&
424 (hapd->conf->ftm_initiator || hapd->conf->ftm_responder))
425 len = 9;
b5bf84ba 426#ifdef CONFIG_WNM_AP
0a66ce3c
JM
427 if (len < 4)
428 len = 4;
b5bf84ba 429#endif /* CONFIG_WNM_AP */
3fb17a95
JM
430#ifdef CONFIG_HS20
431 if (hapd->conf->hs20 && len < 6)
432 len = 6;
433#endif /* CONFIG_HS20 */
e5783434
JM
434#ifdef CONFIG_MBO
435 if (hapd->conf->mbo_enabled && len < 6)
436 len = 6;
437#endif /* CONFIG_MBO */
f55acd90
JM
438#ifdef CONFIG_FILS
439 if ((!(hapd->conf->wpa & WPA_PROTO_RSN) ||
440 !wpa_key_mgmt_fils(hapd->conf->wpa_key_mgmt)) && len < 10)
441 len = 10;
442#endif /* CONFIG_FILS */
42d30863
JM
443#ifdef CONFIG_SAE
444 if (len < 11 && hapd->conf->wpa &&
445 wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt) &&
446 hostapd_sae_pw_id_in_use(hapd->conf))
447 len = 11;
448#endif /* CONFIG_SAE */
8cd6b7bc
JB
449 if (len < hapd->iface->extended_capa_len)
450 len = hapd->iface->extended_capa_len;
06c4d247
JM
451 if (len == 0)
452 return eid;
453
454 *pos++ = WLAN_EID_EXT_CAPAB;
455 *pos++ = len;
8cd6b7bc
JB
456 for (i = 0; i < len; i++, pos++) {
457 hostapd_ext_capab_byte(hapd, pos, i);
06c4d247 458
8cd6b7bc
JB
459 if (i < hapd->iface->extended_capa_len) {
460 *pos &= ~hapd->iface->extended_capa_mask[i];
461 *pos |= hapd->iface->extended_capa[i];
462 }
463 }
b93c8509 464
3db5439a
JM
465 while (len > 0 && eid[1 + len] == 0) {
466 len--;
467 eid[1] = len;
468 }
469 if (len == 0)
470 return eid;
471
472 return eid + 2 + len;
06c4d247
JM
473}
474
475
c551700f
KP
476u8 * hostapd_eid_qos_map_set(struct hostapd_data *hapd, u8 *eid)
477{
478 u8 *pos = eid;
479 u8 len = hapd->conf->qos_map_set_len;
480
481 if (!len)
482 return eid;
483
484 *pos++ = WLAN_EID_QOS_MAP_SET;
485 *pos++ = len;
486 os_memcpy(pos, hapd->conf->qos_map_set, len);
487 pos += len;
488
489 return pos;
490}
491
492
06c4d247
JM
493u8 * hostapd_eid_interworking(struct hostapd_data *hapd, u8 *eid)
494{
495 u8 *pos = eid;
496#ifdef CONFIG_INTERWORKING
497 u8 *len;
498
499 if (!hapd->conf->interworking)
500 return eid;
501
502 *pos++ = WLAN_EID_INTERWORKING;
503 len = pos++;
504
505 *pos = hapd->conf->access_network_type;
506 if (hapd->conf->internet)
507 *pos |= INTERWORKING_ANO_INTERNET;
508 if (hapd->conf->asra)
509 *pos |= INTERWORKING_ANO_ASRA;
510 if (hapd->conf->esr)
511 *pos |= INTERWORKING_ANO_ESR;
512 if (hapd->conf->uesa)
513 *pos |= INTERWORKING_ANO_UESA;
514 pos++;
515
516 if (hapd->conf->venue_info_set) {
517 *pos++ = hapd->conf->venue_group;
518 *pos++ = hapd->conf->venue_type;
519 }
520
521 if (!is_zero_ether_addr(hapd->conf->hessid)) {
522 os_memcpy(pos, hapd->conf->hessid, ETH_ALEN);
523 pos += ETH_ALEN;
524 }
525
526 *len = pos - len - 1;
527#endif /* CONFIG_INTERWORKING */
528
529 return pos;
530}
c7c178e1
JM
531
532
533u8 * hostapd_eid_adv_proto(struct hostapd_data *hapd, u8 *eid)
534{
535 u8 *pos = eid;
536#ifdef CONFIG_INTERWORKING
537
538 /* TODO: Separate configuration for ANQP? */
539 if (!hapd->conf->interworking)
540 return eid;
541
542 *pos++ = WLAN_EID_ADV_PROTO;
543 *pos++ = 2;
1d21e9dd 544 *pos++ = 0x7F; /* Query Response Length Limit | PAME-BI */
c7c178e1
JM
545 *pos++ = ACCESS_NETWORK_QUERY_PROTOCOL;
546#endif /* CONFIG_INTERWORKING */
547
548 return pos;
549}
4b2a77ab
JM
550
551
552u8 * hostapd_eid_roaming_consortium(struct hostapd_data *hapd, u8 *eid)
553{
554 u8 *pos = eid;
555#ifdef CONFIG_INTERWORKING
556 u8 *len;
557 unsigned int i, count;
558
559 if (!hapd->conf->interworking ||
560 hapd->conf->roaming_consortium == NULL ||
561 hapd->conf->roaming_consortium_count == 0)
562 return eid;
563
564 *pos++ = WLAN_EID_ROAMING_CONSORTIUM;
565 len = pos++;
566
567 /* Number of ANQP OIs (in addition to the max 3 listed here) */
568 if (hapd->conf->roaming_consortium_count > 3 + 255)
569 *pos++ = 255;
570 else if (hapd->conf->roaming_consortium_count > 3)
571 *pos++ = hapd->conf->roaming_consortium_count - 3;
572 else
573 *pos++ = 0;
574
575 /* OU #1 and #2 Lengths */
576 *pos = hapd->conf->roaming_consortium[0].len;
577 if (hapd->conf->roaming_consortium_count > 1)
578 *pos |= hapd->conf->roaming_consortium[1].len << 4;
579 pos++;
580
581 if (hapd->conf->roaming_consortium_count > 3)
582 count = 3;
583 else
584 count = hapd->conf->roaming_consortium_count;
585
586 for (i = 0; i < count; i++) {
587 os_memcpy(pos, hapd->conf->roaming_consortium[i].oi,
588 hapd->conf->roaming_consortium[i].len);
589 pos += hapd->conf->roaming_consortium[i].len;
590 }
591
592 *len = pos - len - 1;
593#endif /* CONFIG_INTERWORKING */
594
595 return pos;
596}
39b97072
JM
597
598
599u8 * hostapd_eid_time_adv(struct hostapd_data *hapd, u8 *eid)
600{
601 if (hapd->conf->time_advertisement != 2)
602 return eid;
603
604 if (hapd->time_adv == NULL &&
605 hostapd_update_time_adv(hapd) < 0)
606 return eid;
607
4c8a333b
JM
608 if (hapd->time_adv == NULL)
609 return eid;
610
39b97072
JM
611 os_memcpy(eid, wpabuf_head(hapd->time_adv),
612 wpabuf_len(hapd->time_adv));
613 eid += wpabuf_len(hapd->time_adv);
614
615 return eid;
616}
617
618
619u8 * hostapd_eid_time_zone(struct hostapd_data *hapd, u8 *eid)
620{
621 size_t len;
622
b375b04b 623 if (hapd->conf->time_advertisement != 2 || !hapd->conf->time_zone)
39b97072
JM
624 return eid;
625
626 len = os_strlen(hapd->conf->time_zone);
627
628 *eid++ = WLAN_EID_TIME_ZONE;
629 *eid++ = len;
630 os_memcpy(eid, hapd->conf->time_zone, len);
631 eid += len;
632
633 return eid;
634}
635
636
637int hostapd_update_time_adv(struct hostapd_data *hapd)
638{
639 const int elen = 2 + 1 + 10 + 5 + 1;
640 struct os_time t;
641 struct os_tm tm;
642 u8 *pos;
643
644 if (hapd->conf->time_advertisement != 2)
645 return 0;
646
647 if (os_get_time(&t) < 0 || os_gmtime(t.sec, &tm) < 0)
648 return -1;
649
650 if (!hapd->time_adv) {
651 hapd->time_adv = wpabuf_alloc(elen);
652 if (hapd->time_adv == NULL)
653 return -1;
654 pos = wpabuf_put(hapd->time_adv, elen);
655 } else
656 pos = wpabuf_mhead_u8(hapd->time_adv);
657
658 *pos++ = WLAN_EID_TIME_ADVERTISEMENT;
659 *pos++ = 1 + 10 + 5 + 1;
660
661 *pos++ = 2; /* UTC time at which the TSF timer is 0 */
662
663 /* Time Value at TSF 0 */
664 /* FIX: need to calculate this based on the current TSF value */
665 WPA_PUT_LE16(pos, tm.year); /* Year */
666 pos += 2;
667 *pos++ = tm.month; /* Month */
668 *pos++ = tm.day; /* Day of month */
669 *pos++ = tm.hour; /* Hours */
670 *pos++ = tm.min; /* Minutes */
671 *pos++ = tm.sec; /* Seconds */
672 WPA_PUT_LE16(pos, 0); /* Milliseconds (not used) */
673 pos += 2;
674 *pos++ = 0; /* Reserved */
675
676 /* Time Error */
677 /* TODO: fill in an estimate on the error */
678 *pos++ = 0;
679 *pos++ = 0;
680 *pos++ = 0;
681 *pos++ = 0;
682 *pos++ = 0;
683
684 *pos++ = hapd->time_update_counter++;
685
686 return 0;
687}
b6668734
JM
688
689
690u8 * hostapd_eid_bss_max_idle_period(struct hostapd_data *hapd, u8 *eid)
691{
692 u8 *pos = eid;
693
b5bf84ba 694#ifdef CONFIG_WNM_AP
b6668734
JM
695 if (hapd->conf->ap_max_inactivity > 0) {
696 unsigned int val;
697 *pos++ = WLAN_EID_BSS_MAX_IDLE_PERIOD;
698 *pos++ = 3;
699 val = hapd->conf->ap_max_inactivity;
700 if (val > 68000)
701 val = 68000;
702 val *= 1000;
703 val /= 1024;
704 if (val == 0)
705 val = 1;
706 if (val > 65535)
707 val = 65535;
708 WPA_PUT_LE16(pos, val);
709 pos += 2;
710 *pos++ = 0x00; /* TODO: Protected Keep-Alive Required */
711 }
b5bf84ba 712#endif /* CONFIG_WNM_AP */
b6668734
JM
713
714 return pos;
715}
fb9a1c3e
AS
716
717
718#ifdef CONFIG_MBO
719
076f1ea1
BL
720u8 * hostapd_eid_mbo_rssi_assoc_rej(struct hostapd_data *hapd, u8 *eid,
721 size_t len, int delta)
722{
723 u8 mbo[4];
724
725 mbo[0] = OCE_ATTR_ID_RSSI_BASED_ASSOC_REJECT;
726 mbo[1] = 2;
727 /* Delta RSSI */
728 mbo[2] = delta;
729 /* Retry delay */
730 mbo[3] = hapd->iconf->rssi_reject_assoc_timeout;
731
732 return eid + mbo_add_ie(eid, len, mbo, 4);
733}
734
735
fb9a1c3e
AS
736u8 * hostapd_eid_mbo(struct hostapd_data *hapd, u8 *eid, size_t len)
737{
65833d71 738 u8 mbo[9], *mbo_pos = mbo;
fb9a1c3e
AS
739 u8 *pos = eid;
740
0f0aa2a6
AB
741 if (!hapd->conf->mbo_enabled &&
742 !OCE_STA_CFON_ENABLED(hapd) && !OCE_AP_ENABLED(hapd))
fb9a1c3e
AS
743 return eid;
744
65833d71
AP
745 if (hapd->conf->mbo_enabled) {
746 *mbo_pos++ = MBO_ATTR_ID_AP_CAPA_IND;
747 *mbo_pos++ = 1;
748 /* Not Cellular aware */
749 *mbo_pos++ = 0;
750 }
fb9a1c3e 751
65833d71 752 if (hapd->conf->mbo_enabled && hapd->mbo_assoc_disallow) {
fb9a1c3e
AS
753 *mbo_pos++ = MBO_ATTR_ID_ASSOC_DISALLOW;
754 *mbo_pos++ = 1;
755 *mbo_pos++ = hapd->mbo_assoc_disallow;
756 }
757
0f0aa2a6 758 if (OCE_STA_CFON_ENABLED(hapd) || OCE_AP_ENABLED(hapd)) {
65833d71
AP
759 u8 ctrl;
760
761 ctrl = OCE_RELEASE;
0f0aa2a6 762 if (OCE_STA_CFON_ENABLED(hapd) && !OCE_AP_ENABLED(hapd))
65833d71
AP
763 ctrl |= OCE_IS_STA_CFON;
764
765 *mbo_pos++ = OCE_ATTR_ID_CAPA_IND;
766 *mbo_pos++ = 1;
767 *mbo_pos++ = ctrl;
768 }
769
fb9a1c3e
AS
770 pos += mbo_add_ie(pos, len, mbo, mbo_pos - mbo);
771
772 return pos;
773}
774
775
776u8 hostapd_mbo_ie_len(struct hostapd_data *hapd)
777{
65833d71
AP
778 u8 len;
779
0f0aa2a6
AB
780 if (!hapd->conf->mbo_enabled &&
781 !OCE_STA_CFON_ENABLED(hapd) && !OCE_AP_ENABLED(hapd))
fb9a1c3e
AS
782 return 0;
783
784 /*
785 * MBO IE header (6) + Capability Indication attribute (3) +
786 * Association Disallowed attribute (3) = 12
787 */
65833d71
AP
788 len = 6;
789 if (hapd->conf->mbo_enabled)
790 len += 3 + (hapd->mbo_assoc_disallow ? 3 : 0);
791
792 /* OCE capability indication attribute (3) */
0f0aa2a6 793 if (OCE_STA_CFON_ENABLED(hapd) || OCE_AP_ENABLED(hapd))
65833d71
AP
794 len += 3;
795
796 return len;
fb9a1c3e
AS
797}
798
799#endif /* CONFIG_MBO */
adf0478e
JM
800
801
18e3e9c6
AP
802#ifdef CONFIG_OWE
803static int hostapd_eid_owe_trans_enabled(struct hostapd_data *hapd)
804{
805 return hapd->conf->owe_transition_ssid_len > 0 &&
806 !is_zero_ether_addr(hapd->conf->owe_transition_bssid);
807}
808#endif /* CONFIG_OWE */
809
810
811size_t hostapd_eid_owe_trans_len(struct hostapd_data *hapd)
812{
813#ifdef CONFIG_OWE
814 if (!hostapd_eid_owe_trans_enabled(hapd))
815 return 0;
816 return 6 + ETH_ALEN + 1 + hapd->conf->owe_transition_ssid_len;
817#else /* CONFIG_OWE */
818 return 0;
819#endif /* CONFIG_OWE */
820}
821
822
823u8 * hostapd_eid_owe_trans(struct hostapd_data *hapd, u8 *eid,
824 size_t len)
825{
826#ifdef CONFIG_OWE
827 u8 *pos = eid;
828 size_t elen;
829
830 if (hapd->conf->owe_transition_ifname[0] &&
831 !hostapd_eid_owe_trans_enabled(hapd))
832 hostapd_owe_trans_get_info(hapd);
833
834 if (!hostapd_eid_owe_trans_enabled(hapd))
835 return pos;
836
837 elen = hostapd_eid_owe_trans_len(hapd);
838 if (len < elen) {
839 wpa_printf(MSG_DEBUG,
840 "OWE: Not enough room in the buffer for OWE IE");
841 return pos;
842 }
843
844 *pos++ = WLAN_EID_VENDOR_SPECIFIC;
845 *pos++ = elen - 2;
846 WPA_PUT_BE24(pos, OUI_WFA);
847 pos += 3;
848 *pos++ = OWE_OUI_TYPE;
849 os_memcpy(pos, hapd->conf->owe_transition_bssid, ETH_ALEN);
850 pos += ETH_ALEN;
851 *pos++ = hapd->conf->owe_transition_ssid_len;
852 os_memcpy(pos, hapd->conf->owe_transition_ssid,
853 hapd->conf->owe_transition_ssid_len);
854 pos += hapd->conf->owe_transition_ssid_len;
855
856 return pos;
857#else /* CONFIG_OWE */
858 return eid;
859#endif /* CONFIG_OWE */
860}
861
862
adf0478e
JM
863void ap_copy_sta_supp_op_classes(struct sta_info *sta,
864 const u8 *supp_op_classes,
865 size_t supp_op_classes_len)
866{
867 if (!supp_op_classes)
868 return;
869 os_free(sta->supp_op_classes);
870 sta->supp_op_classes = os_malloc(1 + supp_op_classes_len);
871 if (!sta->supp_op_classes)
872 return;
873
874 sta->supp_op_classes[0] = supp_op_classes_len;
875 os_memcpy(sta->supp_op_classes + 1, supp_op_classes,
876 supp_op_classes_len);
877}
198a942c
JM
878
879
880u8 * hostapd_eid_fils_indic(struct hostapd_data *hapd, u8 *eid, int hessid)
881{
882 u8 *pos = eid;
883#ifdef CONFIG_FILS
884 u8 *len;
885 u16 fils_info = 0;
26bf70e3
JM
886 size_t realms;
887 struct fils_realm *realm;
198a942c
JM
888
889 if (!(hapd->conf->wpa & WPA_PROTO_RSN) ||
890 !wpa_key_mgmt_fils(hapd->conf->wpa_key_mgmt))
891 return pos;
892
26bf70e3
JM
893 realms = dl_list_len(&hapd->conf->fils_realms);
894 if (realms > 7)
895 realms = 7; /* 3 bit count field limits this to max 7 */
896
198a942c
JM
897 *pos++ = WLAN_EID_FILS_INDICATION;
898 len = pos++;
899 /* TODO: B0..B2: Number of Public Key Identifiers */
94f66e8a 900 if (hapd->conf->erp_domain) {
94f66e8a 901 /* B3..B5: Number of Realm Identifiers */
26bf70e3 902 fils_info |= realms << 3;
94f66e8a 903 }
198a942c
JM
904 /* TODO: B6: FILS IP Address Configuration */
905 if (hapd->conf->fils_cache_id_set)
906 fils_info |= BIT(7);
907 if (hessid && !is_zero_ether_addr(hapd->conf->hessid))
908 fils_info |= BIT(8); /* HESSID Included */
909 /* FILS Shared Key Authentication without PFS Supported */
910 fils_info |= BIT(9);
1764559e
JM
911 if (hapd->conf->fils_dh_group) {
912 /* FILS Shared Key Authentication with PFS Supported */
913 fils_info |= BIT(10);
914 }
198a942c
JM
915 /* TODO: B11: FILS Public Key Authentication Supported */
916 /* B12..B15: Reserved */
917 WPA_PUT_LE16(pos, fils_info);
918 pos += 2;
919 if (hapd->conf->fils_cache_id_set) {
920 os_memcpy(pos, hapd->conf->fils_cache_id, FILS_CACHE_ID_LEN);
921 pos += FILS_CACHE_ID_LEN;
922 }
923 if (hessid && !is_zero_ether_addr(hapd->conf->hessid)) {
924 os_memcpy(pos, hapd->conf->hessid, ETH_ALEN);
925 pos += ETH_ALEN;
926 }
26bf70e3
JM
927
928 dl_list_for_each(realm, &hapd->conf->fils_realms, struct fils_realm,
929 list) {
930 if (realms == 0)
931 break;
932 realms--;
933 os_memcpy(pos, realm->hash, 2);
94f66e8a
JM
934 pos += 2;
935 }
198a942c
JM
936 *len = pos - len - 1;
937#endif /* CONFIG_FILS */
938
939 return pos;
940}
1034f67b
MV
941
942
943#ifdef CONFIG_OCV
944int get_tx_parameters(struct sta_info *sta, int ap_max_chanwidth,
945 int ap_seg1_idx, int *bandwidth, int *seg1_idx)
946{
947 int ht_40mhz = 0;
948 int vht_80p80 = 0;
949 int requested_bw;
950
951 if (sta->ht_capabilities)
952 ht_40mhz = !!(sta->ht_capabilities->ht_capabilities_info &
953 HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET);
954
955 if (sta->vht_operation) {
956 struct ieee80211_vht_operation *oper = sta->vht_operation;
957
958 /*
959 * If a VHT Operation element was present, use it to determine
960 * the supported channel bandwidth.
961 */
962 if (oper->vht_op_info_chwidth == 0) {
963 requested_bw = ht_40mhz ? 40 : 20;
964 } else if (oper->vht_op_info_chan_center_freq_seg1_idx == 0) {
965 requested_bw = 80;
966 } else {
967 int diff;
968
969 requested_bw = 160;
970 diff = abs((int)
971 oper->vht_op_info_chan_center_freq_seg0_idx -
972 (int)
973 oper->vht_op_info_chan_center_freq_seg1_idx);
974 vht_80p80 = oper->vht_op_info_chan_center_freq_seg1_idx
975 != 0 && diff > 16;
976 }
977 } else if (sta->vht_capabilities) {
978 struct ieee80211_vht_capabilities *capab;
979 int vht_chanwidth;
980
981 capab = sta->vht_capabilities;
982
983 /*
984 * If only the VHT Capabilities element is present (e.g., for
985 * normal clients), use it to determine the supported channel
986 * bandwidth.
987 */
988 vht_chanwidth = capab->vht_capabilities_info &
989 VHT_CAP_SUPP_CHAN_WIDTH_MASK;
990 vht_80p80 = capab->vht_capabilities_info &
991 VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ;
992
993 /* TODO: Also take into account Extended NSS BW Support field */
994 requested_bw = vht_chanwidth ? 160 : 80;
995 } else {
996 requested_bw = ht_40mhz ? 40 : 20;
997 }
998
999 *bandwidth = requested_bw < ap_max_chanwidth ?
1000 requested_bw : ap_max_chanwidth;
1001
1002 *seg1_idx = 0;
1003 if (ap_seg1_idx && vht_80p80)
1004 *seg1_idx = ap_seg1_idx;
1005
1006 return 0;
1007}
1008#endif /* CONFIG_OCV */
cb992597
JM
1009
1010
1011u8 * hostapd_eid_rsnxe(struct hostapd_data *hapd, u8 *eid, size_t len)
1012{
1013 u8 *pos = eid;
1014
1015 if (!(hapd->conf->wpa & WPA_PROTO_RSN) ||
9f50538e 1016 !wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt) ||
e36a5894
JM
1017 (hapd->conf->sae_pwe != 1 && hapd->conf->sae_pwe != 2 &&
1018 !hostapd_sae_pw_id_in_use(hapd->conf)) ||
641d79f1 1019 hapd->conf->sae_pwe == 3 ||
cb992597
JM
1020 len < 3)
1021 return pos;
1022
1023 *pos++ = WLAN_EID_RSNX;
1024 *pos++ = 1;
1025 /* bits 0-3 = 0 since only one octet of Extended RSN Capabilities is
1026 * used for now */
1027 *pos++ = BIT(WLAN_RSNX_CAPAB_SAE_H2E);
1028
1029 return pos;
1030}