diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c index 71296440a..2860b57f5 100644 --- a/src/ap/ap_drv_ops.c +++ b/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; } diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h index a9406bdca..115099d13 100644 --- a/src/ap/ap_drv_ops.h +++ b/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); diff --git a/src/ap/beacon.c b/src/ap/beacon.c index 8fa5aef67..7a4b267bb 100644 --- a/src/ap/beacon.c +++ b/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, ¶ms)) wpa_printf(MSG_ERROR, "Failed to set beacon parameters"); + hostapd_free_ap_extra_ies(hapd, beacon, proberesp, assocresp); os_free(tail); os_free(head); diff --git a/src/drivers/driver.h b/src/drivers/driver.h index 96ca09912..39a6ae6a8 100644 --- a/src/drivers/driver.h +++ b/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; }; /** diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c index 52aa60f50..995997482 100644 --- a/src/drivers/driver_nl80211.c +++ b/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)",