1f05cddf9SRui Paulo /* 2f05cddf9SRui Paulo * hostapd / IEEE 802.11 Management 3f05cddf9SRui Paulo * Copyright (c) 2002-2012, Jouni Malinen <j@w1.fi> 4f05cddf9SRui Paulo * 5f05cddf9SRui Paulo * This software may be distributed under the terms of the BSD license. 6f05cddf9SRui Paulo * See README for more details. 7f05cddf9SRui Paulo */ 8f05cddf9SRui Paulo 9f05cddf9SRui Paulo #include "utils/includes.h" 10f05cddf9SRui Paulo 11f05cddf9SRui Paulo #include "utils/common.h" 12f05cddf9SRui Paulo #include "common/ieee802_11_defs.h" 13f05cddf9SRui Paulo #include "hostapd.h" 14f05cddf9SRui Paulo #include "sta_info.h" 15f05cddf9SRui Paulo #include "ap_config.h" 16f05cddf9SRui Paulo #include "ap_drv_ops.h" 17f05cddf9SRui Paulo #include "ieee802_11.h" 18f05cddf9SRui Paulo 19f05cddf9SRui Paulo 20f05cddf9SRui Paulo #ifdef CONFIG_IEEE80211W 21f05cddf9SRui Paulo 22f05cddf9SRui Paulo u8 * hostapd_eid_assoc_comeback_time(struct hostapd_data *hapd, 23f05cddf9SRui Paulo struct sta_info *sta, u8 *eid) 24f05cddf9SRui Paulo { 25f05cddf9SRui Paulo u8 *pos = eid; 26f05cddf9SRui Paulo u32 timeout, tu; 275b9c547cSRui Paulo struct os_reltime now, passed; 28f05cddf9SRui Paulo 29f05cddf9SRui Paulo *pos++ = WLAN_EID_TIMEOUT_INTERVAL; 30f05cddf9SRui Paulo *pos++ = 5; 31f05cddf9SRui Paulo *pos++ = WLAN_TIMEOUT_ASSOC_COMEBACK; 325b9c547cSRui Paulo os_get_reltime(&now); 335b9c547cSRui Paulo os_reltime_sub(&now, &sta->sa_query_start, &passed); 34f05cddf9SRui Paulo tu = (passed.sec * 1000000 + passed.usec) / 1024; 35f05cddf9SRui Paulo if (hapd->conf->assoc_sa_query_max_timeout > tu) 36f05cddf9SRui Paulo timeout = hapd->conf->assoc_sa_query_max_timeout - tu; 37f05cddf9SRui Paulo else 38f05cddf9SRui Paulo timeout = 0; 39f05cddf9SRui Paulo if (timeout < hapd->conf->assoc_sa_query_max_timeout) 40f05cddf9SRui Paulo timeout++; /* add some extra time for local timers */ 41f05cddf9SRui Paulo WPA_PUT_LE32(pos, timeout); 42f05cddf9SRui Paulo pos += 4; 43f05cddf9SRui Paulo 44f05cddf9SRui Paulo return pos; 45f05cddf9SRui Paulo } 46f05cddf9SRui Paulo 47f05cddf9SRui Paulo 48f05cddf9SRui Paulo /* MLME-SAQuery.request */ 49f05cddf9SRui Paulo void ieee802_11_send_sa_query_req(struct hostapd_data *hapd, 50f05cddf9SRui Paulo const u8 *addr, const u8 *trans_id) 51f05cddf9SRui Paulo { 52f05cddf9SRui Paulo struct ieee80211_mgmt mgmt; 53f05cddf9SRui Paulo u8 *end; 54f05cddf9SRui Paulo 55f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "IEEE 802.11: Sending SA Query Request to " 56f05cddf9SRui Paulo MACSTR, MAC2STR(addr)); 57f05cddf9SRui Paulo wpa_hexdump(MSG_DEBUG, "IEEE 802.11: SA Query Transaction ID", 58f05cddf9SRui Paulo trans_id, WLAN_SA_QUERY_TR_ID_LEN); 59f05cddf9SRui Paulo 60f05cddf9SRui Paulo os_memset(&mgmt, 0, sizeof(mgmt)); 61f05cddf9SRui Paulo mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, 62f05cddf9SRui Paulo WLAN_FC_STYPE_ACTION); 63f05cddf9SRui Paulo os_memcpy(mgmt.da, addr, ETH_ALEN); 64f05cddf9SRui Paulo os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN); 65f05cddf9SRui Paulo os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN); 66f05cddf9SRui Paulo mgmt.u.action.category = WLAN_ACTION_SA_QUERY; 67f05cddf9SRui Paulo mgmt.u.action.u.sa_query_req.action = WLAN_SA_QUERY_REQUEST; 68f05cddf9SRui Paulo os_memcpy(mgmt.u.action.u.sa_query_req.trans_id, trans_id, 69f05cddf9SRui Paulo WLAN_SA_QUERY_TR_ID_LEN); 70f05cddf9SRui Paulo end = mgmt.u.action.u.sa_query_req.trans_id + WLAN_SA_QUERY_TR_ID_LEN; 71f05cddf9SRui Paulo if (hostapd_drv_send_mlme(hapd, &mgmt, end - (u8 *) &mgmt, 0) < 0) 725b9c547cSRui Paulo wpa_printf(MSG_INFO, "ieee802_11_send_sa_query_req: send failed"); 73f05cddf9SRui Paulo } 74f05cddf9SRui Paulo 75f05cddf9SRui Paulo 76f05cddf9SRui Paulo static void ieee802_11_send_sa_query_resp(struct hostapd_data *hapd, 77f05cddf9SRui Paulo const u8 *sa, const u8 *trans_id) 78f05cddf9SRui Paulo { 79f05cddf9SRui Paulo struct sta_info *sta; 80f05cddf9SRui Paulo struct ieee80211_mgmt resp; 81f05cddf9SRui Paulo u8 *end; 82f05cddf9SRui Paulo 83f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "IEEE 802.11: Received SA Query Request from " 84f05cddf9SRui Paulo MACSTR, MAC2STR(sa)); 85f05cddf9SRui Paulo wpa_hexdump(MSG_DEBUG, "IEEE 802.11: SA Query Transaction ID", 86f05cddf9SRui Paulo trans_id, WLAN_SA_QUERY_TR_ID_LEN); 87f05cddf9SRui Paulo 88f05cddf9SRui Paulo sta = ap_get_sta(hapd, sa); 89f05cddf9SRui Paulo if (sta == NULL || !(sta->flags & WLAN_STA_ASSOC)) { 90f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "IEEE 802.11: Ignore SA Query Request " 91f05cddf9SRui Paulo "from unassociated STA " MACSTR, MAC2STR(sa)); 92f05cddf9SRui Paulo return; 93f05cddf9SRui Paulo } 94f05cddf9SRui Paulo 95f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "IEEE 802.11: Sending SA Query Response to " 96f05cddf9SRui Paulo MACSTR, MAC2STR(sa)); 97f05cddf9SRui Paulo 98f05cddf9SRui Paulo os_memset(&resp, 0, sizeof(resp)); 99f05cddf9SRui Paulo resp.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, 100f05cddf9SRui Paulo WLAN_FC_STYPE_ACTION); 101f05cddf9SRui Paulo os_memcpy(resp.da, sa, ETH_ALEN); 102f05cddf9SRui Paulo os_memcpy(resp.sa, hapd->own_addr, ETH_ALEN); 103f05cddf9SRui Paulo os_memcpy(resp.bssid, hapd->own_addr, ETH_ALEN); 104f05cddf9SRui Paulo resp.u.action.category = WLAN_ACTION_SA_QUERY; 105f05cddf9SRui Paulo resp.u.action.u.sa_query_req.action = WLAN_SA_QUERY_RESPONSE; 106f05cddf9SRui Paulo os_memcpy(resp.u.action.u.sa_query_req.trans_id, trans_id, 107f05cddf9SRui Paulo WLAN_SA_QUERY_TR_ID_LEN); 108f05cddf9SRui Paulo end = resp.u.action.u.sa_query_req.trans_id + WLAN_SA_QUERY_TR_ID_LEN; 109f05cddf9SRui Paulo if (hostapd_drv_send_mlme(hapd, &resp, end - (u8 *) &resp, 0) < 0) 1105b9c547cSRui Paulo wpa_printf(MSG_INFO, "ieee80211_mgmt_sa_query_request: send failed"); 111f05cddf9SRui Paulo } 112f05cddf9SRui Paulo 113f05cddf9SRui Paulo 114f05cddf9SRui Paulo void ieee802_11_sa_query_action(struct hostapd_data *hapd, const u8 *sa, 115f05cddf9SRui Paulo const u8 action_type, const u8 *trans_id) 116f05cddf9SRui Paulo { 117f05cddf9SRui Paulo struct sta_info *sta; 118f05cddf9SRui Paulo int i; 119f05cddf9SRui Paulo 120f05cddf9SRui Paulo if (action_type == WLAN_SA_QUERY_REQUEST) { 121f05cddf9SRui Paulo ieee802_11_send_sa_query_resp(hapd, sa, trans_id); 122f05cddf9SRui Paulo return; 123f05cddf9SRui Paulo } 124f05cddf9SRui Paulo 125f05cddf9SRui Paulo if (action_type != WLAN_SA_QUERY_RESPONSE) { 126f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "IEEE 802.11: Unexpected SA Query " 127f05cddf9SRui Paulo "Action %d", action_type); 128f05cddf9SRui Paulo return; 129f05cddf9SRui Paulo } 130f05cddf9SRui Paulo 131f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "IEEE 802.11: Received SA Query Response from " 132f05cddf9SRui Paulo MACSTR, MAC2STR(sa)); 133f05cddf9SRui Paulo wpa_hexdump(MSG_DEBUG, "IEEE 802.11: SA Query Transaction ID", 134f05cddf9SRui Paulo trans_id, WLAN_SA_QUERY_TR_ID_LEN); 135f05cddf9SRui Paulo 136f05cddf9SRui Paulo /* MLME-SAQuery.confirm */ 137f05cddf9SRui Paulo 138f05cddf9SRui Paulo sta = ap_get_sta(hapd, sa); 139f05cddf9SRui Paulo if (sta == NULL || sta->sa_query_trans_id == NULL) { 140f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "IEEE 802.11: No matching STA with " 141f05cddf9SRui Paulo "pending SA Query request found"); 142f05cddf9SRui Paulo return; 143f05cddf9SRui Paulo } 144f05cddf9SRui Paulo 145f05cddf9SRui Paulo for (i = 0; i < sta->sa_query_count; i++) { 146f05cddf9SRui Paulo if (os_memcmp(sta->sa_query_trans_id + 147f05cddf9SRui Paulo i * WLAN_SA_QUERY_TR_ID_LEN, 148f05cddf9SRui Paulo trans_id, WLAN_SA_QUERY_TR_ID_LEN) == 0) 149f05cddf9SRui Paulo break; 150f05cddf9SRui Paulo } 151f05cddf9SRui Paulo 152f05cddf9SRui Paulo if (i >= sta->sa_query_count) { 153f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "IEEE 802.11: No matching SA Query " 154f05cddf9SRui Paulo "transaction identifier found"); 155f05cddf9SRui Paulo return; 156f05cddf9SRui Paulo } 157f05cddf9SRui Paulo 158f05cddf9SRui Paulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, 159f05cddf9SRui Paulo HOSTAPD_LEVEL_DEBUG, 160f05cddf9SRui Paulo "Reply to pending SA Query received"); 161f05cddf9SRui Paulo ap_sta_stop_sa_query(hapd, sta); 162f05cddf9SRui Paulo } 163f05cddf9SRui Paulo 164f05cddf9SRui Paulo #endif /* CONFIG_IEEE80211W */ 165f05cddf9SRui Paulo 166f05cddf9SRui Paulo 1675b9c547cSRui Paulo static void hostapd_ext_capab_byte(struct hostapd_data *hapd, u8 *pos, int idx) 168f05cddf9SRui Paulo { 169f05cddf9SRui Paulo *pos = 0x00; 1705b9c547cSRui Paulo 1715b9c547cSRui Paulo switch (idx) { 1725b9c547cSRui Paulo case 0: /* Bits 0-7 */ 1735b9c547cSRui Paulo if (hapd->iconf->obss_interval) 1745b9c547cSRui Paulo *pos |= 0x01; /* Bit 0 - Coexistence management */ 175780fb4a2SCy Schubert if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_AP_CSA) 176780fb4a2SCy Schubert *pos |= 0x04; /* Bit 2 - Extended Channel Switching */ 1775b9c547cSRui Paulo break; 1785b9c547cSRui Paulo case 1: /* Bits 8-15 */ 1795b9c547cSRui Paulo if (hapd->conf->proxy_arp) 1805b9c547cSRui Paulo *pos |= 0x10; /* Bit 12 - Proxy ARP */ 181*85732ac8SCy Schubert if (hapd->conf->coloc_intf_reporting) { 182*85732ac8SCy Schubert /* Bit 13 - Collocated Interference Reporting */ 183*85732ac8SCy Schubert *pos |= 0x20; 184*85732ac8SCy Schubert } 1855b9c547cSRui Paulo break; 1865b9c547cSRui Paulo case 2: /* Bits 16-23 */ 187f05cddf9SRui Paulo if (hapd->conf->wnm_sleep_mode) 188f05cddf9SRui Paulo *pos |= 0x02; /* Bit 17 - WNM-Sleep Mode */ 189f05cddf9SRui Paulo if (hapd->conf->bss_transition) 190f05cddf9SRui Paulo *pos |= 0x08; /* Bit 19 - BSS Transition */ 1915b9c547cSRui Paulo break; 1925b9c547cSRui Paulo case 3: /* Bits 24-31 */ 193*85732ac8SCy Schubert #ifdef CONFIG_WNM_AP 194f05cddf9SRui Paulo *pos |= 0x02; /* Bit 25 - SSID List */ 195*85732ac8SCy Schubert #endif /* CONFIG_WNM_AP */ 196f05cddf9SRui Paulo if (hapd->conf->time_advertisement == 2) 197f05cddf9SRui Paulo *pos |= 0x08; /* Bit 27 - UTC TSF Offset */ 198f05cddf9SRui Paulo if (hapd->conf->interworking) 199f05cddf9SRui Paulo *pos |= 0x80; /* Bit 31 - Interworking */ 2005b9c547cSRui Paulo break; 2015b9c547cSRui Paulo case 4: /* Bits 32-39 */ 2025b9c547cSRui Paulo if (hapd->conf->qos_map_set_len) 2035b9c547cSRui Paulo *pos |= 0x01; /* Bit 32 - QoS Map */ 204f05cddf9SRui Paulo if (hapd->conf->tdls & TDLS_PROHIBIT) 205f05cddf9SRui Paulo *pos |= 0x40; /* Bit 38 - TDLS Prohibited */ 2065b9c547cSRui Paulo if (hapd->conf->tdls & TDLS_PROHIBIT_CHAN_SWITCH) { 2075b9c547cSRui Paulo /* Bit 39 - TDLS Channel Switching Prohibited */ 2085b9c547cSRui Paulo *pos |= 0x80; 2095b9c547cSRui Paulo } 2105b9c547cSRui Paulo break; 2115b9c547cSRui Paulo case 5: /* Bits 40-47 */ 2125b9c547cSRui Paulo #ifdef CONFIG_HS20 2135b9c547cSRui Paulo if (hapd->conf->hs20) 2145b9c547cSRui Paulo *pos |= 0x40; /* Bit 46 - WNM-Notification */ 2155b9c547cSRui Paulo #endif /* CONFIG_HS20 */ 216780fb4a2SCy Schubert #ifdef CONFIG_MBO 217780fb4a2SCy Schubert if (hapd->conf->mbo_enabled) 218780fb4a2SCy Schubert *pos |= 0x40; /* Bit 46 - WNM-Notification */ 219780fb4a2SCy Schubert #endif /* CONFIG_MBO */ 2205b9c547cSRui Paulo break; 2215b9c547cSRui Paulo case 6: /* Bits 48-55 */ 222f05cddf9SRui Paulo if (hapd->conf->ssid.utf8_ssid) 223f05cddf9SRui Paulo *pos |= 0x01; /* Bit 48 - UTF-8 SSID */ 2245b9c547cSRui Paulo break; 225*85732ac8SCy Schubert case 7: /* Bits 56-63 */ 226*85732ac8SCy Schubert break; 227780fb4a2SCy Schubert case 8: /* Bits 64-71 */ 228780fb4a2SCy Schubert if (hapd->conf->ftm_responder) 229780fb4a2SCy Schubert *pos |= 0x40; /* Bit 70 - FTM responder */ 230780fb4a2SCy Schubert if (hapd->conf->ftm_initiator) 231780fb4a2SCy Schubert *pos |= 0x80; /* Bit 71 - FTM initiator */ 232780fb4a2SCy Schubert break; 233*85732ac8SCy Schubert case 9: /* Bits 72-79 */ 234*85732ac8SCy Schubert #ifdef CONFIG_FILS 235*85732ac8SCy Schubert if ((hapd->conf->wpa & WPA_PROTO_RSN) && 236*85732ac8SCy Schubert wpa_key_mgmt_fils(hapd->conf->wpa_key_mgmt)) 237*85732ac8SCy Schubert *pos |= 0x01; 238*85732ac8SCy Schubert #endif /* CONFIG_FILS */ 239*85732ac8SCy Schubert break; 2405b9c547cSRui Paulo } 2415b9c547cSRui Paulo } 2425b9c547cSRui Paulo 2435b9c547cSRui Paulo 2445b9c547cSRui Paulo u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid) 2455b9c547cSRui Paulo { 2465b9c547cSRui Paulo u8 *pos = eid; 2475b9c547cSRui Paulo u8 len = 0, i; 2485b9c547cSRui Paulo 2495b9c547cSRui Paulo if (hapd->conf->tdls & (TDLS_PROHIBIT | TDLS_PROHIBIT_CHAN_SWITCH)) 2505b9c547cSRui Paulo len = 5; 2515b9c547cSRui Paulo if (len < 4 && hapd->conf->interworking) 2525b9c547cSRui Paulo len = 4; 2535b9c547cSRui Paulo if (len < 3 && hapd->conf->wnm_sleep_mode) 2545b9c547cSRui Paulo len = 3; 2555b9c547cSRui Paulo if (len < 1 && hapd->iconf->obss_interval) 2565b9c547cSRui Paulo len = 1; 2575b9c547cSRui Paulo if (len < 7 && hapd->conf->ssid.utf8_ssid) 2585b9c547cSRui Paulo len = 7; 259780fb4a2SCy Schubert if (len < 9 && 260780fb4a2SCy Schubert (hapd->conf->ftm_initiator || hapd->conf->ftm_responder)) 261780fb4a2SCy Schubert len = 9; 262*85732ac8SCy Schubert #ifdef CONFIG_WNM_AP 2635b9c547cSRui Paulo if (len < 4) 2645b9c547cSRui Paulo len = 4; 265*85732ac8SCy Schubert #endif /* CONFIG_WNM_AP */ 2665b9c547cSRui Paulo #ifdef CONFIG_HS20 2675b9c547cSRui Paulo if (hapd->conf->hs20 && len < 6) 2685b9c547cSRui Paulo len = 6; 2695b9c547cSRui Paulo #endif /* CONFIG_HS20 */ 270780fb4a2SCy Schubert #ifdef CONFIG_MBO 271780fb4a2SCy Schubert if (hapd->conf->mbo_enabled && len < 6) 272780fb4a2SCy Schubert len = 6; 273780fb4a2SCy Schubert #endif /* CONFIG_MBO */ 274*85732ac8SCy Schubert #ifdef CONFIG_FILS 275*85732ac8SCy Schubert if ((!(hapd->conf->wpa & WPA_PROTO_RSN) || 276*85732ac8SCy Schubert !wpa_key_mgmt_fils(hapd->conf->wpa_key_mgmt)) && len < 10) 277*85732ac8SCy Schubert len = 10; 278*85732ac8SCy Schubert #endif /* CONFIG_FILS */ 2795b9c547cSRui Paulo if (len < hapd->iface->extended_capa_len) 2805b9c547cSRui Paulo len = hapd->iface->extended_capa_len; 2815b9c547cSRui Paulo if (len == 0) 2825b9c547cSRui Paulo return eid; 2835b9c547cSRui Paulo 2845b9c547cSRui Paulo *pos++ = WLAN_EID_EXT_CAPAB; 2855b9c547cSRui Paulo *pos++ = len; 2865b9c547cSRui Paulo for (i = 0; i < len; i++, pos++) { 2875b9c547cSRui Paulo hostapd_ext_capab_byte(hapd, pos, i); 2885b9c547cSRui Paulo 2895b9c547cSRui Paulo if (i < hapd->iface->extended_capa_len) { 2905b9c547cSRui Paulo *pos &= ~hapd->iface->extended_capa_mask[i]; 2915b9c547cSRui Paulo *pos |= hapd->iface->extended_capa[i]; 2925b9c547cSRui Paulo } 2935b9c547cSRui Paulo } 2945b9c547cSRui Paulo 2955b9c547cSRui Paulo while (len > 0 && eid[1 + len] == 0) { 2965b9c547cSRui Paulo len--; 2975b9c547cSRui Paulo eid[1] = len; 2985b9c547cSRui Paulo } 2995b9c547cSRui Paulo if (len == 0) 3005b9c547cSRui Paulo return eid; 3015b9c547cSRui Paulo 3025b9c547cSRui Paulo return eid + 2 + len; 3035b9c547cSRui Paulo } 3045b9c547cSRui Paulo 3055b9c547cSRui Paulo 3065b9c547cSRui Paulo u8 * hostapd_eid_qos_map_set(struct hostapd_data *hapd, u8 *eid) 3075b9c547cSRui Paulo { 3085b9c547cSRui Paulo u8 *pos = eid; 3095b9c547cSRui Paulo u8 len = hapd->conf->qos_map_set_len; 3105b9c547cSRui Paulo 3115b9c547cSRui Paulo if (!len) 3125b9c547cSRui Paulo return eid; 3135b9c547cSRui Paulo 3145b9c547cSRui Paulo *pos++ = WLAN_EID_QOS_MAP_SET; 3155b9c547cSRui Paulo *pos++ = len; 3165b9c547cSRui Paulo os_memcpy(pos, hapd->conf->qos_map_set, len); 3175b9c547cSRui Paulo pos += len; 318f05cddf9SRui Paulo 319f05cddf9SRui Paulo return pos; 320f05cddf9SRui Paulo } 321f05cddf9SRui Paulo 322f05cddf9SRui Paulo 323f05cddf9SRui Paulo u8 * hostapd_eid_interworking(struct hostapd_data *hapd, u8 *eid) 324f05cddf9SRui Paulo { 325f05cddf9SRui Paulo u8 *pos = eid; 326f05cddf9SRui Paulo #ifdef CONFIG_INTERWORKING 327f05cddf9SRui Paulo u8 *len; 328f05cddf9SRui Paulo 329f05cddf9SRui Paulo if (!hapd->conf->interworking) 330f05cddf9SRui Paulo return eid; 331f05cddf9SRui Paulo 332f05cddf9SRui Paulo *pos++ = WLAN_EID_INTERWORKING; 333f05cddf9SRui Paulo len = pos++; 334f05cddf9SRui Paulo 335f05cddf9SRui Paulo *pos = hapd->conf->access_network_type; 336f05cddf9SRui Paulo if (hapd->conf->internet) 337f05cddf9SRui Paulo *pos |= INTERWORKING_ANO_INTERNET; 338f05cddf9SRui Paulo if (hapd->conf->asra) 339f05cddf9SRui Paulo *pos |= INTERWORKING_ANO_ASRA; 340f05cddf9SRui Paulo if (hapd->conf->esr) 341f05cddf9SRui Paulo *pos |= INTERWORKING_ANO_ESR; 342f05cddf9SRui Paulo if (hapd->conf->uesa) 343f05cddf9SRui Paulo *pos |= INTERWORKING_ANO_UESA; 344f05cddf9SRui Paulo pos++; 345f05cddf9SRui Paulo 346f05cddf9SRui Paulo if (hapd->conf->venue_info_set) { 347f05cddf9SRui Paulo *pos++ = hapd->conf->venue_group; 348f05cddf9SRui Paulo *pos++ = hapd->conf->venue_type; 349f05cddf9SRui Paulo } 350f05cddf9SRui Paulo 351f05cddf9SRui Paulo if (!is_zero_ether_addr(hapd->conf->hessid)) { 352f05cddf9SRui Paulo os_memcpy(pos, hapd->conf->hessid, ETH_ALEN); 353f05cddf9SRui Paulo pos += ETH_ALEN; 354f05cddf9SRui Paulo } 355f05cddf9SRui Paulo 356f05cddf9SRui Paulo *len = pos - len - 1; 357f05cddf9SRui Paulo #endif /* CONFIG_INTERWORKING */ 358f05cddf9SRui Paulo 359f05cddf9SRui Paulo return pos; 360f05cddf9SRui Paulo } 361f05cddf9SRui Paulo 362f05cddf9SRui Paulo 363f05cddf9SRui Paulo u8 * hostapd_eid_adv_proto(struct hostapd_data *hapd, u8 *eid) 364f05cddf9SRui Paulo { 365f05cddf9SRui Paulo u8 *pos = eid; 366f05cddf9SRui Paulo #ifdef CONFIG_INTERWORKING 367f05cddf9SRui Paulo 368f05cddf9SRui Paulo /* TODO: Separate configuration for ANQP? */ 369f05cddf9SRui Paulo if (!hapd->conf->interworking) 370f05cddf9SRui Paulo return eid; 371f05cddf9SRui Paulo 372f05cddf9SRui Paulo *pos++ = WLAN_EID_ADV_PROTO; 373f05cddf9SRui Paulo *pos++ = 2; 374f05cddf9SRui Paulo *pos++ = 0x7F; /* Query Response Length Limit | PAME-BI */ 375f05cddf9SRui Paulo *pos++ = ACCESS_NETWORK_QUERY_PROTOCOL; 376f05cddf9SRui Paulo #endif /* CONFIG_INTERWORKING */ 377f05cddf9SRui Paulo 378f05cddf9SRui Paulo return pos; 379f05cddf9SRui Paulo } 380f05cddf9SRui Paulo 381f05cddf9SRui Paulo 382f05cddf9SRui Paulo u8 * hostapd_eid_roaming_consortium(struct hostapd_data *hapd, u8 *eid) 383f05cddf9SRui Paulo { 384f05cddf9SRui Paulo u8 *pos = eid; 385f05cddf9SRui Paulo #ifdef CONFIG_INTERWORKING 386f05cddf9SRui Paulo u8 *len; 387f05cddf9SRui Paulo unsigned int i, count; 388f05cddf9SRui Paulo 389f05cddf9SRui Paulo if (!hapd->conf->interworking || 390f05cddf9SRui Paulo hapd->conf->roaming_consortium == NULL || 391f05cddf9SRui Paulo hapd->conf->roaming_consortium_count == 0) 392f05cddf9SRui Paulo return eid; 393f05cddf9SRui Paulo 394f05cddf9SRui Paulo *pos++ = WLAN_EID_ROAMING_CONSORTIUM; 395f05cddf9SRui Paulo len = pos++; 396f05cddf9SRui Paulo 397f05cddf9SRui Paulo /* Number of ANQP OIs (in addition to the max 3 listed here) */ 398f05cddf9SRui Paulo if (hapd->conf->roaming_consortium_count > 3 + 255) 399f05cddf9SRui Paulo *pos++ = 255; 400f05cddf9SRui Paulo else if (hapd->conf->roaming_consortium_count > 3) 401f05cddf9SRui Paulo *pos++ = hapd->conf->roaming_consortium_count - 3; 402f05cddf9SRui Paulo else 403f05cddf9SRui Paulo *pos++ = 0; 404f05cddf9SRui Paulo 405f05cddf9SRui Paulo /* OU #1 and #2 Lengths */ 406f05cddf9SRui Paulo *pos = hapd->conf->roaming_consortium[0].len; 407f05cddf9SRui Paulo if (hapd->conf->roaming_consortium_count > 1) 408f05cddf9SRui Paulo *pos |= hapd->conf->roaming_consortium[1].len << 4; 409f05cddf9SRui Paulo pos++; 410f05cddf9SRui Paulo 411f05cddf9SRui Paulo if (hapd->conf->roaming_consortium_count > 3) 412f05cddf9SRui Paulo count = 3; 413f05cddf9SRui Paulo else 414f05cddf9SRui Paulo count = hapd->conf->roaming_consortium_count; 415f05cddf9SRui Paulo 416f05cddf9SRui Paulo for (i = 0; i < count; i++) { 417f05cddf9SRui Paulo os_memcpy(pos, hapd->conf->roaming_consortium[i].oi, 418f05cddf9SRui Paulo hapd->conf->roaming_consortium[i].len); 419f05cddf9SRui Paulo pos += hapd->conf->roaming_consortium[i].len; 420f05cddf9SRui Paulo } 421f05cddf9SRui Paulo 422f05cddf9SRui Paulo *len = pos - len - 1; 423f05cddf9SRui Paulo #endif /* CONFIG_INTERWORKING */ 424f05cddf9SRui Paulo 425f05cddf9SRui Paulo return pos; 426f05cddf9SRui Paulo } 427f05cddf9SRui Paulo 428f05cddf9SRui Paulo 429f05cddf9SRui Paulo u8 * hostapd_eid_time_adv(struct hostapd_data *hapd, u8 *eid) 430f05cddf9SRui Paulo { 431f05cddf9SRui Paulo if (hapd->conf->time_advertisement != 2) 432f05cddf9SRui Paulo return eid; 433f05cddf9SRui Paulo 434f05cddf9SRui Paulo if (hapd->time_adv == NULL && 435f05cddf9SRui Paulo hostapd_update_time_adv(hapd) < 0) 436f05cddf9SRui Paulo return eid; 437f05cddf9SRui Paulo 438f05cddf9SRui Paulo if (hapd->time_adv == NULL) 439f05cddf9SRui Paulo return eid; 440f05cddf9SRui Paulo 441f05cddf9SRui Paulo os_memcpy(eid, wpabuf_head(hapd->time_adv), 442f05cddf9SRui Paulo wpabuf_len(hapd->time_adv)); 443f05cddf9SRui Paulo eid += wpabuf_len(hapd->time_adv); 444f05cddf9SRui Paulo 445f05cddf9SRui Paulo return eid; 446f05cddf9SRui Paulo } 447f05cddf9SRui Paulo 448f05cddf9SRui Paulo 449f05cddf9SRui Paulo u8 * hostapd_eid_time_zone(struct hostapd_data *hapd, u8 *eid) 450f05cddf9SRui Paulo { 451f05cddf9SRui Paulo size_t len; 452f05cddf9SRui Paulo 453*85732ac8SCy Schubert if (hapd->conf->time_advertisement != 2 || !hapd->conf->time_zone) 454f05cddf9SRui Paulo return eid; 455f05cddf9SRui Paulo 456f05cddf9SRui Paulo len = os_strlen(hapd->conf->time_zone); 457f05cddf9SRui Paulo 458f05cddf9SRui Paulo *eid++ = WLAN_EID_TIME_ZONE; 459f05cddf9SRui Paulo *eid++ = len; 460f05cddf9SRui Paulo os_memcpy(eid, hapd->conf->time_zone, len); 461f05cddf9SRui Paulo eid += len; 462f05cddf9SRui Paulo 463f05cddf9SRui Paulo return eid; 464f05cddf9SRui Paulo } 465f05cddf9SRui Paulo 466f05cddf9SRui Paulo 467f05cddf9SRui Paulo int hostapd_update_time_adv(struct hostapd_data *hapd) 468f05cddf9SRui Paulo { 469f05cddf9SRui Paulo const int elen = 2 + 1 + 10 + 5 + 1; 470f05cddf9SRui Paulo struct os_time t; 471f05cddf9SRui Paulo struct os_tm tm; 472f05cddf9SRui Paulo u8 *pos; 473f05cddf9SRui Paulo 474f05cddf9SRui Paulo if (hapd->conf->time_advertisement != 2) 475f05cddf9SRui Paulo return 0; 476f05cddf9SRui Paulo 477f05cddf9SRui Paulo if (os_get_time(&t) < 0 || os_gmtime(t.sec, &tm) < 0) 478f05cddf9SRui Paulo return -1; 479f05cddf9SRui Paulo 480f05cddf9SRui Paulo if (!hapd->time_adv) { 481f05cddf9SRui Paulo hapd->time_adv = wpabuf_alloc(elen); 482f05cddf9SRui Paulo if (hapd->time_adv == NULL) 483f05cddf9SRui Paulo return -1; 484f05cddf9SRui Paulo pos = wpabuf_put(hapd->time_adv, elen); 485f05cddf9SRui Paulo } else 486f05cddf9SRui Paulo pos = wpabuf_mhead_u8(hapd->time_adv); 487f05cddf9SRui Paulo 488f05cddf9SRui Paulo *pos++ = WLAN_EID_TIME_ADVERTISEMENT; 489f05cddf9SRui Paulo *pos++ = 1 + 10 + 5 + 1; 490f05cddf9SRui Paulo 491f05cddf9SRui Paulo *pos++ = 2; /* UTC time at which the TSF timer is 0 */ 492f05cddf9SRui Paulo 493f05cddf9SRui Paulo /* Time Value at TSF 0 */ 494f05cddf9SRui Paulo /* FIX: need to calculate this based on the current TSF value */ 495f05cddf9SRui Paulo WPA_PUT_LE16(pos, tm.year); /* Year */ 496f05cddf9SRui Paulo pos += 2; 497f05cddf9SRui Paulo *pos++ = tm.month; /* Month */ 498f05cddf9SRui Paulo *pos++ = tm.day; /* Day of month */ 499f05cddf9SRui Paulo *pos++ = tm.hour; /* Hours */ 500f05cddf9SRui Paulo *pos++ = tm.min; /* Minutes */ 501f05cddf9SRui Paulo *pos++ = tm.sec; /* Seconds */ 502f05cddf9SRui Paulo WPA_PUT_LE16(pos, 0); /* Milliseconds (not used) */ 503f05cddf9SRui Paulo pos += 2; 504f05cddf9SRui Paulo *pos++ = 0; /* Reserved */ 505f05cddf9SRui Paulo 506f05cddf9SRui Paulo /* Time Error */ 507f05cddf9SRui Paulo /* TODO: fill in an estimate on the error */ 508f05cddf9SRui Paulo *pos++ = 0; 509f05cddf9SRui Paulo *pos++ = 0; 510f05cddf9SRui Paulo *pos++ = 0; 511f05cddf9SRui Paulo *pos++ = 0; 512f05cddf9SRui Paulo *pos++ = 0; 513f05cddf9SRui Paulo 514f05cddf9SRui Paulo *pos++ = hapd->time_update_counter++; 515f05cddf9SRui Paulo 516f05cddf9SRui Paulo return 0; 517f05cddf9SRui Paulo } 518f05cddf9SRui Paulo 519f05cddf9SRui Paulo 520f05cddf9SRui Paulo u8 * hostapd_eid_bss_max_idle_period(struct hostapd_data *hapd, u8 *eid) 521f05cddf9SRui Paulo { 522f05cddf9SRui Paulo u8 *pos = eid; 523f05cddf9SRui Paulo 524*85732ac8SCy Schubert #ifdef CONFIG_WNM_AP 525f05cddf9SRui Paulo if (hapd->conf->ap_max_inactivity > 0) { 526f05cddf9SRui Paulo unsigned int val; 527f05cddf9SRui Paulo *pos++ = WLAN_EID_BSS_MAX_IDLE_PERIOD; 528f05cddf9SRui Paulo *pos++ = 3; 529f05cddf9SRui Paulo val = hapd->conf->ap_max_inactivity; 530f05cddf9SRui Paulo if (val > 68000) 531f05cddf9SRui Paulo val = 68000; 532f05cddf9SRui Paulo val *= 1000; 533f05cddf9SRui Paulo val /= 1024; 534f05cddf9SRui Paulo if (val == 0) 535f05cddf9SRui Paulo val = 1; 536f05cddf9SRui Paulo if (val > 65535) 537f05cddf9SRui Paulo val = 65535; 538f05cddf9SRui Paulo WPA_PUT_LE16(pos, val); 539f05cddf9SRui Paulo pos += 2; 540f05cddf9SRui Paulo *pos++ = 0x00; /* TODO: Protected Keep-Alive Required */ 541f05cddf9SRui Paulo } 542*85732ac8SCy Schubert #endif /* CONFIG_WNM_AP */ 543f05cddf9SRui Paulo 544f05cddf9SRui Paulo return pos; 545f05cddf9SRui Paulo } 546780fb4a2SCy Schubert 547780fb4a2SCy Schubert 548780fb4a2SCy Schubert #ifdef CONFIG_MBO 549780fb4a2SCy Schubert 550780fb4a2SCy Schubert u8 * hostapd_eid_mbo(struct hostapd_data *hapd, u8 *eid, size_t len) 551780fb4a2SCy Schubert { 552*85732ac8SCy Schubert u8 mbo[9], *mbo_pos = mbo; 553780fb4a2SCy Schubert u8 *pos = eid; 554780fb4a2SCy Schubert 555*85732ac8SCy Schubert if (!hapd->conf->mbo_enabled && 556*85732ac8SCy Schubert !OCE_STA_CFON_ENABLED(hapd) && !OCE_AP_ENABLED(hapd)) 557780fb4a2SCy Schubert return eid; 558780fb4a2SCy Schubert 559*85732ac8SCy Schubert if (hapd->conf->mbo_enabled) { 560780fb4a2SCy Schubert *mbo_pos++ = MBO_ATTR_ID_AP_CAPA_IND; 561780fb4a2SCy Schubert *mbo_pos++ = 1; 562780fb4a2SCy Schubert /* Not Cellular aware */ 563780fb4a2SCy Schubert *mbo_pos++ = 0; 564*85732ac8SCy Schubert } 565780fb4a2SCy Schubert 566*85732ac8SCy Schubert if (hapd->conf->mbo_enabled && hapd->mbo_assoc_disallow) { 567780fb4a2SCy Schubert *mbo_pos++ = MBO_ATTR_ID_ASSOC_DISALLOW; 568780fb4a2SCy Schubert *mbo_pos++ = 1; 569780fb4a2SCy Schubert *mbo_pos++ = hapd->mbo_assoc_disallow; 570780fb4a2SCy Schubert } 571780fb4a2SCy Schubert 572*85732ac8SCy Schubert if (OCE_STA_CFON_ENABLED(hapd) || OCE_AP_ENABLED(hapd)) { 573*85732ac8SCy Schubert u8 ctrl; 574*85732ac8SCy Schubert 575*85732ac8SCy Schubert ctrl = OCE_RELEASE; 576*85732ac8SCy Schubert if (OCE_STA_CFON_ENABLED(hapd) && !OCE_AP_ENABLED(hapd)) 577*85732ac8SCy Schubert ctrl |= OCE_IS_STA_CFON; 578*85732ac8SCy Schubert 579*85732ac8SCy Schubert *mbo_pos++ = OCE_ATTR_ID_CAPA_IND; 580*85732ac8SCy Schubert *mbo_pos++ = 1; 581*85732ac8SCy Schubert *mbo_pos++ = ctrl; 582*85732ac8SCy Schubert } 583*85732ac8SCy Schubert 584780fb4a2SCy Schubert pos += mbo_add_ie(pos, len, mbo, mbo_pos - mbo); 585780fb4a2SCy Schubert 586780fb4a2SCy Schubert return pos; 587780fb4a2SCy Schubert } 588780fb4a2SCy Schubert 589780fb4a2SCy Schubert 590780fb4a2SCy Schubert u8 hostapd_mbo_ie_len(struct hostapd_data *hapd) 591780fb4a2SCy Schubert { 592*85732ac8SCy Schubert u8 len; 593*85732ac8SCy Schubert 594*85732ac8SCy Schubert if (!hapd->conf->mbo_enabled && 595*85732ac8SCy Schubert !OCE_STA_CFON_ENABLED(hapd) && !OCE_AP_ENABLED(hapd)) 596780fb4a2SCy Schubert return 0; 597780fb4a2SCy Schubert 598780fb4a2SCy Schubert /* 599780fb4a2SCy Schubert * MBO IE header (6) + Capability Indication attribute (3) + 600780fb4a2SCy Schubert * Association Disallowed attribute (3) = 12 601780fb4a2SCy Schubert */ 602*85732ac8SCy Schubert len = 6; 603*85732ac8SCy Schubert if (hapd->conf->mbo_enabled) 604*85732ac8SCy Schubert len += 3 + (hapd->mbo_assoc_disallow ? 3 : 0); 605*85732ac8SCy Schubert 606*85732ac8SCy Schubert /* OCE capability indication attribute (3) */ 607*85732ac8SCy Schubert if (OCE_STA_CFON_ENABLED(hapd) || OCE_AP_ENABLED(hapd)) 608*85732ac8SCy Schubert len += 3; 609*85732ac8SCy Schubert 610*85732ac8SCy Schubert return len; 611780fb4a2SCy Schubert } 612780fb4a2SCy Schubert 613780fb4a2SCy Schubert #endif /* CONFIG_MBO */ 614780fb4a2SCy Schubert 615780fb4a2SCy Schubert 616*85732ac8SCy Schubert #ifdef CONFIG_OWE 617*85732ac8SCy Schubert static int hostapd_eid_owe_trans_enabled(struct hostapd_data *hapd) 618*85732ac8SCy Schubert { 619*85732ac8SCy Schubert return hapd->conf->owe_transition_ssid_len > 0 && 620*85732ac8SCy Schubert !is_zero_ether_addr(hapd->conf->owe_transition_bssid); 621*85732ac8SCy Schubert } 622*85732ac8SCy Schubert #endif /* CONFIG_OWE */ 623*85732ac8SCy Schubert 624*85732ac8SCy Schubert 625*85732ac8SCy Schubert size_t hostapd_eid_owe_trans_len(struct hostapd_data *hapd) 626*85732ac8SCy Schubert { 627*85732ac8SCy Schubert #ifdef CONFIG_OWE 628*85732ac8SCy Schubert if (!hostapd_eid_owe_trans_enabled(hapd)) 629*85732ac8SCy Schubert return 0; 630*85732ac8SCy Schubert return 6 + ETH_ALEN + 1 + hapd->conf->owe_transition_ssid_len; 631*85732ac8SCy Schubert #else /* CONFIG_OWE */ 632*85732ac8SCy Schubert return 0; 633*85732ac8SCy Schubert #endif /* CONFIG_OWE */ 634*85732ac8SCy Schubert } 635*85732ac8SCy Schubert 636*85732ac8SCy Schubert 637*85732ac8SCy Schubert u8 * hostapd_eid_owe_trans(struct hostapd_data *hapd, u8 *eid, 638*85732ac8SCy Schubert size_t len) 639*85732ac8SCy Schubert { 640*85732ac8SCy Schubert #ifdef CONFIG_OWE 641*85732ac8SCy Schubert u8 *pos = eid; 642*85732ac8SCy Schubert size_t elen; 643*85732ac8SCy Schubert 644*85732ac8SCy Schubert if (hapd->conf->owe_transition_ifname[0] && 645*85732ac8SCy Schubert !hostapd_eid_owe_trans_enabled(hapd)) 646*85732ac8SCy Schubert hostapd_owe_trans_get_info(hapd); 647*85732ac8SCy Schubert 648*85732ac8SCy Schubert if (!hostapd_eid_owe_trans_enabled(hapd)) 649*85732ac8SCy Schubert return pos; 650*85732ac8SCy Schubert 651*85732ac8SCy Schubert elen = hostapd_eid_owe_trans_len(hapd); 652*85732ac8SCy Schubert if (len < elen) { 653*85732ac8SCy Schubert wpa_printf(MSG_DEBUG, 654*85732ac8SCy Schubert "OWE: Not enough room in the buffer for OWE IE"); 655*85732ac8SCy Schubert return pos; 656*85732ac8SCy Schubert } 657*85732ac8SCy Schubert 658*85732ac8SCy Schubert *pos++ = WLAN_EID_VENDOR_SPECIFIC; 659*85732ac8SCy Schubert *pos++ = elen - 2; 660*85732ac8SCy Schubert WPA_PUT_BE24(pos, OUI_WFA); 661*85732ac8SCy Schubert pos += 3; 662*85732ac8SCy Schubert *pos++ = OWE_OUI_TYPE; 663*85732ac8SCy Schubert os_memcpy(pos, hapd->conf->owe_transition_bssid, ETH_ALEN); 664*85732ac8SCy Schubert pos += ETH_ALEN; 665*85732ac8SCy Schubert *pos++ = hapd->conf->owe_transition_ssid_len; 666*85732ac8SCy Schubert os_memcpy(pos, hapd->conf->owe_transition_ssid, 667*85732ac8SCy Schubert hapd->conf->owe_transition_ssid_len); 668*85732ac8SCy Schubert pos += hapd->conf->owe_transition_ssid_len; 669*85732ac8SCy Schubert 670*85732ac8SCy Schubert return pos; 671*85732ac8SCy Schubert #else /* CONFIG_OWE */ 672*85732ac8SCy Schubert return eid; 673*85732ac8SCy Schubert #endif /* CONFIG_OWE */ 674*85732ac8SCy Schubert } 675*85732ac8SCy Schubert 676*85732ac8SCy Schubert 677780fb4a2SCy Schubert void ap_copy_sta_supp_op_classes(struct sta_info *sta, 678780fb4a2SCy Schubert const u8 *supp_op_classes, 679780fb4a2SCy Schubert size_t supp_op_classes_len) 680780fb4a2SCy Schubert { 681780fb4a2SCy Schubert if (!supp_op_classes) 682780fb4a2SCy Schubert return; 683780fb4a2SCy Schubert os_free(sta->supp_op_classes); 684780fb4a2SCy Schubert sta->supp_op_classes = os_malloc(1 + supp_op_classes_len); 685780fb4a2SCy Schubert if (!sta->supp_op_classes) 686780fb4a2SCy Schubert return; 687780fb4a2SCy Schubert 688780fb4a2SCy Schubert sta->supp_op_classes[0] = supp_op_classes_len; 689780fb4a2SCy Schubert os_memcpy(sta->supp_op_classes + 1, supp_op_classes, 690780fb4a2SCy Schubert supp_op_classes_len); 691780fb4a2SCy Schubert } 692*85732ac8SCy Schubert 693*85732ac8SCy Schubert 694*85732ac8SCy Schubert u8 * hostapd_eid_fils_indic(struct hostapd_data *hapd, u8 *eid, int hessid) 695*85732ac8SCy Schubert { 696*85732ac8SCy Schubert u8 *pos = eid; 697*85732ac8SCy Schubert #ifdef CONFIG_FILS 698*85732ac8SCy Schubert u8 *len; 699*85732ac8SCy Schubert u16 fils_info = 0; 700*85732ac8SCy Schubert size_t realms; 701*85732ac8SCy Schubert struct fils_realm *realm; 702*85732ac8SCy Schubert 703*85732ac8SCy Schubert if (!(hapd->conf->wpa & WPA_PROTO_RSN) || 704*85732ac8SCy Schubert !wpa_key_mgmt_fils(hapd->conf->wpa_key_mgmt)) 705*85732ac8SCy Schubert return pos; 706*85732ac8SCy Schubert 707*85732ac8SCy Schubert realms = dl_list_len(&hapd->conf->fils_realms); 708*85732ac8SCy Schubert if (realms > 7) 709*85732ac8SCy Schubert realms = 7; /* 3 bit count field limits this to max 7 */ 710*85732ac8SCy Schubert 711*85732ac8SCy Schubert *pos++ = WLAN_EID_FILS_INDICATION; 712*85732ac8SCy Schubert len = pos++; 713*85732ac8SCy Schubert /* TODO: B0..B2: Number of Public Key Identifiers */ 714*85732ac8SCy Schubert if (hapd->conf->erp_domain) { 715*85732ac8SCy Schubert /* B3..B5: Number of Realm Identifiers */ 716*85732ac8SCy Schubert fils_info |= realms << 3; 717*85732ac8SCy Schubert } 718*85732ac8SCy Schubert /* TODO: B6: FILS IP Address Configuration */ 719*85732ac8SCy Schubert if (hapd->conf->fils_cache_id_set) 720*85732ac8SCy Schubert fils_info |= BIT(7); 721*85732ac8SCy Schubert if (hessid && !is_zero_ether_addr(hapd->conf->hessid)) 722*85732ac8SCy Schubert fils_info |= BIT(8); /* HESSID Included */ 723*85732ac8SCy Schubert /* FILS Shared Key Authentication without PFS Supported */ 724*85732ac8SCy Schubert fils_info |= BIT(9); 725*85732ac8SCy Schubert if (hapd->conf->fils_dh_group) { 726*85732ac8SCy Schubert /* FILS Shared Key Authentication with PFS Supported */ 727*85732ac8SCy Schubert fils_info |= BIT(10); 728*85732ac8SCy Schubert } 729*85732ac8SCy Schubert /* TODO: B11: FILS Public Key Authentication Supported */ 730*85732ac8SCy Schubert /* B12..B15: Reserved */ 731*85732ac8SCy Schubert WPA_PUT_LE16(pos, fils_info); 732*85732ac8SCy Schubert pos += 2; 733*85732ac8SCy Schubert if (hapd->conf->fils_cache_id_set) { 734*85732ac8SCy Schubert os_memcpy(pos, hapd->conf->fils_cache_id, FILS_CACHE_ID_LEN); 735*85732ac8SCy Schubert pos += FILS_CACHE_ID_LEN; 736*85732ac8SCy Schubert } 737*85732ac8SCy Schubert if (hessid && !is_zero_ether_addr(hapd->conf->hessid)) { 738*85732ac8SCy Schubert os_memcpy(pos, hapd->conf->hessid, ETH_ALEN); 739*85732ac8SCy Schubert pos += ETH_ALEN; 740*85732ac8SCy Schubert } 741*85732ac8SCy Schubert 742*85732ac8SCy Schubert dl_list_for_each(realm, &hapd->conf->fils_realms, struct fils_realm, 743*85732ac8SCy Schubert list) { 744*85732ac8SCy Schubert if (realms == 0) 745*85732ac8SCy Schubert break; 746*85732ac8SCy Schubert realms--; 747*85732ac8SCy Schubert os_memcpy(pos, realm->hash, 2); 748*85732ac8SCy Schubert pos += 2; 749*85732ac8SCy Schubert } 750*85732ac8SCy Schubert *len = pos - len - 1; 751*85732ac8SCy Schubert #endif /* CONFIG_FILS */ 752*85732ac8SCy Schubert 753*85732ac8SCy Schubert return pos; 754*85732ac8SCy Schubert } 755