Home | History | Annotate | Download | only in ap
      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 
     20 static 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 
     36 static 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 
    150 static 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 
    325 static 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 
    478 static 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 
    509 static 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 
    539 static 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 
    576 int 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 
    647 void 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