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