[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