| /* |
| * FILS HLP request processing |
| * Copyright (c) 2017, Qualcomm Atheros, Inc. |
| * |
| * This software may be distributed under the terms of the BSD license. |
| * See README for more details. |
| */ |
| |
| #include "utils/includes.h" |
| |
| #include "utils/common.h" |
| #include "utils/eloop.h" |
| #include "common/dhcp.h" |
| #include "hostapd.h" |
| #include "sta_info.h" |
| #include "ieee802_11.h" |
| #include "fils_hlp.h" |
| |
| |
| static be16 ip_checksum(const void *buf, size_t len) |
| { |
| u32 sum = 0; |
| const u16 *pos; |
| |
| for (pos = buf; len >= 2; len -= 2) |
| sum += ntohs(*pos++); |
| if (len) |
| sum += ntohs(*pos << 8); |
| |
| sum = (sum >> 16) + (sum & 0xffff); |
| sum += sum >> 16; |
| return htons(~sum); |
| } |
| |
| |
| static int fils_dhcp_request(struct hostapd_data *hapd, struct sta_info *sta, |
| struct dhcp_data *dhcpoffer, u8 *dhcpofferend) |
| { |
| u8 *pos, *end; |
| struct dhcp_data *dhcp; |
| struct sockaddr_in addr; |
| ssize_t res; |
| const u8 *server_id = NULL; |
| |
| if (!sta->hlp_dhcp_discover) { |
| wpa_printf(MSG_DEBUG, |
| "FILS: No pending HLP DHCPDISCOVER available"); |
| return -1; |
| } |
| |
| /* Convert to DHCPREQUEST, remove rapid commit option, replace requested |
| * IP address option with yiaddr. */ |
| pos = wpabuf_mhead(sta->hlp_dhcp_discover); |
| end = pos + wpabuf_len(sta->hlp_dhcp_discover); |
| dhcp = (struct dhcp_data *) pos; |
| pos = (u8 *) (dhcp + 1); |
| pos += 4; /* skip magic */ |
| while (pos < end && *pos != DHCP_OPT_END) { |
| u8 opt, olen; |
| |
| opt = *pos++; |
| if (opt == DHCP_OPT_PAD) |
| continue; |
| if (pos >= end) |
| break; |
| olen = *pos++; |
| if (olen > end - pos) |
| break; |
| |
| switch (opt) { |
| case DHCP_OPT_MSG_TYPE: |
| if (olen > 0) |
| *pos = DHCPREQUEST; |
| break; |
| case DHCP_OPT_RAPID_COMMIT: |
| case DHCP_OPT_REQUESTED_IP_ADDRESS: |
| case DHCP_OPT_SERVER_ID: |
| /* Remove option */ |
| pos -= 2; |
| os_memmove(pos, pos + 2 + olen, end - pos - 2 - olen); |
| end -= 2 + olen; |
| olen = 0; |
| break; |
| } |
| pos += olen; |
| } |
| if (pos >= end || *pos != DHCP_OPT_END) { |
| wpa_printf(MSG_DEBUG, "FILS: Could not update DHCPDISCOVER"); |
| return -1; |
| } |
| sta->hlp_dhcp_discover->used = pos - (u8 *) dhcp; |
| |
| /* Copy Server ID option from DHCPOFFER to DHCPREQUEST */ |
| pos = (u8 *) (dhcpoffer + 1); |
| end = dhcpofferend; |
| pos += 4; /* skip magic */ |
| while (pos < end && *pos != DHCP_OPT_END) { |
| u8 opt, olen; |
| |
| opt = *pos++; |
| if (opt == DHCP_OPT_PAD) |
| continue; |
| if (pos >= end) |
| break; |
| olen = *pos++; |
| if (olen > end - pos) |
| break; |
| |
| switch (opt) { |
| case DHCP_OPT_SERVER_ID: |
| server_id = pos - 2; |
| break; |
| } |
| pos += olen; |
| } |
| |
| if (wpabuf_resize(&sta->hlp_dhcp_discover, |
| 6 + 1 + (server_id ? 2 + server_id[1] : 0))) |
| return -1; |
| if (server_id) |
| wpabuf_put_data(sta->hlp_dhcp_discover, server_id, |
| 2 + server_id[1]); |
| wpabuf_put_u8(sta->hlp_dhcp_discover, DHCP_OPT_REQUESTED_IP_ADDRESS); |
| wpabuf_put_u8(sta->hlp_dhcp_discover, 4); |
| wpabuf_put_data(sta->hlp_dhcp_discover, &dhcpoffer->your_ip, 4); |
| wpabuf_put_u8(sta->hlp_dhcp_discover, DHCP_OPT_END); |
| |
| os_memset(&addr, 0, sizeof(addr)); |
| addr.sin_family = AF_INET; |
| addr.sin_addr.s_addr = hapd->conf->dhcp_server.u.v4.s_addr; |
| addr.sin_port = htons(hapd->conf->dhcp_server_port); |
| res = sendto(hapd->dhcp_sock, wpabuf_head(sta->hlp_dhcp_discover), |
| wpabuf_len(sta->hlp_dhcp_discover), 0, |
| (const struct sockaddr *) &addr, sizeof(addr)); |
| if (res < 0) { |
| wpa_printf(MSG_ERROR, "FILS: DHCP sendto failed: %s", |
| strerror(errno)); |
| return -1; |
| } |
| wpa_printf(MSG_DEBUG, |
| "FILS: Acting as DHCP rapid commit proxy for %s:%d", |
| inet_ntoa(addr.sin_addr), ntohs(addr.sin_port)); |
| wpabuf_free(sta->hlp_dhcp_discover); |
| sta->hlp_dhcp_discover = NULL; |
| sta->fils_dhcp_rapid_commit_proxy = 1; |
| return 0; |
| } |
| |
| |
| static void fils_dhcp_handler(int sd, void *eloop_ctx, void *sock_ctx) |
| { |
| struct hostapd_data *hapd = sock_ctx; |
| struct sta_info *sta; |
| u8 buf[1500], *pos, *end, *end_opt = NULL; |
| struct dhcp_data *dhcp; |
| struct sockaddr_in addr; |
| socklen_t addr_len; |
| ssize_t res; |
| u8 msgtype = 0; |
| int rapid_commit = 0; |
| struct ip *iph; |
| struct udphdr *udph; |
| struct wpabuf *resp; |
| const u8 *rpos; |
| size_t left, len; |
| |
| addr_len = sizeof(addr); |
| res = recvfrom(sd, buf, sizeof(buf), 0, |
| (struct sockaddr *) &addr, &addr_len); |
| if (res < 0) { |
| wpa_printf(MSG_DEBUG, "FILS: DHCP read failed: %s", |
| strerror(errno)); |
| return; |
| } |
| wpa_printf(MSG_DEBUG, "FILS: DHCP response from server %s:%d (len=%d)", |
| inet_ntoa(addr.sin_addr), ntohs(addr.sin_port), (int) res); |
| wpa_hexdump(MSG_MSGDUMP, "FILS: HLP - DHCP server response", buf, res); |
| if ((size_t) res < sizeof(*dhcp)) |
| return; |
| dhcp = (struct dhcp_data *) buf; |
| if (dhcp->op != 2) |
| return; /* Not a BOOTREPLY */ |
| if (dhcp->relay_ip != hapd->conf->own_ip_addr.u.v4.s_addr) { |
| wpa_printf(MSG_DEBUG, |
| "FILS: HLP - DHCP response to unknown relay address 0x%x", |
| dhcp->relay_ip); |
| return; |
| } |
| dhcp->relay_ip = 0; |
| pos = (u8 *) (dhcp + 1); |
| end = &buf[res]; |
| |
| if (end - pos < 4 || WPA_GET_BE32(pos) != DHCP_MAGIC) { |
| wpa_printf(MSG_DEBUG, "FILS: HLP - no DHCP magic in response"); |
| return; |
| } |
| pos += 4; |
| |
| wpa_hexdump(MSG_DEBUG, "FILS: HLP - DHCP options in response", |
| pos, end - pos); |
| while (pos < end && *pos != DHCP_OPT_END) { |
| u8 opt, olen; |
| |
| opt = *pos++; |
| if (opt == DHCP_OPT_PAD) |
| continue; |
| if (pos >= end) |
| break; |
| olen = *pos++; |
| if (olen > end - pos) |
| break; |
| |
| switch (opt) { |
| case DHCP_OPT_MSG_TYPE: |
| if (olen > 0) |
| msgtype = pos[0]; |
| break; |
| case DHCP_OPT_RAPID_COMMIT: |
| rapid_commit = 1; |
| break; |
| } |
| pos += olen; |
| } |
| if (pos < end && *pos == DHCP_OPT_END) |
| end_opt = pos; |
| |
| wpa_printf(MSG_DEBUG, |
| "FILS: HLP - DHCP message type %u (rapid_commit=%d hw_addr=" |
| MACSTR ")", |
| msgtype, rapid_commit, MAC2STR(dhcp->hw_addr)); |
| |
| sta = ap_get_sta(hapd, dhcp->hw_addr); |
| if (!sta || !sta->fils_pending_assoc_req) { |
| wpa_printf(MSG_DEBUG, |
| "FILS: No pending HLP DHCP exchange with hw_addr " |
| MACSTR, MAC2STR(dhcp->hw_addr)); |
| return; |
| } |
| |
| if (hapd->conf->dhcp_rapid_commit_proxy && msgtype == DHCPOFFER && |
| !rapid_commit) { |
| /* Use hostapd to take care of 4-message exchange and convert |
| * the final DHCPACK to rapid commit version. */ |
| if (fils_dhcp_request(hapd, sta, dhcp, end) == 0) |
| return; |
| /* failed, so send the server response as-is */ |
| } else if (msgtype != DHCPACK) { |
| wpa_printf(MSG_DEBUG, |
| "FILS: No DHCPACK available from the server and cannot do rapid commit proxying"); |
| } |
| |
| pos = buf; |
| resp = wpabuf_alloc(2 * ETH_ALEN + 6 + 2 + |
| sizeof(*iph) + sizeof(*udph) + (end - pos) + 2); |
| if (!resp) |
| return; |
| wpabuf_put_data(resp, sta->addr, ETH_ALEN); |
| wpabuf_put_data(resp, hapd->own_addr, ETH_ALEN); |
| wpabuf_put_data(resp, "\xaa\xaa\x03\x00\x00\x00", 6); |
| wpabuf_put_be16(resp, ETH_P_IP); |
| iph = wpabuf_put(resp, sizeof(*iph)); |
| iph->ip_v = 4; |
| iph->ip_hl = sizeof(*iph) / 4; |
| iph->ip_len = htons(sizeof(*iph) + sizeof(*udph) + (end - pos)); |
| iph->ip_ttl = 1; |
| iph->ip_p = 17; /* UDP */ |
| iph->ip_src.s_addr = hapd->conf->dhcp_server.u.v4.s_addr; |
| iph->ip_dst.s_addr = dhcp->client_ip; |
| iph->ip_sum = ip_checksum(iph, sizeof(*iph)); |
| udph = wpabuf_put(resp, sizeof(*udph)); |
| udph->uh_sport = htons(DHCP_SERVER_PORT); |
| udph->uh_dport = htons(DHCP_CLIENT_PORT); |
| udph->uh_ulen = htons(sizeof(*udph) + (end - pos)); |
| udph->uh_sum = htons(0x0000); /* TODO: calculate checksum */ |
| if (hapd->conf->dhcp_rapid_commit_proxy && msgtype == DHCPACK && |
| !rapid_commit && sta->fils_dhcp_rapid_commit_proxy && end_opt) { |
| /* Add rapid commit option */ |
| wpabuf_put_data(resp, pos, end_opt - pos); |
| wpabuf_put_u8(resp, DHCP_OPT_RAPID_COMMIT); |
| wpabuf_put_u8(resp, 0); |
| wpabuf_put_data(resp, end_opt, end - end_opt); |
| } else { |
| wpabuf_put_data(resp, pos, end - pos); |
| } |
| if (wpabuf_resize(&sta->fils_hlp_resp, wpabuf_len(resp) + |
| 2 * wpabuf_len(resp) / 255 + 100)) { |
| wpabuf_free(resp); |
| return; |
| } |
| |
| rpos = wpabuf_head(resp); |
| left = wpabuf_len(resp); |
| |
| wpabuf_put_u8(sta->fils_hlp_resp, WLAN_EID_EXTENSION); /* Element ID */ |
| if (left <= 254) |
| len = 1 + left; |
| else |
| len = 255; |
| wpabuf_put_u8(sta->fils_hlp_resp, len); /* Length */ |
| /* Element ID Extension */ |
| wpabuf_put_u8(sta->fils_hlp_resp, WLAN_EID_EXT_FILS_HLP_CONTAINER); |
| /* Destination MAC Address, Source MAC Address, HLP Packet. |
| * HLP Packet is in MSDU format (i.e., including the LLC/SNAP header |
| * when LPD is used). */ |
| wpabuf_put_data(sta->fils_hlp_resp, rpos, len - 1); |
| rpos += len - 1; |
| left -= len - 1; |
| while (left) { |
| wpabuf_put_u8(sta->fils_hlp_resp, WLAN_EID_FRAGMENT); |
| len = left > 255 ? 255 : left; |
| wpabuf_put_u8(sta->fils_hlp_resp, len); |
| wpabuf_put_data(sta->fils_hlp_resp, rpos, len); |
| rpos += len; |
| left -= len; |
| } |
| wpabuf_free(resp); |
| |
| if (sta->fils_drv_assoc_finish) |
| hostapd_notify_assoc_fils_finish(hapd, sta); |
| else |
| fils_hlp_finish_assoc(hapd, sta); |
| } |
| |
| |
| static int fils_process_hlp_dhcp(struct hostapd_data *hapd, |
| struct sta_info *sta, |
| const u8 *msg, size_t len) |
| { |
| const struct dhcp_data *dhcp; |
| struct wpabuf *dhcp_buf; |
| struct dhcp_data *dhcp_msg; |
| u8 msgtype = 0; |
| int rapid_commit = 0; |
| const u8 *pos = msg, *end; |
| struct sockaddr_in addr; |
| ssize_t res; |
| |
| if (len < sizeof(*dhcp)) |
| return 0; |
| dhcp = (const struct dhcp_data *) pos; |
| end = pos + len; |
| wpa_printf(MSG_DEBUG, |
| "FILS: HLP request DHCP: op=%u htype=%u hlen=%u hops=%u xid=0x%x", |
| dhcp->op, dhcp->htype, dhcp->hlen, dhcp->hops, |
| ntohl(dhcp->xid)); |
| pos += sizeof(*dhcp); |
| if (dhcp->op != 1) |
| return 0; /* Not a BOOTREQUEST */ |
| |
| if (end - pos < 4) |
| return 0; |
| if (WPA_GET_BE32(pos) != DHCP_MAGIC) { |
| wpa_printf(MSG_DEBUG, "FILS: HLP - no DHCP magic"); |
| return 0; |
| } |
| pos += 4; |
| |
| wpa_hexdump(MSG_DEBUG, "FILS: HLP - DHCP options", pos, end - pos); |
| while (pos < end && *pos != DHCP_OPT_END) { |
| u8 opt, olen; |
| |
| opt = *pos++; |
| if (opt == DHCP_OPT_PAD) |
| continue; |
| if (pos >= end) |
| break; |
| olen = *pos++; |
| if (olen > end - pos) |
| break; |
| |
| switch (opt) { |
| case DHCP_OPT_MSG_TYPE: |
| if (olen > 0) |
| msgtype = pos[0]; |
| break; |
| case DHCP_OPT_RAPID_COMMIT: |
| rapid_commit = 1; |
| break; |
| } |
| pos += olen; |
| } |
| |
| wpa_printf(MSG_DEBUG, "FILS: HLP - DHCP message type %u", msgtype); |
| if (msgtype != DHCPDISCOVER) |
| return 0; |
| |
| if (hapd->conf->dhcp_server.af != AF_INET || |
| hapd->conf->dhcp_server.u.v4.s_addr == 0) { |
| wpa_printf(MSG_DEBUG, |
| "FILS: HLP - no DHCPv4 server configured - drop request"); |
| return 0; |
| } |
| |
| if (hapd->conf->own_ip_addr.af != AF_INET || |
| hapd->conf->own_ip_addr.u.v4.s_addr == 0) { |
| wpa_printf(MSG_DEBUG, |
| "FILS: HLP - no IPv4 own_ip_addr configured - drop request"); |
| return 0; |
| } |
| |
| if (hapd->dhcp_sock < 0) { |
| int s; |
| |
| s = socket(AF_INET, SOCK_DGRAM, 0); |
| if (s < 0) { |
| wpa_printf(MSG_ERROR, |
| "FILS: Failed to open DHCP socket: %s", |
| strerror(errno)); |
| return 0; |
| } |
| |
| if (hapd->conf->dhcp_relay_port) { |
| os_memset(&addr, 0, sizeof(addr)); |
| addr.sin_family = AF_INET; |
| addr.sin_addr.s_addr = |
| hapd->conf->own_ip_addr.u.v4.s_addr; |
| addr.sin_port = htons(hapd->conf->dhcp_relay_port); |
| if (bind(s, (struct sockaddr *) &addr, sizeof(addr))) { |
| wpa_printf(MSG_ERROR, |
| "FILS: Failed to bind DHCP socket: %s", |
| strerror(errno)); |
| close(s); |
| return 0; |
| } |
| } |
| if (eloop_register_sock(s, EVENT_TYPE_READ, |
| fils_dhcp_handler, NULL, hapd)) { |
| close(s); |
| return 0; |
| } |
| |
| hapd->dhcp_sock = s; |
| } |
| |
| dhcp_buf = wpabuf_alloc(len); |
| if (!dhcp_buf) |
| return 0; |
| dhcp_msg = wpabuf_put(dhcp_buf, len); |
| os_memcpy(dhcp_msg, msg, len); |
| dhcp_msg->relay_ip = hapd->conf->own_ip_addr.u.v4.s_addr; |
| os_memset(&addr, 0, sizeof(addr)); |
| addr.sin_family = AF_INET; |
| addr.sin_addr.s_addr = hapd->conf->dhcp_server.u.v4.s_addr; |
| addr.sin_port = htons(hapd->conf->dhcp_server_port); |
| res = sendto(hapd->dhcp_sock, dhcp_msg, len, 0, |
| (const struct sockaddr *) &addr, sizeof(addr)); |
| if (res < 0) { |
| wpa_printf(MSG_ERROR, "FILS: DHCP sendto failed: %s", |
| strerror(errno)); |
| wpabuf_free(dhcp_buf); |
| /* Close the socket to try to recover from error */ |
| eloop_unregister_read_sock(hapd->dhcp_sock); |
| close(hapd->dhcp_sock); |
| hapd->dhcp_sock = -1; |
| return 0; |
| } |
| |
| wpa_printf(MSG_DEBUG, |
| "FILS: HLP relayed DHCP request to server %s:%d (rapid_commit=%d)", |
| inet_ntoa(addr.sin_addr), ntohs(addr.sin_port), |
| rapid_commit); |
| if (hapd->conf->dhcp_rapid_commit_proxy && rapid_commit) { |
| /* Store a copy of the DHCPDISCOVER for rapid commit proxying |
| * purposes if the server does not support the rapid commit |
| * option. */ |
| wpa_printf(MSG_DEBUG, |
| "FILS: Store DHCPDISCOVER for rapid commit proxy"); |
| wpabuf_free(sta->hlp_dhcp_discover); |
| sta->hlp_dhcp_discover = dhcp_buf; |
| } else { |
| wpabuf_free(dhcp_buf); |
| } |
| |
| return 1; |
| } |
| |
| |
| static int fils_process_hlp_udp(struct hostapd_data *hapd, |
| struct sta_info *sta, const u8 *dst, |
| const u8 *pos, size_t len) |
| { |
| const struct ip *iph; |
| const struct udphdr *udph; |
| u16 sport, dport, ulen; |
| |
| if (len < sizeof(*iph) + sizeof(*udph)) |
| return 0; |
| iph = (const struct ip *) pos; |
| udph = (const struct udphdr *) (iph + 1); |
| sport = ntohs(udph->uh_sport); |
| dport = ntohs(udph->uh_dport); |
| ulen = ntohs(udph->uh_ulen); |
| wpa_printf(MSG_DEBUG, |
| "FILS: HLP request UDP: sport=%u dport=%u ulen=%u sum=0x%x", |
| sport, dport, ulen, ntohs(udph->uh_sum)); |
| /* TODO: Check UDP checksum */ |
| if (ulen < sizeof(*udph) || ulen > len - sizeof(*iph)) |
| return 0; |
| |
| if (dport == DHCP_SERVER_PORT && sport == DHCP_CLIENT_PORT) { |
| return fils_process_hlp_dhcp(hapd, sta, (const u8 *) (udph + 1), |
| ulen - sizeof(*udph)); |
| } |
| |
| return 0; |
| } |
| |
| |
| static int fils_process_hlp_ip(struct hostapd_data *hapd, |
| struct sta_info *sta, const u8 *dst, |
| const u8 *pos, size_t len) |
| { |
| const struct ip *iph; |
| uint16_t ip_len; |
| |
| if (len < sizeof(*iph)) |
| return 0; |
| iph = (const struct ip *) pos; |
| if (ip_checksum(iph, sizeof(*iph)) != 0) { |
| wpa_printf(MSG_DEBUG, |
| "FILS: HLP request IPv4 packet had invalid header checksum - dropped"); |
| return 0; |
| } |
| ip_len = ntohs(iph->ip_len); |
| if (ip_len > len) |
| return 0; |
| wpa_printf(MSG_DEBUG, |
| "FILS: HLP request IPv4: saddr=%08x daddr=%08x protocol=%u", |
| iph->ip_src.s_addr, iph->ip_dst.s_addr, iph->ip_p); |
| switch (iph->ip_p) { |
| case 17: |
| return fils_process_hlp_udp(hapd, sta, dst, pos, len); |
| default: |
| return 0; |
| } |
| } |
| |
| |
| static int fils_process_hlp_req(struct hostapd_data *hapd, |
| struct sta_info *sta, |
| const u8 *pos, size_t len) |
| { |
| const u8 *pkt, *end; |
| |
| wpa_printf(MSG_DEBUG, "FILS: HLP request from " MACSTR " (dst=" MACSTR |
| " src=" MACSTR " len=%u)", |
| MAC2STR(sta->addr), MAC2STR(pos), MAC2STR(pos + ETH_ALEN), |
| (unsigned int) len); |
| if (os_memcmp(sta->addr, pos + ETH_ALEN, ETH_ALEN) != 0) { |
| wpa_printf(MSG_DEBUG, |
| "FILS: Ignore HLP request with unexpected source address" |
| MACSTR, MAC2STR(pos + ETH_ALEN)); |
| return 0; |
| } |
| |
| end = pos + len; |
| pkt = pos + 2 * ETH_ALEN; |
| if (end - pkt >= 6 && |
| os_memcmp(pkt, "\xaa\xaa\x03\x00\x00\x00", 6) == 0) |
| pkt += 6; /* Remove SNAP/LLC header */ |
| wpa_hexdump(MSG_MSGDUMP, "FILS: HLP request packet", pkt, end - pkt); |
| |
| if (end - pkt < 2) |
| return 0; |
| |
| switch (WPA_GET_BE16(pkt)) { |
| case ETH_P_IP: |
| return fils_process_hlp_ip(hapd, sta, pos, pkt + 2, |
| end - pkt - 2); |
| default: |
| return 0; |
| } |
| } |
| |
| |
| int fils_process_hlp(struct hostapd_data *hapd, struct sta_info *sta, |
| const u8 *pos, int left) |
| { |
| const u8 *end = pos + left; |
| u8 *tmp, *tmp_pos; |
| int ret = 0; |
| |
| if (sta->fils_pending_assoc_req && |
| eloop_is_timeout_registered(fils_hlp_timeout, hapd, sta)) { |
| /* Do not process FILS HLP request again if the station |
| * retransmits (Re)Association Request frame before the previous |
| * HLP response has either been received or timed out. */ |
| wpa_printf(MSG_DEBUG, |
| "FILS: Do not relay another HLP request from " |
| MACSTR |
| " before processing of the already pending one has been completed", |
| MAC2STR(sta->addr)); |
| return 1; |
| } |
| |
| /* Old DHCPDISCOVER is not needed anymore, if it was still pending */ |
| wpabuf_free(sta->hlp_dhcp_discover); |
| sta->hlp_dhcp_discover = NULL; |
| sta->fils_dhcp_rapid_commit_proxy = 0; |
| |
| /* Check if there are any FILS HLP Container elements */ |
| while (end - pos >= 2) { |
| if (2 + pos[1] > end - pos) |
| return 0; |
| if (pos[0] == WLAN_EID_EXTENSION && |
| pos[1] >= 1 + 2 * ETH_ALEN && |
| pos[2] == WLAN_EID_EXT_FILS_HLP_CONTAINER) |
| break; |
| pos += 2 + pos[1]; |
| } |
| if (end - pos < 2) |
| return 0; /* No FILS HLP Container elements */ |
| |
| tmp = os_malloc(end - pos); |
| if (!tmp) |
| return 0; |
| |
| while (end - pos >= 2) { |
| if (2 + pos[1] > end - pos || |
| pos[0] != WLAN_EID_EXTENSION || |
| pos[1] < 1 + 2 * ETH_ALEN || |
| pos[2] != WLAN_EID_EXT_FILS_HLP_CONTAINER) |
| break; |
| tmp_pos = tmp; |
| os_memcpy(tmp_pos, pos + 3, pos[1] - 1); |
| tmp_pos += pos[1] - 1; |
| pos += 2 + pos[1]; |
| |
| /* Add possible fragments */ |
| while (end - pos >= 2 && pos[0] == WLAN_EID_FRAGMENT && |
| 2 + pos[1] <= end - pos) { |
| os_memcpy(tmp_pos, pos + 2, pos[1]); |
| tmp_pos += pos[1]; |
| pos += 2 + pos[1]; |
| } |
| |
| if (fils_process_hlp_req(hapd, sta, tmp, tmp_pos - tmp) > 0) |
| ret = 1; |
| } |
| |
| os_free(tmp); |
| |
| return ret; |
| } |
| |
| |
| void fils_hlp_deinit(struct hostapd_data *hapd) |
| { |
| if (hapd->dhcp_sock >= 0) { |
| eloop_unregister_read_sock(hapd->dhcp_sock); |
| close(hapd->dhcp_sock); |
| hapd->dhcp_sock = -1; |
| } |
| } |