fils_hlp.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636
  1. /*
  2. * FILS HLP request processing
  3. * Copyright (c) 2017, 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 "utils/includes.h"
  9. #include "utils/common.h"
  10. #include "utils/eloop.h"
  11. #include "common/dhcp.h"
  12. #include "hostapd.h"
  13. #include "sta_info.h"
  14. #include "ieee802_11.h"
  15. #include "fils_hlp.h"
  16. static be16 ip_checksum(const void *buf, size_t len)
  17. {
  18. u32 sum = 0;
  19. const u16 *pos;
  20. for (pos = buf; len >= 2; len -= 2)
  21. sum += ntohs(*pos++);
  22. if (len)
  23. sum += ntohs(*pos << 8);
  24. sum = (sum >> 16) + (sum & 0xffff);
  25. sum += sum >> 16;
  26. return htons(~sum);
  27. }
  28. static int fils_dhcp_request(struct hostapd_data *hapd, struct sta_info *sta,
  29. struct dhcp_data *dhcpoffer, u8 *dhcpofferend)
  30. {
  31. u8 *pos, *end;
  32. struct dhcp_data *dhcp;
  33. struct sockaddr_in addr;
  34. ssize_t res;
  35. const u8 *server_id = NULL;
  36. if (!sta->hlp_dhcp_discover) {
  37. wpa_printf(MSG_DEBUG,
  38. "FILS: No pending HLP DHCPDISCOVER available");
  39. return -1;
  40. }
  41. /* Convert to DHCPREQUEST, remove rapid commit option, replace requested
  42. * IP address option with yiaddr. */
  43. pos = wpabuf_mhead(sta->hlp_dhcp_discover);
  44. end = pos + wpabuf_len(sta->hlp_dhcp_discover);
  45. dhcp = (struct dhcp_data *) pos;
  46. pos = (u8 *) (dhcp + 1);
  47. pos += 4; /* skip magic */
  48. while (pos < end && *pos != DHCP_OPT_END) {
  49. u8 opt, olen;
  50. opt = *pos++;
  51. if (opt == DHCP_OPT_PAD)
  52. continue;
  53. if (pos >= end)
  54. break;
  55. olen = *pos++;
  56. if (olen > end - pos)
  57. break;
  58. switch (opt) {
  59. case DHCP_OPT_MSG_TYPE:
  60. if (olen > 0)
  61. *pos = DHCPREQUEST;
  62. break;
  63. case DHCP_OPT_RAPID_COMMIT:
  64. case DHCP_OPT_REQUESTED_IP_ADDRESS:
  65. case DHCP_OPT_SERVER_ID:
  66. /* Remove option */
  67. pos -= 2;
  68. os_memmove(pos, pos + 2 + olen, end - pos - 2 - olen);
  69. end -= 2 + olen;
  70. olen = 0;
  71. break;
  72. }
  73. pos += olen;
  74. }
  75. if (pos >= end || *pos != DHCP_OPT_END) {
  76. wpa_printf(MSG_DEBUG, "FILS: Could not update DHCPDISCOVER");
  77. return -1;
  78. }
  79. sta->hlp_dhcp_discover->used = pos - (u8 *) dhcp;
  80. /* Copy Server ID option from DHCPOFFER to DHCPREQUEST */
  81. pos = (u8 *) (dhcpoffer + 1);
  82. end = dhcpofferend;
  83. pos += 4; /* skip magic */
  84. while (pos < end && *pos != DHCP_OPT_END) {
  85. u8 opt, olen;
  86. opt = *pos++;
  87. if (opt == DHCP_OPT_PAD)
  88. continue;
  89. if (pos >= end)
  90. break;
  91. olen = *pos++;
  92. if (olen > end - pos)
  93. break;
  94. switch (opt) {
  95. case DHCP_OPT_SERVER_ID:
  96. server_id = pos - 2;
  97. break;
  98. }
  99. pos += olen;
  100. }
  101. if (wpabuf_resize(&sta->hlp_dhcp_discover,
  102. 6 + 1 + (server_id ? 2 + server_id[1] : 0)))
  103. return -1;
  104. if (server_id)
  105. wpabuf_put_data(sta->hlp_dhcp_discover, server_id,
  106. 2 + server_id[1]);
  107. wpabuf_put_u8(sta->hlp_dhcp_discover, DHCP_OPT_REQUESTED_IP_ADDRESS);
  108. wpabuf_put_u8(sta->hlp_dhcp_discover, 4);
  109. wpabuf_put_data(sta->hlp_dhcp_discover, &dhcpoffer->your_ip, 4);
  110. wpabuf_put_u8(sta->hlp_dhcp_discover, DHCP_OPT_END);
  111. os_memset(&addr, 0, sizeof(addr));
  112. addr.sin_family = AF_INET;
  113. addr.sin_addr.s_addr = hapd->conf->dhcp_server.u.v4.s_addr;
  114. addr.sin_port = htons(hapd->conf->dhcp_server_port);
  115. res = sendto(hapd->dhcp_sock, wpabuf_head(sta->hlp_dhcp_discover),
  116. wpabuf_len(sta->hlp_dhcp_discover), 0,
  117. (const struct sockaddr *) &addr, sizeof(addr));
  118. if (res < 0) {
  119. wpa_printf(MSG_ERROR, "FILS: DHCP sendto failed: %s",
  120. strerror(errno));
  121. return -1;
  122. }
  123. wpa_printf(MSG_DEBUG,
  124. "FILS: Acting as DHCP rapid commit proxy for %s:%d",
  125. inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
  126. wpabuf_free(sta->hlp_dhcp_discover);
  127. sta->hlp_dhcp_discover = NULL;
  128. sta->fils_dhcp_rapid_commit_proxy = 1;
  129. return 0;
  130. }
  131. static void fils_dhcp_handler(int sd, void *eloop_ctx, void *sock_ctx)
  132. {
  133. struct hostapd_data *hapd = sock_ctx;
  134. struct sta_info *sta;
  135. u8 buf[1500], *pos, *end, *end_opt = NULL;
  136. struct dhcp_data *dhcp;
  137. struct sockaddr_in addr;
  138. socklen_t addr_len;
  139. ssize_t res;
  140. u8 msgtype = 0;
  141. int rapid_commit = 0;
  142. struct iphdr *iph;
  143. struct udphdr *udph;
  144. struct wpabuf *resp;
  145. const u8 *rpos;
  146. size_t left, len;
  147. addr_len = sizeof(addr);
  148. res = recvfrom(sd, buf, sizeof(buf), 0,
  149. (struct sockaddr *) &addr, &addr_len);
  150. if (res < 0) {
  151. wpa_printf(MSG_DEBUG, "FILS: DHCP read failed: %s",
  152. strerror(errno));
  153. return;
  154. }
  155. wpa_printf(MSG_DEBUG, "FILS: DHCP response from server %s:%d (len=%d)",
  156. inet_ntoa(addr.sin_addr), ntohs(addr.sin_port), (int) res);
  157. wpa_hexdump(MSG_MSGDUMP, "FILS: HLP - DHCP server response", buf, res);
  158. if ((size_t) res < sizeof(*dhcp))
  159. return;
  160. dhcp = (struct dhcp_data *) buf;
  161. if (dhcp->op != 2)
  162. return; /* Not a BOOTREPLY */
  163. if (dhcp->relay_ip != hapd->conf->own_ip_addr.u.v4.s_addr) {
  164. wpa_printf(MSG_DEBUG,
  165. "FILS: HLP - DHCP response to unknown relay address 0x%x",
  166. dhcp->relay_ip);
  167. return;
  168. }
  169. dhcp->relay_ip = 0;
  170. pos = (u8 *) (dhcp + 1);
  171. end = &buf[res];
  172. if (end - pos < 4 || WPA_GET_BE32(pos) != DHCP_MAGIC) {
  173. wpa_printf(MSG_DEBUG, "FILS: HLP - no DHCP magic in response");
  174. return;
  175. }
  176. pos += 4;
  177. wpa_hexdump(MSG_DEBUG, "FILS: HLP - DHCP options in response",
  178. pos, end - pos);
  179. while (pos < end && *pos != DHCP_OPT_END) {
  180. u8 opt, olen;
  181. opt = *pos++;
  182. if (opt == DHCP_OPT_PAD)
  183. continue;
  184. if (pos >= end)
  185. break;
  186. olen = *pos++;
  187. if (olen > end - pos)
  188. break;
  189. switch (opt) {
  190. case DHCP_OPT_MSG_TYPE:
  191. if (olen > 0)
  192. msgtype = pos[0];
  193. break;
  194. case DHCP_OPT_RAPID_COMMIT:
  195. rapid_commit = 1;
  196. break;
  197. }
  198. pos += olen;
  199. }
  200. if (pos < end && *pos == DHCP_OPT_END)
  201. end_opt = pos;
  202. wpa_printf(MSG_DEBUG,
  203. "FILS: HLP - DHCP message type %u (rapid_commit=%d hw_addr="
  204. MACSTR ")",
  205. msgtype, rapid_commit, MAC2STR(dhcp->hw_addr));
  206. sta = ap_get_sta(hapd, dhcp->hw_addr);
  207. if (!sta || !sta->fils_pending_assoc_req) {
  208. wpa_printf(MSG_DEBUG,
  209. "FILS: No pending HLP DHCP exchange with hw_addr"
  210. MACSTR, MAC2STR(dhcp->hw_addr));
  211. return;
  212. }
  213. if (hapd->conf->dhcp_rapid_commit_proxy && msgtype == DHCPOFFER &&
  214. !rapid_commit) {
  215. /* Use hostapd to take care of 4-message exchange and convert
  216. * the final DHCPACK to rapid commit version. */
  217. if (fils_dhcp_request(hapd, sta, dhcp, end) == 0)
  218. return;
  219. /* failed, so send the server response as-is */
  220. } else if (msgtype != DHCPACK) {
  221. wpa_printf(MSG_DEBUG,
  222. "FILS: No DHCPACK available from the server and cannot do rapid commit proxying");
  223. }
  224. pos = buf;
  225. resp = wpabuf_alloc(2 * ETH_ALEN + 6 + 2 +
  226. sizeof(*iph) + sizeof(*udph) + (end - pos) + 2);
  227. if (!resp)
  228. return;
  229. wpabuf_put_data(resp, sta->addr, ETH_ALEN);
  230. wpabuf_put_data(resp, hapd->own_addr, ETH_ALEN);
  231. wpabuf_put_data(resp, "\xaa\xaa\x03\x00\x00\x00", 6);
  232. wpabuf_put_be16(resp, ETH_P_IP);
  233. iph = wpabuf_put(resp, sizeof(*iph));
  234. iph->version = 4;
  235. iph->ihl = sizeof(*iph) / 4;
  236. iph->tot_len = htons(sizeof(*iph) + sizeof(*udph) + (end - pos));
  237. iph->ttl = 1;
  238. iph->saddr = hapd->conf->dhcp_server.u.v4.s_addr;
  239. iph->daddr = dhcp->client_ip;
  240. iph->check = ip_checksum(iph, sizeof(*iph));
  241. udph = wpabuf_put(resp, sizeof(*udph));
  242. udph->uh_sport = htons(DHCP_SERVER_PORT);
  243. udph->uh_dport = htons(DHCP_CLIENT_PORT);
  244. udph->len = htons(sizeof(*udph) + (end - pos));
  245. udph->check = htons(0x0000); /* TODO: calculate checksum */
  246. if (hapd->conf->dhcp_rapid_commit_proxy && msgtype == DHCPACK &&
  247. !rapid_commit && sta->fils_dhcp_rapid_commit_proxy && end_opt) {
  248. /* Add rapid commit option */
  249. wpabuf_put_data(resp, pos, end_opt - pos);
  250. wpabuf_put_u8(resp, DHCP_OPT_RAPID_COMMIT);
  251. wpabuf_put_u8(resp, 0);
  252. wpabuf_put_data(resp, end_opt, end - end_opt);
  253. } else {
  254. wpabuf_put_data(resp, pos, end - pos);
  255. }
  256. if (wpabuf_resize(&sta->fils_hlp_resp, wpabuf_len(resp) +
  257. 2 * wpabuf_len(resp) / 255 + 100)) {
  258. wpabuf_free(resp);
  259. return;
  260. }
  261. rpos = wpabuf_head(resp);
  262. left = wpabuf_len(resp);
  263. wpabuf_put_u8(sta->fils_hlp_resp, WLAN_EID_EXTENSION); /* Element ID */
  264. if (left <= 254)
  265. len = 1 + left;
  266. else
  267. len = 255;
  268. wpabuf_put_u8(sta->fils_hlp_resp, len); /* Length */
  269. /* Element ID Extension */
  270. wpabuf_put_u8(sta->fils_hlp_resp, WLAN_EID_EXT_FILS_HLP_CONTAINER);
  271. /* Destination MAC Address, Source MAC Address, HLP Packet.
  272. * HLP Packet is in MSDU format (i.e., including the LLC/SNAP header
  273. * when LPD is used). */
  274. wpabuf_put_data(sta->fils_hlp_resp, rpos, len - 1);
  275. rpos += len - 1;
  276. left -= len - 1;
  277. while (left) {
  278. wpabuf_put_u8(sta->fils_hlp_resp, WLAN_EID_FRAGMENT);
  279. len = left > 255 ? 255 : left;
  280. wpabuf_put_u8(sta->fils_hlp_resp, len);
  281. wpabuf_put_data(sta->fils_hlp_resp, rpos, len);
  282. rpos += len;
  283. left -= len;
  284. }
  285. wpabuf_free(resp);
  286. fils_hlp_finish_assoc(hapd, sta);
  287. }
  288. static int fils_process_hlp_dhcp(struct hostapd_data *hapd,
  289. struct sta_info *sta,
  290. const u8 *msg, size_t len)
  291. {
  292. const struct dhcp_data *dhcp;
  293. struct wpabuf *dhcp_buf;
  294. struct dhcp_data *dhcp_msg;
  295. u8 msgtype = 0;
  296. int rapid_commit = 0;
  297. const u8 *pos = msg, *end;
  298. struct sockaddr_in addr;
  299. ssize_t res;
  300. if (len < sizeof(*dhcp))
  301. return 0;
  302. dhcp = (const struct dhcp_data *) pos;
  303. end = pos + len;
  304. wpa_printf(MSG_DEBUG,
  305. "FILS: HLP request DHCP: op=%u htype=%u hlen=%u hops=%u xid=0x%x",
  306. dhcp->op, dhcp->htype, dhcp->hlen, dhcp->hops,
  307. ntohl(dhcp->xid));
  308. pos += sizeof(*dhcp);
  309. if (dhcp->op != 1)
  310. return 0; /* Not a BOOTREQUEST */
  311. if (end - pos < 4)
  312. return 0;
  313. if (WPA_GET_BE32(pos) != DHCP_MAGIC) {
  314. wpa_printf(MSG_DEBUG, "FILS: HLP - no DHCP magic");
  315. return 0;
  316. }
  317. pos += 4;
  318. wpa_hexdump(MSG_DEBUG, "FILS: HLP - DHCP options", pos, end - pos);
  319. while (pos < end && *pos != DHCP_OPT_END) {
  320. u8 opt, olen;
  321. opt = *pos++;
  322. if (opt == DHCP_OPT_PAD)
  323. continue;
  324. if (pos >= end)
  325. break;
  326. olen = *pos++;
  327. if (olen > end - pos)
  328. break;
  329. switch (opt) {
  330. case DHCP_OPT_MSG_TYPE:
  331. if (olen > 0)
  332. msgtype = pos[0];
  333. break;
  334. case DHCP_OPT_RAPID_COMMIT:
  335. rapid_commit = 1;
  336. break;
  337. }
  338. pos += olen;
  339. }
  340. wpa_printf(MSG_DEBUG, "FILS: HLP - DHCP message type %u", msgtype);
  341. if (msgtype != DHCPDISCOVER)
  342. return 0;
  343. if (hapd->conf->dhcp_server.af != AF_INET ||
  344. hapd->conf->dhcp_server.u.v4.s_addr == 0) {
  345. wpa_printf(MSG_DEBUG,
  346. "FILS: HLP - no DHCPv4 server configured - drop request");
  347. return 0;
  348. }
  349. if (hapd->conf->own_ip_addr.af != AF_INET ||
  350. hapd->conf->own_ip_addr.u.v4.s_addr == 0) {
  351. wpa_printf(MSG_DEBUG,
  352. "FILS: HLP - no IPv4 own_ip_addr configured - drop request");
  353. return 0;
  354. }
  355. if (hapd->dhcp_sock < 0) {
  356. int s;
  357. s = socket(AF_INET, SOCK_DGRAM, 0);
  358. if (s < 0) {
  359. wpa_printf(MSG_ERROR,
  360. "FILS: Failed to open DHCP socket: %s",
  361. strerror(errno));
  362. return 0;
  363. }
  364. if (hapd->conf->dhcp_relay_port) {
  365. os_memset(&addr, 0, sizeof(addr));
  366. addr.sin_family = AF_INET;
  367. addr.sin_addr.s_addr =
  368. hapd->conf->own_ip_addr.u.v4.s_addr;
  369. addr.sin_port = htons(hapd->conf->dhcp_relay_port);
  370. if (bind(s, (struct sockaddr *) &addr, sizeof(addr))) {
  371. wpa_printf(MSG_ERROR,
  372. "FILS: Failed to bind DHCP socket: %s",
  373. strerror(errno));
  374. close(s);
  375. return 0;
  376. }
  377. }
  378. if (eloop_register_sock(s, EVENT_TYPE_READ,
  379. fils_dhcp_handler, NULL, hapd)) {
  380. close(s);
  381. return 0;
  382. }
  383. hapd->dhcp_sock = s;
  384. }
  385. dhcp_buf = wpabuf_alloc(len);
  386. if (!dhcp_buf)
  387. return 0;
  388. dhcp_msg = wpabuf_put(dhcp_buf, len);
  389. os_memcpy(dhcp_msg, msg, len);
  390. dhcp_msg->relay_ip = hapd->conf->own_ip_addr.u.v4.s_addr;
  391. os_memset(&addr, 0, sizeof(addr));
  392. addr.sin_family = AF_INET;
  393. addr.sin_addr.s_addr = hapd->conf->dhcp_server.u.v4.s_addr;
  394. addr.sin_port = htons(hapd->conf->dhcp_server_port);
  395. res = sendto(hapd->dhcp_sock, dhcp_msg, len, 0,
  396. (const struct sockaddr *) &addr, sizeof(addr));
  397. if (res < 0) {
  398. wpa_printf(MSG_ERROR, "FILS: DHCP sendto failed: %s",
  399. strerror(errno));
  400. wpabuf_free(dhcp_buf);
  401. /* Close the socket to try to recover from error */
  402. eloop_unregister_read_sock(hapd->dhcp_sock);
  403. close(hapd->dhcp_sock);
  404. hapd->dhcp_sock = -1;
  405. return 0;
  406. }
  407. wpa_printf(MSG_DEBUG,
  408. "FILS: HLP relayed DHCP request to server %s:%d (rapid_commit=%d)",
  409. inet_ntoa(addr.sin_addr), ntohs(addr.sin_port),
  410. rapid_commit);
  411. if (hapd->conf->dhcp_rapid_commit_proxy && rapid_commit) {
  412. /* Store a copy of the DHCPDISCOVER for rapid commit proxying
  413. * purposes if the server does not support the rapid commit
  414. * option. */
  415. wpa_printf(MSG_DEBUG,
  416. "FILS: Store DHCPDISCOVER for rapid commit proxy");
  417. wpabuf_free(sta->hlp_dhcp_discover);
  418. sta->hlp_dhcp_discover = dhcp_buf;
  419. } else {
  420. wpabuf_free(dhcp_buf);
  421. }
  422. return 1;
  423. }
  424. static int fils_process_hlp_udp(struct hostapd_data *hapd,
  425. struct sta_info *sta, const u8 *dst,
  426. const u8 *pos, size_t len)
  427. {
  428. const struct iphdr *iph;
  429. const struct udphdr *udph;
  430. u16 sport, dport, ulen;
  431. if (len < sizeof(*iph) + sizeof(*udph))
  432. return 0;
  433. iph = (const struct iphdr *) pos;
  434. udph = (const struct udphdr *) (iph + 1);
  435. sport = ntohs(udph->uh_sport);
  436. dport = ntohs(udph->uh_dport);
  437. ulen = ntohs(udph->uh_ulen);
  438. wpa_printf(MSG_DEBUG,
  439. "FILS: HLP request UDP: sport=%u dport=%u ulen=%u sum=0x%x",
  440. sport, dport, ulen, ntohs(udph->uh_sum));
  441. /* TODO: Check UDP checksum */
  442. if (ulen < sizeof(*udph) || ulen > len - sizeof(*iph))
  443. return 0;
  444. if (dport == DHCP_SERVER_PORT && sport == DHCP_CLIENT_PORT) {
  445. return fils_process_hlp_dhcp(hapd, sta, (const u8 *) (udph + 1),
  446. ulen - sizeof(*udph));
  447. }
  448. return 0;
  449. }
  450. static int fils_process_hlp_ip(struct hostapd_data *hapd,
  451. struct sta_info *sta, const u8 *dst,
  452. const u8 *pos, size_t len)
  453. {
  454. const struct iphdr *iph;
  455. u16 tot_len;
  456. if (len < sizeof(*iph))
  457. return 0;
  458. iph = (const struct iphdr *) pos;
  459. if (ip_checksum(iph, sizeof(*iph)) != 0) {
  460. wpa_printf(MSG_DEBUG,
  461. "FILS: HLP request IPv4 packet had invalid header checksum - dropped");
  462. return 0;
  463. }
  464. tot_len = ntohs(iph->tot_len);
  465. if (tot_len > len)
  466. return 0;
  467. wpa_printf(MSG_DEBUG,
  468. "FILS: HLP request IPv4: saddr=%08x daddr=%08x protocol=%u",
  469. iph->saddr, iph->daddr, iph->protocol);
  470. switch (iph->protocol) {
  471. case 17:
  472. return fils_process_hlp_udp(hapd, sta, dst, pos, len);
  473. }
  474. return 0;
  475. }
  476. static int fils_process_hlp_req(struct hostapd_data *hapd,
  477. struct sta_info *sta,
  478. const u8 *pos, size_t len)
  479. {
  480. const u8 *pkt, *end;
  481. wpa_printf(MSG_DEBUG, "FILS: HLP request from " MACSTR " (dst=" MACSTR
  482. " src=" MACSTR " len=%u)",
  483. MAC2STR(sta->addr), MAC2STR(pos), MAC2STR(pos + ETH_ALEN),
  484. (unsigned int) len);
  485. if (os_memcmp(sta->addr, pos + ETH_ALEN, ETH_ALEN) != 0) {
  486. wpa_printf(MSG_DEBUG,
  487. "FILS: Ignore HLP request with unexpected source address"
  488. MACSTR, MAC2STR(pos + ETH_ALEN));
  489. return 0;
  490. }
  491. end = pos + len;
  492. pkt = pos + 2 * ETH_ALEN;
  493. if (end - pkt >= 6 &&
  494. os_memcmp(pkt, "\xaa\xaa\x03\x00\x00\x00", 6) == 0)
  495. pkt += 6; /* Remove SNAP/LLC header */
  496. wpa_hexdump(MSG_MSGDUMP, "FILS: HLP request packet", pkt, end - pkt);
  497. if (end - pkt < 2)
  498. return 0;
  499. switch (WPA_GET_BE16(pkt)) {
  500. case ETH_P_IP:
  501. return fils_process_hlp_ip(hapd, sta, pos, pkt + 2,
  502. end - pkt - 2);
  503. }
  504. return 0;
  505. }
  506. int fils_process_hlp(struct hostapd_data *hapd, struct sta_info *sta,
  507. const u8 *pos, int left)
  508. {
  509. const u8 *end = pos + left;
  510. u8 *tmp, *tmp_pos;
  511. int ret = 0;
  512. /* Old DHCPDISCOVER is not needed anymore, if it was still pending */
  513. wpabuf_free(sta->hlp_dhcp_discover);
  514. sta->hlp_dhcp_discover = NULL;
  515. sta->fils_dhcp_rapid_commit_proxy = 0;
  516. /* Check if there are any FILS HLP Container elements */
  517. while (end - pos >= 2) {
  518. if (2 + pos[1] > end - pos)
  519. return 0;
  520. if (pos[0] == WLAN_EID_EXTENSION &&
  521. pos[1] >= 1 + 2 * ETH_ALEN &&
  522. pos[2] == WLAN_EID_EXT_FILS_HLP_CONTAINER)
  523. break;
  524. pos += 2 + pos[1];
  525. }
  526. if (end - pos < 2)
  527. return 0; /* No FILS HLP Container elements */
  528. tmp = os_malloc(end - pos);
  529. if (!tmp)
  530. return 0;
  531. while (end - pos >= 2) {
  532. if (2 + pos[1] > end - pos ||
  533. pos[0] != WLAN_EID_EXTENSION ||
  534. pos[1] < 1 + 2 * ETH_ALEN ||
  535. pos[2] != WLAN_EID_EXT_FILS_HLP_CONTAINER)
  536. break;
  537. tmp_pos = tmp;
  538. os_memcpy(tmp_pos, pos + 3, pos[1] - 1);
  539. tmp_pos += pos[1] - 1;
  540. pos += 2 + pos[1];
  541. /* Add possible fragments */
  542. while (end - pos >= 2 && pos[0] == WLAN_EID_FRAGMENT &&
  543. 2 + pos[1] <= end - pos) {
  544. os_memcpy(tmp_pos, pos + 2, pos[1]);
  545. tmp_pos += pos[1];
  546. pos += 2 + pos[1];
  547. }
  548. if (fils_process_hlp_req(hapd, sta, tmp, tmp_pos - tmp) > 0)
  549. ret = 1;
  550. }
  551. os_free(tmp);
  552. return ret;
  553. }
  554. void fils_hlp_deinit(struct hostapd_data *hapd)
  555. {
  556. if (hapd->dhcp_sock >= 0) {
  557. eloop_unregister_read_sock(hapd->dhcp_sock);
  558. close(hapd->dhcp_sock);
  559. hapd->dhcp_sock = -1;
  560. }
  561. }