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