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 ip *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->ip_v = 4; 263 iph->ip_hl = sizeof(*iph) / 4; 264 iph->ip_len = htons(sizeof(*iph) + sizeof(*udph) + (end - pos)); 265 iph->ip_ttl = 1; 266 iph->ip_p = 17; /* UDP */ 267 iph->ip_src.s_addr = hapd->conf->dhcp_server.u.v4.s_addr; 268 iph->ip_dst.s_addr = dhcp->client_ip; 269 iph->ip_sum = 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 ip *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 ip *) 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 ip *iph; 514 uint16_t ip_len; 515 516 if (len < sizeof(*iph)) 517 return 0; 518 iph = (const struct ip *) 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 ip_len = ntohs(iph->ip_len); 525 if (ip_len > len) 526 return 0; 527 wpa_printf(MSG_DEBUG, 528 "FILS: HLP request IPv4: saddr=%08x daddr=%08x protocol=%u", 529 iph->ip_src.s_addr, iph->ip_dst.s_addr, iph->ip_p); 530 switch (iph->ip_p) { 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