[PATCH 2/3] hostapd: set driver probe-response template

Guy Eilam guy
Sat Oct 22 06:08:46 PDT 2011


Configure a Probe response template for drivers that support it. The
template is updated when the beacon is updated, as they are made up
of mostly the same elements.

Signed-off-by: Guy Eilam <guy at wizery.com>
---
 src/ap/ap_drv_ops.h    |    9 ++
 src/ap/ap_list.c       |    4 +-
 src/ap/beacon.c        |  242 +++++++++++++++++++++++++++++-------------------
 src/ap/beacon.h        |    4 +-
 src/ap/hostapd.c       |    4 +-
 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   |   14 +++
 wpa_supplicant/ap.c    |    2 +-
 11 files changed, 183 insertions(+), 108 deletions(-)

diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h
index ebb6eff..f9c727c 100644
--- a/src/ap/ap_drv_ops.h
+++ b/src/ap/ap_drv_ops.h
@@ -216,4 +216,13 @@ static inline void hostapd_drv_poll_client(struct hostapd_data *hapd,
 	hapd->driver->poll_client(hapd->drv_priv, own_addr, addr, qos);
 }
 
+static inline int hostapd_drv_set_probe_resp(struct hostapd_data *hapd,
+					     const u8 *resp, size_t resp_len)
+{
+	if (hapd->driver == NULL || hapd->driver->set_probe_resp == NULL)
+		return 0;
+	return hapd->driver->set_probe_resp(hapd->drv_priv,
+					    resp, resp_len);
+}
+
 #endif /* AP_DRV_OPS */
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 528808c..d0ea3fc 100644
--- a/src/ap/beacon.c
+++ b/src/ap/beacon.c
@@ -198,18 +198,129 @@ static u8 * hostapd_eid_wpa(struct hostapd_data *hapd, u8 *eid, size_t len)
 }
 
 
+#define MAX_PROBERESP_LEN 768
+
+static struct ieee80211_mgmt *
+hostapd_alloc_probe_resp(struct hostapd_data *hapd, size_t resp_basic_len)
+{
+	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 */
+	return os_zalloc(buflen);
+}
+
+
+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))
@@ -232,7 +343,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 "
@@ -279,7 +389,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;
 	}
@@ -327,112 +436,48 @@ 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);
+	resp = hostapd_alloc_probe_resp(hapd, MAX_PROBERESP_LEN);
 	if (resp == NULL)
 		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));
+	resp_len = hostapd_gen_probe_resp(hapd, mgmt, resp, MAX_PROBERESP_LEN, (int)elems.p2p);
 
-	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);
+	if (hostapd_drv_send_mlme(hapd, resp, resp_len) < 0)
+		perror("handle_probe_req: send");
 
-#ifdef CONFIG_IEEE80211N
-	pos = hostapd_eid_ht_capabilities(hapd, pos);
-	pos = hostapd_eid_ht_operation(hapd, pos);
-#endif /* CONFIG_IEEE80211N */
+	os_free(resp);
 
-	pos = hostapd_eid_ext_capab(hapd, pos);
+	wpa_printf(MSG_EXCESSIVE, "STA " MACSTR " sent probe request for %s "
+		   "SSID", MAC2STR(mgmt->sa),
+		   elems.ssid_len == 0 ? "broadcast" : "our");
+}
 
-	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);
+static void ieee802_11_set_probe_resp(struct hostapd_data *hapd)
+{
+	struct ieee80211_mgmt *resp;
+	size_t resp_len;
 
-	/* Wi-Fi Alliance WMM */
-	pos = hostapd_eid_wmm(hapd, pos);
+	/* only set the probe response if the driver supports probe response offloading */
+	if (!(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_PROBE_RESP_OFFLOAD))
+		return;
 
-#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 */
+	resp = hostapd_alloc_probe_resp(hapd, MAX_PROBERESP_LEN);
+	if (resp == NULL)
+		return;
 
-#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, NULL, resp, MAX_PROBERESP_LEN, 0);
 
-	if (hostapd_drv_send_mlme(hapd, resp, pos - (u8 *) resp) < 0)
-		perror("handle_probe_req: send");
+	if (hostapd_drv_set_probe_resp(hapd, (u8 *) resp, resp_len))
+		wpa_printf(MSG_ERROR, "Failed to set probe_response template");
 
 	os_free(resp);
-
-	wpa_printf(MSG_EXCESSIVE, "STA " MACSTR " sent probe request for %s "
-		   "SSID", MAC2STR(mgmt->sa),
-		   elems.ssid_len == 0 ? "broadcast" : "our");
 }
 
 #endif /* NEED_AP_MLME */
 
 
-void ieee802_11_set_beacon(struct hostapd_data *hapd)
+static void ieee802_11_set_beacon(struct hostapd_data *hapd)
 {
 	struct ieee80211_mgmt *head = NULL;
 	u8 *tail = NULL;
@@ -630,11 +675,18 @@ 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)
+{
+	ieee802_11_set_beacon(hapd);
+	ieee802_11_set_probe_resp(hapd);
+}
+
+
+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 23c8b1a..14435fd 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 &&
@@ -641,7 +641,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/ieee802_11.c b/src/ap/ieee802_11.c
index 2b24c3f..065233e 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 d82b9ce..ae88a12 100644
--- a/src/ap/sta_info.c
+++ b/src/ap/sta_info.c
@@ -197,7 +197,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 2078d5c..a19e6ae 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -1504,6 +1504,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 c4959bf..5c1523b 100644
--- a/wpa_supplicant/ap.c
+++ b/wpa_supplicant/ap.c
@@ -894,7 +894,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);
 
-- 
1.7.4.1




More information about the Hostap mailing list