wps.c 17 KB

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