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