interworking.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724
  1. /*
  2. * Interworking (IEEE 802.11u)
  3. * Copyright (c) 2011, Qualcomm Atheros
  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 "common/ieee802_11_defs.h"
  17. #include "common/gas.h"
  18. #include "common/wpa_ctrl.h"
  19. #include "drivers/driver.h"
  20. #include "eap_common/eap_defs.h"
  21. #include "wpa_supplicant_i.h"
  22. #include "config.h"
  23. #include "bss.h"
  24. #include "scan.h"
  25. #include "gas_query.h"
  26. #include "interworking.h"
  27. static void interworking_next_anqp_fetch(struct wpa_supplicant *wpa_s);
  28. static struct wpabuf * anqp_build_req(u16 info_ids[], size_t num_ids,
  29. struct wpabuf *extra)
  30. {
  31. struct wpabuf *buf;
  32. size_t i;
  33. u8 *len_pos;
  34. buf = gas_anqp_build_initial_req(0, 4 + num_ids * 2 +
  35. (extra ? wpabuf_len(extra) : 0));
  36. if (buf == NULL)
  37. return NULL;
  38. len_pos = gas_anqp_add_element(buf, ANQP_QUERY_LIST);
  39. for (i = 0; i < num_ids; i++)
  40. wpabuf_put_le16(buf, info_ids[i]);
  41. gas_anqp_set_element_len(buf, len_pos);
  42. if (extra)
  43. wpabuf_put_buf(buf, extra);
  44. gas_anqp_set_len(buf);
  45. return buf;
  46. }
  47. static void interworking_anqp_resp_cb(void *ctx, const u8 *dst,
  48. u8 dialog_token,
  49. enum gas_query_result result,
  50. const struct wpabuf *adv_proto,
  51. const struct wpabuf *resp,
  52. u16 status_code)
  53. {
  54. struct wpa_supplicant *wpa_s = ctx;
  55. anqp_resp_cb(wpa_s, dst, dialog_token, result, adv_proto, resp,
  56. status_code);
  57. interworking_next_anqp_fetch(wpa_s);
  58. }
  59. static int interworking_anqp_send_req(struct wpa_supplicant *wpa_s,
  60. struct wpa_bss *bss)
  61. {
  62. struct wpabuf *buf;
  63. int ret = 0;
  64. int res;
  65. u16 info_ids[] = {
  66. ANQP_CAPABILITY_LIST,
  67. ANQP_VENUE_NAME,
  68. ANQP_NETWORK_AUTH_TYPE,
  69. ANQP_ROAMING_CONSORTIUM,
  70. ANQP_IP_ADDR_TYPE_AVAILABILITY,
  71. ANQP_NAI_REALM,
  72. ANQP_3GPP_CELLULAR_NETWORK,
  73. ANQP_DOMAIN_NAME
  74. };
  75. struct wpabuf *extra = NULL;
  76. wpa_printf(MSG_DEBUG, "Interworking: ANQP Query Request to " MACSTR,
  77. MAC2STR(bss->bssid));
  78. buf = anqp_build_req(info_ids, sizeof(info_ids) / sizeof(info_ids[0]),
  79. extra);
  80. wpabuf_free(extra);
  81. if (buf == NULL)
  82. return -1;
  83. res = gas_query_req(wpa_s->gas, bss->bssid, bss->freq, buf,
  84. interworking_anqp_resp_cb, wpa_s);
  85. if (res < 0) {
  86. wpa_printf(MSG_DEBUG, "ANQP: Failed to send Query Request");
  87. ret = -1;
  88. } else
  89. wpa_printf(MSG_DEBUG, "ANQP: Query started with dialog token "
  90. "%u", res);
  91. wpabuf_free(buf);
  92. return ret;
  93. }
  94. struct nai_realm_eap {
  95. u8 method;
  96. u8 inner_method;
  97. enum nai_realm_eap_auth_inner_non_eap inner_non_eap;
  98. u8 cred_type;
  99. u8 tunneled_cred_type;
  100. };
  101. struct nai_realm {
  102. u8 encoding;
  103. char *realm;
  104. u8 eap_count;
  105. struct nai_realm_eap *eap;
  106. };
  107. static void nai_realm_free(struct nai_realm *realms, u16 count)
  108. {
  109. u16 i;
  110. if (realms == NULL)
  111. return;
  112. for (i = 0; i < count; i++) {
  113. os_free(realms[i].eap);
  114. os_free(realms[i].realm);
  115. }
  116. os_free(realms);
  117. }
  118. static const u8 * nai_realm_parse_eap(struct nai_realm_eap *e, const u8 *pos,
  119. const u8 *end)
  120. {
  121. u8 elen, auth_count, a;
  122. const u8 *e_end;
  123. if (pos + 3 > end) {
  124. wpa_printf(MSG_DEBUG, "No room for EAP Method fixed fields");
  125. return NULL;
  126. }
  127. elen = *pos++;
  128. if (pos + elen > end || elen < 2) {
  129. wpa_printf(MSG_DEBUG, "No room for EAP Method subfield");
  130. return NULL;
  131. }
  132. e_end = pos + elen;
  133. e->method = *pos++;
  134. auth_count = *pos++;
  135. wpa_printf(MSG_DEBUG, "EAP Method: len=%u method=%u auth_count=%u",
  136. elen, e->method, auth_count);
  137. for (a = 0; a < auth_count; a++) {
  138. u8 id, len;
  139. if (pos + 2 > end || pos + 2 + pos[1] > end) {
  140. wpa_printf(MSG_DEBUG, "No room for Authentication "
  141. "Parameter subfield");
  142. return NULL;
  143. }
  144. id = *pos++;
  145. len = *pos++;
  146. switch (id) {
  147. case NAI_REALM_EAP_AUTH_NON_EAP_INNER_AUTH:
  148. if (len < 1)
  149. break;
  150. e->inner_non_eap = *pos;
  151. if (e->method != EAP_TYPE_TTLS)
  152. break;
  153. switch (*pos) {
  154. case NAI_REALM_INNER_NON_EAP_PAP:
  155. wpa_printf(MSG_DEBUG, "EAP-TTLS/PAP");
  156. break;
  157. case NAI_REALM_INNER_NON_EAP_CHAP:
  158. wpa_printf(MSG_DEBUG, "EAP-TTLS/CHAP");
  159. break;
  160. case NAI_REALM_INNER_NON_EAP_MSCHAP:
  161. wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAP");
  162. break;
  163. case NAI_REALM_INNER_NON_EAP_MSCHAPV2:
  164. wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2");
  165. break;
  166. }
  167. break;
  168. case NAI_REALM_EAP_AUTH_INNER_AUTH_EAP_METHOD:
  169. if (len < 1)
  170. break;
  171. e->inner_method = *pos;
  172. wpa_printf(MSG_DEBUG, "Inner EAP method: %u",
  173. e->inner_method);
  174. break;
  175. case NAI_REALM_EAP_AUTH_CRED_TYPE:
  176. if (len < 1)
  177. break;
  178. e->cred_type = *pos;
  179. wpa_printf(MSG_DEBUG, "Credential Type: %u",
  180. e->cred_type);
  181. break;
  182. case NAI_REALM_EAP_AUTH_TUNNELED_CRED_TYPE:
  183. if (len < 1)
  184. break;
  185. e->tunneled_cred_type = *pos;
  186. wpa_printf(MSG_DEBUG, "Tunneled EAP Method Credential "
  187. "Type: %u", e->tunneled_cred_type);
  188. break;
  189. default:
  190. wpa_printf(MSG_DEBUG, "Unsupported Authentication "
  191. "Parameter: id=%u len=%u", id, len);
  192. wpa_hexdump(MSG_DEBUG, "Authentication Parameter "
  193. "Value", pos, len);
  194. break;
  195. }
  196. pos += len;
  197. }
  198. return e_end;
  199. }
  200. static const u8 * nai_realm_parse_realm(struct nai_realm *r, const u8 *pos,
  201. const u8 *end)
  202. {
  203. u16 len;
  204. const u8 *f_end;
  205. u8 realm_len, e;
  206. if (end - pos < 4) {
  207. wpa_printf(MSG_DEBUG, "No room for NAI Realm Data "
  208. "fixed fields");
  209. return NULL;
  210. }
  211. len = WPA_GET_LE16(pos); /* NAI Realm Data field Length */
  212. pos += 2;
  213. if (pos + len > end || len < 3) {
  214. wpa_printf(MSG_DEBUG, "No room for NAI Realm Data "
  215. "(len=%u; left=%u)",
  216. len, (unsigned int) (end - pos));
  217. return NULL;
  218. }
  219. f_end = pos + len;
  220. r->encoding = *pos++;
  221. realm_len = *pos++;
  222. if (pos + realm_len > f_end) {
  223. wpa_printf(MSG_DEBUG, "No room for NAI Realm "
  224. "(len=%u; left=%u)",
  225. realm_len, (unsigned int) (f_end - pos));
  226. return NULL;
  227. }
  228. wpa_hexdump_ascii(MSG_DEBUG, "NAI Realm", pos, realm_len);
  229. r->realm = os_malloc(realm_len + 1);
  230. if (r->realm == NULL)
  231. return NULL;
  232. os_memcpy(r->realm, pos, realm_len);
  233. r->realm[realm_len] = '\0';
  234. pos += realm_len;
  235. if (pos + 1 > f_end) {
  236. wpa_printf(MSG_DEBUG, "No room for EAP Method Count");
  237. return NULL;
  238. }
  239. r->eap_count = *pos++;
  240. wpa_printf(MSG_DEBUG, "EAP Count: %u", r->eap_count);
  241. if (pos + r->eap_count * 3 > f_end) {
  242. wpa_printf(MSG_DEBUG, "No room for EAP Methods");
  243. return NULL;
  244. }
  245. r->eap = os_zalloc(r->eap_count * sizeof(struct nai_realm_eap));
  246. if (r->eap == NULL)
  247. return NULL;
  248. for (e = 0; e < r->eap_count; e++) {
  249. pos = nai_realm_parse_eap(&r->eap[e], pos, f_end);
  250. if (pos == NULL)
  251. return NULL;
  252. }
  253. return f_end;
  254. }
  255. static struct nai_realm * nai_realm_parse(struct wpabuf *anqp, u16 *count)
  256. {
  257. struct nai_realm *realm;
  258. const u8 *pos, *end;
  259. u16 i, num;
  260. if (anqp == NULL || wpabuf_len(anqp) < 2)
  261. return NULL;
  262. pos = wpabuf_head_u8(anqp);
  263. end = pos + wpabuf_len(anqp);
  264. num = WPA_GET_LE16(pos);
  265. wpa_printf(MSG_DEBUG, "NAI Realm Count: %u", num);
  266. pos += 2;
  267. if (num * 5 > end - pos) {
  268. wpa_printf(MSG_DEBUG, "Invalid NAI Realm Count %u - not "
  269. "enough data (%u octets) for that many realms",
  270. num, (unsigned int) (end - pos));
  271. return NULL;
  272. }
  273. realm = os_zalloc(num * sizeof(struct nai_realm));
  274. if (realm == NULL)
  275. return NULL;
  276. for (i = 0; i < num; i++) {
  277. pos = nai_realm_parse_realm(&realm[i], pos, end);
  278. if (pos == NULL) {
  279. nai_realm_free(realm, num);
  280. return NULL;
  281. }
  282. }
  283. *count = num;
  284. return realm;
  285. }
  286. static int nai_realm_match(struct nai_realm *realm, const char *home_realm)
  287. {
  288. char *tmp, *pos, *end;
  289. int match = 0;
  290. if (realm->realm == NULL)
  291. return 0;
  292. if (os_strchr(realm->realm, ';') == NULL)
  293. return os_strcasecmp(realm->realm, home_realm) == 0;
  294. tmp = os_strdup(realm->realm);
  295. if (tmp == NULL)
  296. return 0;
  297. pos = tmp;
  298. while (*pos) {
  299. end = os_strchr(pos, ';');
  300. if (end)
  301. *end = '\0';
  302. if (os_strcasecmp(pos, home_realm) == 0) {
  303. match = 1;
  304. break;
  305. }
  306. if (end == NULL)
  307. break;
  308. pos = end + 1;
  309. }
  310. os_free(tmp);
  311. return match;
  312. }
  313. int interworking_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
  314. {
  315. if (bss == NULL)
  316. return -1;
  317. wpa_printf(MSG_DEBUG, "Interworking: Connect with " MACSTR,
  318. MAC2STR(bss->bssid));
  319. /* TODO: create network block and connect */
  320. return 0;
  321. }
  322. static int interworking_credentials_available(struct wpa_supplicant *wpa_s,
  323. struct wpa_bss *bss)
  324. {
  325. struct nai_realm *realm;
  326. u16 count, i;
  327. int found = 0;
  328. if (bss->anqp_nai_realm == NULL)
  329. return 0;
  330. if (wpa_s->conf->home_realm == NULL)
  331. return 0;
  332. wpa_printf(MSG_DEBUG, "Interworking: Parsing NAI Realm list from "
  333. MACSTR, MAC2STR(bss->bssid));
  334. realm = nai_realm_parse(bss->anqp_nai_realm, &count);
  335. if (realm == NULL) {
  336. wpa_printf(MSG_DEBUG, "Interworking: Could not parse NAI "
  337. "Realm list from " MACSTR, MAC2STR(bss->bssid));
  338. return 0;
  339. }
  340. for (i = 0; i < count; i++) {
  341. if (nai_realm_match(&realm[i], wpa_s->conf->home_realm)) {
  342. found++;
  343. break;
  344. }
  345. }
  346. nai_realm_free(realm, count);
  347. return found;
  348. }
  349. static void interworking_select_network(struct wpa_supplicant *wpa_s)
  350. {
  351. struct wpa_bss *bss, *selected = NULL;
  352. unsigned int count = 0;
  353. wpa_s->network_select = 0;
  354. dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
  355. if (!interworking_credentials_available(wpa_s, bss))
  356. continue;
  357. count++;
  358. wpa_msg(wpa_s, MSG_INFO, INTERWORKING_AP MACSTR,
  359. MAC2STR(bss->bssid));
  360. if (selected == NULL && wpa_s->auto_select)
  361. selected = bss;
  362. }
  363. if (count == 0) {
  364. wpa_msg(wpa_s, MSG_INFO, INTERWORKING_NO_MATCH "No network "
  365. "with matching credentials found");
  366. }
  367. if (selected)
  368. interworking_connect(wpa_s, selected);
  369. }
  370. static void interworking_next_anqp_fetch(struct wpa_supplicant *wpa_s)
  371. {
  372. struct wpa_bss *bss;
  373. int found = 0;
  374. const u8 *ie;
  375. if (!wpa_s->fetch_anqp_in_progress)
  376. return;
  377. dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
  378. if (!(bss->caps & IEEE80211_CAP_ESS))
  379. continue;
  380. ie = wpa_bss_get_ie(bss, WLAN_EID_EXT_CAPAB);
  381. if (ie == NULL || ie[1] < 4 || !(ie[5] & 0x80))
  382. continue; /* AP does not support Interworking */
  383. if (!(bss->flags & WPA_BSS_ANQP_FETCH_TRIED)) {
  384. found++;
  385. bss->flags |= WPA_BSS_ANQP_FETCH_TRIED;
  386. wpa_msg(wpa_s, MSG_INFO, "Starting ANQP fetch for "
  387. MACSTR, MAC2STR(bss->bssid));
  388. interworking_anqp_send_req(wpa_s, bss);
  389. break;
  390. }
  391. }
  392. if (found == 0) {
  393. wpa_msg(wpa_s, MSG_INFO, "ANQP fetch completed");
  394. wpa_s->fetch_anqp_in_progress = 0;
  395. if (wpa_s->network_select)
  396. interworking_select_network(wpa_s);
  397. }
  398. }
  399. static void interworking_start_fetch_anqp(struct wpa_supplicant *wpa_s)
  400. {
  401. struct wpa_bss *bss;
  402. dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list)
  403. bss->flags &= ~WPA_BSS_ANQP_FETCH_TRIED;
  404. wpa_s->fetch_anqp_in_progress = 1;
  405. interworking_next_anqp_fetch(wpa_s);
  406. }
  407. int interworking_fetch_anqp(struct wpa_supplicant *wpa_s)
  408. {
  409. if (wpa_s->fetch_anqp_in_progress || wpa_s->network_select)
  410. return 0;
  411. wpa_s->network_select = 0;
  412. interworking_start_fetch_anqp(wpa_s);
  413. return 0;
  414. }
  415. void interworking_stop_fetch_anqp(struct wpa_supplicant *wpa_s)
  416. {
  417. if (!wpa_s->fetch_anqp_in_progress)
  418. return;
  419. wpa_s->fetch_anqp_in_progress = 0;
  420. }
  421. int anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst,
  422. u16 info_ids[], size_t num_ids)
  423. {
  424. struct wpabuf *buf;
  425. int ret = 0;
  426. int freq;
  427. struct wpa_bss *bss;
  428. int res;
  429. freq = wpa_s->assoc_freq;
  430. bss = wpa_bss_get_bssid(wpa_s, dst);
  431. if (bss)
  432. freq = bss->freq;
  433. if (freq <= 0)
  434. return -1;
  435. wpa_printf(MSG_DEBUG, "ANQP: Query Request to " MACSTR " for %u id(s)",
  436. MAC2STR(dst), (unsigned int) num_ids);
  437. buf = anqp_build_req(info_ids, num_ids, NULL);
  438. if (buf == NULL)
  439. return -1;
  440. res = gas_query_req(wpa_s->gas, dst, freq, buf, anqp_resp_cb, wpa_s);
  441. if (res < 0) {
  442. wpa_printf(MSG_DEBUG, "ANQP: Failed to send Query Request");
  443. ret = -1;
  444. } else
  445. wpa_printf(MSG_DEBUG, "ANQP: Query started with dialog token "
  446. "%u", res);
  447. wpabuf_free(buf);
  448. return ret;
  449. }
  450. static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s,
  451. const u8 *sa, u16 info_id,
  452. const u8 *data, size_t slen)
  453. {
  454. const u8 *pos = data;
  455. struct wpa_bss *bss = wpa_bss_get_bssid(wpa_s, sa);
  456. switch (info_id) {
  457. case ANQP_CAPABILITY_LIST:
  458. wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
  459. " ANQP Capability list", MAC2STR(sa));
  460. break;
  461. case ANQP_VENUE_NAME:
  462. wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
  463. " Venue Name", MAC2STR(sa));
  464. wpa_hexdump_ascii(MSG_DEBUG, "ANQP: Venue Name", pos, slen);
  465. if (bss) {
  466. wpabuf_free(bss->anqp_venue_name);
  467. bss->anqp_venue_name = wpabuf_alloc_copy(pos, slen);
  468. }
  469. break;
  470. case ANQP_NETWORK_AUTH_TYPE:
  471. wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
  472. " Network Authentication Type information",
  473. MAC2STR(sa));
  474. wpa_hexdump_ascii(MSG_DEBUG, "ANQP: Network Authentication "
  475. "Type", pos, slen);
  476. if (bss) {
  477. wpabuf_free(bss->anqp_network_auth_type);
  478. bss->anqp_network_auth_type =
  479. wpabuf_alloc_copy(pos, slen);
  480. }
  481. break;
  482. case ANQP_ROAMING_CONSORTIUM:
  483. wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
  484. " Roaming Consortium list", MAC2STR(sa));
  485. wpa_hexdump_ascii(MSG_DEBUG, "ANQP: Roaming Consortium",
  486. pos, slen);
  487. if (bss) {
  488. wpabuf_free(bss->anqp_roaming_consortium);
  489. bss->anqp_roaming_consortium =
  490. wpabuf_alloc_copy(pos, slen);
  491. }
  492. break;
  493. case ANQP_IP_ADDR_TYPE_AVAILABILITY:
  494. wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
  495. " IP Address Type Availability information",
  496. MAC2STR(sa));
  497. wpa_hexdump(MSG_MSGDUMP, "ANQP: IP Address Availability",
  498. pos, slen);
  499. if (bss) {
  500. wpabuf_free(bss->anqp_ip_addr_type_availability);
  501. bss->anqp_ip_addr_type_availability =
  502. wpabuf_alloc_copy(pos, slen);
  503. }
  504. break;
  505. case ANQP_NAI_REALM:
  506. wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
  507. " NAI Realm list", MAC2STR(sa));
  508. wpa_hexdump_ascii(MSG_DEBUG, "ANQP: NAI Realm", pos, slen);
  509. if (bss) {
  510. wpabuf_free(bss->anqp_nai_realm);
  511. bss->anqp_nai_realm = wpabuf_alloc_copy(pos, slen);
  512. }
  513. break;
  514. case ANQP_3GPP_CELLULAR_NETWORK:
  515. wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
  516. " 3GPP Cellular Network information", MAC2STR(sa));
  517. wpa_hexdump_ascii(MSG_DEBUG, "ANQP: 3GPP Cellular Network",
  518. pos, slen);
  519. if (bss) {
  520. wpabuf_free(bss->anqp_3gpp);
  521. bss->anqp_3gpp = wpabuf_alloc_copy(pos, slen);
  522. }
  523. break;
  524. case ANQP_DOMAIN_NAME:
  525. wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
  526. " Domain Name list", MAC2STR(sa));
  527. wpa_hexdump_ascii(MSG_MSGDUMP, "ANQP: Domain Name", pos, slen);
  528. if (bss) {
  529. wpabuf_free(bss->anqp_domain_name);
  530. bss->anqp_domain_name = wpabuf_alloc_copy(pos, slen);
  531. }
  532. break;
  533. case ANQP_VENDOR_SPECIFIC:
  534. if (slen < 3)
  535. return;
  536. switch (WPA_GET_BE24(pos)) {
  537. default:
  538. wpa_printf(MSG_DEBUG, "Interworking: Unsupported "
  539. "vendor-specific ANQP OUI %06x",
  540. WPA_GET_BE24(pos));
  541. return;
  542. }
  543. break;
  544. default:
  545. wpa_printf(MSG_DEBUG, "Interworking: Unsupported ANQP Info ID "
  546. "%u", info_id);
  547. break;
  548. }
  549. }
  550. void anqp_resp_cb(void *ctx, const u8 *dst, u8 dialog_token,
  551. enum gas_query_result result,
  552. const struct wpabuf *adv_proto,
  553. const struct wpabuf *resp, u16 status_code)
  554. {
  555. struct wpa_supplicant *wpa_s = ctx;
  556. const u8 *pos;
  557. const u8 *end;
  558. u16 info_id;
  559. u16 slen;
  560. if (result != GAS_QUERY_SUCCESS)
  561. return;
  562. pos = wpabuf_head(adv_proto);
  563. if (wpabuf_len(adv_proto) < 4 || pos[0] != WLAN_EID_ADV_PROTO ||
  564. pos[1] < 2 || pos[3] != ACCESS_NETWORK_QUERY_PROTOCOL) {
  565. wpa_printf(MSG_DEBUG, "ANQP: Unexpected Advertisement "
  566. "Protocol in response");
  567. return;
  568. }
  569. pos = wpabuf_head(resp);
  570. end = pos + wpabuf_len(resp);
  571. while (pos < end) {
  572. if (pos + 4 > end) {
  573. wpa_printf(MSG_DEBUG, "ANQP: Invalid element");
  574. break;
  575. }
  576. info_id = WPA_GET_LE16(pos);
  577. pos += 2;
  578. slen = WPA_GET_LE16(pos);
  579. pos += 2;
  580. if (pos + slen > end) {
  581. wpa_printf(MSG_DEBUG, "ANQP: Invalid element length "
  582. "for Info ID %u", info_id);
  583. break;
  584. }
  585. interworking_parse_rx_anqp_resp(wpa_s, dst, info_id, pos,
  586. slen);
  587. pos += slen;
  588. }
  589. }
  590. static void interworking_scan_res_handler(struct wpa_supplicant *wpa_s,
  591. struct wpa_scan_results *scan_res)
  592. {
  593. wpa_printf(MSG_DEBUG, "Interworking: Scan results available - start "
  594. "ANQP fetch");
  595. interworking_start_fetch_anqp(wpa_s);
  596. }
  597. int interworking_select(struct wpa_supplicant *wpa_s, int auto_select)
  598. {
  599. interworking_stop_fetch_anqp(wpa_s);
  600. wpa_s->network_select = 1;
  601. wpa_s->auto_select = !!auto_select;
  602. wpa_printf(MSG_DEBUG, "Interworking: Start scan for network "
  603. "selection");
  604. wpa_s->scan_res_handler = interworking_scan_res_handler;
  605. wpa_s->scan_req = 2;
  606. wpa_supplicant_req_scan(wpa_s, 0, 0);
  607. return 0;
  608. }