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; 27*5b9c547cSRui 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; 32*5b9c547cSRui Paulo os_get_reltime(&now); 33*5b9c547cSRui 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) 72*5b9c547cSRui 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) 110*5b9c547cSRui 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 167*5b9c547cSRui Paulo static void hostapd_ext_capab_byte(struct hostapd_data *hapd, u8 *pos, int idx) 168f05cddf9SRui Paulo { 169f05cddf9SRui Paulo *pos = 0x00; 170*5b9c547cSRui Paulo 171*5b9c547cSRui Paulo switch (idx) { 172*5b9c547cSRui Paulo case 0: /* Bits 0-7 */ 173*5b9c547cSRui Paulo if (hapd->iconf->obss_interval) 174*5b9c547cSRui Paulo *pos |= 0x01; /* Bit 0 - Coexistence management */ 175*5b9c547cSRui Paulo break; 176*5b9c547cSRui Paulo case 1: /* Bits 8-15 */ 177*5b9c547cSRui Paulo if (hapd->conf->proxy_arp) 178*5b9c547cSRui Paulo *pos |= 0x10; /* Bit 12 - Proxy ARP */ 179*5b9c547cSRui Paulo break; 180*5b9c547cSRui Paulo case 2: /* Bits 16-23 */ 181f05cddf9SRui Paulo if (hapd->conf->wnm_sleep_mode) 182f05cddf9SRui Paulo *pos |= 0x02; /* Bit 17 - WNM-Sleep Mode */ 183f05cddf9SRui Paulo if (hapd->conf->bss_transition) 184f05cddf9SRui Paulo *pos |= 0x08; /* Bit 19 - BSS Transition */ 185*5b9c547cSRui Paulo break; 186*5b9c547cSRui Paulo case 3: /* Bits 24-31 */ 187f05cddf9SRui Paulo #ifdef CONFIG_WNM 188f05cddf9SRui Paulo *pos |= 0x02; /* Bit 25 - SSID List */ 189f05cddf9SRui Paulo #endif /* CONFIG_WNM */ 190f05cddf9SRui Paulo if (hapd->conf->time_advertisement == 2) 191f05cddf9SRui Paulo *pos |= 0x08; /* Bit 27 - UTC TSF Offset */ 192f05cddf9SRui Paulo if (hapd->conf->interworking) 193f05cddf9SRui Paulo *pos |= 0x80; /* Bit 31 - Interworking */ 194*5b9c547cSRui Paulo break; 195*5b9c547cSRui Paulo case 4: /* Bits 32-39 */ 196*5b9c547cSRui Paulo if (hapd->conf->qos_map_set_len) 197*5b9c547cSRui Paulo *pos |= 0x01; /* Bit 32 - QoS Map */ 198f05cddf9SRui Paulo if (hapd->conf->tdls & TDLS_PROHIBIT) 199f05cddf9SRui Paulo *pos |= 0x40; /* Bit 38 - TDLS Prohibited */ 200*5b9c547cSRui Paulo if (hapd->conf->tdls & TDLS_PROHIBIT_CHAN_SWITCH) { 201*5b9c547cSRui Paulo /* Bit 39 - TDLS Channel Switching Prohibited */ 202*5b9c547cSRui Paulo *pos |= 0x80; 203*5b9c547cSRui Paulo } 204*5b9c547cSRui Paulo break; 205*5b9c547cSRui Paulo case 5: /* Bits 40-47 */ 206*5b9c547cSRui Paulo #ifdef CONFIG_HS20 207*5b9c547cSRui Paulo if (hapd->conf->hs20) 208*5b9c547cSRui Paulo *pos |= 0x40; /* Bit 46 - WNM-Notification */ 209*5b9c547cSRui Paulo #endif /* CONFIG_HS20 */ 210*5b9c547cSRui Paulo break; 211*5b9c547cSRui Paulo case 6: /* Bits 48-55 */ 212f05cddf9SRui Paulo if (hapd->conf->ssid.utf8_ssid) 213f05cddf9SRui Paulo *pos |= 0x01; /* Bit 48 - UTF-8 SSID */ 214*5b9c547cSRui Paulo break; 215*5b9c547cSRui Paulo } 216*5b9c547cSRui Paulo } 217*5b9c547cSRui Paulo 218*5b9c547cSRui Paulo 219*5b9c547cSRui Paulo u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid) 220*5b9c547cSRui Paulo { 221*5b9c547cSRui Paulo u8 *pos = eid; 222*5b9c547cSRui Paulo u8 len = 0, i; 223*5b9c547cSRui Paulo 224*5b9c547cSRui Paulo if (hapd->conf->tdls & (TDLS_PROHIBIT | TDLS_PROHIBIT_CHAN_SWITCH)) 225*5b9c547cSRui Paulo len = 5; 226*5b9c547cSRui Paulo if (len < 4 && hapd->conf->interworking) 227*5b9c547cSRui Paulo len = 4; 228*5b9c547cSRui Paulo if (len < 3 && hapd->conf->wnm_sleep_mode) 229*5b9c547cSRui Paulo len = 3; 230*5b9c547cSRui Paulo if (len < 1 && hapd->iconf->obss_interval) 231*5b9c547cSRui Paulo len = 1; 232*5b9c547cSRui Paulo if (len < 7 && hapd->conf->ssid.utf8_ssid) 233*5b9c547cSRui Paulo len = 7; 234*5b9c547cSRui Paulo #ifdef CONFIG_WNM 235*5b9c547cSRui Paulo if (len < 4) 236*5b9c547cSRui Paulo len = 4; 237*5b9c547cSRui Paulo #endif /* CONFIG_WNM */ 238*5b9c547cSRui Paulo #ifdef CONFIG_HS20 239*5b9c547cSRui Paulo if (hapd->conf->hs20 && len < 6) 240*5b9c547cSRui Paulo len = 6; 241*5b9c547cSRui Paulo #endif /* CONFIG_HS20 */ 242*5b9c547cSRui Paulo if (len < hapd->iface->extended_capa_len) 243*5b9c547cSRui Paulo len = hapd->iface->extended_capa_len; 244*5b9c547cSRui Paulo if (len == 0) 245*5b9c547cSRui Paulo return eid; 246*5b9c547cSRui Paulo 247*5b9c547cSRui Paulo *pos++ = WLAN_EID_EXT_CAPAB; 248*5b9c547cSRui Paulo *pos++ = len; 249*5b9c547cSRui Paulo for (i = 0; i < len; i++, pos++) { 250*5b9c547cSRui Paulo hostapd_ext_capab_byte(hapd, pos, i); 251*5b9c547cSRui Paulo 252*5b9c547cSRui Paulo if (i < hapd->iface->extended_capa_len) { 253*5b9c547cSRui Paulo *pos &= ~hapd->iface->extended_capa_mask[i]; 254*5b9c547cSRui Paulo *pos |= hapd->iface->extended_capa[i]; 255*5b9c547cSRui Paulo } 256*5b9c547cSRui Paulo } 257*5b9c547cSRui Paulo 258*5b9c547cSRui Paulo while (len > 0 && eid[1 + len] == 0) { 259*5b9c547cSRui Paulo len--; 260*5b9c547cSRui Paulo eid[1] = len; 261*5b9c547cSRui Paulo } 262*5b9c547cSRui Paulo if (len == 0) 263*5b9c547cSRui Paulo return eid; 264*5b9c547cSRui Paulo 265*5b9c547cSRui Paulo return eid + 2 + len; 266*5b9c547cSRui Paulo } 267*5b9c547cSRui Paulo 268*5b9c547cSRui Paulo 269*5b9c547cSRui Paulo u8 * hostapd_eid_qos_map_set(struct hostapd_data *hapd, u8 *eid) 270*5b9c547cSRui Paulo { 271*5b9c547cSRui Paulo u8 *pos = eid; 272*5b9c547cSRui Paulo u8 len = hapd->conf->qos_map_set_len; 273*5b9c547cSRui Paulo 274*5b9c547cSRui Paulo if (!len) 275*5b9c547cSRui Paulo return eid; 276*5b9c547cSRui Paulo 277*5b9c547cSRui Paulo *pos++ = WLAN_EID_QOS_MAP_SET; 278*5b9c547cSRui Paulo *pos++ = len; 279*5b9c547cSRui Paulo os_memcpy(pos, hapd->conf->qos_map_set, len); 280*5b9c547cSRui Paulo pos += len; 281f05cddf9SRui Paulo 282f05cddf9SRui Paulo return pos; 283f05cddf9SRui Paulo } 284f05cddf9SRui Paulo 285f05cddf9SRui Paulo 286f05cddf9SRui Paulo u8 * hostapd_eid_interworking(struct hostapd_data *hapd, u8 *eid) 287f05cddf9SRui Paulo { 288f05cddf9SRui Paulo u8 *pos = eid; 289f05cddf9SRui Paulo #ifdef CONFIG_INTERWORKING 290f05cddf9SRui Paulo u8 *len; 291f05cddf9SRui Paulo 292f05cddf9SRui Paulo if (!hapd->conf->interworking) 293f05cddf9SRui Paulo return eid; 294f05cddf9SRui Paulo 295f05cddf9SRui Paulo *pos++ = WLAN_EID_INTERWORKING; 296f05cddf9SRui Paulo len = pos++; 297f05cddf9SRui Paulo 298f05cddf9SRui Paulo *pos = hapd->conf->access_network_type; 299f05cddf9SRui Paulo if (hapd->conf->internet) 300f05cddf9SRui Paulo *pos |= INTERWORKING_ANO_INTERNET; 301f05cddf9SRui Paulo if (hapd->conf->asra) 302f05cddf9SRui Paulo *pos |= INTERWORKING_ANO_ASRA; 303f05cddf9SRui Paulo if (hapd->conf->esr) 304f05cddf9SRui Paulo *pos |= INTERWORKING_ANO_ESR; 305f05cddf9SRui Paulo if (hapd->conf->uesa) 306f05cddf9SRui Paulo *pos |= INTERWORKING_ANO_UESA; 307f05cddf9SRui Paulo pos++; 308f05cddf9SRui Paulo 309f05cddf9SRui Paulo if (hapd->conf->venue_info_set) { 310f05cddf9SRui Paulo *pos++ = hapd->conf->venue_group; 311f05cddf9SRui Paulo *pos++ = hapd->conf->venue_type; 312f05cddf9SRui Paulo } 313f05cddf9SRui Paulo 314f05cddf9SRui Paulo if (!is_zero_ether_addr(hapd->conf->hessid)) { 315f05cddf9SRui Paulo os_memcpy(pos, hapd->conf->hessid, ETH_ALEN); 316f05cddf9SRui Paulo pos += ETH_ALEN; 317f05cddf9SRui Paulo } 318f05cddf9SRui Paulo 319f05cddf9SRui Paulo *len = pos - len - 1; 320f05cddf9SRui Paulo #endif /* CONFIG_INTERWORKING */ 321f05cddf9SRui Paulo 322f05cddf9SRui Paulo return pos; 323f05cddf9SRui Paulo } 324f05cddf9SRui Paulo 325f05cddf9SRui Paulo 326f05cddf9SRui Paulo u8 * hostapd_eid_adv_proto(struct hostapd_data *hapd, u8 *eid) 327f05cddf9SRui Paulo { 328f05cddf9SRui Paulo u8 *pos = eid; 329f05cddf9SRui Paulo #ifdef CONFIG_INTERWORKING 330f05cddf9SRui Paulo 331f05cddf9SRui Paulo /* TODO: Separate configuration for ANQP? */ 332f05cddf9SRui Paulo if (!hapd->conf->interworking) 333f05cddf9SRui Paulo return eid; 334f05cddf9SRui Paulo 335f05cddf9SRui Paulo *pos++ = WLAN_EID_ADV_PROTO; 336f05cddf9SRui Paulo *pos++ = 2; 337f05cddf9SRui Paulo *pos++ = 0x7F; /* Query Response Length Limit | PAME-BI */ 338f05cddf9SRui Paulo *pos++ = ACCESS_NETWORK_QUERY_PROTOCOL; 339f05cddf9SRui Paulo #endif /* CONFIG_INTERWORKING */ 340f05cddf9SRui Paulo 341f05cddf9SRui Paulo return pos; 342f05cddf9SRui Paulo } 343f05cddf9SRui Paulo 344f05cddf9SRui Paulo 345f05cddf9SRui Paulo u8 * hostapd_eid_roaming_consortium(struct hostapd_data *hapd, u8 *eid) 346f05cddf9SRui Paulo { 347f05cddf9SRui Paulo u8 *pos = eid; 348f05cddf9SRui Paulo #ifdef CONFIG_INTERWORKING 349f05cddf9SRui Paulo u8 *len; 350f05cddf9SRui Paulo unsigned int i, count; 351f05cddf9SRui Paulo 352f05cddf9SRui Paulo if (!hapd->conf->interworking || 353f05cddf9SRui Paulo hapd->conf->roaming_consortium == NULL || 354f05cddf9SRui Paulo hapd->conf->roaming_consortium_count == 0) 355f05cddf9SRui Paulo return eid; 356f05cddf9SRui Paulo 357f05cddf9SRui Paulo *pos++ = WLAN_EID_ROAMING_CONSORTIUM; 358f05cddf9SRui Paulo len = pos++; 359f05cddf9SRui Paulo 360f05cddf9SRui Paulo /* Number of ANQP OIs (in addition to the max 3 listed here) */ 361f05cddf9SRui Paulo if (hapd->conf->roaming_consortium_count > 3 + 255) 362f05cddf9SRui Paulo *pos++ = 255; 363f05cddf9SRui Paulo else if (hapd->conf->roaming_consortium_count > 3) 364f05cddf9SRui Paulo *pos++ = hapd->conf->roaming_consortium_count - 3; 365f05cddf9SRui Paulo else 366f05cddf9SRui Paulo *pos++ = 0; 367f05cddf9SRui Paulo 368f05cddf9SRui Paulo /* OU #1 and #2 Lengths */ 369f05cddf9SRui Paulo *pos = hapd->conf->roaming_consortium[0].len; 370f05cddf9SRui Paulo if (hapd->conf->roaming_consortium_count > 1) 371f05cddf9SRui Paulo *pos |= hapd->conf->roaming_consortium[1].len << 4; 372f05cddf9SRui Paulo pos++; 373f05cddf9SRui Paulo 374f05cddf9SRui Paulo if (hapd->conf->roaming_consortium_count > 3) 375f05cddf9SRui Paulo count = 3; 376f05cddf9SRui Paulo else 377f05cddf9SRui Paulo count = hapd->conf->roaming_consortium_count; 378f05cddf9SRui Paulo 379f05cddf9SRui Paulo for (i = 0; i < count; i++) { 380f05cddf9SRui Paulo os_memcpy(pos, hapd->conf->roaming_consortium[i].oi, 381f05cddf9SRui Paulo hapd->conf->roaming_consortium[i].len); 382f05cddf9SRui Paulo pos += hapd->conf->roaming_consortium[i].len; 383f05cddf9SRui Paulo } 384f05cddf9SRui Paulo 385f05cddf9SRui Paulo *len = pos - len - 1; 386f05cddf9SRui Paulo #endif /* CONFIG_INTERWORKING */ 387f05cddf9SRui Paulo 388f05cddf9SRui Paulo return pos; 389f05cddf9SRui Paulo } 390f05cddf9SRui Paulo 391f05cddf9SRui Paulo 392f05cddf9SRui Paulo u8 * hostapd_eid_time_adv(struct hostapd_data *hapd, u8 *eid) 393f05cddf9SRui Paulo { 394f05cddf9SRui Paulo if (hapd->conf->time_advertisement != 2) 395f05cddf9SRui Paulo return eid; 396f05cddf9SRui Paulo 397f05cddf9SRui Paulo if (hapd->time_adv == NULL && 398f05cddf9SRui Paulo hostapd_update_time_adv(hapd) < 0) 399f05cddf9SRui Paulo return eid; 400f05cddf9SRui Paulo 401f05cddf9SRui Paulo if (hapd->time_adv == NULL) 402f05cddf9SRui Paulo return eid; 403f05cddf9SRui Paulo 404f05cddf9SRui Paulo os_memcpy(eid, wpabuf_head(hapd->time_adv), 405f05cddf9SRui Paulo wpabuf_len(hapd->time_adv)); 406f05cddf9SRui Paulo eid += wpabuf_len(hapd->time_adv); 407f05cddf9SRui Paulo 408f05cddf9SRui Paulo return eid; 409f05cddf9SRui Paulo } 410f05cddf9SRui Paulo 411f05cddf9SRui Paulo 412f05cddf9SRui Paulo u8 * hostapd_eid_time_zone(struct hostapd_data *hapd, u8 *eid) 413f05cddf9SRui Paulo { 414f05cddf9SRui Paulo size_t len; 415f05cddf9SRui Paulo 416f05cddf9SRui Paulo if (hapd->conf->time_advertisement != 2) 417f05cddf9SRui Paulo return eid; 418f05cddf9SRui Paulo 419f05cddf9SRui Paulo len = os_strlen(hapd->conf->time_zone); 420f05cddf9SRui Paulo 421f05cddf9SRui Paulo *eid++ = WLAN_EID_TIME_ZONE; 422f05cddf9SRui Paulo *eid++ = len; 423f05cddf9SRui Paulo os_memcpy(eid, hapd->conf->time_zone, len); 424f05cddf9SRui Paulo eid += len; 425f05cddf9SRui Paulo 426f05cddf9SRui Paulo return eid; 427f05cddf9SRui Paulo } 428f05cddf9SRui Paulo 429f05cddf9SRui Paulo 430f05cddf9SRui Paulo int hostapd_update_time_adv(struct hostapd_data *hapd) 431f05cddf9SRui Paulo { 432f05cddf9SRui Paulo const int elen = 2 + 1 + 10 + 5 + 1; 433f05cddf9SRui Paulo struct os_time t; 434f05cddf9SRui Paulo struct os_tm tm; 435f05cddf9SRui Paulo u8 *pos; 436f05cddf9SRui Paulo 437f05cddf9SRui Paulo if (hapd->conf->time_advertisement != 2) 438f05cddf9SRui Paulo return 0; 439f05cddf9SRui Paulo 440f05cddf9SRui Paulo if (os_get_time(&t) < 0 || os_gmtime(t.sec, &tm) < 0) 441f05cddf9SRui Paulo return -1; 442f05cddf9SRui Paulo 443f05cddf9SRui Paulo if (!hapd->time_adv) { 444f05cddf9SRui Paulo hapd->time_adv = wpabuf_alloc(elen); 445f05cddf9SRui Paulo if (hapd->time_adv == NULL) 446f05cddf9SRui Paulo return -1; 447f05cddf9SRui Paulo pos = wpabuf_put(hapd->time_adv, elen); 448f05cddf9SRui Paulo } else 449f05cddf9SRui Paulo pos = wpabuf_mhead_u8(hapd->time_adv); 450f05cddf9SRui Paulo 451f05cddf9SRui Paulo *pos++ = WLAN_EID_TIME_ADVERTISEMENT; 452f05cddf9SRui Paulo *pos++ = 1 + 10 + 5 + 1; 453f05cddf9SRui Paulo 454f05cddf9SRui Paulo *pos++ = 2; /* UTC time at which the TSF timer is 0 */ 455f05cddf9SRui Paulo 456f05cddf9SRui Paulo /* Time Value at TSF 0 */ 457f05cddf9SRui Paulo /* FIX: need to calculate this based on the current TSF value */ 458f05cddf9SRui Paulo WPA_PUT_LE16(pos, tm.year); /* Year */ 459f05cddf9SRui Paulo pos += 2; 460f05cddf9SRui Paulo *pos++ = tm.month; /* Month */ 461f05cddf9SRui Paulo *pos++ = tm.day; /* Day of month */ 462f05cddf9SRui Paulo *pos++ = tm.hour; /* Hours */ 463f05cddf9SRui Paulo *pos++ = tm.min; /* Minutes */ 464f05cddf9SRui Paulo *pos++ = tm.sec; /* Seconds */ 465f05cddf9SRui Paulo WPA_PUT_LE16(pos, 0); /* Milliseconds (not used) */ 466f05cddf9SRui Paulo pos += 2; 467f05cddf9SRui Paulo *pos++ = 0; /* Reserved */ 468f05cddf9SRui Paulo 469f05cddf9SRui Paulo /* Time Error */ 470f05cddf9SRui Paulo /* TODO: fill in an estimate on the error */ 471f05cddf9SRui Paulo *pos++ = 0; 472f05cddf9SRui Paulo *pos++ = 0; 473f05cddf9SRui Paulo *pos++ = 0; 474f05cddf9SRui Paulo *pos++ = 0; 475f05cddf9SRui Paulo *pos++ = 0; 476f05cddf9SRui Paulo 477f05cddf9SRui Paulo *pos++ = hapd->time_update_counter++; 478f05cddf9SRui Paulo 479f05cddf9SRui Paulo return 0; 480f05cddf9SRui Paulo } 481f05cddf9SRui Paulo 482f05cddf9SRui Paulo 483f05cddf9SRui Paulo u8 * hostapd_eid_bss_max_idle_period(struct hostapd_data *hapd, u8 *eid) 484f05cddf9SRui Paulo { 485f05cddf9SRui Paulo u8 *pos = eid; 486f05cddf9SRui Paulo 487f05cddf9SRui Paulo #ifdef CONFIG_WNM 488f05cddf9SRui Paulo if (hapd->conf->ap_max_inactivity > 0) { 489f05cddf9SRui Paulo unsigned int val; 490f05cddf9SRui Paulo *pos++ = WLAN_EID_BSS_MAX_IDLE_PERIOD; 491f05cddf9SRui Paulo *pos++ = 3; 492f05cddf9SRui Paulo val = hapd->conf->ap_max_inactivity; 493f05cddf9SRui Paulo if (val > 68000) 494f05cddf9SRui Paulo val = 68000; 495f05cddf9SRui Paulo val *= 1000; 496f05cddf9SRui Paulo val /= 1024; 497f05cddf9SRui Paulo if (val == 0) 498f05cddf9SRui Paulo val = 1; 499f05cddf9SRui Paulo if (val > 65535) 500f05cddf9SRui Paulo val = 65535; 501f05cddf9SRui Paulo WPA_PUT_LE16(pos, val); 502f05cddf9SRui Paulo pos += 2; 503f05cddf9SRui Paulo *pos++ = 0x00; /* TODO: Protected Keep-Alive Required */ 504f05cddf9SRui Paulo } 505f05cddf9SRui Paulo #endif /* CONFIG_WNM */ 506f05cddf9SRui Paulo 507f05cddf9SRui Paulo return pos; 508f05cddf9SRui Paulo } 509