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