if (wps_build_version(ie) ||
wps_build_req_type(ie, req_type) ||
- wps_build_version2(ie)) {
+ wps_build_wfa_ext(ie, 0, NULL, 0)) {
wpabuf_free(ie);
return NULL;
}
if (wps_build_version(ie) ||
wps_build_resp_type(ie, WPS_RESP_AP) ||
- wps_build_version2(ie)) {
+ wps_build_wfa_ext(ie, 0, NULL, 0)) {
wpabuf_free(ie);
return NULL;
}
wps_build_dev_password_id(ie, pbc ? DEV_PW_PUSHBUTTON :
DEV_PW_DEFAULT) ||
#ifdef CONFIG_WPS2
- wps_build_version2(ie) ||
wps_build_manufacturer(dev, ie) ||
wps_build_model_name(dev, ie) ||
wps_build_model_number(dev, ie) ||
wps_build_dev_name(dev, ie) ||
- (req_type == WPS_REQ_ENROLLEE &&
- wps_build_req_to_enroll(ie))
+ wps_build_wfa_ext(ie, req_type == WPS_REQ_ENROLLEE, NULL, 0)
#else /* CONFIG_WPS2 */
0
#endif /* CONFIG_WPS2 */
}
-int wps_build_version2(struct wpabuf *msg)
+int wps_build_wfa_ext(struct wpabuf *msg, int req_to_enroll,
+ const u8 *auth_macs, size_t auth_macs_count)
{
#ifdef CONFIG_WPS2
+ u8 *len;
+
+ wpabuf_put_be16(msg, ATTR_VENDOR_EXT);
+ len = wpabuf_put(msg, 2); /* to be filled */
+ wpabuf_put_be24(msg, WPS_VENDOR_ID_WFA);
+
wpa_printf(MSG_DEBUG, "WPS: * Version2 (0x%x)", WPS_VERSION);
- wpabuf_put_be16(msg, ATTR_VERSION2);
- wpabuf_put_be16(msg, 1);
+ wpabuf_put_u8(msg, WFA_ELEM_VERSION2);
+ wpabuf_put_u8(msg, 1);
wpabuf_put_u8(msg, WPS_VERSION);
+
+ if (req_to_enroll) {
+ wpa_printf(MSG_DEBUG, "WPS: * Request to Enroll (1)");
+ wpabuf_put_u8(msg, WFA_ELEM_REQUEST_TO_ENROLL);
+ wpabuf_put_u8(msg, 1);
+ wpabuf_put_u8(msg, 1);
+ }
+
+ if (auth_macs && auth_macs_count) {
+ size_t i;
+ wpa_printf(MSG_DEBUG, "WPS: * AuthorizedMACs (count=%d)",
+ (int) auth_macs_count);
+ wpabuf_put_u8(msg, WFA_ELEM_AUTHORIZEDMACS);
+ wpabuf_put_u8(msg, auth_macs_count * ETH_ALEN);
+ wpabuf_put_data(msg, auth_macs, auth_macs_count * ETH_ALEN);
+ for (i = 0; i < auth_macs_count; i++)
+ wpa_printf(MSG_DEBUG, "WPS: AuthorizedMAC: " MACSTR,
+ MAC2STR(&auth_macs[i * ETH_ALEN]));
+ }
+
+ WPA_PUT_BE16(len, (u8 *) wpabuf_put(msg, 0) - len - 2);
+#endif /* CONFIG_WPS2 */
+
#ifdef CONFIG_WPS_EXTENSIBILITY_TESTING
wpa_printf(MSG_DEBUG, "WPS: * Extensibility Testing - extra "
"attribute";
wpabuf_put_be16(msg, 1);
wpabuf_put_u8(msg, 42);
#endif /* CONFIG_WPS_EXTENSIBILITY_TESTING */
-#endif /* CONFIG_WPS2 */
return 0;
}
#endif /* CONFIG_WPS_OOB */
-int wps_build_req_to_enroll(struct wpabuf *msg)
-{
-#ifdef CONFIG_WPS2
- wpa_printf(MSG_DEBUG, "WPS: * Request to Enroll (1)");
- wpabuf_put_be16(msg, ATTR_REQUEST_TO_ENROLL);
- wpabuf_put_be16(msg, 1);
- wpabuf_put_u8(msg, 1);
-#endif /* CONFIG_WPS2 */
- return 0;
-}
-
-
/* Encapsulate WPS IE data with one (or more, if needed) IE headers */
struct wpabuf * wps_ie_encapsulate(struct wpabuf *data)
{
#endif /* CONFIG_WPS_STRICT */
+static int wps_set_vendor_ext_wfa_subelem(struct wps_parse_attr *attr,
+ u8 id, u8 len, const u8 *pos)
+{
+ wpa_printf(MSG_MSGDUMP, "WPS: WFA subelement id=%u len=%u",
+ id, len);
+ switch (id) {
+ case WFA_ELEM_VERSION2:
+ if (len != 1) {
+ wpa_printf(MSG_DEBUG, "WPS: Invalid Version2 length "
+ "%u", len);
+ return -1;
+ }
+ attr->version2 = pos;
+ break;
+ case WFA_ELEM_AUTHORIZEDMACS:
+ attr->authorized_macs = pos;
+ attr->authorized_macs_len = len;
+ break;
+ case WFA_ELEM_NETWORK_KEY_SHAREABLE:
+ if (len != 1) {
+ wpa_printf(MSG_DEBUG, "WPS: Invalid Network Key "
+ "Shareable length %u", len);
+ return -1;
+ }
+ attr->network_key_shareable = pos;
+ break;
+ case WFA_ELEM_REQUEST_TO_ENROLL:
+ if (len != 1) {
+ wpa_printf(MSG_DEBUG, "WPS: Invalid Request to Enroll "
+ "length %u", len);
+ return -1;
+ }
+ attr->request_to_enroll = pos;
+ break;
+ case WFA_ELEM_SETTINGS_DELAY_TIME:
+ if (len != 1) {
+ wpa_printf(MSG_DEBUG, "WPS: Invalid Settings Delay "
+ "Time length %u", len);
+ return -1;
+ }
+ attr->settings_delay_time = pos;
+ break;
+ default:
+ wpa_printf(MSG_MSGDUMP, "WPS: Skipped unknown WFA Vendor "
+ "Extension subelement %u", id);
+ break;
+ }
+
+ return 0;
+}
+
+
+static int wps_parse_vendor_ext_wfa(struct wps_parse_attr *attr, const u8 *pos,
+ u16 len)
+{
+ const u8 *end = pos + len;
+ u8 id, elen;
+
+ while (pos + 2 < end) {
+ id = *pos++;
+ elen = *pos++;
+ if (pos + elen > end)
+ break;
+ if (wps_set_vendor_ext_wfa_subelem(attr, id, elen, pos) < 0)
+ return -1;
+ pos += elen;
+ }
+
+ return 0;
+}
+
+
+static int wps_parse_vendor_ext(struct wps_parse_attr *attr, const u8 *pos,
+ u16 len)
+{
+ u32 vendor_id;
+
+ if (len < 3) {
+ wpa_printf(MSG_DEBUG, "WPS: Skip invalid Vendor Extension");
+ return 0;
+ }
+
+ vendor_id = WPA_GET_BE24(pos);
+ switch (vendor_id) {
+ case WPS_VENDOR_ID_WFA:
+ return wps_parse_vendor_ext_wfa(attr, pos + 3, len - 3);
+ default:
+ wpa_printf(MSG_MSGDUMP, "WPS: Skip unknown Vendor Extension "
+ "(Vendor ID %u)", vendor_id);
+ break;
+ }
+
+ return 0;
+}
+
+
static int wps_set_attr(struct wps_parse_attr *attr, u16 type,
const u8 *pos, u16 len)
{
}
attr->version = pos;
break;
-#ifdef CONFIG_WPS2
- case ATTR_VERSION2:
- if (len != 1) {
- wpa_printf(MSG_DEBUG, "WPS: Invalid Version2 length "
- "%u", len);
- return -1;
- }
- attr->version2 = pos;
- break;
-#endif /* CONFIG_WPS2 */
case ATTR_MSG_TYPE:
if (len != 1) {
wpa_printf(MSG_DEBUG, "WPS: Invalid Message Type "
attr->ap_setup_locked = pos;
break;
#ifdef CONFIG_WPS2
- case ATTR_SETTINGS_DELAY_TIME:
- if (len != 1) {
- wpa_printf(MSG_DEBUG, "WPS: Invalid Settings Delay "
- "Time length %u", len);
- return -1;
- }
- attr->settings_delay_time = pos;
- break;
- case ATTR_NETWORK_KEY_SHAREABLE:
- if (len != 1) {
- wpa_printf(MSG_DEBUG, "WPS: Invalid Network Key "
- "Shareable length %u", len);
- return -1;
- }
- attr->network_key_shareable = pos;
- break;
- case ATTR_REQUEST_TO_ENROLL:
- if (len != 1) {
- wpa_printf(MSG_DEBUG, "WPS: Invalid Request to Enroll "
- "length %u", len);
- return -1;
- }
- attr->request_to_enroll = pos;
- break;
- case ATTR_AUTHORIZED_MACS:
- attr->authorized_macs = pos;
- attr->authorized_macs_len = len;
- break;
case ATTR_REQUESTED_DEV_TYPE:
if (len != WPS_DEV_TYPE_LEN) {
wpa_printf(MSG_DEBUG, "WPS: Invalid Requested Device "
attr->num_req_dev_type++;
break;
#endif /* CONFIG_WPS2 */
+ case ATTR_VENDOR_EXT:
+ if (wps_parse_vendor_ext(attr, pos, len) < 0)
+ return -1;
+ break;
default:
wpa_printf(MSG_DEBUG, "WPS: Unsupported attribute type 0x%x "
"len=%u", type, len);
type, len);
if (len > end - pos) {
wpa_printf(MSG_DEBUG, "WPS: Attribute overflow");
+ wpa_hexdump_buf(MSG_MSGDUMP, "WPS: Message data", msg);
return -1;
}
ATTR_802_1X_ENABLED = 0x1062,
ATTR_APPSESSIONKEY = 0x1063,
ATTR_WEPTRANSMITKEY = 0x1064,
-#ifdef CONFIG_WPS2
- ATTR_SETTINGS_DELAY_TIME = 0x1065,
- ATTR_NETWORK_KEY_SHAREABLE = 0x1066,
- ATTR_VERSION2 = 0x1067,
- ATTR_REQUEST_TO_ENROLL = 0x1068,
- ATTR_AUTHORIZED_MACS = 0x1069,
ATTR_REQUESTED_DEV_TYPE = 0x106a,
-#endif /* CONFIG_WPS2 */
ATTR_EXTENSIBILITY_TEST = 0x10fa /* _NOT_ defined in the spec */
};
+#define WPS_VENDOR_ID_WFA 14122
+
+/* WFA Vendor Extension subelements */
+enum {
+ WFA_ELEM_VERSION2 = 0x00,
+ WFA_ELEM_AUTHORIZEDMACS = 0x01,
+ WFA_ELEM_NETWORK_KEY_SHAREABLE = 0x02,
+ WFA_ELEM_REQUEST_TO_ENROLL = 0x03,
+ WFA_ELEM_SETTINGS_DELAY_TIME = 0x04
+};
+
/* Device Password ID */
enum wps_dev_password_id {
DEV_PW_DEFAULT = 0x0000,
wps_build_dev_password_id(msg, wps->dev_pw_id) ||
wps_build_config_error(msg, WPS_CFG_NO_ERROR) ||
wps_build_os_version(&wps->wps->dev, msg) ||
- wps_build_version2(msg)) {
+ wps_build_wfa_ext(msg, 0, NULL, 0)) {
wpabuf_free(msg);
return NULL;
}
wps_build_msg_type(msg, WPS_M3) ||
wps_build_registrar_nonce(wps, msg) ||
wps_build_e_hash(wps, msg) ||
- wps_build_version2(msg) ||
+ wps_build_wfa_ext(msg, 0, NULL, 0) ||
wps_build_authenticator(wps, msg)) {
wpabuf_free(msg);
return NULL;
wps_build_e_snonce1(wps, plain) ||
wps_build_key_wrap_auth(wps, plain) ||
wps_build_encr_settings(wps, msg, plain) ||
- wps_build_version2(msg) ||
+ wps_build_wfa_ext(msg, 0, NULL, 0) ||
wps_build_authenticator(wps, msg)) {
wpabuf_free(plain);
wpabuf_free(msg);
(wps->wps->ap && wps_build_ap_settings(wps, plain)) ||
wps_build_key_wrap_auth(wps, plain) ||
wps_build_encr_settings(wps, msg, plain) ||
- wps_build_version2(msg) ||
+ wps_build_wfa_ext(msg, 0, NULL, 0) ||
wps_build_authenticator(wps, msg)) {
wpabuf_free(plain);
wpabuf_free(msg);
wps_build_msg_type(msg, WPS_WSC_DONE) ||
wps_build_enrollee_nonce(wps, msg) ||
wps_build_registrar_nonce(wps, msg) ||
- wps_build_version2(msg)) {
+ wps_build_wfa_ext(msg, 0, NULL, 0)) {
wpabuf_free(msg);
return NULL;
}
wps_build_msg_type(msg, WPS_WSC_ACK) ||
wps_build_enrollee_nonce(wps, msg) ||
wps_build_registrar_nonce(wps, msg) ||
- wps_build_version2(msg)) {
+ wps_build_wfa_ext(msg, 0, NULL, 0)) {
wpabuf_free(msg);
return NULL;
}
wps_build_enrollee_nonce(wps, msg) ||
wps_build_registrar_nonce(wps, msg) ||
wps_build_config_error(msg, wps->config_error) ||
- wps_build_version2(msg)) {
+ wps_build_wfa_ext(msg, 0, NULL, 0)) {
wpabuf_free(msg);
return NULL;
}
{
struct wpabuf *msg;
struct wps_er_ap *ap;
+ struct wps_registrar *reg = er->wps->registrar;
+ const u8 *auth_macs;
+ size_t count;
if (er->skip_set_sel_reg) {
wpa_printf(MSG_DEBUG, "WPS ER: Skip SetSelectedRegistrar");
if (msg == NULL)
return;
+ auth_macs = wps_authorized_macs(reg, &count);
+
if (wps_build_version(msg) ||
wps_er_build_selected_registrar(msg, sel_reg) ||
wps_er_build_dev_password_id(msg, dev_passwd_id) ||
wps_er_build_sel_reg_config_methods(msg, sel_reg_config_methods) ||
- wps_build_version2(msg) ||
- wps_build_authorized_macs(er->wps->registrar, msg) ||
+ wps_build_wfa_ext(msg, 0, auth_macs, count) ||
wps_er_build_uuid_r(msg, er->wps->uuid)) {
wpabuf_free(msg);
return;
int wps_build_encr_settings(struct wps_data *wps, struct wpabuf *msg,
struct wpabuf *plain);
int wps_build_version(struct wpabuf *msg);
-int wps_build_version2(struct wpabuf *msg);
+int wps_build_wfa_ext(struct wpabuf *msg, int req_to_enroll,
+ const u8 *auth_macs, size_t auth_macs_count);
int wps_build_msg_type(struct wpabuf *msg, enum wps_msg_type msg_type);
int wps_build_enrollee_nonce(struct wps_data *wps, struct wpabuf *msg);
int wps_build_registrar_nonce(struct wps_data *wps, struct wpabuf *msg);
int wps_build_conn_type_flags(struct wps_data *wps, struct wpabuf *msg);
int wps_build_assoc_state(struct wps_data *wps, struct wpabuf *msg);
int wps_build_oob_dev_password(struct wpabuf *msg, struct wps_context *wps);
-int wps_build_req_to_enroll(struct wpabuf *msg);
struct wpabuf * wps_ie_encapsulate(struct wpabuf *data);
/* wps_attr_process.c */
int wps_device_store(struct wps_registrar *reg,
struct wps_device_data *dev, const u8 *uuid);
void wps_registrar_selected_registrar_changed(struct wps_registrar *reg);
-int wps_build_authorized_macs(struct wps_registrar *reg, struct wpabuf *msg);
+const u8 * wps_authorized_macs(struct wps_registrar *reg, size_t *count);
int wps_registrar_pbc_overlap(struct wps_registrar *reg,
const u8 *addr, const u8 *uuid_e);
}
-int wps_build_authorized_macs(struct wps_registrar *reg, struct wpabuf *msg)
+const u8 * wps_authorized_macs(struct wps_registrar *reg, size_t *count)
{
-#ifdef CONFIG_WPS2
- int count = 0, i;
+ *count = 0;
- while (count < WPS_MAX_AUTHORIZED_MACS) {
- if (is_zero_ether_addr(reg->authorized_macs_union[count]))
+#ifdef CONFIG_WPS2
+ while (*count < WPS_MAX_AUTHORIZED_MACS) {
+ if (is_zero_ether_addr(reg->authorized_macs_union[*count]))
break;
- count++;
+ (*count)++;
}
-
- if (count == 0)
- return 0;
-
- wpa_printf(MSG_DEBUG, "WPS: * AuthorizedMACs (count=%d)", count);
- wpabuf_put_be16(msg, ATTR_AUTHORIZED_MACS);
- wpabuf_put_be16(msg, count * ETH_ALEN);
- wpabuf_put_data(msg, reg->authorized_macs_union, count * ETH_ALEN);
- for (i = 0; i < count; i++)
- wpa_printf(MSG_DEBUG, "WPS: AuthorizedMAC: " MACSTR,
- MAC2STR(reg->authorized_macs_union[i]));
#endif /* CONFIG_WPS2 */
- return 0;
+ return (const u8 *) reg->authorized_macs_union;
}
{
struct wpabuf *beacon;
struct wpabuf *probe;
+ const u8 *auth_macs;
+ size_t count;
if (reg->set_ie_cb == NULL)
return 0;
return -1;
}
+ auth_macs = wps_authorized_macs(reg, &count);
+
wpa_printf(MSG_DEBUG, "WPS: Build Beacon IEs");
if (wps_build_version(beacon) ||
wps_build_selected_registrar(reg, beacon) ||
wps_build_sel_reg_dev_password_id(reg, beacon) ||
wps_build_sel_reg_config_methods(reg, beacon) ||
- wps_build_version2(beacon) ||
- wps_build_authorized_macs(reg, beacon)) {
+ wps_build_wfa_ext(beacon, 0, auth_macs, count)) {
wpabuf_free(beacon);
wpabuf_free(probe);
return -1;
wps_build_device_attrs(®->wps->dev, probe) ||
wps_build_probe_config_methods(reg, probe) ||
wps_build_rf_bands(®->wps->dev, probe) ||
- wps_build_version2(probe) ||
- wps_build_authorized_macs(reg, probe)) {
+ wps_build_wfa_ext(probe, 0, auth_macs, count)) {
wpabuf_free(beacon);
wpabuf_free(probe);
return -1;
wps_build_config_error(msg, WPS_CFG_NO_ERROR) ||
wps_build_dev_password_id(msg, wps->dev_pw_id) ||
wps_build_os_version(&wps->wps->dev, msg) ||
- wps_build_version2(msg) ||
+ wps_build_wfa_ext(msg, 0, NULL, 0) ||
wps_build_authenticator(wps, msg)) {
wpabuf_free(msg);
return NULL;
wps_build_assoc_state(wps, msg) ||
wps_build_config_error(msg, err) ||
wps_build_os_version(&wps->wps->dev, msg) ||
- wps_build_version2(msg)) {
+ wps_build_wfa_ext(msg, 0, NULL, 0)) {
wpabuf_free(msg);
return NULL;
}
wps_build_r_snonce1(wps, plain) ||
wps_build_key_wrap_auth(wps, plain) ||
wps_build_encr_settings(wps, msg, plain) ||
- wps_build_version2(msg) ||
+ wps_build_wfa_ext(msg, 0, NULL, 0) ||
wps_build_authenticator(wps, msg)) {
wpabuf_free(plain);
wpabuf_free(msg);
wps_build_r_snonce2(wps, plain) ||
wps_build_key_wrap_auth(wps, plain) ||
wps_build_encr_settings(wps, msg, plain) ||
- wps_build_version2(msg) ||
+ wps_build_wfa_ext(msg, 0, NULL, 0) ||
wps_build_authenticator(wps, msg)) {
wpabuf_free(plain);
wpabuf_free(msg);
(!wps->wps->ap && !wps->er && wps_build_ap_settings(wps, plain)) ||
wps_build_key_wrap_auth(wps, plain) ||
wps_build_encr_settings(wps, msg, plain) ||
- wps_build_version2(msg) ||
+ wps_build_wfa_ext(msg, 0, NULL, 0) ||
wps_build_authenticator(wps, msg)) {
wpabuf_free(plain);
wpabuf_free(msg);
wps_build_msg_type(msg, WPS_WSC_ACK) ||
wps_build_enrollee_nonce(wps, msg) ||
wps_build_registrar_nonce(wps, msg) ||
- wps_build_version2(msg)) {
+ wps_build_wfa_ext(msg, 0, NULL, 0)) {
wpabuf_free(msg);
return NULL;
}
wps_build_enrollee_nonce(wps, msg) ||
wps_build_registrar_nonce(wps, msg) ||
wps_build_config_error(msg, wps->config_error) ||
- wps_build_version2(msg)) {
+ wps_build_wfa_ext(msg, 0, NULL, 0)) {
wpabuf_free(msg);
return NULL;
}
wpabuf_put_be16(msg, ATTR_REGISTRAR_NONCE);
wpabuf_put_be16(msg, WPS_NONCE_LEN);
wpabuf_put(msg, WPS_NONCE_LEN);
- wps_build_version2(msg);
+ wps_build_wfa_ext(msg, 0, NULL, 0);
return msg;
}