]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/wpa/src/ap/fils_hlp.c
Update hostapd/wpa_supplicant to 2.8 to fix multiple vulnerabilities.
[FreeBSD/FreeBSD.git] / contrib / wpa / src / ap / fils_hlp.c
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 }