Home | History | Annotate | Download | only in wps
      1 /*
      2  * Wi-Fi Protected Setup
      3  * Copyright (c) 2007-2009, Jouni Malinen <j (at) w1.fi>
      4  *
      5  * This software may be distributed under the terms of the BSD license.
      6  * See README for more details.
      7  */
      8 
      9 #include "includes.h"
     10 
     11 #include "common.h"
     12 #include "crypto/dh_group5.h"
     13 #include "common/ieee802_11_defs.h"
     14 #include "wps_i.h"
     15 #include "wps_dev_attr.h"
     16 
     17 
     18 #ifdef CONFIG_WPS_TESTING
     19 int wps_version_number = 0x20;
     20 int wps_testing_dummy_cred = 0;
     21 int wps_corrupt_pkhash = 0;
     22 int wps_force_auth_types_in_use = 0;
     23 u16 wps_force_auth_types = 0;
     24 int wps_force_encr_types_in_use = 0;
     25 u16 wps_force_encr_types = 0;
     26 #endif /* CONFIG_WPS_TESTING */
     27 
     28 
     29 /**
     30  * wps_init - Initialize WPS Registration protocol data
     31  * @cfg: WPS configuration
     32  * Returns: Pointer to allocated data or %NULL on failure
     33  *
     34  * This function is used to initialize WPS data for a registration protocol
     35  * instance (i.e., each run of registration protocol as a Registrar of
     36  * Enrollee. The caller is responsible for freeing this data after the
     37  * registration run has been completed by calling wps_deinit().
     38  */
     39 struct wps_data * wps_init(const struct wps_config *cfg)
     40 {
     41 	struct wps_data *data = os_zalloc(sizeof(*data));
     42 	if (data == NULL)
     43 		return NULL;
     44 	data->wps = cfg->wps;
     45 	data->registrar = cfg->registrar;
     46 	if (cfg->registrar) {
     47 		os_memcpy(data->uuid_r, cfg->wps->uuid, WPS_UUID_LEN);
     48 	} else {
     49 		os_memcpy(data->mac_addr_e, cfg->wps->dev.mac_addr, ETH_ALEN);
     50 		os_memcpy(data->uuid_e, cfg->wps->uuid, WPS_UUID_LEN);
     51 	}
     52 	if (cfg->pin) {
     53 		data->dev_pw_id = cfg->dev_pw_id;
     54 		data->dev_password = os_malloc(cfg->pin_len);
     55 		if (data->dev_password == NULL) {
     56 			os_free(data);
     57 			return NULL;
     58 		}
     59 		os_memcpy(data->dev_password, cfg->pin, cfg->pin_len);
     60 		data->dev_password_len = cfg->pin_len;
     61 		wpa_hexdump_key(MSG_DEBUG, "WPS: AP PIN dev_password",
     62 				data->dev_password, data->dev_password_len);
     63 	}
     64 
     65 #ifdef CONFIG_WPS_NFC
     66 	if (cfg->pin == NULL &&
     67 	    cfg->dev_pw_id == DEV_PW_NFC_CONNECTION_HANDOVER)
     68 		data->dev_pw_id = cfg->dev_pw_id;
     69 
     70 	if (cfg->wps->ap && !cfg->registrar && cfg->wps->ap_nfc_dev_pw_id) {
     71 		/* Keep AP PIN as alternative Device Password */
     72 		data->alt_dev_pw_id = data->dev_pw_id;
     73 		data->alt_dev_password = data->dev_password;
     74 		data->alt_dev_password_len = data->dev_password_len;
     75 
     76 		data->dev_pw_id = cfg->wps->ap_nfc_dev_pw_id;
     77 		data->dev_password =
     78 			os_malloc(wpabuf_len(cfg->wps->ap_nfc_dev_pw));
     79 		if (data->dev_password == NULL) {
     80 			os_free(data);
     81 			return NULL;
     82 		}
     83 		os_memcpy(data->dev_password,
     84 			  wpabuf_head(cfg->wps->ap_nfc_dev_pw),
     85 			  wpabuf_len(cfg->wps->ap_nfc_dev_pw));
     86 		data->dev_password_len = wpabuf_len(cfg->wps->ap_nfc_dev_pw);
     87 		wpa_hexdump_key(MSG_DEBUG, "WPS: NFC dev_password",
     88 			    data->dev_password, data->dev_password_len);
     89 	}
     90 #endif /* CONFIG_WPS_NFC */
     91 
     92 	data->pbc = cfg->pbc;
     93 	if (cfg->pbc) {
     94 		/* Use special PIN '00000000' for PBC */
     95 		data->dev_pw_id = DEV_PW_PUSHBUTTON;
     96 		bin_clear_free(data->dev_password, data->dev_password_len);
     97 		data->dev_password = (u8 *) os_strdup("00000000");
     98 		if (data->dev_password == NULL) {
     99 			os_free(data);
    100 			return NULL;
    101 		}
    102 		data->dev_password_len = 8;
    103 	}
    104 
    105 	data->state = data->registrar ? RECV_M1 : SEND_M1;
    106 
    107 	if (cfg->assoc_wps_ie) {
    108 		struct wps_parse_attr attr;
    109 		wpa_hexdump_buf(MSG_DEBUG, "WPS: WPS IE from (Re)AssocReq",
    110 				cfg->assoc_wps_ie);
    111 		if (wps_parse_msg(cfg->assoc_wps_ie, &attr) < 0) {
    112 			wpa_printf(MSG_DEBUG, "WPS: Failed to parse WPS IE "
    113 				   "from (Re)AssocReq");
    114 		} else if (attr.request_type == NULL) {
    115 			wpa_printf(MSG_DEBUG, "WPS: No Request Type attribute "
    116 				   "in (Re)AssocReq WPS IE");
    117 		} else {
    118 			wpa_printf(MSG_DEBUG, "WPS: Request Type (from WPS IE "
    119 				   "in (Re)AssocReq WPS IE): %d",
    120 				   *attr.request_type);
    121 			data->request_type = *attr.request_type;
    122 		}
    123 	}
    124 
    125 	if (cfg->new_ap_settings) {
    126 		data->new_ap_settings =
    127 			os_malloc(sizeof(*data->new_ap_settings));
    128 		if (data->new_ap_settings == NULL) {
    129 			bin_clear_free(data->dev_password,
    130 				       data->dev_password_len);
    131 			os_free(data);
    132 			return NULL;
    133 		}
    134 		os_memcpy(data->new_ap_settings, cfg->new_ap_settings,
    135 			  sizeof(*data->new_ap_settings));
    136 	}
    137 
    138 	if (cfg->peer_addr)
    139 		os_memcpy(data->peer_dev.mac_addr, cfg->peer_addr, ETH_ALEN);
    140 	if (cfg->p2p_dev_addr)
    141 		os_memcpy(data->p2p_dev_addr, cfg->p2p_dev_addr, ETH_ALEN);
    142 
    143 	data->use_psk_key = cfg->use_psk_key;
    144 	data->pbc_in_m1 = cfg->pbc_in_m1;
    145 
    146 	if (cfg->peer_pubkey_hash) {
    147 		os_memcpy(data->peer_pubkey_hash, cfg->peer_pubkey_hash,
    148 			  WPS_OOB_PUBKEY_HASH_LEN);
    149 		data->peer_pubkey_hash_set = 1;
    150 	}
    151 
    152 	return data;
    153 }
    154 
    155 
    156 /**
    157  * wps_deinit - Deinitialize WPS Registration protocol data
    158  * @data: WPS Registration protocol data from wps_init()
    159  */
    160 void wps_deinit(struct wps_data *data)
    161 {
    162 #ifdef CONFIG_WPS_NFC
    163 	if (data->registrar && data->nfc_pw_token)
    164 		wps_registrar_remove_nfc_pw_token(data->wps->registrar,
    165 						  data->nfc_pw_token);
    166 #endif /* CONFIG_WPS_NFC */
    167 
    168 	if (data->wps_pin_revealed) {
    169 		wpa_printf(MSG_DEBUG, "WPS: Full PIN information revealed and "
    170 			   "negotiation failed");
    171 		if (data->registrar)
    172 			wps_registrar_invalidate_pin(data->wps->registrar,
    173 						     data->uuid_e);
    174 	} else if (data->registrar)
    175 		wps_registrar_unlock_pin(data->wps->registrar, data->uuid_e);
    176 
    177 	wpabuf_clear_free(data->dh_privkey);
    178 	wpabuf_free(data->dh_pubkey_e);
    179 	wpabuf_free(data->dh_pubkey_r);
    180 	wpabuf_free(data->last_msg);
    181 	bin_clear_free(data->dev_password, data->dev_password_len);
    182 	bin_clear_free(data->alt_dev_password, data->alt_dev_password_len);
    183 	bin_clear_free(data->new_psk, data->new_psk_len);
    184 	wps_device_data_free(&data->peer_dev);
    185 	bin_clear_free(data->new_ap_settings, sizeof(*data->new_ap_settings));
    186 	dh5_free(data->dh_ctx);
    187 	os_free(data);
    188 }
    189 
    190 
    191 /**
    192  * wps_process_msg - Process a WPS message
    193  * @wps: WPS Registration protocol data from wps_init()
    194  * @op_code: Message OP Code
    195  * @msg: Message data
    196  * Returns: Processing result
    197  *
    198  * This function is used to process WPS messages with OP Codes WSC_ACK,
    199  * WSC_NACK, WSC_MSG, and WSC_Done. The caller (e.g., EAP server/peer) is
    200  * responsible for reassembling the messages before calling this function.
    201  * Response to this message is built by calling wps_get_msg().
    202  */
    203 enum wps_process_res wps_process_msg(struct wps_data *wps,
    204 				     enum wsc_op_code op_code,
    205 				     const struct wpabuf *msg)
    206 {
    207 	if (wps->registrar)
    208 		return wps_registrar_process_msg(wps, op_code, msg);
    209 	else
    210 		return wps_enrollee_process_msg(wps, op_code, msg);
    211 }
    212 
    213 
    214 /**
    215  * wps_get_msg - Build a WPS message
    216  * @wps: WPS Registration protocol data from wps_init()
    217  * @op_code: Buffer for returning message OP Code
    218  * Returns: The generated WPS message or %NULL on failure
    219  *
    220  * This function is used to build a response to a message processed by calling
    221  * wps_process_msg(). The caller is responsible for freeing the buffer.
    222  */
    223 struct wpabuf * wps_get_msg(struct wps_data *wps, enum wsc_op_code *op_code)
    224 {
    225 	if (wps->registrar)
    226 		return wps_registrar_get_msg(wps, op_code);
    227 	else
    228 		return wps_enrollee_get_msg(wps, op_code);
    229 }
    230 
    231 
    232 /**
    233  * wps_is_selected_pbc_registrar - Check whether WPS IE indicates active PBC
    234  * @msg: WPS IE contents from Beacon or Probe Response frame
    235  * Returns: 1 if PBC Registrar is active, 0 if not
    236  */
    237 int wps_is_selected_pbc_registrar(const struct wpabuf *msg)
    238 {
    239 	struct wps_parse_attr attr;
    240 
    241 	/*
    242 	 * In theory, this could also verify that attr.sel_reg_config_methods
    243 	 * includes WPS_CONFIG_PUSHBUTTON, but some deployed AP implementations
    244 	 * do not set Selected Registrar Config Methods attribute properly, so
    245 	 * it is safer to just use Device Password ID here.
    246 	 */
    247 
    248 	if (wps_parse_msg(msg, &attr) < 0 ||
    249 	    !attr.selected_registrar || *attr.selected_registrar == 0 ||
    250 	    !attr.dev_password_id ||
    251 	    WPA_GET_BE16(attr.dev_password_id) != DEV_PW_PUSHBUTTON)
    252 		return 0;
    253 
    254 #ifdef CONFIG_WPS_STRICT
    255 	if (!attr.sel_reg_config_methods ||
    256 	    !(WPA_GET_BE16(attr.sel_reg_config_methods) &
    257 	      WPS_CONFIG_PUSHBUTTON))
    258 		return 0;
    259 #endif /* CONFIG_WPS_STRICT */
    260 
    261 	return 1;
    262 }
    263 
    264 
    265 static int is_selected_pin_registrar(struct wps_parse_attr *attr)
    266 {
    267 	/*
    268 	 * In theory, this could also verify that attr.sel_reg_config_methods
    269 	 * includes WPS_CONFIG_LABEL, WPS_CONFIG_DISPLAY, or WPS_CONFIG_KEYPAD,
    270 	 * but some deployed AP implementations do not set Selected Registrar
    271 	 * Config Methods attribute properly, so it is safer to just use
    272 	 * Device Password ID here.
    273 	 */
    274 
    275 	if (!attr->selected_registrar || *attr->selected_registrar == 0)
    276 		return 0;
    277 
    278 	if (attr->dev_password_id != NULL &&
    279 	    WPA_GET_BE16(attr->dev_password_id) == DEV_PW_PUSHBUTTON)
    280 		return 0;
    281 
    282 #ifdef CONFIG_WPS_STRICT
    283 	if (!attr->sel_reg_config_methods ||
    284 	    !(WPA_GET_BE16(attr->sel_reg_config_methods) &
    285 	      (WPS_CONFIG_LABEL | WPS_CONFIG_DISPLAY | WPS_CONFIG_KEYPAD)))
    286 		return 0;
    287 #endif /* CONFIG_WPS_STRICT */
    288 
    289 	return 1;
    290 }
    291 
    292 
    293 /**
    294  * wps_is_selected_pin_registrar - Check whether WPS IE indicates active PIN
    295  * @msg: WPS IE contents from Beacon or Probe Response frame
    296  * Returns: 1 if PIN Registrar is active, 0 if not
    297  */
    298 int wps_is_selected_pin_registrar(const struct wpabuf *msg)
    299 {
    300 	struct wps_parse_attr attr;
    301 
    302 	if (wps_parse_msg(msg, &attr) < 0)
    303 		return 0;
    304 
    305 	return is_selected_pin_registrar(&attr);
    306 }
    307 
    308 
    309 /**
    310  * wps_is_addr_authorized - Check whether WPS IE authorizes MAC address
    311  * @msg: WPS IE contents from Beacon or Probe Response frame
    312  * @addr: MAC address to search for
    313  * @ver1_compat: Whether to use version 1 compatibility mode
    314  * Returns: 2 if the specified address is explicit authorized, 1 if address is
    315  * authorized (broadcast), 0 if not
    316  */
    317 int wps_is_addr_authorized(const struct wpabuf *msg, const u8 *addr,
    318 			   int ver1_compat)
    319 {
    320 	struct wps_parse_attr attr;
    321 	unsigned int i;
    322 	const u8 *pos;
    323 	const u8 bcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
    324 
    325 	if (wps_parse_msg(msg, &attr) < 0)
    326 		return 0;
    327 
    328 	if (!attr.version2 && ver1_compat) {
    329 		/*
    330 		 * Version 1.0 AP - AuthorizedMACs not used, so revert back to
    331 		 * old mechanism of using SelectedRegistrar.
    332 		 */
    333 		return is_selected_pin_registrar(&attr);
    334 	}
    335 
    336 	if (!attr.authorized_macs)
    337 		return 0;
    338 
    339 	pos = attr.authorized_macs;
    340 	for (i = 0; i < attr.authorized_macs_len / ETH_ALEN; i++) {
    341 		if (os_memcmp(pos, addr, ETH_ALEN) == 0)
    342 			return 2;
    343 		if (os_memcmp(pos, bcast, ETH_ALEN) == 0)
    344 			return 1;
    345 		pos += ETH_ALEN;
    346 	}
    347 
    348 	return 0;
    349 }
    350 
    351 
    352 /**
    353  * wps_ap_priority_compar - Prioritize WPS IE from two APs
    354  * @wps_a: WPS IE contents from Beacon or Probe Response frame
    355  * @wps_b: WPS IE contents from Beacon or Probe Response frame
    356  * Returns: 1 if wps_b is considered more likely selection for WPS
    357  * provisioning, -1 if wps_a is considered more like, or 0 if no preference
    358  */
    359 int wps_ap_priority_compar(const struct wpabuf *wps_a,
    360 			   const struct wpabuf *wps_b)
    361 {
    362 	struct wps_parse_attr attr;
    363 	int sel_a, sel_b;
    364 
    365 	if (wps_a == NULL || wps_parse_msg(wps_a, &attr) < 0)
    366 		return 1;
    367 	sel_a = attr.selected_registrar && *attr.selected_registrar != 0;
    368 
    369 	if (wps_b == NULL || wps_parse_msg(wps_b, &attr) < 0)
    370 		return -1;
    371 	sel_b = attr.selected_registrar && *attr.selected_registrar != 0;
    372 
    373 	if (sel_a && !sel_b)
    374 		return -1;
    375 	if (!sel_a && sel_b)
    376 		return 1;
    377 
    378 	return 0;
    379 }
    380 
    381 
    382 /**
    383  * wps_get_uuid_e - Get UUID-E from WPS IE
    384  * @msg: WPS IE contents from Beacon or Probe Response frame
    385  * Returns: Pointer to UUID-E or %NULL if not included
    386  *
    387  * The returned pointer is to the msg contents and it remains valid only as
    388  * long as the msg buffer is valid.
    389  */
    390 const u8 * wps_get_uuid_e(const struct wpabuf *msg)
    391 {
    392 	struct wps_parse_attr attr;
    393 
    394 	if (wps_parse_msg(msg, &attr) < 0)
    395 		return NULL;
    396 	return attr.uuid_e;
    397 }
    398 
    399 
    400 /**
    401  * wps_is_20 - Check whether WPS attributes claim support for WPS 2.0
    402  */
    403 int wps_is_20(const struct wpabuf *msg)
    404 {
    405 	struct wps_parse_attr attr;
    406 
    407 	if (msg == NULL || wps_parse_msg(msg, &attr) < 0)
    408 		return 0;
    409 	return attr.version2 != NULL;
    410 }
    411 
    412 
    413 /**
    414  * wps_build_assoc_req_ie - Build WPS IE for (Re)Association Request
    415  * @req_type: Value for Request Type attribute
    416  * Returns: WPS IE or %NULL on failure
    417  *
    418  * The caller is responsible for freeing the buffer.
    419  */
    420 struct wpabuf * wps_build_assoc_req_ie(enum wps_request_type req_type)
    421 {
    422 	struct wpabuf *ie;
    423 	u8 *len;
    424 
    425 	wpa_printf(MSG_DEBUG, "WPS: Building WPS IE for (Re)Association "
    426 		   "Request");
    427 	ie = wpabuf_alloc(100);
    428 	if (ie == NULL)
    429 		return NULL;
    430 
    431 	wpabuf_put_u8(ie, WLAN_EID_VENDOR_SPECIFIC);
    432 	len = wpabuf_put(ie, 1);
    433 	wpabuf_put_be32(ie, WPS_DEV_OUI_WFA);
    434 
    435 	if (wps_build_version(ie) ||
    436 	    wps_build_req_type(ie, req_type) ||
    437 	    wps_build_wfa_ext(ie, 0, NULL, 0)) {
    438 		wpabuf_free(ie);
    439 		return NULL;
    440 	}
    441 
    442 	*len = wpabuf_len(ie) - 2;
    443 
    444 	return ie;
    445 }
    446 
    447 
    448 /**
    449  * wps_build_assoc_resp_ie - Build WPS IE for (Re)Association Response
    450  * Returns: WPS IE or %NULL on failure
    451  *
    452  * The caller is responsible for freeing the buffer.
    453  */
    454 struct wpabuf * wps_build_assoc_resp_ie(void)
    455 {
    456 	struct wpabuf *ie;
    457 	u8 *len;
    458 
    459 	wpa_printf(MSG_DEBUG, "WPS: Building WPS IE for (Re)Association "
    460 		   "Response");
    461 	ie = wpabuf_alloc(100);
    462 	if (ie == NULL)
    463 		return NULL;
    464 
    465 	wpabuf_put_u8(ie, WLAN_EID_VENDOR_SPECIFIC);
    466 	len = wpabuf_put(ie, 1);
    467 	wpabuf_put_be32(ie, WPS_DEV_OUI_WFA);
    468 
    469 	if (wps_build_version(ie) ||
    470 	    wps_build_resp_type(ie, WPS_RESP_AP) ||
    471 	    wps_build_wfa_ext(ie, 0, NULL, 0)) {
    472 		wpabuf_free(ie);
    473 		return NULL;
    474 	}
    475 
    476 	*len = wpabuf_len(ie) - 2;
    477 
    478 	return ie;
    479 }
    480 
    481 
    482 /**
    483  * wps_build_probe_req_ie - Build WPS IE for Probe Request
    484  * @pw_id: Password ID (DEV_PW_PUSHBUTTON for active PBC and DEV_PW_DEFAULT for
    485  * most other use cases)
    486  * @dev: Device attributes
    487  * @uuid: Own UUID
    488  * @req_type: Value for Request Type attribute
    489  * @num_req_dev_types: Number of requested device types
    490  * @req_dev_types: Requested device types (8 * num_req_dev_types octets) or
    491  *	%NULL if none
    492  * Returns: WPS IE or %NULL on failure
    493  *
    494  * The caller is responsible for freeing the buffer.
    495  */
    496 struct wpabuf * wps_build_probe_req_ie(u16 pw_id, struct wps_device_data *dev,
    497 				       const u8 *uuid,
    498 				       enum wps_request_type req_type,
    499 				       unsigned int num_req_dev_types,
    500 				       const u8 *req_dev_types)
    501 {
    502 	struct wpabuf *ie;
    503 
    504 	wpa_printf(MSG_DEBUG, "WPS: Building WPS IE for Probe Request");
    505 
    506 	ie = wpabuf_alloc(500);
    507 	if (ie == NULL)
    508 		return NULL;
    509 
    510 	if (wps_build_version(ie) ||
    511 	    wps_build_req_type(ie, req_type) ||
    512 	    wps_build_config_methods(ie, dev->config_methods) ||
    513 	    wps_build_uuid_e(ie, uuid) ||
    514 	    wps_build_primary_dev_type(dev, ie) ||
    515 	    wps_build_rf_bands(dev, ie, 0) ||
    516 	    wps_build_assoc_state(NULL, ie) ||
    517 	    wps_build_config_error(ie, WPS_CFG_NO_ERROR) ||
    518 	    wps_build_dev_password_id(ie, pw_id) ||
    519 	    wps_build_manufacturer(dev, ie) ||
    520 	    wps_build_model_name(dev, ie) ||
    521 	    wps_build_model_number(dev, ie) ||
    522 	    wps_build_dev_name(dev, ie) ||
    523 	    wps_build_wfa_ext(ie, req_type == WPS_REQ_ENROLLEE, NULL, 0) ||
    524 	    wps_build_req_dev_type(dev, ie, num_req_dev_types, req_dev_types)
    525 	    ||
    526 	    wps_build_secondary_dev_type(dev, ie)
    527 		) {
    528 		wpabuf_free(ie);
    529 		return NULL;
    530 	}
    531 
    532 	return wps_ie_encapsulate(ie);
    533 }
    534 
    535 
    536 void wps_free_pending_msgs(struct upnp_pending_message *msgs)
    537 {
    538 	struct upnp_pending_message *p, *prev;
    539 	p = msgs;
    540 	while (p) {
    541 		prev = p;
    542 		p = p->next;
    543 		wpabuf_free(prev->msg);
    544 		os_free(prev);
    545 	}
    546 }
    547 
    548 
    549 int wps_attr_text(struct wpabuf *data, char *buf, char *end)
    550 {
    551 	struct wps_parse_attr attr;
    552 	char *pos = buf;
    553 	int ret;
    554 
    555 	if (wps_parse_msg(data, &attr) < 0)
    556 		return -1;
    557 
    558 	if (attr.wps_state) {
    559 		if (*attr.wps_state == WPS_STATE_NOT_CONFIGURED)
    560 			ret = os_snprintf(pos, end - pos,
    561 					  "wps_state=unconfigured\n");
    562 		else if (*attr.wps_state == WPS_STATE_CONFIGURED)
    563 			ret = os_snprintf(pos, end - pos,
    564 					  "wps_state=configured\n");
    565 		else
    566 			ret = 0;
    567 		if (os_snprintf_error(end - pos, ret))
    568 			return pos - buf;
    569 		pos += ret;
    570 	}
    571 
    572 	if (attr.ap_setup_locked && *attr.ap_setup_locked) {
    573 		ret = os_snprintf(pos, end - pos,
    574 				  "wps_ap_setup_locked=1\n");
    575 		if (os_snprintf_error(end - pos, ret))
    576 			return pos - buf;
    577 		pos += ret;
    578 	}
    579 
    580 	if (attr.selected_registrar && *attr.selected_registrar) {
    581 		ret = os_snprintf(pos, end - pos,
    582 				  "wps_selected_registrar=1\n");
    583 		if (os_snprintf_error(end - pos, ret))
    584 			return pos - buf;
    585 		pos += ret;
    586 	}
    587 
    588 	if (attr.dev_password_id) {
    589 		ret = os_snprintf(pos, end - pos,
    590 				  "wps_device_password_id=%u\n",
    591 				  WPA_GET_BE16(attr.dev_password_id));
    592 		if (os_snprintf_error(end - pos, ret))
    593 			return pos - buf;
    594 		pos += ret;
    595 	}
    596 
    597 	if (attr.sel_reg_config_methods) {
    598 		ret = os_snprintf(pos, end - pos,
    599 				  "wps_selected_registrar_config_methods="
    600 				  "0x%04x\n",
    601 				  WPA_GET_BE16(attr.sel_reg_config_methods));
    602 		if (os_snprintf_error(end - pos, ret))
    603 			return pos - buf;
    604 		pos += ret;
    605 	}
    606 
    607 	if (attr.primary_dev_type) {
    608 		char devtype[WPS_DEV_TYPE_BUFSIZE];
    609 		ret = os_snprintf(pos, end - pos,
    610 				  "wps_primary_device_type=%s\n",
    611 				  wps_dev_type_bin2str(attr.primary_dev_type,
    612 						       devtype,
    613 						       sizeof(devtype)));
    614 		if (os_snprintf_error(end - pos, ret))
    615 			return pos - buf;
    616 		pos += ret;
    617 	}
    618 
    619 	if (attr.dev_name) {
    620 		char *str = os_malloc(attr.dev_name_len + 1);
    621 		size_t i;
    622 		if (str == NULL)
    623 			return pos - buf;
    624 		for (i = 0; i < attr.dev_name_len; i++) {
    625 			if (attr.dev_name[i] == 0 ||
    626 			    is_ctrl_char(attr.dev_name[i]))
    627 				str[i] = '_';
    628 			else
    629 				str[i] = attr.dev_name[i];
    630 		}
    631 		str[i] = '\0';
    632 		ret = os_snprintf(pos, end - pos, "wps_device_name=%s\n", str);
    633 		os_free(str);
    634 		if (os_snprintf_error(end - pos, ret))
    635 			return pos - buf;
    636 		pos += ret;
    637 	}
    638 
    639 	if (attr.config_methods) {
    640 		ret = os_snprintf(pos, end - pos,
    641 				  "wps_config_methods=0x%04x\n",
    642 				  WPA_GET_BE16(attr.config_methods));
    643 		if (os_snprintf_error(end - pos, ret))
    644 			return pos - buf;
    645 		pos += ret;
    646 	}
    647 
    648 	return pos - buf;
    649 }
    650 
    651 
    652 const char * wps_ei_str(enum wps_error_indication ei)
    653 {
    654 	switch (ei) {
    655 	case WPS_EI_NO_ERROR:
    656 		return "No Error";
    657 	case WPS_EI_SECURITY_TKIP_ONLY_PROHIBITED:
    658 		return "TKIP Only Prohibited";
    659 	case WPS_EI_SECURITY_WEP_PROHIBITED:
    660 		return "WEP Prohibited";
    661 	case WPS_EI_AUTH_FAILURE:
    662 		return "Authentication Failure";
    663 	default:
    664 		return "Unknown";
    665 	}
    666 }
    667