Provide extra IEs for AP mode management frames with set_ap
authorJouni Malinen <jouni@qca.qualcomm.com>
Fri, 26 Aug 2011 18:14:25 +0000 (21:14 +0300)
committerJouni Malinen <j@w1.fi>
Fri, 26 Aug 2011 18:14:25 +0000 (21:14 +0300)
Drivers that build Beacon, Probe Response, and (Re)Association
Response frames can use this information to and WPS and P2P IE
when needed.

src/ap/ap_drv_ops.c
src/ap/ap_drv_ops.h
src/ap/beacon.c
src/drivers/driver.h
src/drivers/driver_nl80211.c

index 7129644..2860b57 100644 (file)
@@ -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;
 }
index a9406bd..115099d 100644 (file)
@@ -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);
index 8fa5aef..7a4b267 100644 (file)
@@ -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);
index 96ca099..39a6ae6 100644 (file)
@@ -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;
 };
 
 /**
index 52aa60f..9959974 100644 (file)
@@ -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)",