From patchwork Tue Nov 8 14:11:17 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Arik Nemtsov X-Patchwork-Id: 124368 Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Received: from maxx.maxx.shmoo.com (maxx.shmoo.com [205.134.188.171]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client CN "maxx.shmoo.com", Issuer "CA Cert Signing Authority" (not verified)) by ozlabs.org (Postfix) with ESMTPS id D2885B6F0E for ; Wed, 9 Nov 2011 01:11:53 +1100 (EST) Received: from localhost (localhost [127.0.0.1]) by maxx.maxx.shmoo.com (Postfix) with ESMTP id 57B5B9D207; Tue, 8 Nov 2011 09:11:49 -0500 (EST) X-Virus-Scanned: amavisd-new at maxx.shmoo.com Received: from maxx.maxx.shmoo.com ([127.0.0.1]) by localhost (maxx.shmoo.com [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 28erOvmBGR-j; Tue, 8 Nov 2011 09:11:49 -0500 (EST) Received: from maxx.shmoo.com (localhost [127.0.0.1]) by maxx.maxx.shmoo.com (Postfix) with ESMTP id 4A6C49D1F8; Tue, 8 Nov 2011 09:11:35 -0500 (EST) X-Original-To: mailman-post+hostap@maxx.shmoo.com Delivered-To: mailman-post+hostap@maxx.shmoo.com Received: from localhost (localhost [127.0.0.1]) by maxx.maxx.shmoo.com (Postfix) with ESMTP id EC1BA9D1F8 for ; Tue, 8 Nov 2011 09:11:33 -0500 (EST) X-Virus-Scanned: amavisd-new at maxx.shmoo.com Received: from maxx.maxx.shmoo.com ([127.0.0.1]) by localhost (maxx.shmoo.com [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id MEAvHr-9rDIY for ; Tue, 8 Nov 2011 09:11:29 -0500 (EST) Received: from mail-ww0-f48.google.com (mail-ww0-f48.google.com [74.125.82.48]) (using TLSv1 with cipher RC4-SHA (128/128 bits)) (Client CN "smtp.gmail.com", Issuer "Google Internet Authority" (not verified)) by maxx.maxx.shmoo.com (Postfix) with ESMTPS id 512A79D1EC for ; Tue, 8 Nov 2011 09:11:29 -0500 (EST) Received: by wwg9 with SMTP id 9so484235wwg.5 for ; Tue, 08 Nov 2011 06:11:28 -0800 (PST) Received: by 10.227.208.149 with SMTP id gc21mr32849977wbb.10.1320761487944; Tue, 08 Nov 2011 06:11:27 -0800 (PST) Received: from localhost.localdomain (46-116-162-41.bb.netvision.net.il. [46.116.162.41]) by mx.google.com with ESMTPS id en13sm1839901wbb.22.2011.11.08.06.11.25 (version=TLSv1/SSLv3 cipher=OTHER); Tue, 08 Nov 2011 06:11:26 -0800 (PST) From: Arik Nemtsov To: hostap@lists.shmoo.com Subject: [PATCH v3 2/3] hostap: set driver probe-response template Date: Tue, 8 Nov 2011 16:11:17 +0200 Message-Id: <1320761478-29133-2-git-send-email-arik@wizery.com> X-Mailer: git-send-email 1.7.5.4 In-Reply-To: <1320761478-29133-1-git-send-email-arik@wizery.com> References: <1320761478-29133-1-git-send-email-arik@wizery.com> Cc: Arik Nemtsov X-BeenThere: hostap@lists.shmoo.com X-Mailman-Version: 2.1.9 Precedence: list List-Id: HostAP Project List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: hostap-bounces@lists.shmoo.com Errors-To: hostap-bounces@lists.shmoo.com Configure a probe response template for drivers that support it. The template is updated when the beacon is updated. The probe response template is propagated to kernel via the set_ap() callback. Signed-off-by: Guy Eilam Signed-off-by: Arik Nemtsov --- v1->3: - save offload-supported protocols bitmap in AP/P2P GO modes - use set_ap() to propagate probe-response (and re-factor beacon generating code so both happen in a common function) - add warnings when unsupported protocols are offloaded hostapd/main.c | 5 +- src/ap/ap_list.c | 4 +- src/ap/beacon.c | 364 ++++++++++++++++++++++++------------- src/ap/beacon.h | 4 +- src/ap/hostapd.c | 4 +- src/ap/hostapd.h | 7 + src/ap/ieee802_11.c | 6 +- src/ap/ieee802_11_ht.c | 2 +- src/ap/sta_info.c | 2 +- src/ap/wps_hostapd.c | 2 +- src/drivers/driver.h | 27 +++ wpa_supplicant/ap.c | 4 +- wpa_supplicant/wpa_supplicant.c | 2 + wpa_supplicant/wpa_supplicant_i.h | 7 + 14 files changed, 298 insertions(+), 142 deletions(-) diff --git a/hostapd/main.c b/hostapd/main.c index 99c137d..a781e44 100644 --- a/hostapd/main.c +++ b/hostapd/main.c @@ -303,8 +303,11 @@ static int hostapd_driver_init(struct hostapd_iface *iface) } if (hapd->driver->get_capa && - hapd->driver->get_capa(hapd->drv_priv, &capa) == 0) + hapd->driver->get_capa(hapd->drv_priv, &capa) == 0) { iface->drv_flags = capa.flags; + iface->probe_resp_offload_protocols = + capa.probe_resp_offload_protocols; + } return 0; } diff --git a/src/ap/ap_list.c b/src/ap/ap_list.c index 9b9fc9e..40ded63 100644 --- a/src/ap/ap_list.c +++ b/src/ap/ap_list.c @@ -326,7 +326,7 @@ void ap_list_process_beacon(struct hostapd_iface *iface, #endif /* CONFIG_IEEE80211N */ if (set_beacon) - ieee802_11_set_beacons(iface); + ieee802_11_set_beacons_and_probes(iface); } @@ -381,7 +381,7 @@ static void ap_list_timer(void *eloop_ctx, void *timeout_ctx) } if (set_beacon) - ieee802_11_set_beacons(iface); + ieee802_11_set_beacons_and_probes(iface); } diff --git a/src/ap/beacon.c b/src/ap/beacon.c index 4ba223c..f3b306a 100644 --- a/src/ap/beacon.c +++ b/src/ap/beacon.c @@ -186,18 +186,133 @@ static u8 * hostapd_eid_wpa(struct hostapd_data *hapd, u8 *eid, size_t len) } +#define MAX_PROBERESP_LEN 768 + +int hostapd_alloc_probe_resp(struct hostapd_data *hapd, size_t resp_basic_len, + u8 **proberesp) +{ + size_t buflen = resp_basic_len; +#ifdef CONFIG_WPS + if (hapd->wps_probe_resp_ie) + buflen += wpabuf_len(hapd->wps_probe_resp_ie); +#endif /* CONFIG_WPS */ +#ifdef CONFIG_P2P + if (hapd->p2p_probe_resp_ie) + buflen += wpabuf_len(hapd->p2p_probe_resp_ie); +#endif /* CONFIG_P2P */ + *proberesp = os_zalloc(buflen); + if (*proberesp == NULL) + return -1; + + return 0; +} + + +static size_t hostapd_gen_probe_resp(struct hostapd_data *hapd, + const struct ieee80211_mgmt *req, + struct ieee80211_mgmt *resp, + size_t resp_basic_len, + int is_p2p) +{ + u8 *pos, *epos; + struct sta_info *sta = NULL; + + /* TODO: verify that supp_rates contains at least one matching rate + * with AP configuration */ + epos = ((u8 *) resp) + resp_basic_len; + + resp->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, + WLAN_FC_STYPE_PROBE_RESP); + if (req) + os_memcpy(resp->da, req->sa, ETH_ALEN); + else + os_memset(resp->da, 0, sizeof(resp->da)); + os_memcpy(resp->sa, hapd->own_addr, ETH_ALEN); + + os_memcpy(resp->bssid, hapd->own_addr, ETH_ALEN); + resp->u.probe_resp.beacon_int = + host_to_le16(hapd->iconf->beacon_int); + + /* hardware or low-level driver will setup seq_ctrl and timestamp */ + resp->u.probe_resp.capab_info = + host_to_le16(hostapd_own_capab_info(hapd, sta, 1)); + + pos = resp->u.probe_resp.variable; + *pos++ = WLAN_EID_SSID; + *pos++ = hapd->conf->ssid.ssid_len; + os_memcpy(pos, hapd->conf->ssid.ssid, hapd->conf->ssid.ssid_len); + pos += hapd->conf->ssid.ssid_len; + + /* Supported rates */ + pos = hostapd_eid_supp_rates(hapd, pos); + + /* DS Params */ + pos = hostapd_eid_ds_params(hapd, pos); + + pos = hostapd_eid_country(hapd, pos, epos - pos); + + /* ERP Information element */ + pos = hostapd_eid_erp_info(hapd, pos); + + /* Extended supported rates */ + pos = hostapd_eid_ext_supp_rates(hapd, pos); + + /* RSN, MDIE, WPA */ + pos = hostapd_eid_wpa(hapd, pos, epos - pos); + +#ifdef CONFIG_IEEE80211N + pos = hostapd_eid_ht_capabilities(hapd, pos); + pos = hostapd_eid_ht_operation(hapd, pos); +#endif /* CONFIG_IEEE80211N */ + + pos = hostapd_eid_ext_capab(hapd, pos); + + pos = hostapd_eid_time_adv(hapd, pos); + pos = hostapd_eid_time_zone(hapd, pos); + + pos = hostapd_eid_interworking(hapd, pos); + pos = hostapd_eid_adv_proto(hapd, pos); + pos = hostapd_eid_roaming_consortium(hapd, pos); + + /* Wi-Fi Alliance WMM */ + pos = hostapd_eid_wmm(hapd, pos); + +#ifdef CONFIG_WPS + if (hapd->conf->wps_state && hapd->wps_probe_resp_ie) { + os_memcpy(pos, wpabuf_head(hapd->wps_probe_resp_ie), + wpabuf_len(hapd->wps_probe_resp_ie)); + pos += wpabuf_len(hapd->wps_probe_resp_ie); + } +#endif /* CONFIG_WPS */ + +#ifdef CONFIG_P2P + if ((hapd->conf->p2p & P2P_ENABLED) && is_p2p && + hapd->p2p_probe_resp_ie) { + os_memcpy(pos, wpabuf_head(hapd->p2p_probe_resp_ie), + wpabuf_len(hapd->p2p_probe_resp_ie)); + pos += wpabuf_len(hapd->p2p_probe_resp_ie); + } +#endif /* CONFIG_P2P */ +#ifdef CONFIG_P2P_MANAGER + if ((hapd->conf->p2p & (P2P_MANAGE | P2P_ENABLED | P2P_GROUP_OWNER)) == + P2P_MANAGE) + pos = hostapd_eid_p2p_manage(hapd, pos); +#endif /* CONFIG_P2P_MANAGER */ + + return pos - (u8 *) resp; +} + + void handle_probe_req(struct hostapd_data *hapd, const struct ieee80211_mgmt *mgmt, size_t len) { struct ieee80211_mgmt *resp; struct ieee802_11_elems elems; char *ssid; - u8 *pos, *epos; const u8 *ie; - size_t ssid_len, ie_len; + size_t ie_len; struct sta_info *sta = NULL; - size_t buflen; - size_t i; + size_t i, resp_len; ie = mgmt->u.probe_req.variable; if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req)) @@ -220,7 +335,6 @@ void handle_probe_req(struct hostapd_data *hapd, } ssid = NULL; - ssid_len = 0; if ((!elems.ssid || !elems.supp_rates)) { wpa_printf(MSG_DEBUG, "STA " MACSTR " sent probe request " @@ -267,7 +381,6 @@ void handle_probe_req(struct hostapd_data *hapd, os_memcmp(elems.ssid, hapd->conf->ssid.ssid, elems.ssid_len) == 0)) { ssid = hapd->conf->ssid.ssid; - ssid_len = hapd->conf->ssid.ssid_len; if (sta) sta->ssid_probe = &hapd->conf->ssid; } @@ -315,99 +428,13 @@ void handle_probe_req(struct hostapd_data *hapd, } #endif /* CONFIG_INTERWORKING */ - /* TODO: verify that supp_rates contains at least one matching rate - * with AP configuration */ -#define MAX_PROBERESP_LEN 768 - buflen = MAX_PROBERESP_LEN; -#ifdef CONFIG_WPS - if (hapd->wps_probe_resp_ie) - buflen += wpabuf_len(hapd->wps_probe_resp_ie); -#endif /* CONFIG_WPS */ -#ifdef CONFIG_P2P - if (hapd->p2p_probe_resp_ie) - buflen += wpabuf_len(hapd->p2p_probe_resp_ie); -#endif /* CONFIG_P2P */ - resp = os_zalloc(buflen); - if (resp == NULL) + if (hostapd_alloc_probe_resp(hapd, MAX_PROBERESP_LEN, (u8 **)&resp) < 0) return; - epos = ((u8 *) resp) + MAX_PROBERESP_LEN; - - resp->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, - WLAN_FC_STYPE_PROBE_RESP); - os_memcpy(resp->da, mgmt->sa, ETH_ALEN); - os_memcpy(resp->sa, hapd->own_addr, ETH_ALEN); - - os_memcpy(resp->bssid, hapd->own_addr, ETH_ALEN); - resp->u.probe_resp.beacon_int = - host_to_le16(hapd->iconf->beacon_int); - - /* hardware or low-level driver will setup seq_ctrl and timestamp */ - resp->u.probe_resp.capab_info = - host_to_le16(hostapd_own_capab_info(hapd, sta, 1)); - pos = resp->u.probe_resp.variable; - *pos++ = WLAN_EID_SSID; - *pos++ = ssid_len; - os_memcpy(pos, ssid, ssid_len); - pos += ssid_len; - - /* Supported rates */ - pos = hostapd_eid_supp_rates(hapd, pos); - - /* DS Params */ - pos = hostapd_eid_ds_params(hapd, pos); - - pos = hostapd_eid_country(hapd, pos, epos - pos); - - /* ERP Information element */ - pos = hostapd_eid_erp_info(hapd, pos); - - /* Extended supported rates */ - pos = hostapd_eid_ext_supp_rates(hapd, pos); - - /* RSN, MDIE, WPA */ - pos = hostapd_eid_wpa(hapd, pos, epos - pos); - -#ifdef CONFIG_IEEE80211N - pos = hostapd_eid_ht_capabilities(hapd, pos); - pos = hostapd_eid_ht_operation(hapd, pos); -#endif /* CONFIG_IEEE80211N */ - - pos = hostapd_eid_ext_capab(hapd, pos); - - pos = hostapd_eid_time_adv(hapd, pos); - pos = hostapd_eid_time_zone(hapd, pos); - - pos = hostapd_eid_interworking(hapd, pos); - pos = hostapd_eid_adv_proto(hapd, pos); - pos = hostapd_eid_roaming_consortium(hapd, pos); - - /* Wi-Fi Alliance WMM */ - pos = hostapd_eid_wmm(hapd, pos); - -#ifdef CONFIG_WPS - if (hapd->conf->wps_state && hapd->wps_probe_resp_ie) { - os_memcpy(pos, wpabuf_head(hapd->wps_probe_resp_ie), - wpabuf_len(hapd->wps_probe_resp_ie)); - pos += wpabuf_len(hapd->wps_probe_resp_ie); - } -#endif /* CONFIG_WPS */ - -#ifdef CONFIG_P2P - if ((hapd->conf->p2p & P2P_ENABLED) && elems.p2p && - hapd->p2p_probe_resp_ie) { - os_memcpy(pos, wpabuf_head(hapd->p2p_probe_resp_ie), - wpabuf_len(hapd->p2p_probe_resp_ie)); - pos += wpabuf_len(hapd->p2p_probe_resp_ie); - } -#endif /* CONFIG_P2P */ -#ifdef CONFIG_P2P_MANAGER - if ((hapd->conf->p2p & (P2P_MANAGE | P2P_ENABLED | P2P_GROUP_OWNER)) == - P2P_MANAGE) - pos = hostapd_eid_p2p_manage(hapd, pos); -#endif /* CONFIG_P2P_MANAGER */ + resp_len = hostapd_gen_probe_resp(hapd, mgmt, resp, MAX_PROBERESP_LEN, + (int)elems.p2p); - if (hostapd_drv_send_mlme(hapd, resp, pos - (u8 *) resp) < 0) + if (hostapd_drv_send_mlme(hapd, resp, resp_len) < 0) perror("handle_probe_req: send"); os_free(resp); @@ -417,28 +444,15 @@ void handle_probe_req(struct hostapd_data *hapd, elems.ssid_len == 0 ? "broadcast" : "our"); } -#endif /* NEED_AP_MLME */ - -void ieee802_11_set_beacon(struct hostapd_data *hapd) +static int hostapd_alloc_beacon(struct hostapd_data *hapd, + u8 **head, u8 **tail) { - struct ieee80211_mgmt *head = NULL; - u8 *tail = NULL; - size_t head_len = 0, tail_len = 0; - struct wpa_driver_ap_params params; - struct wpabuf *beacon, *proberesp, *assocresp; -#ifdef NEED_AP_MLME - u16 capab_info; - u8 *pos, *tailpos; -#endif /* NEED_AP_MLME */ - - hapd->beacon_set_done = 1; - -#ifdef NEED_AP_MLME + size_t tail_len; #define BEACON_HEAD_BUF_SIZE 256 #define BEACON_TAIL_BUF_SIZE 512 - head = os_zalloc(BEACON_HEAD_BUF_SIZE); + *head = os_zalloc(BEACON_HEAD_BUF_SIZE); tail_len = BEACON_TAIL_BUF_SIZE; #ifdef CONFIG_WPS if (hapd->conf->wps_state && hapd->wps_beacon_ie) @@ -448,14 +462,28 @@ void ieee802_11_set_beacon(struct hostapd_data *hapd) if (hapd->p2p_beacon_ie) tail_len += wpabuf_len(hapd->p2p_beacon_ie); #endif /* CONFIG_P2P */ - tailpos = tail = os_malloc(tail_len); - if (head == NULL || tail == NULL) { - wpa_printf(MSG_ERROR, "Failed to set beacon data"); - os_free(head); - os_free(tail); - return; + *tail = os_malloc(tail_len); + if (*head == NULL || *tail == NULL) { + wpa_printf(MSG_ERROR, "Failed to alloc beacon data"); + os_free(*head); + os_free(*tail); + return -1; } + return 0; +} + + +static void hostapd_gen_beacon(struct hostapd_data *hapd, + struct ieee80211_mgmt *head, + u8 *tail, size_t *head_len, + size_t *tail_len) +{ + u16 capab_info; + u8 *pos, *tailpos; + + tailpos = tail; + head->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, WLAN_FC_STYPE_BEACON); head->duration = host_to_le16(0); @@ -493,7 +521,7 @@ void ieee802_11_set_beacon(struct hostapd_data *hapd) /* DS Params */ pos = hostapd_eid_ds_params(hapd, pos); - head_len = pos - (u8 *) head; + *head_len = pos - (u8 *) head; tailpos = hostapd_eid_country(hapd, tailpos, tail + BEACON_TAIL_BUF_SIZE - tailpos); @@ -549,15 +577,30 @@ void ieee802_11_set_beacon(struct hostapd_data *hapd) tailpos = hostapd_eid_p2p_manage(hapd, tailpos); #endif /* CONFIG_P2P_MANAGER */ - tail_len = tailpos > tail ? tailpos - tail : 0; + *tail_len = tailpos > tail ? tailpos - tail : 0; + +} #endif /* NEED_AP_MLME */ + +static void ieee802_11_set_ap(struct hostapd_data *hapd, const u8 *head, + size_t head_len, const u8 *tail, size_t tail_len, + const u8 *proberesp, size_t proberesp_len) +{ + struct wpa_driver_ap_params params; + struct wpabuf *beacon_ies = NULL, *proberesp_ies = NULL, + *assocresp_ies = NULL; + + hapd->beacon_set_done = 1; + os_memset(¶ms, 0, sizeof(params)); params.head = (u8 *) head; params.head_len = head_len; params.tail = tail; params.tail_len = tail_len; + params.proberesp = proberesp; + params.proberesp_len = proberesp_len; params.dtim_period = hapd->conf->dtim_period; params.beacon_int = hapd->iconf->beacon_int; params.ssid = (u8 *) hapd->conf->ssid.ssid; @@ -583,10 +626,12 @@ void ieee802_11_set_beacon(struct hostapd_data *hapd) params.hide_ssid = HIDDEN_SSID_ZERO_CONTENTS; break; } - hostapd_build_ap_extra_ies(hapd, &beacon, &proberesp, &assocresp); - params.beacon_ies = beacon; - params.proberesp_ies = proberesp; - params.assocresp_ies = assocresp; + + hostapd_build_ap_extra_ies(hapd, &beacon_ies, &proberesp_ies, + &assocresp_ies); + params.beacon_ies = beacon_ies; + params.proberesp_ies = proberesp_ies; + params.assocresp_ies = assocresp_ies; params.isolate = hapd->conf->isolate; #ifdef NEED_AP_MLME params.cts_protect = !!(ieee802_11_erp_info(hapd) & @@ -611,18 +656,81 @@ void ieee802_11_set_beacon(struct hostapd_data *hapd) params.access_network_type = hapd->conf->access_network_type; if (hostapd_drv_set_ap(hapd, ¶ms)) wpa_printf(MSG_ERROR, "Failed to set beacon parameters"); - hostapd_free_ap_extra_ies(hapd, beacon, proberesp, assocresp); + hostapd_free_ap_extra_ies(hapd, beacon_ies, proberesp_ies, + assocresp_ies); + +} + + +void ieee802_11_set_beacon_and_probe(struct hostapd_data *hapd) +{ + u8 *resp = NULL, *head = NULL, *tail = NULL; + size_t resp_len = 0, head_len = 0, tail_len = 0; + + if (hostapd_alloc_beacon(hapd, &head, &tail) < 0) + goto fail; + + hostapd_gen_beacon(hapd, (struct ieee80211_mgmt *)head, tail, + &head_len, &tail_len); + +#ifdef NEED_AP_MLME + + /* check probe response offloading caps and print warnings */ + if (!(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_PROBE_RESP_OFFLOAD)) + goto set; + +#ifdef CONFIG_WPS + if (hapd->conf->wps_state && hapd->wps_probe_resp_ie && + (!(hapd->iface->probe_resp_offload_protocols & + WPA_DRIVER_PROBE_RESP_OFFLOAD_SUPPORT_WPS) || + !(hapd->iface->probe_resp_offload_protocols & + WPA_DRIVER_PROBE_RESP_OFFLOAD_SUPPORT_WPS2))) + wpa_printf(MSG_WARNING, "Device is trying to offload WPS " + "probe-responses while not supporting WPS/WPS2 " + "probe-response offloading."); +#endif /* CONFIG_WPS */ + +#ifdef CONFIG_P2P + if ((hapd->conf->p2p & P2P_ENABLED) && hapd->p2p_probe_resp_ie && + !(hapd->iface->probe_resp_offload_protocols & + WPA_DRIVER_PROBE_RESP_OFFLOAD_SUPPORT_P2P)) + wpa_printf(MSG_WARNING, "Device is trying to offload P2P " + "probe-responses while not supporting P2P " + "probe-response offloading."); +#endif /* CONFIG_P2P */ + + if (hapd->conf->interworking && + !(hapd->iface->probe_resp_offload_protocols & + WPA_DRIVER_PROBE_RESP_OFFLOAD_SUPPORT_80211U)) + wpa_printf(MSG_WARNING, "Device is trying to offload 802.11u " + "(interworking) probe-responses while not " + "supporting 802.11u probe-response offloading."); + + if (hostapd_alloc_probe_resp(hapd, MAX_PROBERESP_LEN, &resp) < 0) + goto set; + + /* we generate a probe-resp for the non-p2p case */ + resp_len = hostapd_gen_probe_resp(hapd, NULL, + (struct ieee80211_mgmt *)resp, + MAX_PROBERESP_LEN, 0); +#endif /* NEED_AP_MLME */ + +set: + ieee802_11_set_ap(hapd, head, head_len, tail, tail_len, resp, resp_len); + +fail: os_free(tail); os_free(head); + os_free(resp); } -void ieee802_11_set_beacons(struct hostapd_iface *iface) +void ieee802_11_set_beacons_and_probes(struct hostapd_iface *iface) { size_t i; for (i = 0; i < iface->num_bss; i++) - ieee802_11_set_beacon(iface->bss[i]); + ieee802_11_set_beacon_and_probe(iface->bss[i]); } #endif /* CONFIG_NATIVE_WINDOWS */ diff --git a/src/ap/beacon.h b/src/ap/beacon.h index a944f5f..df687da 100644 --- a/src/ap/beacon.h +++ b/src/ap/beacon.h @@ -20,7 +20,7 @@ struct ieee80211_mgmt; void handle_probe_req(struct hostapd_data *hapd, const struct ieee80211_mgmt *mgmt, size_t len); -void ieee802_11_set_beacon(struct hostapd_data *hapd); -void ieee802_11_set_beacons(struct hostapd_iface *iface); +void ieee802_11_set_beacon_and_probe(struct hostapd_data *hapd); +void ieee802_11_set_beacons_and_probes(struct hostapd_iface *iface); #endif /* BEACON_H */ diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c index e180a08..70b46da 100644 --- a/src/ap/hostapd.c +++ b/src/ap/hostapd.c @@ -81,7 +81,7 @@ static void hostapd_reload_bss(struct hostapd_data *hapd) hostapd_set_generic_elem(hapd, (u8 *) "", 0); } - ieee802_11_set_beacon(hapd); + ieee802_11_set_beacon_and_probe(hapd); hostapd_update_wps(hapd); if (hapd->conf->ssid.ssid_set && @@ -629,7 +629,7 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first) return -1; } - ieee802_11_set_beacon(hapd); + ieee802_11_set_beacon_and_probe(hapd); if (hapd->wpa_auth && wpa_init_keys(hapd->wpa_auth) < 0) return -1; diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h index 5401e80..916e9f2 100644 --- a/src/ap/hostapd.h +++ b/src/ap/hostapd.h @@ -191,6 +191,13 @@ struct hostapd_iface { struct ap_info *ap_iter_list; unsigned int drv_flags; + + /* + * A bitmap of supported protocols for probe response offload. See + * struct wpa_driver_capa in driver.h + */ + unsigned int probe_resp_offload_protocols; + struct hostapd_hw_modes *hw_features; int num_hw_features; struct hostapd_hw_modes *current_mode; diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c index 9fad335..d65f8d1 100644 --- a/src/ap/ieee802_11.c +++ b/src/ap/ieee802_11.c @@ -1018,7 +1018,7 @@ static void handle_assoc(struct hostapd_data *hapd, sta->nonerp_set = 1; hapd->iface->num_sta_non_erp++; if (hapd->iface->num_sta_non_erp == 1) - ieee802_11_set_beacons(hapd->iface); + ieee802_11_set_beacons_and_probes(hapd->iface); } if (!(sta->capability & WLAN_CAPABILITY_SHORT_SLOT_TIME) && @@ -1028,7 +1028,7 @@ static void handle_assoc(struct hostapd_data *hapd, if (hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G && hapd->iface->num_sta_no_short_slot_time == 1) - ieee802_11_set_beacons(hapd->iface); + ieee802_11_set_beacons_and_probes(hapd->iface); } if (sta->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) @@ -1042,7 +1042,7 @@ static void handle_assoc(struct hostapd_data *hapd, hapd->iface->num_sta_no_short_preamble++; if (hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G && hapd->iface->num_sta_no_short_preamble == 1) - ieee802_11_set_beacons(hapd->iface); + ieee802_11_set_beacons_and_probes(hapd->iface); } #ifdef CONFIG_IEEE80211N diff --git a/src/ap/ieee802_11_ht.c b/src/ap/ieee802_11_ht.c index 6c3696f..32d1e7c 100644 --- a/src/ap/ieee802_11_ht.c +++ b/src/ap/ieee802_11_ht.c @@ -236,7 +236,7 @@ void update_ht_state(struct hostapd_data *hapd, struct sta_info *sta) update_sta_no_ht(hapd, sta); if (hostapd_ht_operation_update(hapd->iface) > 0) - ieee802_11_set_beacons(hapd->iface); + ieee802_11_set_beacons_and_probes(hapd->iface); } diff --git a/src/ap/sta_info.c b/src/ap/sta_info.c index dc689ba..df0682d 100644 --- a/src/ap/sta_info.c +++ b/src/ap/sta_info.c @@ -198,7 +198,7 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta) #endif /* NEED_AP_MLME && CONFIG_IEEE80211N */ if (set_beacon) - ieee802_11_set_beacons(hapd->iface); + ieee802_11_set_beacons_and_probes(hapd->iface); eloop_cancel_timeout(ap_handle_timer, hapd, sta); eloop_cancel_timeout(ap_handle_session_timer, hapd, sta); diff --git a/src/ap/wps_hostapd.c b/src/ap/wps_hostapd.c index 671bc67..500e8a1 100644 --- a/src/ap/wps_hostapd.c +++ b/src/ap/wps_hostapd.c @@ -142,7 +142,7 @@ static int hostapd_wps_set_ie_cb(void *ctx, struct wpabuf *beacon_ie, wpabuf_free(hapd->wps_probe_resp_ie); hapd->wps_probe_resp_ie = probe_resp_ie; if (hapd->beacon_set_done) - ieee802_11_set_beacon(hapd); + ieee802_11_set_beacon_and_probe(hapd); return hostapd_set_ap_wps_ie(hapd); } diff --git a/src/drivers/driver.h b/src/drivers/driver.h index 2500c1e..477af6e 100644 --- a/src/drivers/driver.h +++ b/src/drivers/driver.h @@ -556,6 +556,19 @@ struct wpa_driver_ap_params { int beacon_int; /** + * proberesp - Probe response template + * + * This is used by drivers that reply to probe requests internally in + * AP mode and require the full probe response template. + */ + const u8 *proberesp; + + /** + * proberesp_len - Length of the proberesp buffer in octets + */ + size_t proberesp_len; + + /** * ssid - The SSID to use in Beacon/Probe Response frames */ const u8 *ssid; @@ -1444,6 +1457,20 @@ struct wpa_driver_ops { int (*set_ap)(void *priv, struct wpa_driver_ap_params *params); /** + * set_probe_resp - Set Probe Response frame template + * @priv: Private driver interface data + * @resp: Probe Response template + * @resp_len: Length of the resp buffer in octets + * Returns: 0 on success, -1 on failure + * + * This function is used to configure a Probe Response template for the + * driver in AP mode. The driver is responsible for building the full + * Probe Response frame by setting the destination address to that of + * the desired recipient. + */ + int (*set_probe_resp)(void *priv, const u8 *resp, size_t resp_len); + + /** * hapd_init - Initialize driver interface (hostapd only) * @hapd: Pointer to hostapd context * @params: Configuration for the driver wrapper diff --git a/wpa_supplicant/ap.c b/wpa_supplicant/ap.c index e3d5433..1e17175 100644 --- a/wpa_supplicant/ap.c +++ b/wpa_supplicant/ap.c @@ -454,6 +454,8 @@ int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s, return -1; hapd_iface->owner = wpa_s; hapd_iface->drv_flags = wpa_s->drv_flags; + hapd_iface->probe_resp_offload_protocols = + wpa_s->probe_resp_offload_protocols; wpa_s->ap_iface->conf = conf = hostapd_config_defaults(); if (conf == NULL) { @@ -900,7 +902,7 @@ int wpa_supplicant_ap_update_beacon(struct wpa_supplicant *wpa_s) P2P_GROUP_FORMATION; #endif /* CONFIG_P2P */ - ieee802_11_set_beacons(iface); + ieee802_11_set_beacons_and_probes(iface); hapd = iface->bss[0]; hostapd_set_ap_wps_ie(hapd); diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c index 2b3140e..1bff61c 100644 --- a/wpa_supplicant/wpa_supplicant.c +++ b/wpa_supplicant/wpa_supplicant.c @@ -2325,6 +2325,8 @@ next_driver: if (wpa_drv_get_capa(wpa_s, &capa) == 0) { wpa_s->drv_capa_known = 1; wpa_s->drv_flags = capa.flags; + wpa_s->probe_resp_offload_protocols = + capa.probe_resp_offload_protocols; wpa_s->max_scan_ssids = capa.max_scan_ssids; wpa_s->max_sched_scan_ssids = capa.max_sched_scan_ssids; wpa_s->sched_scan_supported = capa.sched_scan_supported; diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h index fd04a7d..f661383 100644 --- a/wpa_supplicant/wpa_supplicant_i.h +++ b/wpa_supplicant/wpa_supplicant_i.h @@ -339,6 +339,13 @@ struct wpa_supplicant { int scan_interval; /* time in sec between scans to find suitable AP */ unsigned int drv_flags; + + /* + * A bitmap of supported protocols for probe response offload. See + * struct wpa_driver_capa in driver.h + */ + unsigned int probe_resp_offload_protocols; + int max_scan_ssids; int max_sched_scan_ssids; int sched_scan_supported;