interworking.c 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446
  1. /*
  2. * Interworking (IEEE 802.11u)
  3. * Copyright (c) 2011-2012, Qualcomm Atheros, Inc.
  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 "common/ieee802_11_defs.h"
  11. #include "common/gas.h"
  12. #include "common/wpa_ctrl.h"
  13. #include "utils/pcsc_funcs.h"
  14. #include "drivers/driver.h"
  15. #include "eap_common/eap_defs.h"
  16. #include "eap_peer/eap_methods.h"
  17. #include "wpa_supplicant_i.h"
  18. #include "config.h"
  19. #include "config_ssid.h"
  20. #include "bss.h"
  21. #include "scan.h"
  22. #include "notify.h"
  23. #include "gas_query.h"
  24. #include "interworking.h"
  25. #if defined(EAP_SIM) | defined(EAP_SIM_DYNAMIC)
  26. #define INTERWORKING_3GPP
  27. #else
  28. #if defined(EAP_AKA) | defined(EAP_AKA_DYNAMIC)
  29. #define INTERWORKING_3GPP
  30. #else
  31. #if defined(EAP_AKA_PRIME) | defined(EAP_AKA_PRIME_DYNAMIC)
  32. #define INTERWORKING_3GPP
  33. #endif
  34. #endif
  35. #endif
  36. static void interworking_next_anqp_fetch(struct wpa_supplicant *wpa_s);
  37. static void interworking_reconnect(struct wpa_supplicant *wpa_s)
  38. {
  39. if (wpa_s->wpa_state >= WPA_AUTHENTICATING) {
  40. wpa_supplicant_cancel_sched_scan(wpa_s);
  41. wpa_supplicant_deauthenticate(wpa_s,
  42. WLAN_REASON_DEAUTH_LEAVING);
  43. }
  44. wpa_s->disconnected = 0;
  45. wpa_s->reassociate = 1;
  46. wpa_supplicant_req_scan(wpa_s, 0, 0);
  47. }
  48. static struct wpabuf * anqp_build_req(u16 info_ids[], size_t num_ids,
  49. struct wpabuf *extra)
  50. {
  51. struct wpabuf *buf;
  52. size_t i;
  53. u8 *len_pos;
  54. buf = gas_anqp_build_initial_req(0, 4 + num_ids * 2 +
  55. (extra ? wpabuf_len(extra) : 0));
  56. if (buf == NULL)
  57. return NULL;
  58. len_pos = gas_anqp_add_element(buf, ANQP_QUERY_LIST);
  59. for (i = 0; i < num_ids; i++)
  60. wpabuf_put_le16(buf, info_ids[i]);
  61. gas_anqp_set_element_len(buf, len_pos);
  62. if (extra)
  63. wpabuf_put_buf(buf, extra);
  64. gas_anqp_set_len(buf);
  65. return buf;
  66. }
  67. static void interworking_anqp_resp_cb(void *ctx, const u8 *dst,
  68. u8 dialog_token,
  69. enum gas_query_result result,
  70. const struct wpabuf *adv_proto,
  71. const struct wpabuf *resp,
  72. u16 status_code)
  73. {
  74. struct wpa_supplicant *wpa_s = ctx;
  75. anqp_resp_cb(wpa_s, dst, dialog_token, result, adv_proto, resp,
  76. status_code);
  77. interworking_next_anqp_fetch(wpa_s);
  78. }
  79. static int interworking_anqp_send_req(struct wpa_supplicant *wpa_s,
  80. struct wpa_bss *bss)
  81. {
  82. struct wpabuf *buf;
  83. int ret = 0;
  84. int res;
  85. u16 info_ids[] = {
  86. ANQP_CAPABILITY_LIST,
  87. ANQP_VENUE_NAME,
  88. ANQP_NETWORK_AUTH_TYPE,
  89. ANQP_ROAMING_CONSORTIUM,
  90. ANQP_IP_ADDR_TYPE_AVAILABILITY,
  91. ANQP_NAI_REALM,
  92. ANQP_3GPP_CELLULAR_NETWORK,
  93. ANQP_DOMAIN_NAME
  94. };
  95. struct wpabuf *extra = NULL;
  96. wpa_printf(MSG_DEBUG, "Interworking: ANQP Query Request to " MACSTR,
  97. MAC2STR(bss->bssid));
  98. buf = anqp_build_req(info_ids, sizeof(info_ids) / sizeof(info_ids[0]),
  99. extra);
  100. wpabuf_free(extra);
  101. if (buf == NULL)
  102. return -1;
  103. res = gas_query_req(wpa_s->gas, bss->bssid, bss->freq, buf,
  104. interworking_anqp_resp_cb, wpa_s);
  105. if (res < 0) {
  106. wpa_printf(MSG_DEBUG, "ANQP: Failed to send Query Request");
  107. ret = -1;
  108. } else
  109. wpa_printf(MSG_DEBUG, "ANQP: Query started with dialog token "
  110. "%u", res);
  111. wpabuf_free(buf);
  112. return ret;
  113. }
  114. struct nai_realm_eap {
  115. u8 method;
  116. u8 inner_method;
  117. enum nai_realm_eap_auth_inner_non_eap inner_non_eap;
  118. u8 cred_type;
  119. u8 tunneled_cred_type;
  120. };
  121. struct nai_realm {
  122. u8 encoding;
  123. char *realm;
  124. u8 eap_count;
  125. struct nai_realm_eap *eap;
  126. };
  127. static void nai_realm_free(struct nai_realm *realms, u16 count)
  128. {
  129. u16 i;
  130. if (realms == NULL)
  131. return;
  132. for (i = 0; i < count; i++) {
  133. os_free(realms[i].eap);
  134. os_free(realms[i].realm);
  135. }
  136. os_free(realms);
  137. }
  138. static const u8 * nai_realm_parse_eap(struct nai_realm_eap *e, const u8 *pos,
  139. const u8 *end)
  140. {
  141. u8 elen, auth_count, a;
  142. const u8 *e_end;
  143. if (pos + 3 > end) {
  144. wpa_printf(MSG_DEBUG, "No room for EAP Method fixed fields");
  145. return NULL;
  146. }
  147. elen = *pos++;
  148. if (pos + elen > end || elen < 2) {
  149. wpa_printf(MSG_DEBUG, "No room for EAP Method subfield");
  150. return NULL;
  151. }
  152. e_end = pos + elen;
  153. e->method = *pos++;
  154. auth_count = *pos++;
  155. wpa_printf(MSG_DEBUG, "EAP Method: len=%u method=%u auth_count=%u",
  156. elen, e->method, auth_count);
  157. for (a = 0; a < auth_count; a++) {
  158. u8 id, len;
  159. if (pos + 2 > end || pos + 2 + pos[1] > end) {
  160. wpa_printf(MSG_DEBUG, "No room for Authentication "
  161. "Parameter subfield");
  162. return NULL;
  163. }
  164. id = *pos++;
  165. len = *pos++;
  166. switch (id) {
  167. case NAI_REALM_EAP_AUTH_NON_EAP_INNER_AUTH:
  168. if (len < 1)
  169. break;
  170. e->inner_non_eap = *pos;
  171. if (e->method != EAP_TYPE_TTLS)
  172. break;
  173. switch (*pos) {
  174. case NAI_REALM_INNER_NON_EAP_PAP:
  175. wpa_printf(MSG_DEBUG, "EAP-TTLS/PAP");
  176. break;
  177. case NAI_REALM_INNER_NON_EAP_CHAP:
  178. wpa_printf(MSG_DEBUG, "EAP-TTLS/CHAP");
  179. break;
  180. case NAI_REALM_INNER_NON_EAP_MSCHAP:
  181. wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAP");
  182. break;
  183. case NAI_REALM_INNER_NON_EAP_MSCHAPV2:
  184. wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2");
  185. break;
  186. }
  187. break;
  188. case NAI_REALM_EAP_AUTH_INNER_AUTH_EAP_METHOD:
  189. if (len < 1)
  190. break;
  191. e->inner_method = *pos;
  192. wpa_printf(MSG_DEBUG, "Inner EAP method: %u",
  193. e->inner_method);
  194. break;
  195. case NAI_REALM_EAP_AUTH_CRED_TYPE:
  196. if (len < 1)
  197. break;
  198. e->cred_type = *pos;
  199. wpa_printf(MSG_DEBUG, "Credential Type: %u",
  200. e->cred_type);
  201. break;
  202. case NAI_REALM_EAP_AUTH_TUNNELED_CRED_TYPE:
  203. if (len < 1)
  204. break;
  205. e->tunneled_cred_type = *pos;
  206. wpa_printf(MSG_DEBUG, "Tunneled EAP Method Credential "
  207. "Type: %u", e->tunneled_cred_type);
  208. break;
  209. default:
  210. wpa_printf(MSG_DEBUG, "Unsupported Authentication "
  211. "Parameter: id=%u len=%u", id, len);
  212. wpa_hexdump(MSG_DEBUG, "Authentication Parameter "
  213. "Value", pos, len);
  214. break;
  215. }
  216. pos += len;
  217. }
  218. return e_end;
  219. }
  220. static const u8 * nai_realm_parse_realm(struct nai_realm *r, const u8 *pos,
  221. const u8 *end)
  222. {
  223. u16 len;
  224. const u8 *f_end;
  225. u8 realm_len, e;
  226. if (end - pos < 4) {
  227. wpa_printf(MSG_DEBUG, "No room for NAI Realm Data "
  228. "fixed fields");
  229. return NULL;
  230. }
  231. len = WPA_GET_LE16(pos); /* NAI Realm Data field Length */
  232. pos += 2;
  233. if (pos + len > end || len < 3) {
  234. wpa_printf(MSG_DEBUG, "No room for NAI Realm Data "
  235. "(len=%u; left=%u)",
  236. len, (unsigned int) (end - pos));
  237. return NULL;
  238. }
  239. f_end = pos + len;
  240. r->encoding = *pos++;
  241. realm_len = *pos++;
  242. if (pos + realm_len > f_end) {
  243. wpa_printf(MSG_DEBUG, "No room for NAI Realm "
  244. "(len=%u; left=%u)",
  245. realm_len, (unsigned int) (f_end - pos));
  246. return NULL;
  247. }
  248. wpa_hexdump_ascii(MSG_DEBUG, "NAI Realm", pos, realm_len);
  249. r->realm = os_malloc(realm_len + 1);
  250. if (r->realm == NULL)
  251. return NULL;
  252. os_memcpy(r->realm, pos, realm_len);
  253. r->realm[realm_len] = '\0';
  254. pos += realm_len;
  255. if (pos + 1 > f_end) {
  256. wpa_printf(MSG_DEBUG, "No room for EAP Method Count");
  257. return NULL;
  258. }
  259. r->eap_count = *pos++;
  260. wpa_printf(MSG_DEBUG, "EAP Count: %u", r->eap_count);
  261. if (pos + r->eap_count * 3 > f_end) {
  262. wpa_printf(MSG_DEBUG, "No room for EAP Methods");
  263. return NULL;
  264. }
  265. r->eap = os_zalloc(r->eap_count * sizeof(struct nai_realm_eap));
  266. if (r->eap == NULL)
  267. return NULL;
  268. for (e = 0; e < r->eap_count; e++) {
  269. pos = nai_realm_parse_eap(&r->eap[e], pos, f_end);
  270. if (pos == NULL)
  271. return NULL;
  272. }
  273. return f_end;
  274. }
  275. static struct nai_realm * nai_realm_parse(struct wpabuf *anqp, u16 *count)
  276. {
  277. struct nai_realm *realm;
  278. const u8 *pos, *end;
  279. u16 i, num;
  280. if (anqp == NULL || wpabuf_len(anqp) < 2)
  281. return NULL;
  282. pos = wpabuf_head_u8(anqp);
  283. end = pos + wpabuf_len(anqp);
  284. num = WPA_GET_LE16(pos);
  285. wpa_printf(MSG_DEBUG, "NAI Realm Count: %u", num);
  286. pos += 2;
  287. if (num * 5 > end - pos) {
  288. wpa_printf(MSG_DEBUG, "Invalid NAI Realm Count %u - not "
  289. "enough data (%u octets) for that many realms",
  290. num, (unsigned int) (end - pos));
  291. return NULL;
  292. }
  293. realm = os_zalloc(num * sizeof(struct nai_realm));
  294. if (realm == NULL)
  295. return NULL;
  296. for (i = 0; i < num; i++) {
  297. pos = nai_realm_parse_realm(&realm[i], pos, end);
  298. if (pos == NULL) {
  299. nai_realm_free(realm, num);
  300. return NULL;
  301. }
  302. }
  303. *count = num;
  304. return realm;
  305. }
  306. static int nai_realm_match(struct nai_realm *realm, const char *home_realm)
  307. {
  308. char *tmp, *pos, *end;
  309. int match = 0;
  310. if (realm->realm == NULL || home_realm == NULL)
  311. return 0;
  312. if (os_strchr(realm->realm, ';') == NULL)
  313. return os_strcasecmp(realm->realm, home_realm) == 0;
  314. tmp = os_strdup(realm->realm);
  315. if (tmp == NULL)
  316. return 0;
  317. pos = tmp;
  318. while (*pos) {
  319. end = os_strchr(pos, ';');
  320. if (end)
  321. *end = '\0';
  322. if (os_strcasecmp(pos, home_realm) == 0) {
  323. match = 1;
  324. break;
  325. }
  326. if (end == NULL)
  327. break;
  328. pos = end + 1;
  329. }
  330. os_free(tmp);
  331. return match;
  332. }
  333. static int nai_realm_cred_username(struct nai_realm_eap *eap)
  334. {
  335. if (eap_get_name(EAP_VENDOR_IETF, eap->method) == NULL)
  336. return 0; /* method not supported */
  337. if (eap->method != EAP_TYPE_TTLS && eap->method != EAP_TYPE_PEAP) {
  338. /* Only tunneled methods with username/password supported */
  339. return 0;
  340. }
  341. if (eap->method == EAP_TYPE_PEAP &&
  342. eap_get_name(EAP_VENDOR_IETF, eap->inner_method) == NULL)
  343. return 0;
  344. if (eap->method == EAP_TYPE_TTLS) {
  345. if (eap->inner_method == 0 && eap->inner_non_eap == 0)
  346. return 0;
  347. if (eap->inner_method &&
  348. eap_get_name(EAP_VENDOR_IETF, eap->inner_method) == NULL)
  349. return 0;
  350. if (eap->inner_non_eap &&
  351. eap->inner_non_eap != NAI_REALM_INNER_NON_EAP_PAP &&
  352. eap->inner_non_eap != NAI_REALM_INNER_NON_EAP_CHAP &&
  353. eap->inner_non_eap != NAI_REALM_INNER_NON_EAP_MSCHAP &&
  354. eap->inner_non_eap != NAI_REALM_INNER_NON_EAP_MSCHAPV2)
  355. return 0;
  356. }
  357. if (eap->inner_method &&
  358. eap->inner_method != EAP_TYPE_GTC &&
  359. eap->inner_method != EAP_TYPE_MSCHAPV2)
  360. return 0;
  361. return 1;
  362. }
  363. static int nai_realm_cred_cert(struct nai_realm_eap *eap)
  364. {
  365. if (eap_get_name(EAP_VENDOR_IETF, eap->method) == NULL)
  366. return 0; /* method not supported */
  367. if (eap->method != EAP_TYPE_TLS) {
  368. /* Only EAP-TLS supported for credential authentication */
  369. return 0;
  370. }
  371. return 1;
  372. }
  373. static struct nai_realm_eap * nai_realm_find_eap(struct wpa_cred *cred,
  374. struct nai_realm *realm)
  375. {
  376. u8 e;
  377. if (cred == NULL ||
  378. cred->username == NULL ||
  379. cred->username[0] == '\0' ||
  380. ((cred->password == NULL ||
  381. cred->password[0] == '\0') &&
  382. (cred->private_key == NULL ||
  383. cred->private_key[0] == '\0')))
  384. return NULL;
  385. for (e = 0; e < realm->eap_count; e++) {
  386. struct nai_realm_eap *eap = &realm->eap[e];
  387. if (cred->password && cred->password[0] &&
  388. nai_realm_cred_username(eap))
  389. return eap;
  390. if (cred->private_key && cred->private_key[0] &&
  391. nai_realm_cred_cert(eap))
  392. return eap;
  393. }
  394. return NULL;
  395. }
  396. #ifdef INTERWORKING_3GPP
  397. static int plmn_id_match(struct wpabuf *anqp, const char *imsi, int mnc_len)
  398. {
  399. u8 plmn[3];
  400. const u8 *pos, *end;
  401. u8 udhl;
  402. /* See Annex A of 3GPP TS 24.234 v8.1.0 for description */
  403. plmn[0] = (imsi[0] - '0') | ((imsi[1] - '0') << 4);
  404. plmn[1] = imsi[2] - '0';
  405. /* default to MNC length 3 if unknown */
  406. if (mnc_len != 2)
  407. plmn[1] |= (imsi[5] - '0') << 4;
  408. else
  409. plmn[1] |= 0xf0;
  410. plmn[2] = (imsi[3] - '0') | ((imsi[4] - '0') << 4);
  411. if (anqp == NULL)
  412. return 0;
  413. pos = wpabuf_head_u8(anqp);
  414. end = pos + wpabuf_len(anqp);
  415. if (pos + 2 > end)
  416. return 0;
  417. if (*pos != 0) {
  418. wpa_printf(MSG_DEBUG, "Unsupported GUD version 0x%x", *pos);
  419. return 0;
  420. }
  421. pos++;
  422. udhl = *pos++;
  423. if (pos + udhl > end) {
  424. wpa_printf(MSG_DEBUG, "Invalid UDHL");
  425. return 0;
  426. }
  427. end = pos + udhl;
  428. while (pos + 2 <= end) {
  429. u8 iei, len;
  430. const u8 *l_end;
  431. iei = *pos++;
  432. len = *pos++ & 0x7f;
  433. if (pos + len > end)
  434. break;
  435. l_end = pos + len;
  436. if (iei == 0 && len > 0) {
  437. /* PLMN List */
  438. u8 num, i;
  439. num = *pos++;
  440. for (i = 0; i < num; i++) {
  441. if (pos + 3 > end)
  442. break;
  443. if (os_memcmp(pos, plmn, 3) == 0)
  444. return 1; /* Found matching PLMN */
  445. }
  446. }
  447. pos = l_end;
  448. }
  449. return 0;
  450. }
  451. static int build_root_nai(char *nai, size_t nai_len, const char *imsi,
  452. char prefix)
  453. {
  454. const char *sep, *msin;
  455. char *end, *pos;
  456. size_t msin_len, plmn_len;
  457. /*
  458. * TS 23.003, Clause 14 (3GPP to WLAN Interworking)
  459. * Root NAI:
  460. * <aka:0|sim:1><IMSI>@wlan.mnc<MNC>.mcc<MCC>.3gppnetwork.org
  461. * <MNC> is zero-padded to three digits in case two-digit MNC is used
  462. */
  463. if (imsi == NULL || os_strlen(imsi) > 16) {
  464. wpa_printf(MSG_DEBUG, "No valid IMSI available");
  465. return -1;
  466. }
  467. sep = os_strchr(imsi, '-');
  468. if (sep == NULL)
  469. return -1;
  470. plmn_len = sep - imsi;
  471. if (plmn_len != 5 && plmn_len != 6)
  472. return -1;
  473. msin = sep + 1;
  474. msin_len = os_strlen(msin);
  475. pos = nai;
  476. end = nai + nai_len;
  477. if (prefix)
  478. *pos++ = prefix;
  479. os_memcpy(pos, imsi, plmn_len);
  480. pos += plmn_len;
  481. os_memcpy(pos, msin, msin_len);
  482. pos += msin_len;
  483. pos += os_snprintf(pos, end - pos, "@wlan.mnc");
  484. if (plmn_len == 5) {
  485. *pos++ = '0';
  486. *pos++ = imsi[3];
  487. *pos++ = imsi[4];
  488. } else {
  489. *pos++ = imsi[3];
  490. *pos++ = imsi[4];
  491. *pos++ = imsi[5];
  492. }
  493. pos += os_snprintf(pos, end - pos, ".mcc%c%c%c.3gppnetwork.org",
  494. imsi[0], imsi[1], imsi[2]);
  495. return 0;
  496. }
  497. static int set_root_nai(struct wpa_ssid *ssid, const char *imsi, char prefix)
  498. {
  499. char nai[100];
  500. if (build_root_nai(nai, sizeof(nai), imsi, prefix) < 0)
  501. return -1;
  502. return wpa_config_set_quoted(ssid, "identity", nai);
  503. }
  504. #endif /* INTERWORKING_3GPP */
  505. static int interworking_connect_3gpp(struct wpa_supplicant *wpa_s,
  506. struct wpa_bss *bss)
  507. {
  508. #ifdef INTERWORKING_3GPP
  509. struct wpa_cred *cred;
  510. struct wpa_ssid *ssid;
  511. const u8 *ie;
  512. if (bss->anqp_3gpp == NULL)
  513. return -1;
  514. for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
  515. char *sep;
  516. const char *imsi;
  517. int mnc_len;
  518. #ifdef PCSC_FUNCS
  519. if (cred->pcsc && wpa_s->conf->pcsc_reader && wpa_s->scard &&
  520. wpa_s->imsi[0]) {
  521. imsi = wpa_s->imsi;
  522. mnc_len = wpa_s->mnc_len;
  523. goto compare;
  524. }
  525. #endif /* PCSC_FUNCS */
  526. if (cred->imsi == NULL || !cred->imsi[0] ||
  527. cred->milenage == NULL || !cred->milenage[0])
  528. continue;
  529. sep = os_strchr(cred->imsi, '-');
  530. if (sep == NULL ||
  531. (sep - cred->imsi != 5 && sep - cred->imsi != 6))
  532. continue;
  533. mnc_len = sep - cred->imsi - 3;
  534. imsi = cred->imsi;
  535. #ifdef PCSC_FUNCS
  536. compare:
  537. #endif /* PCSC_FUNCS */
  538. if (plmn_id_match(bss->anqp_3gpp, imsi, mnc_len))
  539. break;
  540. }
  541. if (cred == NULL)
  542. return -1;
  543. ie = wpa_bss_get_ie(bss, WLAN_EID_SSID);
  544. if (ie == NULL)
  545. return -1;
  546. wpa_printf(MSG_DEBUG, "Interworking: Connect with " MACSTR " (3GPP)",
  547. MAC2STR(bss->bssid));
  548. ssid = wpa_config_add_network(wpa_s->conf);
  549. if (ssid == NULL)
  550. return -1;
  551. wpas_notify_network_added(wpa_s, ssid);
  552. wpa_config_set_network_defaults(ssid);
  553. ssid->priority = cred->priority;
  554. ssid->temporary = 1;
  555. ssid->ssid = os_zalloc(ie[1] + 1);
  556. if (ssid->ssid == NULL)
  557. goto fail;
  558. os_memcpy(ssid->ssid, ie + 2, ie[1]);
  559. ssid->ssid_len = ie[1];
  560. /* TODO: figure out whether to use EAP-SIM, EAP-AKA, or EAP-AKA' */
  561. if (wpa_config_set(ssid, "eap", "SIM", 0) < 0) {
  562. wpa_printf(MSG_DEBUG, "EAP-SIM not supported");
  563. goto fail;
  564. }
  565. if (cred->pcsc && wpa_s->scard && scard_supports_umts(wpa_s->scard))
  566. wpa_config_set(ssid, "eap", "AKA", 0);
  567. if (!cred->pcsc && set_root_nai(ssid, cred->imsi, '1') < 0) {
  568. wpa_printf(MSG_DEBUG, "Failed to set Root NAI");
  569. goto fail;
  570. }
  571. if (cred->milenage && cred->milenage[0]) {
  572. if (wpa_config_set_quoted(ssid, "password",
  573. cred->milenage) < 0)
  574. goto fail;
  575. } else if (cred->pcsc) {
  576. if (wpa_config_set_quoted(ssid, "pcsc", "") < 0)
  577. goto fail;
  578. if (wpa_s->conf->pcsc_pin &&
  579. wpa_config_set_quoted(ssid, "pin", wpa_s->conf->pcsc_pin)
  580. < 0)
  581. goto fail;
  582. }
  583. if (cred->password && cred->password[0] &&
  584. wpa_config_set_quoted(ssid, "password", cred->password) < 0)
  585. goto fail;
  586. wpa_config_update_prio_list(wpa_s->conf);
  587. interworking_reconnect(wpa_s);
  588. return 0;
  589. fail:
  590. wpas_notify_network_removed(wpa_s, ssid);
  591. wpa_config_remove_network(wpa_s->conf, ssid->id);
  592. #endif /* INTERWORKING_3GPP */
  593. return -1;
  594. }
  595. int interworking_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
  596. {
  597. struct wpa_cred *cred;
  598. struct wpa_ssid *ssid;
  599. struct nai_realm *realm;
  600. struct nai_realm_eap *eap = NULL;
  601. u16 count, i;
  602. char buf[100];
  603. const u8 *ie;
  604. if (wpa_s->conf->cred == NULL || bss == NULL)
  605. return -1;
  606. ie = wpa_bss_get_ie(bss, WLAN_EID_SSID);
  607. if (ie == NULL || ie[1] == 0) {
  608. wpa_printf(MSG_DEBUG, "Interworking: No SSID known for "
  609. MACSTR, MAC2STR(bss->bssid));
  610. return -1;
  611. }
  612. realm = nai_realm_parse(bss->anqp_nai_realm, &count);
  613. if (realm == NULL) {
  614. wpa_printf(MSG_DEBUG, "Interworking: Could not parse NAI "
  615. "Realm list from " MACSTR, MAC2STR(bss->bssid));
  616. count = 0;
  617. }
  618. for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
  619. for (i = 0; i < count; i++) {
  620. if (!nai_realm_match(&realm[i], cred->realm))
  621. continue;
  622. eap = nai_realm_find_eap(cred, &realm[i]);
  623. if (eap)
  624. break;
  625. }
  626. if (eap)
  627. break;
  628. }
  629. if (!eap) {
  630. if (interworking_connect_3gpp(wpa_s, bss) == 0) {
  631. if (realm)
  632. nai_realm_free(realm, count);
  633. return 0;
  634. }
  635. wpa_printf(MSG_DEBUG, "Interworking: No matching credentials "
  636. "and EAP method found for " MACSTR,
  637. MAC2STR(bss->bssid));
  638. nai_realm_free(realm, count);
  639. return -1;
  640. }
  641. wpa_printf(MSG_DEBUG, "Interworking: Connect with " MACSTR,
  642. MAC2STR(bss->bssid));
  643. ssid = wpa_config_add_network(wpa_s->conf);
  644. if (ssid == NULL) {
  645. nai_realm_free(realm, count);
  646. return -1;
  647. }
  648. wpas_notify_network_added(wpa_s, ssid);
  649. wpa_config_set_network_defaults(ssid);
  650. ssid->priority = cred->priority;
  651. ssid->temporary = 1;
  652. ssid->ssid = os_zalloc(ie[1] + 1);
  653. if (ssid->ssid == NULL)
  654. goto fail;
  655. os_memcpy(ssid->ssid, ie + 2, ie[1]);
  656. ssid->ssid_len = ie[1];
  657. if (wpa_config_set(ssid, "eap", eap_get_name(EAP_VENDOR_IETF,
  658. eap->method), 0) < 0)
  659. goto fail;
  660. if (eap->method == EAP_TYPE_TTLS &&
  661. cred->username && cred->username[0]) {
  662. const char *pos;
  663. char *anon;
  664. /* Use anonymous NAI in Phase 1 */
  665. pos = os_strchr(cred->username, '@');
  666. if (pos) {
  667. size_t buflen = 9 + os_strlen(pos) + 1;
  668. anon = os_malloc(buflen);
  669. if (anon == NULL)
  670. goto fail;
  671. os_snprintf(anon, buflen, "anonymous%s", pos);
  672. } else if (cred->realm) {
  673. size_t buflen = 10 + os_strlen(cred->realm) + 1;
  674. anon = os_malloc(buflen);
  675. if (anon == NULL)
  676. goto fail;
  677. os_snprintf(anon, buflen, "anonymous@%s", cred->realm);
  678. } else {
  679. anon = os_strdup("anonymous");
  680. if (anon == NULL)
  681. goto fail;
  682. }
  683. if (wpa_config_set_quoted(ssid, "anonymous_identity", anon) <
  684. 0) {
  685. os_free(anon);
  686. goto fail;
  687. }
  688. os_free(anon);
  689. }
  690. if (cred->username && cred->username[0] &&
  691. wpa_config_set_quoted(ssid, "identity", cred->username) < 0)
  692. goto fail;
  693. if (cred->password && cred->password[0] &&
  694. wpa_config_set_quoted(ssid, "password", cred->password) < 0)
  695. goto fail;
  696. if (cred->client_cert && cred->client_cert[0] &&
  697. wpa_config_set_quoted(ssid, "client_cert", cred->client_cert) < 0)
  698. goto fail;
  699. if (cred->private_key && cred->private_key[0] &&
  700. wpa_config_set_quoted(ssid, "private_key", cred->private_key) < 0)
  701. goto fail;
  702. if (cred->private_key_passwd && cred->private_key_passwd[0] &&
  703. wpa_config_set_quoted(ssid, "private_key_passwd",
  704. cred->private_key_passwd) < 0)
  705. goto fail;
  706. switch (eap->method) {
  707. case EAP_TYPE_TTLS:
  708. if (eap->inner_method) {
  709. os_snprintf(buf, sizeof(buf), "\"autheap=%s\"",
  710. eap_get_name(EAP_VENDOR_IETF,
  711. eap->inner_method));
  712. if (wpa_config_set(ssid, "phase2", buf, 0) < 0)
  713. goto fail;
  714. break;
  715. }
  716. switch (eap->inner_non_eap) {
  717. case NAI_REALM_INNER_NON_EAP_PAP:
  718. if (wpa_config_set(ssid, "phase2", "\"auth=PAP\"", 0) <
  719. 0)
  720. goto fail;
  721. break;
  722. case NAI_REALM_INNER_NON_EAP_CHAP:
  723. if (wpa_config_set(ssid, "phase2", "\"auth=CHAP\"", 0)
  724. < 0)
  725. goto fail;
  726. break;
  727. case NAI_REALM_INNER_NON_EAP_MSCHAP:
  728. if (wpa_config_set(ssid, "phase2", "\"auth=MSCHAP\"",
  729. 0) < 0)
  730. goto fail;
  731. break;
  732. case NAI_REALM_INNER_NON_EAP_MSCHAPV2:
  733. if (wpa_config_set(ssid, "phase2", "\"auth=MSCHAPV2\"",
  734. 0) < 0)
  735. goto fail;
  736. break;
  737. }
  738. break;
  739. case EAP_TYPE_PEAP:
  740. os_snprintf(buf, sizeof(buf), "\"auth=%s\"",
  741. eap_get_name(EAP_VENDOR_IETF, eap->inner_method));
  742. if (wpa_config_set(ssid, "phase2", buf, 0) < 0)
  743. goto fail;
  744. break;
  745. case EAP_TYPE_TLS:
  746. break;
  747. }
  748. if (cred->ca_cert && cred->ca_cert[0] &&
  749. wpa_config_set_quoted(ssid, "ca_cert", cred->ca_cert) < 0)
  750. goto fail;
  751. nai_realm_free(realm, count);
  752. wpa_config_update_prio_list(wpa_s->conf);
  753. interworking_reconnect(wpa_s);
  754. return 0;
  755. fail:
  756. wpas_notify_network_removed(wpa_s, ssid);
  757. wpa_config_remove_network(wpa_s->conf, ssid->id);
  758. nai_realm_free(realm, count);
  759. return -1;
  760. }
  761. static struct wpa_cred * interworking_credentials_available_3gpp(
  762. struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
  763. {
  764. struct wpa_cred *cred, *selected = NULL;
  765. int ret;
  766. #ifdef INTERWORKING_3GPP
  767. if (bss->anqp_3gpp == NULL)
  768. return NULL;
  769. for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
  770. char *sep;
  771. const char *imsi;
  772. int mnc_len;
  773. #ifdef PCSC_FUNCS
  774. if (cred->pcsc && wpa_s->conf->pcsc_reader && wpa_s->scard &&
  775. wpa_s->imsi[0]) {
  776. imsi = wpa_s->imsi;
  777. mnc_len = wpa_s->mnc_len;
  778. goto compare;
  779. }
  780. #endif /* PCSC_FUNCS */
  781. if (cred->imsi == NULL || !cred->imsi[0] ||
  782. cred->milenage == NULL || !cred->milenage[0])
  783. continue;
  784. sep = os_strchr(cred->imsi, '-');
  785. if (sep == NULL ||
  786. (sep - cred->imsi != 5 && sep - cred->imsi != 6))
  787. continue;
  788. mnc_len = sep - cred->imsi - 3;
  789. imsi = cred->imsi;
  790. #ifdef PCSC_FUNCS
  791. compare:
  792. #endif /* PCSC_FUNCS */
  793. wpa_printf(MSG_DEBUG, "Interworking: Parsing 3GPP info from "
  794. MACSTR, MAC2STR(bss->bssid));
  795. ret = plmn_id_match(bss->anqp_3gpp, imsi, mnc_len);
  796. wpa_printf(MSG_DEBUG, "PLMN match %sfound", ret ? "" : "not ");
  797. if (ret) {
  798. if (selected == NULL ||
  799. selected->priority < cred->priority)
  800. selected = cred;
  801. }
  802. }
  803. #endif /* INTERWORKING_3GPP */
  804. return selected;
  805. }
  806. static struct wpa_cred * interworking_credentials_available_realm(
  807. struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
  808. {
  809. struct wpa_cred *cred, *selected = NULL;
  810. struct nai_realm *realm;
  811. u16 count, i;
  812. if (bss->anqp_nai_realm == NULL)
  813. return NULL;
  814. if (wpa_s->conf->cred == NULL)
  815. return NULL;
  816. wpa_printf(MSG_DEBUG, "Interworking: Parsing NAI Realm list from "
  817. MACSTR, MAC2STR(bss->bssid));
  818. realm = nai_realm_parse(bss->anqp_nai_realm, &count);
  819. if (realm == NULL) {
  820. wpa_printf(MSG_DEBUG, "Interworking: Could not parse NAI "
  821. "Realm list from " MACSTR, MAC2STR(bss->bssid));
  822. return NULL;
  823. }
  824. for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
  825. if (cred->realm == NULL)
  826. continue;
  827. for (i = 0; i < count; i++) {
  828. if (!nai_realm_match(&realm[i], cred->realm))
  829. continue;
  830. if (nai_realm_find_eap(cred, &realm[i])) {
  831. if (selected == NULL ||
  832. selected->priority < cred->priority)
  833. selected = cred;
  834. break;
  835. }
  836. }
  837. }
  838. nai_realm_free(realm, count);
  839. return selected;
  840. }
  841. static struct wpa_cred * interworking_credentials_available(
  842. struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
  843. {
  844. struct wpa_cred *cred, *cred2;
  845. cred = interworking_credentials_available_realm(wpa_s, bss);
  846. cred2 = interworking_credentials_available_3gpp(wpa_s, bss);
  847. if (cred && cred2 && cred2->priority >= cred->priority)
  848. cred = cred2;
  849. if (!cred)
  850. cred = cred2;
  851. return cred;
  852. }
  853. static int domain_name_list_contains(struct wpabuf *domain_names,
  854. const char *domain)
  855. {
  856. const u8 *pos, *end;
  857. size_t len;
  858. len = os_strlen(domain);
  859. pos = wpabuf_head(domain_names);
  860. end = pos + wpabuf_len(domain_names);
  861. while (pos + 1 < end) {
  862. if (pos + 1 + pos[0] > end)
  863. break;
  864. wpa_hexdump_ascii(MSG_DEBUG, "Interworking: AP domain name",
  865. pos + 1, pos[0]);
  866. if (pos[0] == len &&
  867. os_strncasecmp(domain, (const char *) (pos + 1), len) == 0)
  868. return 1;
  869. pos += 1 + pos[0];
  870. }
  871. return 0;
  872. }
  873. static int interworking_home_sp(struct wpa_supplicant *wpa_s,
  874. struct wpabuf *domain_names)
  875. {
  876. struct wpa_cred *cred;
  877. #ifdef INTERWORKING_3GPP
  878. char nai[100], *realm;
  879. #endif /* INTERWORKING_3GPP */
  880. if (domain_names == NULL || wpa_s->conf->cred == NULL)
  881. return -1;
  882. for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
  883. #ifdef INTERWORKING_3GPP
  884. if (cred->imsi &&
  885. build_root_nai(nai, sizeof(nai), cred->imsi, 0) == 0) {
  886. realm = os_strchr(nai, '@');
  887. if (realm)
  888. realm++;
  889. wpa_printf(MSG_DEBUG, "Interworking: Search for match "
  890. "with SIM/USIM domain %s", realm);
  891. if (realm &&
  892. domain_name_list_contains(domain_names, realm))
  893. return 1;
  894. }
  895. #endif /* INTERWORKING_3GPP */
  896. if (cred->domain == NULL)
  897. continue;
  898. wpa_printf(MSG_DEBUG, "Interworking: Search for match with "
  899. "home SP FQDN %s", cred->domain);
  900. if (domain_name_list_contains(domain_names, cred->domain))
  901. return 1;
  902. }
  903. return 0;
  904. }
  905. static int interworking_find_network_match(struct wpa_supplicant *wpa_s)
  906. {
  907. struct wpa_bss *bss;
  908. struct wpa_ssid *ssid;
  909. dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
  910. for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
  911. if (ssid->disabled || ssid->mode != WPAS_MODE_INFRA)
  912. continue;
  913. if (ssid->ssid_len != bss->ssid_len ||
  914. os_memcmp(ssid->ssid, bss->ssid, ssid->ssid_len) !=
  915. 0)
  916. continue;
  917. /*
  918. * TODO: Consider more accurate matching of security
  919. * configuration similarly to what is done in events.c
  920. */
  921. return 1;
  922. }
  923. }
  924. return 0;
  925. }
  926. static void interworking_select_network(struct wpa_supplicant *wpa_s)
  927. {
  928. struct wpa_bss *bss, *selected = NULL, *selected_home = NULL;
  929. int selected_prio = -999999, selected_home_prio = -999999;
  930. unsigned int count = 0;
  931. const char *type;
  932. int res;
  933. struct wpa_cred *cred;
  934. wpa_s->network_select = 0;
  935. dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
  936. cred = interworking_credentials_available(wpa_s, bss);
  937. if (!cred)
  938. continue;
  939. count++;
  940. res = interworking_home_sp(wpa_s, bss->anqp_domain_name);
  941. if (res > 0)
  942. type = "home";
  943. else if (res == 0)
  944. type = "roaming";
  945. else
  946. type = "unknown";
  947. wpa_msg(wpa_s, MSG_INFO, INTERWORKING_AP MACSTR " type=%s",
  948. MAC2STR(bss->bssid), type);
  949. if (wpa_s->auto_select) {
  950. if (selected == NULL ||
  951. cred->priority > selected_prio) {
  952. selected = bss;
  953. selected_prio = cred->priority;
  954. }
  955. if (res > 0 &&
  956. (selected_home == NULL ||
  957. cred->priority > selected_home_prio)) {
  958. selected_home = bss;
  959. selected_home_prio = cred->priority;
  960. }
  961. }
  962. }
  963. if (selected_home && selected_home != selected &&
  964. selected_home_prio >= selected_prio) {
  965. /* Prefer network operated by the Home SP */
  966. selected = selected_home;
  967. }
  968. if (count == 0) {
  969. /*
  970. * No matching network was found based on configured
  971. * credentials. Check whether any of the enabled network blocks
  972. * have matching APs.
  973. */
  974. if (interworking_find_network_match(wpa_s)) {
  975. wpa_printf(MSG_DEBUG, "Interworking: Possible BSS "
  976. "match for enabled network configurations");
  977. interworking_reconnect(wpa_s);
  978. return;
  979. }
  980. wpa_msg(wpa_s, MSG_INFO, INTERWORKING_NO_MATCH "No network "
  981. "with matching credentials found");
  982. }
  983. if (selected)
  984. interworking_connect(wpa_s, selected);
  985. }
  986. static void interworking_next_anqp_fetch(struct wpa_supplicant *wpa_s)
  987. {
  988. struct wpa_bss *bss;
  989. int found = 0;
  990. const u8 *ie;
  991. if (!wpa_s->fetch_anqp_in_progress)
  992. return;
  993. dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
  994. if (!(bss->caps & IEEE80211_CAP_ESS))
  995. continue;
  996. ie = wpa_bss_get_ie(bss, WLAN_EID_EXT_CAPAB);
  997. if (ie == NULL || ie[1] < 4 || !(ie[5] & 0x80))
  998. continue; /* AP does not support Interworking */
  999. if (!(bss->flags & WPA_BSS_ANQP_FETCH_TRIED)) {
  1000. found++;
  1001. bss->flags |= WPA_BSS_ANQP_FETCH_TRIED;
  1002. wpa_msg(wpa_s, MSG_INFO, "Starting ANQP fetch for "
  1003. MACSTR, MAC2STR(bss->bssid));
  1004. interworking_anqp_send_req(wpa_s, bss);
  1005. break;
  1006. }
  1007. }
  1008. if (found == 0) {
  1009. wpa_msg(wpa_s, MSG_INFO, "ANQP fetch completed");
  1010. wpa_s->fetch_anqp_in_progress = 0;
  1011. if (wpa_s->network_select)
  1012. interworking_select_network(wpa_s);
  1013. }
  1014. }
  1015. static void interworking_start_fetch_anqp(struct wpa_supplicant *wpa_s)
  1016. {
  1017. struct wpa_bss *bss;
  1018. dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list)
  1019. bss->flags &= ~WPA_BSS_ANQP_FETCH_TRIED;
  1020. wpa_s->fetch_anqp_in_progress = 1;
  1021. interworking_next_anqp_fetch(wpa_s);
  1022. }
  1023. int interworking_fetch_anqp(struct wpa_supplicant *wpa_s)
  1024. {
  1025. if (wpa_s->fetch_anqp_in_progress || wpa_s->network_select)
  1026. return 0;
  1027. wpa_s->network_select = 0;
  1028. interworking_start_fetch_anqp(wpa_s);
  1029. return 0;
  1030. }
  1031. void interworking_stop_fetch_anqp(struct wpa_supplicant *wpa_s)
  1032. {
  1033. if (!wpa_s->fetch_anqp_in_progress)
  1034. return;
  1035. wpa_s->fetch_anqp_in_progress = 0;
  1036. }
  1037. int anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst,
  1038. u16 info_ids[], size_t num_ids)
  1039. {
  1040. struct wpabuf *buf;
  1041. int ret = 0;
  1042. int freq;
  1043. struct wpa_bss *bss;
  1044. int res;
  1045. freq = wpa_s->assoc_freq;
  1046. bss = wpa_bss_get_bssid(wpa_s, dst);
  1047. if (bss)
  1048. freq = bss->freq;
  1049. if (freq <= 0)
  1050. return -1;
  1051. wpa_printf(MSG_DEBUG, "ANQP: Query Request to " MACSTR " for %u id(s)",
  1052. MAC2STR(dst), (unsigned int) num_ids);
  1053. buf = anqp_build_req(info_ids, num_ids, NULL);
  1054. if (buf == NULL)
  1055. return -1;
  1056. res = gas_query_req(wpa_s->gas, dst, freq, buf, anqp_resp_cb, wpa_s);
  1057. if (res < 0) {
  1058. wpa_printf(MSG_DEBUG, "ANQP: Failed to send Query Request");
  1059. ret = -1;
  1060. } else
  1061. wpa_printf(MSG_DEBUG, "ANQP: Query started with dialog token "
  1062. "%u", res);
  1063. wpabuf_free(buf);
  1064. return ret;
  1065. }
  1066. static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s,
  1067. const u8 *sa, u16 info_id,
  1068. const u8 *data, size_t slen)
  1069. {
  1070. const u8 *pos = data;
  1071. struct wpa_bss *bss = wpa_bss_get_bssid(wpa_s, sa);
  1072. switch (info_id) {
  1073. case ANQP_CAPABILITY_LIST:
  1074. wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
  1075. " ANQP Capability list", MAC2STR(sa));
  1076. break;
  1077. case ANQP_VENUE_NAME:
  1078. wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
  1079. " Venue Name", MAC2STR(sa));
  1080. wpa_hexdump_ascii(MSG_DEBUG, "ANQP: Venue Name", pos, slen);
  1081. if (bss) {
  1082. wpabuf_free(bss->anqp_venue_name);
  1083. bss->anqp_venue_name = wpabuf_alloc_copy(pos, slen);
  1084. }
  1085. break;
  1086. case ANQP_NETWORK_AUTH_TYPE:
  1087. wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
  1088. " Network Authentication Type information",
  1089. MAC2STR(sa));
  1090. wpa_hexdump_ascii(MSG_DEBUG, "ANQP: Network Authentication "
  1091. "Type", pos, slen);
  1092. if (bss) {
  1093. wpabuf_free(bss->anqp_network_auth_type);
  1094. bss->anqp_network_auth_type =
  1095. wpabuf_alloc_copy(pos, slen);
  1096. }
  1097. break;
  1098. case ANQP_ROAMING_CONSORTIUM:
  1099. wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
  1100. " Roaming Consortium list", MAC2STR(sa));
  1101. wpa_hexdump_ascii(MSG_DEBUG, "ANQP: Roaming Consortium",
  1102. pos, slen);
  1103. if (bss) {
  1104. wpabuf_free(bss->anqp_roaming_consortium);
  1105. bss->anqp_roaming_consortium =
  1106. wpabuf_alloc_copy(pos, slen);
  1107. }
  1108. break;
  1109. case ANQP_IP_ADDR_TYPE_AVAILABILITY:
  1110. wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
  1111. " IP Address Type Availability information",
  1112. MAC2STR(sa));
  1113. wpa_hexdump(MSG_MSGDUMP, "ANQP: IP Address Availability",
  1114. pos, slen);
  1115. if (bss) {
  1116. wpabuf_free(bss->anqp_ip_addr_type_availability);
  1117. bss->anqp_ip_addr_type_availability =
  1118. wpabuf_alloc_copy(pos, slen);
  1119. }
  1120. break;
  1121. case ANQP_NAI_REALM:
  1122. wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
  1123. " NAI Realm list", MAC2STR(sa));
  1124. wpa_hexdump_ascii(MSG_DEBUG, "ANQP: NAI Realm", pos, slen);
  1125. if (bss) {
  1126. wpabuf_free(bss->anqp_nai_realm);
  1127. bss->anqp_nai_realm = wpabuf_alloc_copy(pos, slen);
  1128. }
  1129. break;
  1130. case ANQP_3GPP_CELLULAR_NETWORK:
  1131. wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
  1132. " 3GPP Cellular Network information", MAC2STR(sa));
  1133. wpa_hexdump_ascii(MSG_DEBUG, "ANQP: 3GPP Cellular Network",
  1134. pos, slen);
  1135. if (bss) {
  1136. wpabuf_free(bss->anqp_3gpp);
  1137. bss->anqp_3gpp = wpabuf_alloc_copy(pos, slen);
  1138. }
  1139. break;
  1140. case ANQP_DOMAIN_NAME:
  1141. wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
  1142. " Domain Name list", MAC2STR(sa));
  1143. wpa_hexdump_ascii(MSG_MSGDUMP, "ANQP: Domain Name", pos, slen);
  1144. if (bss) {
  1145. wpabuf_free(bss->anqp_domain_name);
  1146. bss->anqp_domain_name = wpabuf_alloc_copy(pos, slen);
  1147. }
  1148. break;
  1149. case ANQP_VENDOR_SPECIFIC:
  1150. if (slen < 3)
  1151. return;
  1152. switch (WPA_GET_BE24(pos)) {
  1153. default:
  1154. wpa_printf(MSG_DEBUG, "Interworking: Unsupported "
  1155. "vendor-specific ANQP OUI %06x",
  1156. WPA_GET_BE24(pos));
  1157. return;
  1158. }
  1159. break;
  1160. default:
  1161. wpa_printf(MSG_DEBUG, "Interworking: Unsupported ANQP Info ID "
  1162. "%u", info_id);
  1163. break;
  1164. }
  1165. }
  1166. void anqp_resp_cb(void *ctx, const u8 *dst, u8 dialog_token,
  1167. enum gas_query_result result,
  1168. const struct wpabuf *adv_proto,
  1169. const struct wpabuf *resp, u16 status_code)
  1170. {
  1171. struct wpa_supplicant *wpa_s = ctx;
  1172. const u8 *pos;
  1173. const u8 *end;
  1174. u16 info_id;
  1175. u16 slen;
  1176. if (result != GAS_QUERY_SUCCESS)
  1177. return;
  1178. pos = wpabuf_head(adv_proto);
  1179. if (wpabuf_len(adv_proto) < 4 || pos[0] != WLAN_EID_ADV_PROTO ||
  1180. pos[1] < 2 || pos[3] != ACCESS_NETWORK_QUERY_PROTOCOL) {
  1181. wpa_printf(MSG_DEBUG, "ANQP: Unexpected Advertisement "
  1182. "Protocol in response");
  1183. return;
  1184. }
  1185. pos = wpabuf_head(resp);
  1186. end = pos + wpabuf_len(resp);
  1187. while (pos < end) {
  1188. if (pos + 4 > end) {
  1189. wpa_printf(MSG_DEBUG, "ANQP: Invalid element");
  1190. break;
  1191. }
  1192. info_id = WPA_GET_LE16(pos);
  1193. pos += 2;
  1194. slen = WPA_GET_LE16(pos);
  1195. pos += 2;
  1196. if (pos + slen > end) {
  1197. wpa_printf(MSG_DEBUG, "ANQP: Invalid element length "
  1198. "for Info ID %u", info_id);
  1199. break;
  1200. }
  1201. interworking_parse_rx_anqp_resp(wpa_s, dst, info_id, pos,
  1202. slen);
  1203. pos += slen;
  1204. }
  1205. }
  1206. static void interworking_scan_res_handler(struct wpa_supplicant *wpa_s,
  1207. struct wpa_scan_results *scan_res)
  1208. {
  1209. wpa_printf(MSG_DEBUG, "Interworking: Scan results available - start "
  1210. "ANQP fetch");
  1211. interworking_start_fetch_anqp(wpa_s);
  1212. }
  1213. int interworking_select(struct wpa_supplicant *wpa_s, int auto_select)
  1214. {
  1215. interworking_stop_fetch_anqp(wpa_s);
  1216. wpa_s->network_select = 1;
  1217. wpa_s->auto_select = !!auto_select;
  1218. wpa_printf(MSG_DEBUG, "Interworking: Start scan for network "
  1219. "selection");
  1220. wpa_s->scan_res_handler = interworking_scan_res_handler;
  1221. wpa_s->scan_req = 2;
  1222. wpa_supplicant_req_scan(wpa_s, 0, 0);
  1223. return 0;
  1224. }