From 4028a7fd4382ac0612fdd146f5a21ee01dc56fbe Mon Sep 17 00:00:00 2001 From: Jean-Michel Bachot Date: Sat, 19 Mar 2011 11:44:42 +0200 Subject: [PATCH] WPS: Add support for adding WPS Vendor Extensions This adds the ability to add WPS vendor extensions to an AP (or GO). They will be added to the WSC IE(s) in Beacon and Probe Response frames. Signed-off-by: Johannes Berg --- src/ap/ap_config.h | 1 + src/ap/wps_hostapd.c | 32 ++++++++++++++++++++++++++++++++ src/wps/wps.h | 3 +++ src/wps/wps_dev_attr.c | 19 +++++++++++++++++++ src/wps/wps_dev_attr.h | 1 + src/wps/wps_registrar.c | 19 +++++++++++++++---- 6 files changed, 71 insertions(+), 4 deletions(-) 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;