Browse Source

Provide extra IEs for AP mode management frames with set_ap

Drivers that build Beacon, Probe Response, and (Re)Association
Response frames can use this information to and WPS and P2P IE
when needed.
Jouni Malinen 13 years ago
parent
commit
fb91db5639
5 changed files with 114 additions and 43 deletions
  1. 65 43
      src/ap/ap_drv_ops.c
  2. 7 0
      src/ap/ap_drv_ops.h
  3. 6 0
      src/ap/beacon.c
  4. 21 0
      src/drivers/driver.h
  5. 15 0
      src/drivers/driver_nl80211.c

+ 65 - 43
src/ap/ap_drv_ops.c

@@ -41,49 +41,47 @@ u32 hostapd_sta_flags_to_drv(u32 flags)
 }
 
 
-int hostapd_set_ap_wps_ie(struct hostapd_data *hapd)
+int hostapd_build_ap_extra_ies(struct hostapd_data *hapd,
+			       struct wpabuf **beacon,
+			       struct wpabuf **proberesp,
+			       struct wpabuf **assocresp)
 {
-	struct wpabuf *beacon, *proberesp, *assocresp = NULL;
-	int ret;
-
-	if (hapd->driver == NULL || hapd->driver->set_ap_wps_ie == NULL)
-		return 0;
-
-	beacon = hapd->wps_beacon_ie;
-	proberesp = hapd->wps_probe_resp_ie;
+	*beacon = hapd->wps_beacon_ie;
+	*proberesp = hapd->wps_probe_resp_ie;
+	*assocresp = NULL;
 
 #ifdef CONFIG_P2P
 	if (hapd->wps_beacon_ie == NULL && hapd->p2p_beacon_ie == NULL)
-		beacon = NULL;
+		*beacon = NULL;
 	else {
-		beacon = wpabuf_alloc((hapd->wps_beacon_ie ?
-				       wpabuf_len(hapd->wps_beacon_ie) : 0) +
-				      (hapd->p2p_beacon_ie ?
-				       wpabuf_len(hapd->p2p_beacon_ie) : 0));
-		if (beacon == NULL)
+		*beacon = wpabuf_alloc((hapd->wps_beacon_ie ?
+					wpabuf_len(hapd->wps_beacon_ie) : 0) +
+				       (hapd->p2p_beacon_ie ?
+					wpabuf_len(hapd->p2p_beacon_ie) : 0));
+		if (*beacon == NULL)
 			return -1;
 		if (hapd->wps_beacon_ie)
-			wpabuf_put_buf(beacon, hapd->wps_beacon_ie);
+			wpabuf_put_buf(*beacon, hapd->wps_beacon_ie);
 		if (hapd->p2p_beacon_ie)
-			wpabuf_put_buf(beacon, hapd->p2p_beacon_ie);
+			wpabuf_put_buf(*beacon, hapd->p2p_beacon_ie);
 	}
 
 	if (hapd->wps_probe_resp_ie == NULL && hapd->p2p_probe_resp_ie == NULL)
-		proberesp = NULL;
+		*proberesp = NULL;
 	else {
-		proberesp = wpabuf_alloc(
+		*proberesp = wpabuf_alloc(
 			(hapd->wps_probe_resp_ie ?
 			 wpabuf_len(hapd->wps_probe_resp_ie) : 0) +
 			(hapd->p2p_probe_resp_ie ?
 			 wpabuf_len(hapd->p2p_probe_resp_ie) : 0));
-		if (proberesp == NULL) {
-			wpabuf_free(beacon);
+		if (*proberesp == NULL) {
+			wpabuf_free(*beacon);
 			return -1;
 		}
 		if (hapd->wps_probe_resp_ie)
-			wpabuf_put_buf(proberesp, hapd->wps_probe_resp_ie);
+			wpabuf_put_buf(*proberesp, hapd->wps_probe_resp_ie);
 		if (hapd->p2p_probe_resp_ie)
-			wpabuf_put_buf(proberesp, hapd->p2p_probe_resp_ie);
+			wpabuf_put_buf(*proberesp, hapd->p2p_probe_resp_ie);
 	}
 #endif /* CONFIG_P2P */
 
@@ -91,67 +89,91 @@ int hostapd_set_ap_wps_ie(struct hostapd_data *hapd)
 	if (hapd->conf->p2p & P2P_MANAGE) {
 		struct wpabuf *a;
 
-		a = wpabuf_alloc(100 + (beacon ? wpabuf_len(beacon) : 0));
+		a = wpabuf_alloc(100 + (*beacon ? wpabuf_len(*beacon) : 0));
 		if (a) {
 			u8 *start, *p;
-			if (beacon)
-				wpabuf_put_buf(a, beacon);
-			if (beacon != hapd->wps_beacon_ie)
-				wpabuf_free(beacon);
+			if (*beacon)
+				wpabuf_put_buf(a, *beacon);
+			if (*beacon != hapd->wps_beacon_ie)
+				wpabuf_free(*beacon);
 			start = wpabuf_put(a, 0);
 			p = hostapd_eid_p2p_manage(hapd, start);
 			wpabuf_put(a, p - start);
-			beacon = a;
+			*beacon = a;
 		}
 
-		a = wpabuf_alloc(100 + (proberesp ? wpabuf_len(proberesp) :
+		a = wpabuf_alloc(100 + (*proberesp ? wpabuf_len(*proberesp) :
 					0));
 		if (a) {
 			u8 *start, *p;
-			if (proberesp)
-				wpabuf_put_buf(a, proberesp);
-			if (proberesp != hapd->wps_probe_resp_ie)
-				wpabuf_free(proberesp);
+			if (*proberesp)
+				wpabuf_put_buf(a, *proberesp);
+			if (*proberesp != hapd->wps_probe_resp_ie)
+				wpabuf_free(*proberesp);
 			start = wpabuf_put(a, 0);
 			p = hostapd_eid_p2p_manage(hapd, start);
 			wpabuf_put(a, p - start);
-			proberesp = a;
+			*proberesp = a;
 		}
 	}
 #endif /* CONFIG_P2P_MANAGER */
 
 #ifdef CONFIG_WPS2
 	if (hapd->conf->wps_state)
-		assocresp = wps_build_assoc_resp_ie();
+		*assocresp = wps_build_assoc_resp_ie();
 #endif /* CONFIG_WPS2 */
 
 #ifdef CONFIG_P2P_MANAGER
 	if (hapd->conf->p2p & P2P_MANAGE) {
 		struct wpabuf *a;
-		a = wpabuf_alloc(100 + (assocresp ? wpabuf_len(assocresp) :
+		a = wpabuf_alloc(100 + (*assocresp ? wpabuf_len(*assocresp) :
 					0));
 		if (a) {
 			u8 *start, *p;
 			start = wpabuf_put(a, 0);
 			p = hostapd_eid_p2p_manage(hapd, start);
 			wpabuf_put(a, p - start);
-			if (assocresp) {
-				wpabuf_put_buf(a, assocresp);
-				wpabuf_free(assocresp);
+			if (*assocresp) {
+				wpabuf_put_buf(a, *assocresp);
+				wpabuf_free(*assocresp);
 			}
-			assocresp = a;
+			*assocresp = a;
 		}
 	}
 #endif /* CONFIG_P2P_MANAGER */
 
-	ret = hapd->driver->set_ap_wps_ie(hapd->drv_priv, beacon, proberesp,
-					  assocresp);
+	return 0;
+}
+
 
+void hostapd_free_ap_extra_ies(struct hostapd_data *hapd, struct wpabuf *beacon,
+			       struct wpabuf *proberesp,
+			       struct wpabuf *assocresp)
+{
 	if (beacon != hapd->wps_beacon_ie)
 		wpabuf_free(beacon);
 	if (proberesp != hapd->wps_probe_resp_ie)
 		wpabuf_free(proberesp);
 	wpabuf_free(assocresp);
+}
+
+
+int hostapd_set_ap_wps_ie(struct hostapd_data *hapd)
+{
+	struct wpabuf *beacon, *proberesp, *assocresp;
+	int ret;
+
+	if (hapd->driver == NULL || hapd->driver->set_ap_wps_ie == NULL)
+		return 0;
+
+	if (hostapd_build_ap_extra_ies(hapd, &beacon, &proberesp, &assocresp) <
+	    0)
+		return -1;
+
+	ret = hapd->driver->set_ap_wps_ie(hapd->drv_priv, beacon, proberesp,
+					  assocresp);
+
+	hostapd_free_ap_extra_ies(hapd, beacon, proberesp, assocresp);
 
 	return ret;
 }

+ 7 - 0
src/ap/ap_drv_ops.h

@@ -21,6 +21,13 @@ struct wpa_driver_scan_params;
 struct ieee80211_ht_capabilities;
 
 u32 hostapd_sta_flags_to_drv(u32 flags);
+int hostapd_build_ap_extra_ies(struct hostapd_data *hapd,
+			       struct wpabuf **beacon,
+			       struct wpabuf **proberesp,
+			       struct wpabuf **assocresp);
+void hostapd_free_ap_extra_ies(struct hostapd_data *hapd, struct wpabuf *beacon,
+			       struct wpabuf *proberesp,
+			       struct wpabuf *assocresp);
 int hostapd_set_ap_wps_ie(struct hostapd_data *hapd);
 int hostapd_set_authorized(struct hostapd_data *hapd,
 			   struct sta_info *sta, int authorized);

+ 6 - 0
src/ap/beacon.c

@@ -399,6 +399,7 @@ void ieee802_11_set_beacon(struct hostapd_data *hapd)
 	u16 capab_info;
 	size_t head_len, tail_len;
 	struct wpa_driver_ap_params params;
+	struct wpabuf *beacon, *proberesp, *assocresp;
 
 #ifdef CONFIG_P2P
 	if ((hapd->conf->p2p & (P2P_ENABLED | P2P_GROUP_OWNER)) == P2P_ENABLED)
@@ -541,8 +542,13 @@ 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;
 	if (hostapd_drv_set_ap(hapd, &params))
 		wpa_printf(MSG_ERROR, "Failed to set beacon parameters");
+	hostapd_free_ap_extra_ies(hapd, beacon, proberesp, assocresp);
 
 	os_free(tail);
 	os_free(head);

+ 21 - 0
src/drivers/driver.h

@@ -581,6 +581,27 @@ struct wpa_driver_ap_params {
 	 * privacy - Whether privacy is used in the BSS
 	 */
 	int privacy;
+
+	/**
+	 * beacon_ies - WPS/P2P IE(s) for Beacon frames
+	 *
+	 * This is used to add IEs like WPS IE and P2P IE by drivers that do not
+	 * use the full Beacon template.
+	 */
+	const struct wpabuf *beacon_ies;
+
+	/**
+	 * proberesp_ies - P2P/WPS IE(s) for Probe Response frames
+	 *
+	 * This is used to add IEs like WPS IE and P2P IE by drivers that
+	 * reply to Probe Request frames internally.
+	 */
+	const struct wpabuf *proberesp_ies;
+
+	/**
+	 * assocresp_ies - WPS IE(s) for (Re)Association Response frames
+	 */
+	const struct wpabuf *assocresp_ies;
 };
 
 /**

+ 15 - 0
src/drivers/driver_nl80211.c

@@ -3929,6 +3929,21 @@ static int wpa_driver_nl80211_set_ap(void *priv,
 		break;
 	}
 
+	if (params->beacon_ies) {
+		NLA_PUT(msg, NL80211_ATTR_IE, wpabuf_len(params->beacon_ies),
+			wpabuf_head(params->beacon_ies));
+	}
+	if (params->proberesp_ies) {
+		NLA_PUT(msg, NL80211_ATTR_IE_PROBE_RESP,
+			wpabuf_len(params->proberesp_ies),
+			wpabuf_head(params->proberesp_ies));
+	}
+	if (params->assocresp_ies) {
+		NLA_PUT(msg, NL80211_ATTR_IE_ASSOC_RESP,
+			wpabuf_len(params->assocresp_ies),
+			wpabuf_head(params->assocresp_ies));
+	}
+
 	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
 	if (ret) {
 		wpa_printf(MSG_DEBUG, "nl80211: Beacon set failed: %d (%s)",