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

Arik Nemtsov arik
Sun Jan 23 12:40:07 PST 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: Arik Nemtsov <arik at wizery.com>
---
 src/ap/ap_drv_ops.h    |    9 ++
 src/ap/ap_list.c       |    4 +-
 src/ap/beacon.c        |  219 +++++++++++++++++++++++++++++-------------------
 src/ap/beacon.h        |   10 ++-
 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, 173 insertions(+), 101 deletions(-)

diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h
index 5bc9d01..d27cf4c 100644
--- a/src/ap/ap_drv_ops.h
+++ b/src/ap/ap_drv_ops.h
@@ -191,4 +191,13 @@ static inline int hostapd_drv_set_radius_acl_expire(struct hostapd_data *hapd,
 	return hapd->driver->set_radius_acl_expire(hapd->drv_priv, mac);
 }
 
+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 5297dbf..9535e09 100644
--- a/src/ap/ap_list.c
+++ b/src/ap/ap_list.c
@@ -324,7 +324,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);
 }
 
 
@@ -379,7 +379,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 380fb8d..6eca109 100644
--- a/src/ap/beacon.c
+++ b/src/ap/beacon.c
@@ -197,18 +197,117 @@ static u8 * hostapd_eid_wpa(struct hostapd_data *hapd, u8 *eid, size_t len,
 }
 
 
+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)
+{
+	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, sta);
+
+#ifdef CONFIG_IEEE80211N
+	pos = hostapd_eid_ht_capabilities(hapd, pos);
+	pos = hostapd_eid_ht_operation(hapd, pos);
+#endif /* CONFIG_IEEE80211N */
+
+	/* 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 */
+
+	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))
@@ -230,7 +329,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 "
@@ -277,7 +375,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;
 	}
@@ -295,101 +392,44 @@ void handle_probe_req(struct hostapd_data *hapd,
 		return;
 	}
 
-	/* 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);
+	resp_len = hostapd_gen_probe_resp(hapd, mgmt, resp, MAX_PROBERESP_LEN);
 
-	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);
+	if (hostapd_drv_send_mlme(hapd, resp, resp_len) < 0)
+		perror("handle_probe_req: send");
 
-	/* Extended supported rates */
-	pos = hostapd_eid_ext_supp_rates(hapd, pos);
+	os_free(resp);
 
-	/* RSN, MDIE, WPA */
-	pos = hostapd_eid_wpa(hapd, pos, epos - pos, sta);
+	wpa_printf(MSG_EXCESSIVE, "STA " MACSTR " sent probe request for %s "
+		   "SSID", MAC2STR(mgmt->sa),
+		   elems.ssid_len == 0 ? "broadcast" : "our");
+}
 
-#ifdef CONFIG_IEEE80211N
-	pos = hostapd_eid_ht_capabilities(hapd, pos);
-	pos = hostapd_eid_ht_operation(hapd, pos);
-#endif /* CONFIG_IEEE80211N */
 
-	/* Wi-Fi Alliance WMM */
-	pos = hostapd_eid_wmm(hapd, pos);
+static void ieee802_11_set_probe_resp(struct hostapd_data *hapd)
+{
+	struct ieee80211_mgmt *resp;
+	size_t resp_len;
 
-#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);
 
-	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");
 }
 
 
-void ieee802_11_set_beacon(struct hostapd_data *hapd)
+static void ieee802_11_set_beacon(struct hostapd_data *hapd)
 {
 	struct ieee80211_mgmt *head;
 	u8 *pos, *tail, *tailpos;
@@ -521,11 +561,18 @@ no_beacon:
 }
 
 
-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 c1510e1..18b5f95 100644
--- a/src/ap/beacon.h
+++ b/src/ap/beacon.h
@@ -21,14 +21,16 @@ struct ieee80211_mgmt;
 void handle_probe_req(struct hostapd_data *hapd,
 		      const struct ieee80211_mgmt *mgmt, size_t len);
 #ifdef NEED_AP_MLME
-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);
 #else /* NEED_AP_MLME */
-static inline void ieee802_11_set_beacon(struct hostapd_data *hapd)
+static
+inline void ieee802_11_set_beacon_and_probe(struct hostapd_data *hapd)
 {
 }
 
-static inline void ieee802_11_set_beacons(struct hostapd_iface *iface)
+static
+inline void ieee802_11_set_beacons_and_probes(struct hostapd_iface *iface)
 {
 }
 #endif /* NEED_AP_MLME */
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index 16d7c45..b574100 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -74,7 +74,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 &&
@@ -618,7 +618,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->driver && hapd->driver->set_operstate)
 		hapd->driver->set_operstate(hapd->drv_priv, 1);
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index f65b79e..92a7279 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -1021,7 +1021,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) &&
@@ -1031,7 +1031,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)
@@ -1045,7 +1045,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 7541b83..d190684 100644
--- a/src/ap/ieee802_11_ht.c
+++ b/src/ap/ieee802_11_ht.c
@@ -239,7 +239,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 07de034..dce0b8f 100644
--- a/src/ap/sta_info.c
+++ b/src/ap/sta_info.c
@@ -191,7 +191,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 cfff55c..8f2ace0 100644
--- a/src/ap/wps_hostapd.c
+++ b/src/ap/wps_hostapd.c
@@ -140,7 +140,7 @@ static int hostapd_wps_set_ie_cb(void *ctx, struct wpabuf *beacon_ie,
 	hapd->wps_beacon_ie = beacon_ie;
 	wpabuf_free(hapd->wps_probe_resp_ie);
 	hapd->wps_probe_resp_ie = probe_resp_ie;
-	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 b8684fa..f44343a 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -1280,6 +1280,20 @@ struct wpa_driver_ops {
 			  int beacon_int);
 
 	/**
+	 * 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 26ccdea..18a116d 100644
--- a/wpa_supplicant/ap.c
+++ b/wpa_supplicant/ap.c
@@ -792,7 +792,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.1




More information about the Hostap mailing list