wps.c 17 KB

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