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