wps_supplicant.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610
  1. /*
  2. * wpa_supplicant / WPS integration
  3. * Copyright (c) 2008, Jouni Malinen <j@w1.fi>
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License version 2 as
  7. * published by the Free Software Foundation.
  8. *
  9. * Alternatively, this software may be distributed under the terms of BSD
  10. * license.
  11. *
  12. * See README and COPYING for more details.
  13. */
  14. #include "includes.h"
  15. #include "common.h"
  16. #include "ieee802_11_defs.h"
  17. #include "wpa_common.h"
  18. #include "config.h"
  19. #include "eap_peer/eap.h"
  20. #include "wpa_supplicant_i.h"
  21. #include "eloop.h"
  22. #include "wpa_ctrl.h"
  23. #include "eap_common/eap_wsc_common.h"
  24. #include "wps/wps.h"
  25. #include "wps/wps_defs.h"
  26. #include "wps_supplicant.h"
  27. static void wpas_wps_timeout(void *eloop_ctx, void *timeout_ctx);
  28. int wpas_wps_eapol_cb(struct wpa_supplicant *wpa_s)
  29. {
  30. eloop_cancel_timeout(wpas_wps_timeout, wpa_s, NULL);
  31. if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPS && wpa_s->current_ssid &&
  32. !(wpa_s->current_ssid->key_mgmt & WPA_KEY_MGMT_WPS)) {
  33. wpa_printf(MSG_DEBUG, "WPS: Network configuration replaced - "
  34. "try to associate with the received credential");
  35. wpa_supplicant_deauthenticate(wpa_s,
  36. WLAN_REASON_DEAUTH_LEAVING);
  37. wpa_s->reassociate = 1;
  38. wpa_supplicant_req_scan(wpa_s, 0, 0);
  39. return 1;
  40. }
  41. return 0;
  42. }
  43. static int wpa_supplicant_wps_cred(void *ctx,
  44. const struct wps_credential *cred)
  45. {
  46. struct wpa_supplicant *wpa_s = ctx;
  47. struct wpa_ssid *ssid = wpa_s->current_ssid;
  48. wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_CRED_RECEIVED);
  49. if (ssid && (ssid->key_mgmt & WPA_KEY_MGMT_WPS)) {
  50. wpa_printf(MSG_DEBUG, "WPS: Replace WPS network block based "
  51. "on the received credential");
  52. os_free(ssid->eap.identity);
  53. ssid->eap.identity = NULL;
  54. ssid->eap.identity_len = 0;
  55. os_free(ssid->eap.phase1);
  56. ssid->eap.phase1 = NULL;
  57. os_free(ssid->eap.eap_methods);
  58. ssid->eap.eap_methods = NULL;
  59. } else {
  60. wpa_printf(MSG_DEBUG, "WPS: Create a new network based on the "
  61. "received credential");
  62. ssid = wpa_config_add_network(wpa_s->conf);
  63. if (ssid == NULL)
  64. return -1;
  65. }
  66. wpa_config_set_network_defaults(ssid);
  67. os_free(ssid->ssid);
  68. ssid->ssid = os_malloc(cred->ssid_len);
  69. if (ssid->ssid) {
  70. os_memcpy(ssid->ssid, cred->ssid, cred->ssid_len);
  71. ssid->ssid_len = cred->ssid_len;
  72. }
  73. switch (cred->encr_type) {
  74. case WPS_ENCR_NONE:
  75. ssid->pairwise_cipher = ssid->group_cipher = WPA_CIPHER_NONE;
  76. break;
  77. case WPS_ENCR_WEP:
  78. ssid->pairwise_cipher = ssid->group_cipher =
  79. WPA_CIPHER_WEP40 | WPA_CIPHER_WEP104;
  80. if (cred->key_len > 0 && cred->key_len <= MAX_WEP_KEY_LEN &&
  81. cred->key_idx < NUM_WEP_KEYS) {
  82. os_memcpy(ssid->wep_key[cred->key_idx], cred->key,
  83. cred->key_len);
  84. ssid->wep_key_len[cred->key_idx] = cred->key_len;
  85. ssid->wep_tx_keyidx = cred->key_idx;
  86. }
  87. break;
  88. case WPS_ENCR_TKIP:
  89. ssid->pairwise_cipher = WPA_CIPHER_TKIP;
  90. ssid->group_cipher = WPA_CIPHER_TKIP;
  91. break;
  92. case WPS_ENCR_AES:
  93. ssid->pairwise_cipher = WPA_CIPHER_CCMP;
  94. ssid->group_cipher = WPA_CIPHER_CCMP | WPA_CIPHER_TKIP;
  95. break;
  96. }
  97. switch (cred->auth_type) {
  98. case WPS_AUTH_OPEN:
  99. ssid->auth_alg = WPA_AUTH_ALG_OPEN;
  100. ssid->key_mgmt = WPA_KEY_MGMT_NONE;
  101. ssid->proto = 0;
  102. break;
  103. case WPS_AUTH_SHARED:
  104. ssid->auth_alg = WPA_AUTH_ALG_SHARED;
  105. ssid->key_mgmt = WPA_KEY_MGMT_NONE;
  106. ssid->proto = 0;
  107. break;
  108. case WPS_AUTH_WPAPSK:
  109. ssid->auth_alg = WPA_AUTH_ALG_OPEN;
  110. ssid->key_mgmt = WPA_KEY_MGMT_PSK;
  111. ssid->proto = WPA_PROTO_WPA;
  112. break;
  113. case WPS_AUTH_WPA:
  114. ssid->auth_alg = WPA_AUTH_ALG_OPEN;
  115. ssid->key_mgmt = WPA_KEY_MGMT_IEEE8021X;
  116. ssid->proto = WPA_PROTO_WPA;
  117. break;
  118. case WPS_AUTH_WPA2:
  119. ssid->auth_alg = WPA_AUTH_ALG_OPEN;
  120. ssid->key_mgmt = WPA_KEY_MGMT_IEEE8021X;
  121. ssid->proto = WPA_PROTO_RSN;
  122. break;
  123. case WPS_AUTH_WPA2PSK:
  124. ssid->auth_alg = WPA_AUTH_ALG_OPEN;
  125. ssid->key_mgmt = WPA_KEY_MGMT_PSK;
  126. ssid->proto = WPA_PROTO_RSN;
  127. break;
  128. }
  129. if (ssid->key_mgmt == WPA_KEY_MGMT_PSK) {
  130. if (cred->key_len == 2 * PMK_LEN) {
  131. if (hexstr2bin((const char *) cred->key, ssid->psk,
  132. PMK_LEN)) {
  133. wpa_printf(MSG_ERROR, "WPS: Invalid Network "
  134. "Key");
  135. return -1;
  136. }
  137. ssid->psk_set = 1;
  138. } else if (cred->key_len >= 8 && cred->key_len < 2 * PMK_LEN) {
  139. os_free(ssid->passphrase);
  140. ssid->passphrase = os_malloc(cred->key_len + 1);
  141. if (ssid->passphrase == NULL)
  142. return -1;
  143. os_memcpy(ssid->passphrase, cred->key, cred->key_len);
  144. ssid->passphrase[cred->key_len] = '\0';
  145. wpa_config_update_psk(ssid);
  146. } else {
  147. wpa_printf(MSG_ERROR, "WPS: Invalid Network Key "
  148. "length %lu",
  149. (unsigned long) cred->key_len);
  150. return -1;
  151. }
  152. }
  153. #ifndef CONFIG_NO_CONFIG_WRITE
  154. if (wpa_s->conf->update_config &&
  155. wpa_config_write(wpa_s->confname, wpa_s->conf)) {
  156. wpa_printf(MSG_DEBUG, "WPS: Failed to update configuration");
  157. return -1;
  158. }
  159. #endif /* CONFIG_NO_CONFIG_WRITE */
  160. return 0;
  161. }
  162. static void wpa_supplicant_wps_event_m2d(struct wpa_supplicant *wpa_s,
  163. struct wps_event_m2d *m2d)
  164. {
  165. wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_M2D
  166. "dev_password_id=%d config_error=%d",
  167. m2d->dev_password_id, m2d->config_error);
  168. }
  169. static void wpa_supplicant_wps_event(void *ctx, enum wps_event event,
  170. union wps_event_data *data)
  171. {
  172. struct wpa_supplicant *wpa_s = ctx;
  173. switch (event) {
  174. case WPS_EV_M2D:
  175. wpa_supplicant_wps_event_m2d(wpa_s, &data->m2d);
  176. break;
  177. }
  178. }
  179. u8 wpas_wps_get_req_type(struct wpa_ssid *ssid)
  180. {
  181. if (eap_is_wps_pbc_enrollee(&ssid->eap) ||
  182. eap_is_wps_pin_enrollee(&ssid->eap))
  183. return WPS_REQ_ENROLLEE;
  184. else
  185. return WPS_REQ_REGISTRAR;
  186. }
  187. static void wpas_clear_wps(struct wpa_supplicant *wpa_s)
  188. {
  189. int id;
  190. struct wpa_ssid *ssid;
  191. eloop_cancel_timeout(wpas_wps_timeout, wpa_s, NULL);
  192. /* Remove any existing WPS network from configuration */
  193. ssid = wpa_s->conf->ssid;
  194. while (ssid) {
  195. if (ssid->key_mgmt & WPA_KEY_MGMT_WPS) {
  196. if (ssid == wpa_s->current_ssid)
  197. wpa_s->current_ssid = NULL;
  198. id = ssid->id;
  199. } else
  200. id = -1;
  201. ssid = ssid->next;
  202. if (id >= 0)
  203. wpa_config_remove_network(wpa_s->conf, id);
  204. }
  205. }
  206. static void wpas_wps_timeout(void *eloop_ctx, void *timeout_ctx)
  207. {
  208. struct wpa_supplicant *wpa_s = eloop_ctx;
  209. wpa_printf(MSG_DEBUG, "WPS: Requested operation timed out");
  210. wpas_clear_wps(wpa_s);
  211. }
  212. static struct wpa_ssid * wpas_wps_add_network(struct wpa_supplicant *wpa_s,
  213. int registrar, const u8 *bssid)
  214. {
  215. struct wpa_ssid *ssid;
  216. ssid = wpa_config_add_network(wpa_s->conf);
  217. if (ssid == NULL)
  218. return NULL;
  219. wpa_config_set_network_defaults(ssid);
  220. if (wpa_config_set(ssid, "key_mgmt", "WPS", 0) < 0 ||
  221. wpa_config_set(ssid, "eap", "WSC", 0) < 0 ||
  222. wpa_config_set(ssid, "identity", registrar ?
  223. "\"" WSC_ID_REGISTRAR "\"" :
  224. "\"" WSC_ID_ENROLLEE "\"", 0) < 0) {
  225. wpa_config_remove_network(wpa_s->conf, ssid->id);
  226. return NULL;
  227. }
  228. if (bssid) {
  229. size_t i;
  230. struct wpa_scan_res *res;
  231. os_memcpy(ssid->bssid, bssid, ETH_ALEN);
  232. /* Try to get SSID from scan results */
  233. if (wpa_s->scan_res == NULL &&
  234. wpa_supplicant_get_scan_results(wpa_s) < 0)
  235. return ssid; /* Could not find any scan results */
  236. for (i = 0; i < wpa_s->scan_res->num; i++) {
  237. const u8 *ie;
  238. res = wpa_s->scan_res->res[i];
  239. if (os_memcmp(bssid, res->bssid, ETH_ALEN) != 0)
  240. continue;
  241. ie = wpa_scan_get_ie(res, WLAN_EID_SSID);
  242. if (ie == NULL)
  243. break;
  244. os_free(ssid->ssid);
  245. ssid->ssid = os_malloc(ie[1]);
  246. if (ssid->ssid == NULL)
  247. break;
  248. os_memcpy(ssid->ssid, ie + 2, ie[1]);
  249. ssid->ssid_len = ie[1];
  250. break;
  251. }
  252. }
  253. return ssid;
  254. }
  255. static void wpas_wps_reassoc(struct wpa_supplicant *wpa_s,
  256. struct wpa_ssid *selected)
  257. {
  258. struct wpa_ssid *ssid;
  259. /* Mark all other networks disabled and trigger reassociation */
  260. ssid = wpa_s->conf->ssid;
  261. while (ssid) {
  262. ssid->disabled = ssid != selected;
  263. ssid = ssid->next;
  264. }
  265. wpa_s->disconnected = 0;
  266. wpa_s->reassociate = 1;
  267. wpa_supplicant_req_scan(wpa_s, 0, 0);
  268. }
  269. int wpas_wps_start_pbc(struct wpa_supplicant *wpa_s, const u8 *bssid)
  270. {
  271. struct wpa_ssid *ssid;
  272. wpas_clear_wps(wpa_s);
  273. ssid = wpas_wps_add_network(wpa_s, 0, bssid);
  274. if (ssid == NULL)
  275. return -1;
  276. wpa_config_set(ssid, "phase1", "\"pbc=1\"", 0);
  277. eloop_register_timeout(WPS_PBC_WALK_TIME, 0, wpas_wps_timeout,
  278. wpa_s, NULL);
  279. wpas_wps_reassoc(wpa_s, ssid);
  280. return 0;
  281. }
  282. int wpas_wps_start_pin(struct wpa_supplicant *wpa_s, const u8 *bssid,
  283. const char *pin)
  284. {
  285. struct wpa_ssid *ssid;
  286. char val[30];
  287. unsigned int rpin = 0;
  288. wpas_clear_wps(wpa_s);
  289. ssid = wpas_wps_add_network(wpa_s, 0, bssid);
  290. if (ssid == NULL)
  291. return -1;
  292. if (pin)
  293. os_snprintf(val, sizeof(val), "\"pin=%s\"", pin);
  294. else {
  295. rpin = wps_generate_pin();
  296. os_snprintf(val, sizeof(val), "\"pin=%08d\"", rpin);
  297. }
  298. wpa_config_set(ssid, "phase1", val, 0);
  299. eloop_register_timeout(WPS_PBC_WALK_TIME, 0, wpas_wps_timeout,
  300. wpa_s, NULL);
  301. wpas_wps_reassoc(wpa_s, ssid);
  302. return rpin;
  303. }
  304. int wpas_wps_start_reg(struct wpa_supplicant *wpa_s, const u8 *bssid,
  305. const char *pin)
  306. {
  307. struct wpa_ssid *ssid;
  308. char val[30];
  309. if (!pin)
  310. return -1;
  311. wpas_clear_wps(wpa_s);
  312. ssid = wpas_wps_add_network(wpa_s, 1, bssid);
  313. if (ssid == NULL)
  314. return -1;
  315. os_snprintf(val, sizeof(val), "\"pin=%s\"", pin);
  316. wpa_config_set(ssid, "phase1", val, 0);
  317. eloop_register_timeout(WPS_PBC_WALK_TIME, 0, wpas_wps_timeout,
  318. wpa_s, NULL);
  319. wpas_wps_reassoc(wpa_s, ssid);
  320. return 0;
  321. }
  322. int wpas_wps_init(struct wpa_supplicant *wpa_s)
  323. {
  324. struct wps_context *wps;
  325. wps = os_zalloc(sizeof(*wps));
  326. if (wps == NULL)
  327. return -1;
  328. wps->cred_cb = wpa_supplicant_wps_cred;
  329. wps->event_cb = wpa_supplicant_wps_event;
  330. wps->cb_ctx = wpa_s;
  331. wps->dev.device_name = wpa_s->conf->device_name;
  332. wps->dev.manufacturer = wpa_s->conf->manufacturer;
  333. wps->dev.model_name = wpa_s->conf->model_name;
  334. wps->dev.model_number = wpa_s->conf->model_number;
  335. wps->dev.serial_number = wpa_s->conf->serial_number;
  336. if (wpa_s->conf->device_type) {
  337. char *pos;
  338. u8 oui[4];
  339. /* <categ>-<OUI>-<subcateg> */
  340. wps->dev.categ = atoi(wpa_s->conf->device_type);
  341. pos = os_strchr(wpa_s->conf->device_type, '-');
  342. if (pos == NULL) {
  343. wpa_printf(MSG_ERROR, "WPS: Invalid device_type");
  344. os_free(wps);
  345. return -1;
  346. }
  347. pos++;
  348. if (hexstr2bin(pos, oui, 4)) {
  349. wpa_printf(MSG_ERROR, "WPS: Invalid device_type OUI");
  350. os_free(wps);
  351. return -1;
  352. }
  353. wps->dev.oui = WPA_GET_BE32(oui);
  354. pos = os_strchr(pos, '-');
  355. if (pos == NULL) {
  356. wpa_printf(MSG_ERROR, "WPS: Invalid device_type");
  357. os_free(wps);
  358. return -1;
  359. }
  360. pos++;
  361. wps->dev.sub_categ = atoi(pos);
  362. }
  363. wps->dev.os_version = WPA_GET_BE32(wpa_s->conf->os_version);
  364. wps->dev.rf_bands = WPS_RF_24GHZ | WPS_RF_50GHZ; /* TODO: config */
  365. os_memcpy(wps->dev.mac_addr, wpa_s->own_addr, ETH_ALEN);
  366. os_memcpy(wps->uuid, wpa_s->conf->uuid, 16);
  367. wpa_s->wps = wps;
  368. return 0;
  369. }
  370. void wpas_wps_deinit(struct wpa_supplicant *wpa_s)
  371. {
  372. eloop_cancel_timeout(wpas_wps_timeout, wpa_s, NULL);
  373. if (wpa_s->wps == NULL)
  374. return;
  375. os_free(wpa_s->wps->network_key);
  376. os_free(wpa_s->wps);
  377. wpa_s->wps = NULL;
  378. }
  379. int wpas_wps_ssid_bss_match(struct wpa_ssid *ssid, struct wpa_scan_res *bss)
  380. {
  381. struct wpabuf *wps_ie;
  382. if (!(ssid->key_mgmt & WPA_KEY_MGMT_WPS))
  383. return -1;
  384. wps_ie = wpa_scan_get_vendor_ie_multi(bss, WPS_IE_VENDOR_TYPE);
  385. if (eap_is_wps_pbc_enrollee(&ssid->eap)) {
  386. if (!wps_ie) {
  387. wpa_printf(MSG_DEBUG, " skip - non-WPS AP");
  388. return 0;
  389. }
  390. if (!wps_is_selected_pbc_registrar(wps_ie)) {
  391. wpa_printf(MSG_DEBUG, " skip - WPS AP "
  392. "without active PBC Registrar");
  393. wpabuf_free(wps_ie);
  394. return 0;
  395. }
  396. /* TODO: overlap detection */
  397. wpa_printf(MSG_DEBUG, " selected based on WPS IE "
  398. "(Active PBC)");
  399. wpabuf_free(wps_ie);
  400. return 1;
  401. }
  402. if (eap_is_wps_pin_enrollee(&ssid->eap)) {
  403. if (!wps_ie) {
  404. wpa_printf(MSG_DEBUG, " skip - non-WPS AP");
  405. return 0;
  406. }
  407. if (!wps_is_selected_pin_registrar(wps_ie)) {
  408. wpa_printf(MSG_DEBUG, " skip - WPS AP "
  409. "without active PIN Registrar");
  410. wpabuf_free(wps_ie);
  411. return 0;
  412. }
  413. wpa_printf(MSG_DEBUG, " selected based on WPS IE "
  414. "(Active PIN)");
  415. wpabuf_free(wps_ie);
  416. return 1;
  417. }
  418. if (wps_ie) {
  419. wpa_printf(MSG_DEBUG, " selected based on WPS IE");
  420. wpabuf_free(wps_ie);
  421. return 1;
  422. }
  423. return -1;
  424. }
  425. int wpas_wps_ssid_wildcard_ok(struct wpa_ssid *ssid,
  426. struct wpa_scan_res *bss)
  427. {
  428. struct wpabuf *wps_ie = NULL;
  429. int ret = 0;
  430. if (eap_is_wps_pbc_enrollee(&ssid->eap)) {
  431. wps_ie = wpa_scan_get_vendor_ie_multi(bss, WPS_IE_VENDOR_TYPE);
  432. if (wps_ie && wps_is_selected_pbc_registrar(wps_ie)) {
  433. /* allow wildcard SSID for WPS PBC */
  434. ret = 1;
  435. }
  436. } else if (eap_is_wps_pin_enrollee(&ssid->eap)) {
  437. wps_ie = wpa_scan_get_vendor_ie_multi(bss, WPS_IE_VENDOR_TYPE);
  438. if (wps_ie && wps_is_selected_pin_registrar(wps_ie)) {
  439. /* allow wildcard SSID for WPS PIN */
  440. ret = 1;
  441. }
  442. }
  443. wpabuf_free(wps_ie);
  444. return ret;
  445. }
  446. int wpas_wps_scan_pbc_overlap(struct wpa_supplicant *wpa_s,
  447. struct wpa_scan_res *selected,
  448. struct wpa_ssid *ssid)
  449. {
  450. const u8 *sel_uuid, *uuid;
  451. size_t i;
  452. struct wpabuf *wps_ie;
  453. int ret = 0;
  454. if (!eap_is_wps_pbc_enrollee(&ssid->eap))
  455. return 0;
  456. /* Make sure that only one AP is in active PBC mode */
  457. wps_ie = wpa_scan_get_vendor_ie_multi(selected, WPS_IE_VENDOR_TYPE);
  458. if (wps_ie)
  459. sel_uuid = wps_get_uuid_e(wps_ie);
  460. else
  461. sel_uuid = NULL;
  462. if (!sel_uuid) {
  463. wpa_printf(MSG_DEBUG, "WPS: UUID-E not available for PBC "
  464. "overlap detection");
  465. wpabuf_free(wps_ie);
  466. return 1;
  467. }
  468. for (i = 0; i < wpa_s->scan_res->num; i++) {
  469. struct wpa_scan_res *bss = wpa_s->scan_res->res[i];
  470. struct wpabuf *ie;
  471. if (bss == selected)
  472. continue;
  473. ie = wpa_scan_get_vendor_ie_multi(bss, WPS_IE_VENDOR_TYPE);
  474. if (!ie)
  475. continue;
  476. if (!wps_is_selected_pbc_registrar(ie)) {
  477. wpabuf_free(ie);
  478. continue;
  479. }
  480. uuid = wps_get_uuid_e(ie);
  481. if (uuid == NULL) {
  482. wpa_printf(MSG_DEBUG, "WPS: UUID-E not available for "
  483. "PBC overlap detection (other BSS)");
  484. ret = 1;
  485. wpabuf_free(ie);
  486. break;
  487. }
  488. if (os_memcmp(sel_uuid, uuid, 16) != 0) {
  489. ret = 1; /* PBC overlap */
  490. wpabuf_free(ie);
  491. break;
  492. }
  493. /* TODO: verify that this is reasonable dual-band situation */
  494. wpabuf_free(ie);
  495. }
  496. wpabuf_free(wps_ie);
  497. return ret;
  498. }
  499. void wpas_wps_notify_scan_results(struct wpa_supplicant *wpa_s)
  500. {
  501. size_t i;
  502. if (wpa_s->disconnected || wpa_s->wpa_state >= WPA_ASSOCIATED)
  503. return;
  504. for (i = 0; i < wpa_s->scan_res->num; i++) {
  505. struct wpa_scan_res *bss = wpa_s->scan_res->res[i];
  506. struct wpabuf *ie;
  507. ie = wpa_scan_get_vendor_ie_multi(bss, WPS_IE_VENDOR_TYPE);
  508. if (!ie)
  509. continue;
  510. if (wps_is_selected_pbc_registrar(ie))
  511. wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_AP_AVAILABLE_PBC);
  512. else if (wps_is_selected_pin_registrar(ie))
  513. wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_AP_AVAILABLE_PIN);
  514. else
  515. wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_AP_AVAILABLE);
  516. wpabuf_free(ie);
  517. break;
  518. }
  519. }