wps.c 17 KB

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