diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h index fbe8734ff..25720b84a 100644 --- a/src/ap/ap_config.h +++ b/src/ap/ap_config.h @@ -316,6 +316,7 @@ struct hostapd_bss_config { char *model_description; char *model_url; char *upc; + struct wpabuf *wps_vendor_ext[MAX_WPS_VENDOR_EXTENSIONS]; #endif /* CONFIG_WPS */ #define P2P_ENABLED BIT(0) diff --git a/src/ap/wps_hostapd.c b/src/ap/wps_hostapd.c index 92a6dd4a6..fcbd89b9c 100644 --- a/src/ap/wps_hostapd.c +++ b/src/ap/wps_hostapd.c @@ -657,6 +657,31 @@ static int interface_count(struct hostapd_iface *iface) } +static int hostapd_wps_set_vendor_ext(struct hostapd_data *hapd, + struct wps_context *wps) +{ + int i; + + for (i = 0; i < MAX_WPS_VENDOR_EXTENSIONS; i++) { + wpabuf_free(wps->dev.vendor_ext[i]); + wps->dev.vendor_ext[i] = NULL; + + if (hapd->conf->wps_vendor_ext[i] == NULL) + continue; + + wps->dev.vendor_ext[i] = + wpabuf_dup(hapd->conf->wps_vendor_ext[i]); + if (wps->dev.vendor_ext[i] == NULL) { + while (--i >= 0) + wpabuf_free(wps->dev.vendor_ext[i]); + return -1; + } + } + + return 0; +} + + int hostapd_init_wps(struct hostapd_data *hapd, struct hostapd_bss_config *conf) { @@ -731,6 +756,11 @@ int hostapd_init_wps(struct hostapd_data *hapd, os_memcpy(wps->dev.pri_dev_type, hapd->conf->device_type, WPS_DEV_TYPE_LEN); + if (hostapd_wps_set_vendor_ext(hapd, wps) < 0) { + os_free(wps); + return -1; + } + wps->dev.os_version = WPA_GET_BE32(hapd->conf->os_version); wps->dev.rf_bands = hapd->iconf->hw_mode == HOSTAPD_MODE_IEEE80211A ? WPS_RF_50GHZ : WPS_RF_24GHZ; /* FIX: dualband AP */ @@ -900,6 +930,8 @@ void hostapd_update_wps(struct hostapd_data *hapd) hapd->wps->upc = hapd->conf->upc; #endif /* CONFIG_WPS_UPNP */ + hostapd_wps_set_vendor_ext(hapd, hapd->wps); + if (hapd->conf->wps_state) wps_registrar_update_ie(hapd->wps->registrar); else diff --git a/src/wps/wps.h b/src/wps/wps.h index 60a33d524..8b2998295 100644 --- a/src/wps/wps.h +++ b/src/wps/wps.h @@ -64,6 +64,8 @@ struct wps_credential { #define WPS_DEV_TYPE_LEN 8 #define WPS_DEV_TYPE_BUFSIZE 21 #define WPS_SEC_DEV_TYPE_MAX_LEN 128 +/* maximum number of advertised WPS vendor extension attributes */ +#define MAX_WPS_VENDOR_EXTENSIONS 10 /** * struct wps_device_data - WPS Device Data @@ -93,6 +95,7 @@ struct wps_device_data { u8 num_sec_dev_types; u32 os_version; u8 rf_bands; + struct wpabuf *vendor_ext[MAX_WPS_VENDOR_EXTENSIONS]; int p2p; }; diff --git a/src/wps/wps_dev_attr.c b/src/wps/wps_dev_attr.c index 2304bc4e2..7253d21ec 100644 --- a/src/wps/wps_dev_attr.c +++ b/src/wps/wps_dev_attr.c @@ -199,6 +199,25 @@ int wps_build_rf_bands(struct wps_device_data *dev, struct wpabuf *msg) } +int wps_build_vendor_ext(struct wps_device_data *dev, struct wpabuf *msg) +{ + int i; + + for (i = 0; i < MAX_WPS_VENDOR_EXTENSIONS; i++) { + if (dev->vendor_ext[i] == NULL) + continue; + wpa_hexdump(MSG_DEBUG, "WPS: * Vendor Extension", + wpabuf_head_u8(dev->vendor_ext[i]), + wpabuf_len(dev->vendor_ext[i])); + wpabuf_put_be16(msg, ATTR_VENDOR_EXT); + wpabuf_put_be16(msg, wpabuf_len(dev->vendor_ext[i])); + wpabuf_put_buf(msg, dev->vendor_ext[i]); + } + + return 0; +} + + static int wps_process_manufacturer(struct wps_device_data *dev, const u8 *str, size_t str_len) { diff --git a/src/wps/wps_dev_attr.h b/src/wps/wps_dev_attr.h index 84a2cd288..f17f62d64 100644 --- a/src/wps/wps_dev_attr.h +++ b/src/wps/wps_dev_attr.h @@ -36,5 +36,6 @@ int wps_process_rf_bands(struct wps_device_data *dev, const u8 *bands); void wps_device_data_dup(struct wps_device_data *dst, const struct wps_device_data *src); void wps_device_data_free(struct wps_device_data *dev); +int wps_build_vendor_ext(struct wps_device_data *dev, struct wpabuf *msg); #endif /* WPS_DEV_ATTR_H */ diff --git a/src/wps/wps_registrar.c b/src/wps/wps_registrar.c index dbaf99357..65ff40dd6 100644 --- a/src/wps/wps_registrar.c +++ b/src/wps/wps_registrar.c @@ -1113,14 +1113,23 @@ static int wps_set_ie(struct wps_registrar *reg) struct wpabuf *probe; const u8 *auth_macs; size_t count; + size_t vendor_len = 0; + int i; if (reg->set_ie_cb == NULL) return 0; - beacon = wpabuf_alloc(400); + for (i = 0; i < MAX_WPS_VENDOR_EXTENSIONS; i++) { + if (reg->wps->dev.vendor_ext[i]) { + vendor_len += 2 + 2; + vendor_len += wpabuf_len(reg->wps->dev.vendor_ext[i]); + } + } + + beacon = wpabuf_alloc(400 + vendor_len); if (beacon == NULL) return -1; - probe = wpabuf_alloc(500); + probe = wpabuf_alloc(500 + vendor_len); if (probe == NULL) { wpabuf_free(beacon); return -1; @@ -1138,7 +1147,8 @@ static int wps_set_ie(struct wps_registrar *reg) wps_build_sel_reg_config_methods(reg, beacon) || wps_build_sel_pbc_reg_uuid_e(reg, beacon) || (reg->dualband && wps_build_rf_bands(®->wps->dev, beacon)) || - wps_build_wfa_ext(beacon, 0, auth_macs, count)) { + wps_build_wfa_ext(beacon, 0, auth_macs, count) || + wps_build_vendor_ext(®->wps->dev, beacon)) { wpabuf_free(beacon); wpabuf_free(probe); return -1; @@ -1167,7 +1177,8 @@ static int wps_set_ie(struct wps_registrar *reg) wps_build_device_attrs(®->wps->dev, probe) || wps_build_probe_config_methods(reg, probe) || wps_build_rf_bands(®->wps->dev, probe) || - wps_build_wfa_ext(probe, 0, auth_macs, count)) { + wps_build_wfa_ext(probe, 0, auth_macs, count) || + wps_build_vendor_ext(®->wps->dev, probe)) { wpabuf_free(beacon); wpabuf_free(probe); return -1;