wps.c 18 KB

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