Bug Summary

File:src/usr.sbin/hostapd/apme.c
Warning:line 178, column 7
Although the value stored to 'ret' is used in the enclosing expression, the value is never actually read from 'ret'

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name apme.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 1 -pic-is-pie -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/usr.sbin/hostapd/obj -resource-dir /usr/local/lib/clang/13.0.0 -I /usr/src/usr.sbin/hostapd -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/usr.sbin/hostapd/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/ben/Projects/vmm/scan-build/2022-01-12-194120-40624-1 -x c /usr/src/usr.sbin/hostapd/apme.c
1/* $OpenBSD: apme.c,v 1.17 2019/05/10 01:29:31 guenther Exp $ */
2
3/*
4 * Copyright (c) 2004, 2005 Reyk Floeter <reyk@openbsd.org>
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19#include <sys/param.h> /* roundup isclr */
20#include <sys/ioctl.h>
21#include <sys/socket.h>
22#include <sys/time.h>
23#include <sys/uio.h>
24
25#include <net/if.h>
26#include <net/if_media.h>
27#include <net/if_arp.h>
28#include <net/if_llc.h>
29#include <net/bpf.h>
30
31#include <netinet/in.h>
32#include <netinet/if_ether.h>
33#include <arpa/inet.h>
34
35#include <net80211/ieee80211_radiotap.h>
36
37#include <fcntl.h>
38#include <stdlib.h>
39#include <stdio.h>
40#include <string.h>
41#include <unistd.h>
42#include <limits.h>
43
44#include "hostapd.h"
45#include "iapp.h"
46
47void hostapd_apme_frame(struct hostapd_apme *, u_int8_t *, u_int);
48void hostapd_apme_hopper(int, short, void *);
49
50int
51hostapd_apme_add(struct hostapd_config *cfg, const char *name)
52{
53 struct hostapd_apme *apme;
54
55 if (hostapd_apme_lookup(cfg, name) != NULL((void *)0))
56 return (EEXIST17);
57 if ((apme = (struct hostapd_apme *)
58 calloc(1, sizeof(struct hostapd_apme))) == NULL((void *)0))
59 return (ENOMEM12);
60 if (strlcpy(apme->a_iface, name, sizeof(apme->a_iface)) >=
61 sizeof(apme->a_iface)) {
62 free(apme);
63 return (EINVAL22);
64 }
65
66 apme->a_cfg = cfg;
67 apme->a_chanavail = NULL((void *)0);
68
69 TAILQ_INSERT_TAIL(&cfg->c_apmes, apme, a_entries)do { (apme)->a_entries.tqe_next = ((void *)0); (apme)->
a_entries.tqe_prev = (&cfg->c_apmes)->tqh_last; *(&
cfg->c_apmes)->tqh_last = (apme); (&cfg->c_apmes
)->tqh_last = &(apme)->a_entries.tqe_next; } while (
0)
;
70
71 hostapd_log(HOSTAPD_LOG_DEBUG2,
72 "%s: Host AP interface added", apme->a_iface);
73
74 return (0);
75}
76
77int
78hostapd_apme_deauth(struct hostapd_apme *apme)
79{
80 struct hostapd_config *cfg = (struct hostapd_config *)apme->a_cfg;
81 struct hostapd_iapp *iapp = &cfg->c_iapp;
82 u_int8_t buf[sizeof(struct ieee80211_frame) + sizeof(u_int16_t)];
83 struct ieee80211_frame *wh;
84
85 bzero(&buf, sizeof(buf));
86 wh = (struct ieee80211_frame *)&buf[0];
87 wh->i_fc[0] = IEEE80211_FC0_VERSION_00x00 | IEEE80211_FC0_TYPE_MGT0x00 |
88 IEEE80211_FC0_SUBTYPE_DEAUTH0xc0;
89 wh->i_fc[1] = IEEE80211_FC1_DIR_NODS0x00;
90 memset(&wh->i_addr1, 0xff, IEEE80211_ADDR_LEN6);
91 bcopy(apme->a_bssid, wh->i_addr2, IEEE80211_ADDR_LEN6);
92 bcopy(apme->a_bssid, wh->i_addr3, IEEE80211_ADDR_LEN6);
93 *(u_int16_t *)(wh + 1) = htole16(IEEE80211_REASON_AUTH_EXPIRE)((__uint16_t)(IEEE80211_REASON_AUTH_EXPIRE));
94
95 if (write(apme->a_raw, buf, sizeof(buf)) == -1) {
96 hostapd_log(HOSTAPD_LOG_VERBOSE1,
97 "%s/%s: failed to deauthenticate all stations: %s",
98 iapp->i_iface, apme->a_iface,
99 strerror(errno(*__errno())));
100 return (EIO5);
101 }
102
103 hostapd_log(HOSTAPD_LOG_VERBOSE1,
104 "%s/%s: deauthenticated all stations",
105 apme->a_iface, iapp->i_iface);
106
107 return (0);
108}
109
110struct hostapd_apme *
111hostapd_apme_lookup(struct hostapd_config *cfg, const char *name)
112{
113 struct hostapd_apme *apme;
114
115 TAILQ_FOREACH(apme, &cfg->c_apmes, a_entries)for((apme) = ((&cfg->c_apmes)->tqh_first); (apme) !=
((void *)0); (apme) = ((apme)->a_entries.tqe_next))
{
116 if (strcmp(name, apme->a_iface) == 0)
117 return (apme);
118 }
119
120 return (NULL((void *)0));
121}
122
123struct hostapd_apme *
124hostapd_apme_addhopper(struct hostapd_config *cfg, const char *name)
125{
126 struct hostapd_apme *apme;
127
128 if ((apme = hostapd_apme_lookup(cfg, name)) == NULL((void *)0))
129 return (NULL((void *)0));
130 if (apme->a_chanavail != NULL((void *)0))
131 return (NULL((void *)0));
132 apme->a_curchan = IEEE80211_CHAN_MAX255;
133 apme->a_maxchan = roundup(IEEE80211_CHAN_MAX, NBBY)((((255)+((8)-1))/(8))*(8));
134 if ((apme->a_chanavail = (u_int8_t *)
135 calloc(apme->a_maxchan, sizeof(u_int8_t))) == NULL((void *)0))
136 return (NULL((void *)0));
137 memset(apme->a_chanavail, 0xff,
138 apme->a_maxchan * sizeof(u_int8_t));
139 (void)strlcpy(apme->a_chanreq.i_name, apme->a_iface, IFNAMSIZ16);
140
141 return (apme);
142}
143
144void
145hostapd_apme_sethopper(struct hostapd_apme *apme, int now)
146{
147 struct hostapd_config *cfg = (struct hostapd_config *)apme->a_cfg;
148 struct timeval tv;
149
150 bzero(&tv, sizeof(tv));
151 if (!now)
152 bcopy(&cfg->c_apme_hopdelay, &tv, sizeof(tv));
153
154 if (!evtimer_initialized(&apme->a_chanev)((&apme->a_chanev)->ev_flags & 0x80))
155 evtimer_set(&apme->a_chanev, hostapd_apme_hopper, apme)event_set(&apme->a_chanev, -1, 0, hostapd_apme_hopper,
apme)
;
156 if (evtimer_add(&apme->a_chanev, &tv)event_add(&apme->a_chanev, &tv) == -1)
157 hostapd_fatal("failed to add hopper event");
158}
159
160void
161hostapd_apme_hopper(int fd, short sig, void *arg)
162{
163 struct hostapd_apme *apme = (struct hostapd_apme *)arg;
164 struct hostapd_config *cfg = (struct hostapd_config *)apme->a_cfg;
165 int ret;
166
167 if (apme->a_curchan >= IEEE80211_CHAN_MAX255)
168 apme->a_curchan = 0;
169
170 do {
171 if (apme->a_curchan >= IEEE80211_CHAN_MAX255)
172 return;
173 apme->a_curchan %= IEEE80211_CHAN_MAX255;
174 apme->a_curchan++;
175 } while (isclr(apme->a_chanavail, apme->a_curchan)(((apme->a_chanavail)[(apme->a_curchan)>>3] &
(1<<((apme->a_curchan)&(8 -1)))) == 0)
);
176
177 apme->a_chanreq.i_channel = apme->a_curchan;
178 if ((ret = ioctl(cfg->c_apme_ctl, SIOCS80211CHANNEL((unsigned long)0x80000000 | ((sizeof(struct ieee80211chanreq
) & 0x1fff) << 16) | ((('i')) << 8) | ((238))
)
,
Although the value stored to 'ret' is used in the enclosing expression, the value is never actually read from 'ret'
179 &apme->a_chanreq)) != 0) {
180 hostapd_apme_sethopper(apme, 1);
181 return;
182 }
183
184 hostapd_log(HOSTAPD_LOG_DEBUG2,
185 "[priv]: %s setting to channel %d",
186 apme->a_iface, apme->a_curchan);
187
188 hostapd_apme_sethopper(apme, 0);
189}
190
191void
192hostapd_apme_term(struct hostapd_apme *apme)
193{
194 struct hostapd_config *cfg = (struct hostapd_config *)apme->a_cfg;
195
196 /* Remove the channel hopper, if active */
197 if (apme->a_chanavail != NULL((void *)0)) {
198 (void)event_del(&apme->a_chanev);
199 free(apme->a_chanavail);
200 apme->a_chanavail = NULL((void *)0);
201 }
202
203 /* Kick a specified Host AP interface */
204 (void)event_del(&apme->a_ev);
205 if (close(apme->a_raw))
206 hostapd_fatal("failed to close: %s\n",
207 strerror(errno(*__errno())));
208
209 TAILQ_REMOVE(&cfg->c_apmes, apme, a_entries)do { if (((apme)->a_entries.tqe_next) != ((void *)0)) (apme
)->a_entries.tqe_next->a_entries.tqe_prev = (apme)->
a_entries.tqe_prev; else (&cfg->c_apmes)->tqh_last =
(apme)->a_entries.tqe_prev; *(apme)->a_entries.tqe_prev
= (apme)->a_entries.tqe_next; ; ; } while (0)
;
210
211 /* Remove all dynamic roaming addresses */
212 if (cfg->c_flags & HOSTAPD_CFG_F_PRIV0x40)
213 hostapd_roaming_term(apme);
214
215 hostapd_log(HOSTAPD_LOG_DEBUG2,
216 "%s: Host AP interface removed", apme->a_iface);
217
218 free(apme);
219}
220
221void
222hostapd_apme_input(int fd, short sig, void *arg)
223{
224 struct hostapd_apme *apme = (struct hostapd_apme *)arg;
225 u_int8_t buf[IAPP_MAXSIZE512], *bp, *ep;
226 struct bpf_hdr *bph;
227 ssize_t len;
228
229 /* Ignore invalid signals */
230 if (sig != EV_READ0x02)
231 return;
232
233 bzero(&buf, sizeof(buf));
234
235 if ((len = read(fd, buf, sizeof(buf))) <
236 (ssize_t)sizeof(struct ieee80211_frame))
237 return;
238
239 /*
240 * Loop through each frame.
241 */
242
243 bp = (u_int8_t *)&buf;
244 ep = bp + len;
245
246 while (bp < ep) {
247 register u_int caplen, hdrlen;
248
249 bph = (struct bpf_hdr *)bp;
250 caplen = bph->bh_caplen;
251 hdrlen = bph->bh_hdrlen;
252
253 /* Process frame */
254 hostapd_apme_frame(apme, bp + hdrlen, caplen);
255
256 bp += BPF_WORDALIGN(caplen + hdrlen)(((caplen + hdrlen) + (sizeof(u_int32_t) - 1)) & ~(sizeof
(u_int32_t) - 1))
;
257 }
258}
259
260int
261hostapd_apme_output(struct hostapd_apme *apme,
262 struct hostapd_ieee80211_frame *frame)
263{
264 struct iovec iov[2];
265 int iovcnt;
266 struct ieee80211_frame wh;
267
268 bzero(&wh, sizeof(wh));
269
270 switch (frame->i_fc[1] & IEEE80211_FC1_DIR_MASK0x03) {
271 case IEEE80211_FC1_DIR_NODS0x00:
272 bcopy(frame->i_from, wh.i_addr2, IEEE80211_ADDR_LEN6);
273 bcopy(frame->i_to, wh.i_addr1, IEEE80211_ADDR_LEN6);
274 bcopy(frame->i_bssid, wh.i_addr3, IEEE80211_ADDR_LEN6);
275 break;
276 case IEEE80211_FC1_DIR_TODS0x01:
277 bcopy(frame->i_from, wh.i_addr2, IEEE80211_ADDR_LEN6);
278 bcopy(frame->i_to, wh.i_addr3, IEEE80211_ADDR_LEN6);
279 bcopy(frame->i_bssid, wh.i_addr1, IEEE80211_ADDR_LEN6);
280 break;
281 case IEEE80211_FC1_DIR_FROMDS0x02:
282 bcopy(frame->i_from, wh.i_addr3, IEEE80211_ADDR_LEN6);
283 bcopy(frame->i_to, wh.i_addr1, IEEE80211_ADDR_LEN6);
284 bcopy(frame->i_bssid, wh.i_addr2, IEEE80211_ADDR_LEN6);
285 break;
286 default:
287 case IEEE80211_FC1_DIR_DSTODS0x03:
288 return (EINVAL22);
289 }
290
291 wh.i_fc[0] = IEEE80211_FC0_VERSION_00x00 | frame->i_fc[0];
292 wh.i_fc[1] = frame->i_fc[1];
293 bcopy(frame->i_dur, wh.i_dur, sizeof(wh.i_dur));
294 bcopy(frame->i_seq, wh.i_seq, sizeof(wh.i_seq));
295
296 iovcnt = 1;
297 iov[0].iov_base = &wh;
298 iov[0].iov_len = sizeof(struct ieee80211_frame);
299
300 if (frame->i_data != NULL((void *)0) && frame->i_data_len > 0) {
301 iovcnt = 2;
302 iov[1].iov_base = frame->i_data;
303 iov[1].iov_len = frame->i_data_len;
304 }
305
306 if (writev(apme->a_raw, iov, iovcnt) == -1)
307 return (errno(*__errno()));
308
309 return (0);
310}
311
312int
313hostapd_apme_offset(struct hostapd_apme *apme,
314 u_int8_t *buf, const u_int len)
315{
316 struct hostapd_config *cfg = (struct hostapd_config *)apme->a_cfg;
317 struct ieee80211_radiotap_header *rh;
318 u_int rh_len;
319
320 if (cfg->c_apme_dlt == DLT_IEEE802_11105)
321 return (0);
322 else if (cfg->c_apme_dlt != DLT_IEEE802_11_RADIO127)
323 return (-1);
324
325 if (len < sizeof(struct ieee80211_radiotap_header))
326 return (-1);
327
328 rh = (struct ieee80211_radiotap_header*)buf;
329 rh_len = letoh16(rh->it_len)((__uint16_t)(rh->it_len));
330
331 if (rh->it_version != 0)
332 return (-1);
333 if (len <= rh_len)
334 return (-1);
335
336 return ((int)rh_len);
337}
338
339void
340hostapd_apme_frame(struct hostapd_apme *apme, u_int8_t *buf, u_int len)
341{
342 struct hostapd_config *cfg = (struct hostapd_config *)apme->a_cfg;
343 struct hostapd_iapp *iapp = &cfg->c_iapp;
344 struct hostapd_apme *other_apme;
345 struct hostapd_node node;
346 struct ieee80211_frame *wh;
347 int offset;
348
349 if ((offset = hostapd_apme_offset(apme, buf, len)) < 0)
350 return;
351 wh = (struct ieee80211_frame *)(buf + offset);
352
353 /* Ignore short frames or fragments */
354 if (len < sizeof(struct ieee80211_frame))
355 return;
356
357 /* Handle received frames */
358 if ((hostapd_handle_input(apme, buf, len) ==
359 (HOSTAPD_FRAME_F_RET_SKIP0x20000000 >> HOSTAPD_FRAME_F_RET_S28)) ||
360 cfg->c_flags & HOSTAPD_CFG_F_IAPP_PASSIVE0x04)
361 return;
362
363 /*
364 * Only accept local association response frames, ...
365 */
366 if (!((wh->i_fc[1] & IEEE80211_FC1_DIR_MASK0x03) ==
367 IEEE80211_FC1_DIR_NODS0x00 &&
368 (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK0x0c) ==
369 IEEE80211_FC0_TYPE_MGT0x00 &&
370 (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK0xf0) ==
371 IEEE80211_FC0_SUBTYPE_ASSOC_RESP0x10))
372 return;
373
374 /*
375 * ...sent by the Host AP (addr2) to our BSSID (addr3)
376 */
377 if (bcmp(wh->i_addr2, apme->a_bssid, IEEE80211_ADDR_LEN6) != 0 ||
378 bcmp(wh->i_addr3, apme->a_bssid, IEEE80211_ADDR_LEN6) != 0)
379 return;
380
381 cfg->c_stats.cn_rx_apme++;
382
383 /*
384 * Double-check if the station got associated to our Host AP
385 */
386 bcopy(wh->i_addr1, node.ni_macaddr, IEEE80211_ADDR_LEN6);
387 if (hostapd_priv_apme_getnode(apme, &node) != 0) {
388 hostapd_log(HOSTAPD_LOG_DEBUG2,
389 "%s: invalid association from %s on the Host AP",
390 apme->a_iface, etheraddr_string(wh->i_addr1)ether_ntoa((struct ether_addr*)wh->i_addr1));
391 return;
392 }
393 cfg->c_stats.cn_tx_apme++;
394
395 /*
396 * Delete node on other attached Host APs
397 */
398 TAILQ_FOREACH(other_apme, &cfg->c_apmes, a_entries)for((other_apme) = ((&cfg->c_apmes)->tqh_first); (other_apme
) != ((void *)0); (other_apme) = ((other_apme)->a_entries.
tqe_next))
{
399 if (apme == other_apme)
400 continue;
401 if (iapp->i_flags & HOSTAPD_IAPP_F_ROAMING(0x08 | 0x04))
402 (void)hostapd_roaming_del(other_apme, &node);
403 if (hostapd_apme_delnode(other_apme, &node) == 0)
404 cfg->c_stats.cn_tx_apme++;
405 }
406
407 if (iapp->i_flags & HOSTAPD_IAPP_F_ROAMING(0x08 | 0x04))
408 (void)hostapd_roaming_add(apme, &node);
409
410 (void)hostapd_iapp_add_notify(apme, &node);
411}
412
413void
414hostapd_apme_init(struct hostapd_apme *apme)
415{
416 struct hostapd_config *cfg = (struct hostapd_config *)apme->a_cfg;
417 u_int i, dlt;
418 struct ifreq ifr;
419
420 apme->a_raw = hostapd_bpf_open(O_RDWR0x0002);
421
422 apme->a_rawlen = IAPP_MAXSIZE512;
423 if (ioctl(apme->a_raw, BIOCSBLEN(((unsigned long)0x80000000|(unsigned long)0x40000000) | ((sizeof
(u_int) & 0x1fff) << 16) | ((('B')) << 8) | (
(102)))
, &apme->a_rawlen) == -1)
424 hostapd_fatal("failed to set BPF buffer len \"%s\": %s\n",
425 apme->a_iface, strerror(errno(*__errno())));
426
427 i = 1;
428 if (ioctl(apme->a_raw, BIOCIMMEDIATE((unsigned long)0x80000000 | ((sizeof(u_int) & 0x1fff) <<
16) | ((('B')) << 8) | ((112)))
, &i) == -1)
429 hostapd_fatal("failed to set BPF immediate mode on \"%s\": "
430 "%s\n", apme->a_iface, strerror(errno(*__errno())));
431
432 bzero(&ifr, sizeof(struct ifreq));
433 (void)strlcpy(ifr.ifr_name, apme->a_iface, sizeof(ifr.ifr_name));
434
435 /* This may fail, ignore it */
436 (void)ioctl(apme->a_raw, BIOCPROMISC((unsigned long)0x20000000 | ((0 & 0x1fff) << 16) |
((('B')) << 8) | ((105)))
, NULL((void *)0));
437
438 /* Associate the wireless network interface to the BPF descriptor */
439 if (ioctl(apme->a_raw, BIOCSETIF((unsigned long)0x80000000 | ((sizeof(struct ifreq) & 0x1fff
) << 16) | ((('B')) << 8) | ((108)))
, &ifr) == -1)
440 hostapd_fatal("failed to set BPF interface \"%s\": %s\n",
441 apme->a_iface, strerror(errno(*__errno())));
442
443 dlt = cfg->c_apme_dlt;
444 if (ioctl(apme->a_raw, BIOCSDLT((unsigned long)0x80000000 | ((sizeof(u_int) & 0x1fff) <<
16) | ((('B')) << 8) | ((122)))
, &dlt) == -1)
445 hostapd_fatal("failed to set BPF link type on \"%s\": %s\n",
446 apme->a_iface, strerror(errno(*__errno())));
447
448 /* Lock the BPF descriptor, no further configuration */
449 if (ioctl(apme->a_raw, BIOCLOCK((unsigned long)0x20000000 | ((0 & 0x1fff) << 16) |
((('B')) << 8) | ((118)))
, NULL((void *)0)) == -1)
450 hostapd_fatal("failed to lock BPF interface on \"%s\": %s\n",
451 apme->a_iface, strerror(errno(*__errno())));
452}
453
454int
455hostapd_apme_addnode(struct hostapd_apme *apme, struct hostapd_node *node)
456{
457 return (hostapd_priv_apme_setnode(apme, node, 1));
458}
459
460int
461hostapd_apme_delnode(struct hostapd_apme *apme, struct hostapd_node *node)
462{
463 return (hostapd_priv_apme_setnode(apme, node, 0));
464}