Bug Summary

File:dev/ic/if_wi_hostap.c
Warning:line 562, column 2
Value stored to 'status' is never read

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 if_wi_hostap.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 static -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -ffreestanding -mcmodel=kernel -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -target-feature -sse2 -target-feature -sse -target-feature -3dnow -target-feature -mmx -target-feature +save-args -disable-red-zone -no-implicit-float -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/sys/arch/amd64/compile/GENERIC.MP/obj -nostdsysteminc -nobuiltininc -resource-dir /usr/local/lib/clang/13.0.0 -I /usr/src/sys -I /usr/src/sys/arch/amd64/compile/GENERIC.MP/obj -I /usr/src/sys/arch -I /usr/src/sys/dev/pci/drm/include -I /usr/src/sys/dev/pci/drm/include/uapi -I /usr/src/sys/dev/pci/drm/amd/include/asic_reg -I /usr/src/sys/dev/pci/drm/amd/include -I /usr/src/sys/dev/pci/drm/amd/amdgpu -I /usr/src/sys/dev/pci/drm/amd/display -I /usr/src/sys/dev/pci/drm/amd/display/include -I /usr/src/sys/dev/pci/drm/amd/display/dc -I /usr/src/sys/dev/pci/drm/amd/display/amdgpu_dm -I /usr/src/sys/dev/pci/drm/amd/pm/inc -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu/smu11 -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu/smu12 -I /usr/src/sys/dev/pci/drm/amd/pm/powerplay -I /usr/src/sys/dev/pci/drm/amd/pm/powerplay/hwmgr -I /usr/src/sys/dev/pci/drm/amd/pm/powerplay/smumgr -I /usr/src/sys/dev/pci/drm/amd/display/dc/inc -I /usr/src/sys/dev/pci/drm/amd/display/dc/inc/hw -I /usr/src/sys/dev/pci/drm/amd/display/dc/clk_mgr -I /usr/src/sys/dev/pci/drm/amd/display/modules/inc -I /usr/src/sys/dev/pci/drm/amd/display/modules/hdcp -I /usr/src/sys/dev/pci/drm/amd/display/dmub/inc -I /usr/src/sys/dev/pci/drm/i915 -D DDB -D DIAGNOSTIC -D KTRACE -D ACCOUNTING -D KMEMSTATS -D PTRACE -D POOL_DEBUG -D CRYPTO -D SYSVMSG -D SYSVSEM -D SYSVSHM -D UVM_SWAP_ENCRYPT -D FFS -D FFS2 -D FFS_SOFTUPDATES -D UFS_DIRHASH -D QUOTA -D EXT2FS -D MFS -D NFSCLIENT -D NFSSERVER -D CD9660 -D UDF -D MSDOSFS -D FIFO -D FUSE -D SOCKET_SPLICE -D TCP_ECN -D TCP_SIGNATURE -D INET6 -D IPSEC -D PPP_BSDCOMP -D PPP_DEFLATE -D PIPEX -D MROUTING -D MPLS -D BOOT_CONFIG -D USER_PCICONF -D APERTURE -D MTRR -D NTFS -D HIBERNATE -D PCIVERBOSE -D USBVERBOSE -D WSDISPLAY_COMPAT_USL -D WSDISPLAY_COMPAT_RAWKBD -D WSDISPLAY_DEFAULTSCREENS=6 -D X86EMU -D ONEWIREVERBOSE -D MULTIPROCESSOR -D MAXUSERS=80 -D _KERNEL -D CONFIG_DRM_AMD_DC_DCN3_0 -O2 -Wno-pointer-sign -Wno-address-of-packed-member -Wno-constant-conversion -Wno-unused-but-set-variable -Wno-gnu-folding-constant -fdebug-compilation-dir=/usr/src/sys/arch/amd64/compile/GENERIC.MP/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 -o /usr/obj/sys/arch/amd64/compile/GENERIC.MP/scan-build/2022-01-12-131800-47421-1 -x c /usr/src/sys/dev/ic/if_wi_hostap.c
1/* $OpenBSD: if_wi_hostap.c,v 1.52 2018/02/19 08:59:52 mpi Exp $ */
2
3/*
4 * Copyright (c) 2002
5 * Thomas Skibo <skibo@pacbell.net>. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by Thomas Skibo.
18 * 4. Neither the name of the author nor the names of any co-contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY Thomas Skibo AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL Thomas Skibo OR HIS DRINKING PALS
26 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
32 * THE POSSIBILITY OF SUCH DAMAGE.
33 *
34 */
35
36/* This is experimental Host AP software for Prism 2 802.11b interfaces.
37 *
38 * Much of this is based upon the "Linux Host AP driver Host AP driver
39 * for Intersil Prism2" by Jouni Malinen <jkm@ssh.com> or <jkmaline@cc.hut.fi>.
40 */
41
42#include <sys/param.h>
43#include <sys/systm.h>
44#include <sys/sockio.h>
45#include <sys/mbuf.h>
46#include <sys/malloc.h>
47#include <sys/kernel.h>
48#include <sys/timeout.h>
49#include <sys/ucred.h>
50#include <sys/socket.h>
51#include <sys/queue.h>
52#include <sys/syslog.h>
53#include <sys/sysctl.h>
54#include <sys/device.h>
55
56#include <machine/bus.h>
57
58#include <net/if.h>
59#include <net/if_media.h>
60
61#include <netinet/in.h>
62#include <netinet/if_ether.h>
63
64#include <net80211/ieee80211_var.h>
65#include <net80211/ieee80211_ioctl.h>
66
67#include <dev/ic/if_wireg.h>
68#include <dev/ic/if_wi_ieee.h>
69#include <dev/ic/if_wivar.h>
70
71void wihap_timeout(void *v);
72void wihap_sta_timeout(void *v);
73struct wihap_sta_info *wihap_sta_alloc(struct wi_softc *sc, u_int8_t *addr);
74void wihap_sta_delete(struct wihap_sta_info *sta);
75struct wihap_sta_info *wihap_sta_find(struct wihap_info *whi, u_int8_t *addr);
76int wihap_sta_is_assoc(struct wihap_info *whi, u_int8_t addr[]);
77void wihap_auth_req(struct wi_softc *sc, struct wi_frame *rxfrm,
78 caddr_t pkt, int len);
79void wihap_sta_deauth(struct wi_softc *sc, u_int8_t sta_addr[],
80 u_int16_t reason);
81void wihap_deauth_req(struct wi_softc *sc, struct wi_frame *rxfrm,
82 caddr_t pkt, int len);
83void wihap_assoc_req(struct wi_softc *sc, struct wi_frame *rxfrm,
84 caddr_t pkt, int len);
85void wihap_sta_disassoc(struct wi_softc *sc, u_int8_t sta_addr[],
86 u_int16_t reason);
87void wihap_disassoc_req(struct wi_softc *sc, struct wi_frame *rxfrm,
88 caddr_t pkt, int len);
89
90#ifndef SMALL_KERNEL
91/*
92 * take_hword()
93 *
94 * Used for parsing management frames. The pkt pointer and length
95 * variables are updated after the value is removed.
96 */
97static __inline u_int16_t
98take_hword(caddr_t *ppkt, int *plen)
99{
100 u_int16_t s = letoh16(* (u_int16_t *) *ppkt)((__uint16_t)(* (u_int16_t *) *ppkt));
101 *ppkt += sizeof(u_int16_t);
102 *plen -= sizeof(u_int16_t);
103 return s;
104}
105
106/* take_tlv()
107 *
108 * Parse out TLV element from a packet, check for underflow of packet
109 * or overflow of buffer, update pkt/len.
110 */
111static int
112take_tlv(caddr_t *ppkt, int *plen, int id_expect, void *dst, int maxlen)
113{
114 u_int8_t id, len;
115
116 if (*plen < 2)
117 return -1;
118
119 id = ((u_int8_t *)*ppkt)[0];
120 len = ((u_int8_t *)*ppkt)[1];
121
122 if (id != id_expect || *plen < len+2 || maxlen < len)
123 return -1;
124
125 bcopy(*ppkt + 2, dst, len);
126 *plen -= 2 + len;
127 *ppkt += 2 + len;
128
129 return (len);
130}
131
132/* put_hword()
133 * Put half-word element into management frames.
134 */
135static __inline void
136put_hword(caddr_t *ppkt, u_int16_t s)
137{
138 * (u_int16_t *) *ppkt = htole16(s)((__uint16_t)(s));
139 *ppkt += sizeof(u_int16_t);
140}
141
142/* put_tlv()
143 * Put TLV elements into management frames.
144 */
145static void
146put_tlv(caddr_t *ppkt, u_int8_t id, void *src, u_int8_t len)
147{
148 (*ppkt)[0] = id;
149 (*ppkt)[1] = len;
150 bcopy(src, (*ppkt) + 2, len);
151 *ppkt += 2 + len;
152}
153
154static int
155put_rates(caddr_t *ppkt, u_int16_t rates)
156{
157 u_int8_t ratebuf[8];
158 int len = 0;
159
160 if (rates & WI_SUPPRATES_1M0x0001)
161 ratebuf[len++] = 0x82;
162 if (rates & WI_SUPPRATES_2M0x0002)
163 ratebuf[len++] = 0x84;
164 if (rates & WI_SUPPRATES_5M0x0004)
165 ratebuf[len++] = 0x8b;
166 if (rates & WI_SUPPRATES_11M0x0008)
167 ratebuf[len++] = 0x96;
168
169 put_tlv(ppkt, IEEE80211_ELEMID_RATES, ratebuf, len);
170 return len;
171}
172
173/* wihap_init()
174 *
175 * Initialize host AP data structures. Called even if port type is
176 * not AP. Caller MUST raise to splnet().
177 */
178void
179wihap_init(struct wi_softc *sc)
180{
181 int i;
182 struct wihap_info *whi = &sc->wi_hostap_info;
183
184 if (sc->sc_ic.ic_ific_ac.ac_if.if_flags & IFF_DEBUG0x4)
185 printf("wihap_init: sc=%p whi=%p\n", sc, whi);
186
187 bzero(whi, sizeof(struct wihap_info))__builtin_bzero((whi), (sizeof(struct wihap_info)));
188
189 if (sc->wi_ptype != WI_PORTTYPE_HOSTAP0x6)
190 return;
191
192 whi->apflags = WIHAPFL_ACTIVE0x0001;
193
194 TAILQ_INIT(&whi->sta_list)do { (&whi->sta_list)->tqh_first = ((void *)0); (&
whi->sta_list)->tqh_last = &(&whi->sta_list)
->tqh_first; } while (0)
;
195 for (i = 0; i < WI_STA_HASH_SIZE113; i++)
196 LIST_INIT(&whi->sta_hash[i])do { ((&whi->sta_hash[i])->lh_first) = ((void *)0);
} while (0)
;
197
198 whi->inactivity_time = WIHAP_DFLT_INACTIVITY_TIME(120);
199 timeout_set(&whi->tmo, wihap_timeout, sc);
200}
201
202/* wihap_sta_disassoc()
203 *
204 * Send a disassociation frame to a specified station.
205 */
206void
207wihap_sta_disassoc(struct wi_softc *sc, u_int8_t sta_addr[], u_int16_t reason)
208{
209 struct wi_80211_hdr *resp_hdr;
210 caddr_t pkt;
211
212 if (sc->sc_ic.ic_ific_ac.ac_if.if_flags & IFF_DEBUG0x4)
213 printf("Sending disassoc to sta %s\n", ether_sprintf(sta_addr));
214
215 /* Send disassoc packet. */
216 resp_hdr = (struct wi_80211_hdr *)sc->wi_txbuf;
217 bzero(resp_hdr, sizeof(struct wi_80211_hdr))__builtin_bzero((resp_hdr), (sizeof(struct wi_80211_hdr)));
218 resp_hdr->frame_ctl = WI_FTYPE_MGMT0x0000 | WI_STYPE_MGMT_DISAS0x00A0;
219 pkt = (caddr_t)&sc->wi_txbuf + sizeof(struct wi_80211_hdr);
220
221 bcopy(sta_addr, resp_hdr->addr1, ETHER_ADDR_LEN6);
222 bcopy(sc->sc_ic.ic_myaddr, resp_hdr->addr2, IEEE80211_ADDR_LEN6);
223 bcopy(sc->sc_ic.ic_myaddr, resp_hdr->addr3, IEEE80211_ADDR_LEN6);
224
225 put_hword(&pkt, reason);
226
227 wi_mgmt_xmit(sc, (caddr_t)&sc->wi_txbuf,
228 2 + sizeof(struct wi_80211_hdr));
229}
230
231/* wihap_sta_deauth()
232 *
233 * Send a deauthentication message to a specified station.
234 */
235void
236wihap_sta_deauth(struct wi_softc *sc, u_int8_t sta_addr[], u_int16_t reason)
237{
238 struct wi_80211_hdr *resp_hdr;
239 caddr_t pkt;
240
241 if (sc->sc_ic.ic_ific_ac.ac_if.if_flags & IFF_DEBUG0x4)
242 printf("Sending deauth to sta %s\n", ether_sprintf(sta_addr));
243
244 /* Send deauth packet. */
245 resp_hdr = (struct wi_80211_hdr *)sc->wi_txbuf;
246 bzero(resp_hdr, sizeof(struct wi_80211_hdr))__builtin_bzero((resp_hdr), (sizeof(struct wi_80211_hdr)));
247 resp_hdr->frame_ctl = htole16(WI_FTYPE_MGMT | WI_STYPE_MGMT_DEAUTH)((__uint16_t)(0x0000 | 0x00C0));
248 pkt = (caddr_t)&sc->wi_txbuf + sizeof(struct wi_80211_hdr);
249
250 bcopy(sta_addr, resp_hdr->addr1, ETHER_ADDR_LEN6);
251 bcopy(sc->sc_ic.ic_myaddr, resp_hdr->addr2, IEEE80211_ADDR_LEN6);
252 bcopy(sc->sc_ic.ic_myaddr, resp_hdr->addr3, IEEE80211_ADDR_LEN6);
253
254 put_hword(&pkt, reason);
255
256 wi_mgmt_xmit(sc, (caddr_t)&sc->wi_txbuf,
257 2 + sizeof(struct wi_80211_hdr));
258}
259
260/* wihap_shutdown()
261 *
262 * Disassociate all stations and free up data structures.
263 */
264void
265wihap_shutdown(struct wi_softc *sc)
266{
267 struct wihap_info *whi = &sc->wi_hostap_info;
268 struct wihap_sta_info *sta, *next;
269 int i, s;
270
271 if (sc->sc_ic.ic_ific_ac.ac_if.if_flags & IFF_DEBUG0x4)
272 printf("wihap_shutdown: sc=%p whi=%p\n", sc, whi);
273
274 if (!(whi->apflags & WIHAPFL_ACTIVE0x0001))
275 return;
276 whi->apflags = 0;
277
278 s = splnet()splraise(0x7);
279
280 /* Disable wihap inactivity timer. */
281 timeout_del(&whi->tmo);
282
283 /* Delete all stations from the list. */
284 for (sta = TAILQ_FIRST(&whi->sta_list)((&whi->sta_list)->tqh_first); sta != NULL((void *)0); sta = next) {
285 timeout_del(&sta->tmo);
286 if (sc->sc_ic.ic_ific_ac.ac_if.if_flags & IFF_DEBUG0x4)
287 printf("wihap_shutdown: free(sta=%p)\n", sta);
288 next = TAILQ_NEXT(sta, list)((sta)->list.tqe_next);
289 if (sta->challenge)
290 free(sta->challenge, M_TEMP127, 0);
291 free(sta, M_DEVBUF2, 0);
292 }
293 TAILQ_INIT(&whi->sta_list)do { (&whi->sta_list)->tqh_first = ((void *)0); (&
whi->sta_list)->tqh_last = &(&whi->sta_list)
->tqh_first; } while (0)
;
294
295 /* Broadcast disassoc and deauth to all the stations. */
296 if (sc->wi_flags & WI_FLAGS_ATTACHED0x0001) {
297 for (i = 0; i < 5; i++) {
298 wihap_sta_disassoc(sc, etherbroadcastaddr,
299 IEEE80211_REASON_ASSOC_LEAVE);
300 wihap_sta_deauth(sc, etherbroadcastaddr,
301 IEEE80211_REASON_AUTH_LEAVE);
302 DELAY(50)(*delay_func)(50);
303 }
304 }
305
306 splx(s)spllower(s);
307}
308
309/* sta_hash_func()
310 * Hash function for finding stations from ethernet address.
311 */
312static __inline int
313sta_hash_func(u_int8_t addr[])
314{
315 return ((addr[3] + addr[4] + addr[5]) % WI_STA_HASH_SIZE113);
316}
317
318/* addr_cmp(): Maybe this is a faster way to compare addresses? */
319static __inline int
320addr_cmp(u_int8_t a[], u_int8_t b[])
321{
322 return (*(u_int16_t *)(a + 4) == *(u_int16_t *)(b + 4) &&
323 *(u_int16_t *)(a + 2) == *(u_int16_t *)(b + 2) &&
324 *(u_int16_t *)(a ) == *(u_int16_t *)(b));
325}
326
327/* wihap_sta_movetail(): move sta to the tail of the station list in whi */
328static __inline void
329wihap_sta_movetail(struct wihap_info *whi, struct wihap_sta_info *sta)
330{
331 TAILQ_REMOVE(&whi->sta_list, sta, list)do { if (((sta)->list.tqe_next) != ((void *)0)) (sta)->
list.tqe_next->list.tqe_prev = (sta)->list.tqe_prev; else
(&whi->sta_list)->tqh_last = (sta)->list.tqe_prev
; *(sta)->list.tqe_prev = (sta)->list.tqe_next; ((sta)->
list.tqe_prev) = ((void *)-1); ((sta)->list.tqe_next) = ((
void *)-1); } while (0)
;
332 sta->flags &= ~WI_SIFLAGS_DEAD0x1000;
333 TAILQ_INSERT_TAIL(&whi->sta_list, sta, list)do { (sta)->list.tqe_next = ((void *)0); (sta)->list.tqe_prev
= (&whi->sta_list)->tqh_last; *(&whi->sta_list
)->tqh_last = (sta); (&whi->sta_list)->tqh_last =
&(sta)->list.tqe_next; } while (0)
;
334}
335
336void
337wihap_timeout(void *v)
338{
339 struct wi_softc *sc = v;
340 struct wihap_info *whi = &sc->wi_hostap_info;
341 struct wihap_sta_info *sta, *next;
342 int i, s;
343
344 s = splnet()splraise(0x7);
345
346 for (i = 10, sta = TAILQ_FIRST(&whi->sta_list)((&whi->sta_list)->tqh_first);
347 i != 0 && sta != NULL((void *)0) && (sta->flags & WI_SIFLAGS_DEAD0x1000);
348 i--, sta = next) {
349 next = TAILQ_NEXT(sta, list)((sta)->list.tqe_next);
350 if (timeout_pending(&sta->tmo)((&sta->tmo)->to_flags & 0x02)) {
351 /* Became alive again, move to end of list. */
352 wihap_sta_movetail(whi, sta);
353 } else if (sta->flags & WI_SIFLAGS_ASSOC0x0002) {
354 if (sc->sc_ic.ic_ific_ac.ac_if.if_flags & IFF_DEBUG0x4)
355 printf("wihap_timeout: disassoc due to inactivity: %s\n",
356 ether_sprintf(sta->addr));
357
358 /* Disassoc station. */
359 wihap_sta_disassoc(sc, sta->addr,
360 IEEE80211_REASON_ASSOC_EXPIRE);
361 sta->flags &= ~WI_SIFLAGS_ASSOC0x0002;
362
363 /*
364 * Move to end of the list and reset station timeout.
365 * We do this to make sure we don't get deauthed
366 * until inactivity_time seconds have passed.
367 */
368 wihap_sta_movetail(whi, sta);
369 timeout_add_sec(&sta->tmo, whi->inactivity_time);
370 } else if (sta->flags & WI_SIFLAGS_AUTHEN0x0001) {
371 if (sc->sc_ic.ic_ific_ac.ac_if.if_flags & IFF_DEBUG0x4)
372 printf("wihap_timeout: deauth due to inactivity: %s\n",
373 ether_sprintf(sta->addr));
374
375 /* Deauthenticate station. */
376 wihap_sta_deauth(sc, sta->addr,
377 IEEE80211_REASON_AUTH_EXPIRE);
378 sta->flags &= ~WI_SIFLAGS_AUTHEN0x0001;
379
380 /* Delete the station if it's not permanent. */
381 if (sta->flags & WI_SIFLAGS_PERM0x0004)
382 wihap_sta_movetail(whi, sta);
383 else
384 wihap_sta_delete(sta);
385 }
386 }
387
388 /* Restart the timeout if there are still dead stations left. */
389 sta = TAILQ_FIRST(&whi->sta_list)((&whi->sta_list)->tqh_first);
390 if (sta != NULL((void *)0) && (sta->flags & WI_SIFLAGS_DEAD0x1000))
391 timeout_add(&whi->tmo, 1); /* still work left, requeue */
392
393 splx(s)spllower(s);
394}
395
396void
397wihap_sta_timeout(void *v)
398{
399 struct wihap_sta_info *sta = v;
400 struct wi_softc *sc = sta->sc;
401 struct wihap_info *whi = &sc->wi_hostap_info;
402 int s;
403
404 s = splnet()splraise(0x7);
405
406 /* Mark sta as dead and move it to the head of the list. */
407 TAILQ_REMOVE(&whi->sta_list, sta, list)do { if (((sta)->list.tqe_next) != ((void *)0)) (sta)->
list.tqe_next->list.tqe_prev = (sta)->list.tqe_prev; else
(&whi->sta_list)->tqh_last = (sta)->list.tqe_prev
; *(sta)->list.tqe_prev = (sta)->list.tqe_next; ((sta)->
list.tqe_prev) = ((void *)-1); ((sta)->list.tqe_next) = ((
void *)-1); } while (0)
;
408 sta->flags |= WI_SIFLAGS_DEAD0x1000;
409 TAILQ_INSERT_HEAD(&whi->sta_list, sta, list)do { if (((sta)->list.tqe_next = (&whi->sta_list)->
tqh_first) != ((void *)0)) (&whi->sta_list)->tqh_first
->list.tqe_prev = &(sta)->list.tqe_next; else (&
whi->sta_list)->tqh_last = &(sta)->list.tqe_next
; (&whi->sta_list)->tqh_first = (sta); (sta)->list
.tqe_prev = &(&whi->sta_list)->tqh_first; } while
(0)
;
410
411 /* Add wihap timeout if we have not already done so. */
412 if (!timeout_pending(&whi->tmo)((&whi->tmo)->to_flags & 0x02))
413 timeout_add(&whi->tmo, hz / 10);
414
415 splx(s)spllower(s);
416}
417
418/* wihap_sta_delete()
419 * Delete a single station and free up its data structure.
420 * Caller must raise to splnet().
421 */
422void
423wihap_sta_delete(struct wihap_sta_info *sta)
424{
425 struct wi_softc *sc = sta->sc;
426 struct wihap_info *whi = &sc->wi_hostap_info;
427 int i = sta->asid - 0xc001;
428
429 timeout_del(&sta->tmo);
430
431 whi->asid_inuse_mask[i >> 4] &= ~(1UL << (i & 0xf));
432
433 TAILQ_REMOVE(&whi->sta_list, sta, list)do { if (((sta)->list.tqe_next) != ((void *)0)) (sta)->
list.tqe_next->list.tqe_prev = (sta)->list.tqe_prev; else
(&whi->sta_list)->tqh_last = (sta)->list.tqe_prev
; *(sta)->list.tqe_prev = (sta)->list.tqe_next; ((sta)->
list.tqe_prev) = ((void *)-1); ((sta)->list.tqe_next) = ((
void *)-1); } while (0)
;
434 LIST_REMOVE(sta, hash)do { if ((sta)->hash.le_next != ((void *)0)) (sta)->hash
.le_next->hash.le_prev = (sta)->hash.le_prev; *(sta)->
hash.le_prev = (sta)->hash.le_next; ((sta)->hash.le_prev
) = ((void *)-1); ((sta)->hash.le_next) = ((void *)-1); } while
(0)
;
435 if (sta->challenge)
436 free(sta->challenge, M_TEMP127, 0);
437 free(sta, M_DEVBUF2, 0);
438 whi->n_stations--;
439}
440
441/* wihap_sta_alloc()
442 *
443 * Create a new station data structure and put it in the list
444 * and hash table.
445 */
446struct wihap_sta_info *
447wihap_sta_alloc(struct wi_softc *sc, u_int8_t *addr)
448{
449 struct wihap_info *whi = &sc->wi_hostap_info;
450 struct wihap_sta_info *sta;
451 int i, hash = sta_hash_func(addr);
452
453 /* Allocate structure. */
454 sta = malloc(sizeof(*sta), M_DEVBUF2, M_NOWAIT0x0002 | M_ZERO0x0008);
455 if (sta == NULL((void *)0))
456 return (NULL((void *)0));
457
458 /* Allocate an ASID. */
459 i=hash<<4;
460 while (whi->asid_inuse_mask[i >> 4] & (1UL << (i & 0xf)))
461 i = (i == (WI_STA_HASH_SIZE113 << 4) - 1) ? 0 : (i + 1);
462 whi->asid_inuse_mask[i >> 4] |= (1UL << (i & 0xf));
463 sta->asid = 0xc001 + i;
464
465 /* Insert in list and hash list. */
466 TAILQ_INSERT_TAIL(&whi->sta_list, sta, list)do { (sta)->list.tqe_next = ((void *)0); (sta)->list.tqe_prev
= (&whi->sta_list)->tqh_last; *(&whi->sta_list
)->tqh_last = (sta); (&whi->sta_list)->tqh_last =
&(sta)->list.tqe_next; } while (0)
;
467 LIST_INSERT_HEAD(&whi->sta_hash[hash], sta, hash)do { if (((sta)->hash.le_next = (&whi->sta_hash[hash
])->lh_first) != ((void *)0)) (&whi->sta_hash[hash]
)->lh_first->hash.le_prev = &(sta)->hash.le_next
; (&whi->sta_hash[hash])->lh_first = (sta); (sta)->
hash.le_prev = &(&whi->sta_hash[hash])->lh_first
; } while (0)
;
468
469 sta->sc = sc;
470 whi->n_stations++;
471 bcopy(addr, &sta->addr, ETHER_ADDR_LEN6);
472 timeout_set(&sta->tmo, wihap_sta_timeout, sta);
473 timeout_add_sec(&sta->tmo, whi->inactivity_time);
474
475 return (sta);
476}
477
478/* wihap_sta_find()
479 *
480 * Find station structure given address.
481 */
482struct wihap_sta_info *
483wihap_sta_find(struct wihap_info *whi, u_int8_t *addr)
484{
485 int i;
486 struct wihap_sta_info *sta;
487
488 i = sta_hash_func(addr);
489 LIST_FOREACH(sta, &whi->sta_hash[i], hash)for((sta) = ((&whi->sta_hash[i])->lh_first); (sta)!=
((void *)0); (sta) = ((sta)->hash.le_next))
490 if (addr_cmp(addr, sta->addr))
491 return sta;
492
493 return (NULL((void *)0));
494}
495
496static __inline int
497wihap_check_rates(struct wihap_sta_info *sta, u_int8_t rates[], int rates_len)
498{
499 struct wi_softc *sc = sta->sc;
500 int i;
501
502 sta->rates = 0;
503 sta->tx_max_rate = 0;
504 for (i = 0; i < rates_len; i++)
505 switch (rates[i] & 0x7f) {
506 case 0x02:
507 sta->rates |= WI_SUPPRATES_1M0x0001;
508 break;
509 case 0x04:
510 sta->rates |= WI_SUPPRATES_2M0x0002;
511 if (sta->tx_max_rate < 1)
512 sta->tx_max_rate = 1;
513 break;
514 case 0x0b:
515 sta->rates |= WI_SUPPRATES_5M0x0004;
516 if (sta->tx_max_rate < 2)
517 sta->tx_max_rate = 2;
518 break;
519 case 0x16:
520 sta->rates |= WI_SUPPRATES_11M0x0008;
521 sta->tx_max_rate = 3;
522 break;
523 }
524
525 sta->rates &= sc->wi_supprates;
526 sta->tx_curr_rate = sta->tx_max_rate;
527
528 return (sta->rates == 0 ? -1 : 0);
529}
530
531
532/* wihap_auth_req()
533 *
534 * Handle incoming authentication request.
535 */
536void
537wihap_auth_req(struct wi_softc *sc, struct wi_frame *rxfrm,
538 caddr_t pkt, int len)
539{
540 struct wihap_info *whi = &sc->wi_hostap_info;
541 struct wihap_sta_info *sta;
542 int i, s;
543
544 u_int16_t algo;
545 u_int16_t seq;
546 u_int16_t status;
547 int challenge_len;
548 u_int32_t challenge[32];
549
550 struct wi_80211_hdr *resp_hdr;
551
552 if (len < 6) {
553 if (sc->sc_ic.ic_ific_ac.ac_if.if_flags & IFF_DEBUG0x4)
554 printf("wihap_auth_req: station %s short request\n",
555 ether_sprintf(rxfrm->wi_addr2));
556 return;
557 }
558
559 /* Break open packet. */
560 algo = take_hword(&pkt, &len);
561 seq = take_hword(&pkt, &len);
562 status = take_hword(&pkt, &len);
Value stored to 'status' is never read
563 if (sc->sc_ic.ic_ific_ac.ac_if.if_flags & IFF_DEBUG0x4)
564 printf("wihap_auth_req: station %s algo=0x%x seq=0x%x\n",
565 ether_sprintf(rxfrm->wi_addr2), algo, seq);
566
567 /* Ignore vendor private tlv (if any). */
568 (void)take_tlv(&pkt, &len, IEEE80211_ELEMID_VENDOR, challenge,
569 sizeof(challenge));
570
571 challenge_len = 0;
572 if (len > 0 && (challenge_len = take_tlv(&pkt, &len,
573 IEEE80211_ELEMID_CHALLENGE, challenge, sizeof(challenge))) < 0) {
574 status = IEEE80211_STATUS_CHALLENGE;
575 goto fail;
576 }
577
578 /* Find or create station info. */
579 sta = wihap_sta_find(whi, rxfrm->wi_addr2);
580 if (sta == NULL((void *)0)) {
581
582 /* Are we allowing new stations?
583 */
584 if (whi->apflags & WIHAPFL_MAC_FILT0x0002) {
585 status = IEEE80211_STATUS_OTHER; /* XXX */
586 goto fail;
587 }
588
589 /* Check for too many stations.
590 */
591 if (whi->n_stations >= WIHAP_MAX_STATIONS1800) {
592 status = IEEE80211_STATUS_TOOMANY;
593 goto fail;
594 }
595
596 if (sc->sc_ic.ic_ific_ac.ac_if.if_flags & IFF_DEBUG0x4)
597 printf("wihap_auth_req: new station\n");
598
599 /* Create new station. */
600 s = splnet()splraise(0x7);
601 sta = wihap_sta_alloc(sc, rxfrm->wi_addr2);
602 splx(s)spllower(s);
603 if (sta == NULL((void *)0)) {
604 /* Out of memory! */
605 status = IEEE80211_STATUS_TOOMANY;
606 goto fail;
607 }
608 }
609 timeout_add_sec(&sta->tmo, whi->inactivity_time);
610
611 /* Note: it's okay to leave the station info structure around
612 * if the authen fails. It'll be timed out eventually.
613 */
614 switch (algo) {
615 case IEEE80211_AUTH_ALG_OPEN0x0000:
616 if (sc->wi_authtype != IEEE80211_AUTH_OPEN1) {
617 status = IEEE80211_STATUS_ALG;
618 goto fail;
619 }
620 if (seq != 1) {
621 status = IEEE80211_STATUS_SEQUENCE;
622 goto fail;
623 }
624 challenge_len = 0;
625 sta->flags |= WI_SIFLAGS_AUTHEN0x0001;
626 break;
627 case IEEE80211_AUTH_ALG_SHARED0x0001:
628 if (sc->wi_authtype != IEEE80211_AUTH_SHARED2) {
629 status = IEEE80211_STATUS_ALG;
630 goto fail;
631 }
632 switch (seq) {
633 case 1:
634 /* Create a challenge frame. */
635 if (!sta->challenge) {
636 sta->challenge = malloc(128, M_TEMP127, M_NOWAIT0x0002);
637 if (!sta->challenge)
638 return;
639 }
640 for (i = 0; i < 32; i++)
641 challenge[i] = sta->challenge[i] =
642 arc4random();
643
644 if (sc->sc_ic.ic_ific_ac.ac_if.if_flags & IFF_DEBUG0x4)
645 printf("\tchallenge: 0x%x 0x%x ...\n",
646 challenge[0], challenge[1]);
647 challenge_len = 128;
648 break;
649 case 3:
650 if (challenge_len != 128 || !sta->challenge ||
651 !(letoh16(rxfrm->wi_frame_ctl)((__uint16_t)(rxfrm->wi_frame_ctl)) & WI_FCTL_WEP0x4000)) {
652 status = IEEE80211_STATUS_CHALLENGE;
653 goto fail;
654 }
655
656 for (i=0; i<32; i++)
657 if (sta->challenge[i] != challenge[i]) {
658 status = IEEE80211_STATUS_CHALLENGE;
659 goto fail;
660 }
661
662 sta->flags |= WI_SIFLAGS_AUTHEN0x0001;
663 free(sta->challenge, M_TEMP127, 0);
664 sta->challenge = NULL((void *)0);
665 challenge_len = 0;
666 break;
667 default:
668 status = IEEE80211_STATUS_SEQUENCE;
669 goto fail;
670 } /* switch (seq) */
671 break;
672 default:
673 if (sc->sc_ic.ic_ific_ac.ac_if.if_flags & IFF_DEBUG0x4)
674 printf("wihap_auth_req: algorithm unsupported: 0x%x\n",
675 algo);
676 status = IEEE80211_STATUS_ALG;
677 goto fail;
678 } /* switch (algo) */
679
680 status = IEEE80211_STATUS_SUCCESS;
681
682fail:
683 if (sc->sc_ic.ic_ific_ac.ac_if.if_flags & IFF_DEBUG0x4)
684 printf("wihap_auth_req: returns status=0x%x\n", status);
685
686 /* Send response. */
687 resp_hdr = (struct wi_80211_hdr *)&sc->wi_txbuf;
688 bzero(resp_hdr, sizeof(struct wi_80211_hdr))__builtin_bzero((resp_hdr), (sizeof(struct wi_80211_hdr)));
689 resp_hdr->frame_ctl = htole16(WI_FTYPE_MGMT | WI_STYPE_MGMT_AUTH)((__uint16_t)(0x0000 | 0x00B0));
690 bcopy(rxfrm->wi_addr2, resp_hdr->addr1, ETHER_ADDR_LEN6);
691 bcopy(sc->sc_ic.ic_myaddr, resp_hdr->addr2, IEEE80211_ADDR_LEN6);
692 bcopy(sc->sc_ic.ic_myaddr, resp_hdr->addr3, IEEE80211_ADDR_LEN6);
693
694 pkt = (caddr_t)&sc->wi_txbuf + sizeof(struct wi_80211_hdr);
695 put_hword(&pkt, algo);
696 put_hword(&pkt, seq + 1);
697 put_hword(&pkt, status);
698 if (challenge_len > 0)
699 put_tlv(&pkt, IEEE80211_ELEMID_CHALLENGE,
700 challenge, challenge_len);
701
702 wi_mgmt_xmit(sc, (caddr_t)&sc->wi_txbuf,
703 6 + sizeof(struct wi_80211_hdr) +
704 (challenge_len > 0 ? challenge_len + 2 : 0));
705}
706
707
708/* wihap_assoc_req()
709 *
710 * Handle incoming association and reassociation requests.
711 */
712void
713wihap_assoc_req(struct wi_softc *sc, struct wi_frame *rxfrm,
714 caddr_t pkt, int len)
715{
716 struct wihap_info *whi = &sc->wi_hostap_info;
717 struct wihap_sta_info *sta;
718 struct wi_80211_hdr *resp_hdr;
719 u_int16_t capinfo;
720 u_int16_t lstintvl;
721 u_int8_t rates[12];
722 int ssid_len, rates_len;
723 struct ieee80211_nwid ssid;
724 u_int16_t status;
725 u_int16_t asid = 0;
726
727 if (len < 8)
728 return;
729
730 /* Pull out request parameters. */
731 capinfo = take_hword(&pkt, &len);
732 lstintvl = take_hword(&pkt, &len);
733
734 if ((rxfrm->wi_frame_ctl & htole16(WI_FCTL_STYPE)((__uint16_t)(0x00F0))) ==
735 htole16(WI_STYPE_MGMT_REASREQ)((__uint16_t)(0x0020))) {
736 if (len < 6)
737 return;
738 /* Eat the MAC address of the current AP */
739 take_hword(&pkt, &len);
740 take_hword(&pkt, &len);
741 take_hword(&pkt, &len);
742 }
743
744 if ((ssid_len = take_tlv(&pkt, &len, IEEE80211_ELEMID_SSID,
745 ssid.i_nwid, sizeof(ssid))) < 0)
746 return;
747 ssid.i_len = ssid_len;
748 if ((rates_len = take_tlv(&pkt, &len, IEEE80211_ELEMID_RATES,
749 rates, sizeof(rates))) < 0)
750 return;
751
752 if (sc->sc_ic.ic_ific_ac.ac_if.if_flags & IFF_DEBUG0x4)
753 printf("wihap_assoc_req: from station %s\n",
754 ether_sprintf(rxfrm->wi_addr2));
755
756 /* If SSID doesn't match, simply drop. */
757 if (sc->wi_net_name.i_len != ssid.i_len ||
758 memcmp(sc->wi_net_name.i_nwid, ssid.i_nwid, ssid.i_len)__builtin_memcmp((sc->wi_net_name.i_nwid), (ssid.i_nwid), (
ssid.i_len))
) {
759
760 if (sc->sc_ic.ic_ific_ac.ac_if.if_flags & IFF_DEBUG0x4)
761 printf("wihap_assoc_req: bad ssid: '%.*s' != '%.*s'\n",
762 ssid.i_len, ssid.i_nwid, sc->wi_net_name.i_len,
763 sc->wi_net_name.i_nwid);
764 return;
765 }
766
767 /* Is this station authenticated yet? */
768 sta = wihap_sta_find(whi, rxfrm->wi_addr2);
769 if (sta == NULL((void *)0) || !(sta->flags & WI_SIFLAGS_AUTHEN0x0001)) {
770 wihap_sta_deauth(sc, rxfrm->wi_addr2,
771 IEEE80211_REASON_NOT_AUTHED);
772 return;
773 }
774
775 /* Check supported rates against ours. */
776 if (wihap_check_rates(sta, rates, rates_len) < 0) {
777 if (sc->sc_ic.ic_ific_ac.ac_if.if_flags & IFF_DEBUG0x4)
778 printf("wihap_assoc_req: rates mismatch.\n");
779 status = IEEE80211_STATUS_BASIC_RATE;
780 goto fail;
781 }
782
783 /* Check capinfo.
784 * Check for ESS, not IBSS.
785 * Check WEP/PRIVACY flags match.
786 * Refuse stations requesting to be put on CF-polling list.
787 */
788 sta->capinfo = capinfo;
789 status = IEEE80211_STATUS_CAPINFO;
790 if ((capinfo & (IEEE80211_CAPINFO_ESS0x0001 | IEEE80211_CAPINFO_IBSS0x0002)) !=
791 IEEE80211_CAPINFO_ESS0x0001) {
792 if (sc->sc_ic.ic_ific_ac.ac_if.if_flags & IFF_DEBUG0x4)
793 printf("wihap_assoc_req: capinfo: not ESS: "
794 "capinfo=0x%x\n", capinfo);
795 goto fail;
796
797 }
798 if ((sc->wi_use_wep && !(capinfo & IEEE80211_CAPINFO_PRIVACY0x0010)) ||
799 (!sc->wi_use_wep && (capinfo & IEEE80211_CAPINFO_PRIVACY0x0010))) {
800 if (sc->sc_ic.ic_ific_ac.ac_if.if_flags & IFF_DEBUG0x4)
801 printf("wihap_assoc_req: WEP flag mismatch: "
802 "capinfo=0x%x\n", capinfo);
803 goto fail;
804 }
805 if ((capinfo & (IEEE80211_CAPINFO_CF_POLLABLE0x0004 |
806 IEEE80211_CAPINFO_CF_POLLREQ0x0008)) == IEEE80211_CAPINFO_CF_POLLABLE0x0004) {
807 if (sc->sc_ic.ic_ific_ac.ac_if.if_flags & IFF_DEBUG0x4)
808 printf("wihap_assoc_req: polling not supported: "
809 "capinfo=0x%x\n", capinfo);
810 goto fail;
811 }
812
813 /* Use ASID is allocated by whi_sta_alloc(). */
814 asid = sta->asid;
815
816 if (sta->flags & WI_SIFLAGS_ASSOC0x0002) {
817 if (sc->sc_ic.ic_ific_ac.ac_if.if_flags & IFF_DEBUG0x4)
818 printf("wihap_assoc_req: already assoc'ed?\n");
819 }
820
821 sta->flags |= WI_SIFLAGS_ASSOC0x0002;
822 timeout_add_sec(&sta->tmo, whi->inactivity_time);
823 status = IEEE80211_STATUS_SUCCESS;
824
825fail:
826 if (sc->sc_ic.ic_ific_ac.ac_if.if_flags & IFF_DEBUG0x4)
827 printf("wihap_assoc_req: returns status=0x%x\n", status);
828
829 /* Send response. */
830 resp_hdr = (struct wi_80211_hdr *)&sc->wi_txbuf;
831 bzero(resp_hdr, sizeof(struct wi_80211_hdr))__builtin_bzero((resp_hdr), (sizeof(struct wi_80211_hdr)));
832 resp_hdr->frame_ctl = htole16(WI_FTYPE_MGMT | WI_STYPE_MGMT_ASRESP)((__uint16_t)(0x0000 | 0x0010));
833 pkt = (caddr_t)&sc->wi_txbuf + sizeof(struct wi_80211_hdr);
834
835 bcopy(rxfrm->wi_addr2, resp_hdr->addr1, ETHER_ADDR_LEN6);
836 bcopy(sc->sc_ic.ic_myaddr, resp_hdr->addr2, IEEE80211_ADDR_LEN6);
837 bcopy(sc->sc_ic.ic_myaddr, resp_hdr->addr3, IEEE80211_ADDR_LEN6);
838
839 put_hword(&pkt, capinfo);
840 put_hword(&pkt, status);
841 put_hword(&pkt, asid);
842 rates_len = put_rates(&pkt, sc->wi_supprates);
843
844 wi_mgmt_xmit(sc, (caddr_t)&sc->wi_txbuf,
845 8 + rates_len + sizeof(struct wi_80211_hdr));
846}
847
848/* wihap_deauth_req()
849 *
850 * Handle deauthentication requests. Delete the station.
851 */
852void
853wihap_deauth_req(struct wi_softc *sc, struct wi_frame *rxfrm,
854 caddr_t pkt, int len)
855{
856 struct wihap_info *whi = &sc->wi_hostap_info;
857 struct wihap_sta_info *sta;
858 u_int16_t reason;
859
860 if (len<2)
861 return;
862
863 reason = take_hword(&pkt, &len);
864
865 sta = wihap_sta_find(whi, rxfrm->wi_addr2);
866 if (sta == NULL((void *)0)) {
867 if (sc->sc_ic.ic_ific_ac.ac_if.if_flags & IFF_DEBUG0x4)
868 printf("wihap_deauth_req: unknown station: %s\n",
869 ether_sprintf(rxfrm->wi_addr2));
870 }
871 else
872 wihap_sta_delete(sta);
873}
874
875/* wihap_disassoc_req()
876 *
877 * Handle disassociation requests. Just reset the assoc flag.
878 * We'll free up the station resources when we get a deauth
879 * request or when it times out.
880 */
881void
882wihap_disassoc_req(struct wi_softc *sc, struct wi_frame *rxfrm,
883 caddr_t pkt, int len)
884{
885 struct wihap_info *whi = &sc->wi_hostap_info;
886 struct wihap_sta_info *sta;
887 u_int16_t reason;
888
889 if (len < 2)
890 return;
891
892 reason = take_hword(&pkt, &len);
893
894 sta = wihap_sta_find(whi, rxfrm->wi_addr2);
895 if (sta == NULL((void *)0)) {
896 if (sc->sc_ic.ic_ific_ac.ac_if.if_flags & IFF_DEBUG0x4)
897 printf("wihap_disassoc_req: unknown station: %s\n",
898 ether_sprintf(rxfrm->wi_addr2));
899 }
900 else if (!(sta->flags & WI_SIFLAGS_AUTHEN0x0001)) {
901 /*
902 * If station is not authenticated, send deauthentication
903 * frame.
904 */
905 wihap_sta_deauth(sc, rxfrm->wi_addr2,
906 IEEE80211_REASON_NOT_AUTHED);
907 return;
908 }
909 else
910 sta->flags &= ~WI_SIFLAGS_ASSOC0x0002;
911}
912
913/* wihap_debug_frame_type()
914 *
915 * Print out frame type. Used in early debugging.
916 */
917static __inline void
918wihap_debug_frame_type(struct wi_frame *rxfrm)
919{
920 printf("wihap_mgmt_input: len=%d ", letoh16(rxfrm->wi_dat_len)((__uint16_t)(rxfrm->wi_dat_len)));
921
922 if ((rxfrm->wi_frame_ctl & htole16(WI_FCTL_FTYPE)((__uint16_t)(0x000C))) ==
923 htole16(WI_FTYPE_MGMT)((__uint16_t)(0x0000))) {
924
925 printf("MGMT: ");
926
927 switch (letoh16(rxfrm->wi_frame_ctl)((__uint16_t)(rxfrm->wi_frame_ctl)) & WI_FCTL_STYPE0x00F0) {
928 case WI_STYPE_MGMT_ASREQ0x0000:
929 printf("assoc req: \n");
930 break;
931 case WI_STYPE_MGMT_ASRESP0x0010:
932 printf("assoc resp: \n");
933 break;
934 case WI_STYPE_MGMT_REASREQ0x0020:
935 printf("reassoc req: \n");
936 break;
937 case WI_STYPE_MGMT_REASRESP0x0030:
938 printf("reassoc resp: \n");
939 break;
940 case WI_STYPE_MGMT_PROBEREQ0x0040:
941 printf("probe req: \n");
942 break;
943 case WI_STYPE_MGMT_PROBERESP0x0050:
944 printf("probe resp: \n");
945 break;
946 case WI_STYPE_MGMT_BEACON0x0080:
947 printf("beacon: \n");
948 break;
949 case WI_STYPE_MGMT_ATIM0x0090:
950 printf("ann traf ind \n");
951 break;
952 case WI_STYPE_MGMT_DISAS0x00A0:
953 printf("disassociation: \n");
954 break;
955 case WI_STYPE_MGMT_AUTH0x00B0:
956 printf("auth: \n");
957 break;
958 case WI_STYPE_MGMT_DEAUTH0x00C0:
959 printf("deauth: \n");
960 break;
961 default:
962 printf("unknown (stype=0x%x)\n",
963 letoh16(rxfrm->wi_frame_ctl)((__uint16_t)(rxfrm->wi_frame_ctl)) & WI_FCTL_STYPE0x00F0);
964 }
965
966 }
967 else {
968 printf("ftype=0x%x (ctl=0x%x)\n",
969 letoh16(rxfrm->wi_frame_ctl)((__uint16_t)(rxfrm->wi_frame_ctl)) & WI_FCTL_FTYPE0x000C,
970 letoh16(rxfrm->wi_frame_ctl)((__uint16_t)(rxfrm->wi_frame_ctl)));
971 }
972}
973
974/*
975 * wihap_mgmt_input:
976 *
977 * Called for each management frame received in host ap mode.
978 * wihap_mgmt_input() is expected to free the mbuf.
979 */
980void
981wihap_mgmt_input(struct wi_softc *sc, struct wi_frame *rxfrm, struct mbuf *m)
982{
983 caddr_t pkt;
984 int s, len;
985
986 if (sc->sc_ic.ic_ific_ac.ac_if.if_flags & IFF_DEBUG0x4)
987 wihap_debug_frame_type(rxfrm);
988
989 pkt = mtod(m, caddr_t)((caddr_t)((m)->m_hdr.mh_data)) + WI_802_11_OFFSET_RAW0x3C;
990 len = m->m_lenm_hdr.mh_len - WI_802_11_OFFSET_RAW0x3C;
991
992 if ((rxfrm->wi_frame_ctl & htole16(WI_FCTL_FTYPE)((__uint16_t)(0x000C))) ==
993 htole16(WI_FTYPE_MGMT)((__uint16_t)(0x0000))) {
994
995 /* any of the following will mess w/ the station list */
996 s = splsoftclock()splraise(0x4);
997 switch (letoh16(rxfrm->wi_frame_ctl)((__uint16_t)(rxfrm->wi_frame_ctl)) & WI_FCTL_STYPE0x00F0) {
998 case WI_STYPE_MGMT_ASREQ0x0000:
999 wihap_assoc_req(sc, rxfrm, pkt, len);
1000 break;
1001 case WI_STYPE_MGMT_ASRESP0x0010:
1002 break;
1003 case WI_STYPE_MGMT_REASREQ0x0020:
1004 wihap_assoc_req(sc, rxfrm, pkt, len);
1005 break;
1006 case WI_STYPE_MGMT_REASRESP0x0030:
1007 break;
1008 case WI_STYPE_MGMT_PROBEREQ0x0040:
1009 break;
1010 case WI_STYPE_MGMT_PROBERESP0x0050:
1011 break;
1012 case WI_STYPE_MGMT_BEACON0x0080:
1013 break;
1014 case WI_STYPE_MGMT_ATIM0x0090:
1015 break;
1016 case WI_STYPE_MGMT_DISAS0x00A0:
1017 wihap_disassoc_req(sc, rxfrm, pkt, len);
1018 break;
1019 case WI_STYPE_MGMT_AUTH0x00B0:
1020 wihap_auth_req(sc, rxfrm, pkt, len);
1021 break;
1022 case WI_STYPE_MGMT_DEAUTH0x00C0:
1023 wihap_deauth_req(sc, rxfrm, pkt, len);
1024 break;
1025 }
1026 splx(s)spllower(s);
1027 }
1028
1029 m_freem(m);
1030}
1031
1032/* wihap_sta_is_assoc()
1033 *
1034 * Determine if a station is assoc'ed. Update its activity
1035 * counter as a side-effect.
1036 */
1037int
1038wihap_sta_is_assoc(struct wihap_info *whi, u_int8_t addr[])
1039{
1040 struct wihap_sta_info *sta;
1041
1042 sta = wihap_sta_find(whi, addr);
1043 if (sta != NULL((void *)0) && (sta->flags & WI_SIFLAGS_ASSOC0x0002)) {
1044 /* Keep it active. */
1045 timeout_add_sec(&sta->tmo, whi->inactivity_time);
1046 return (1);
1047 }
1048
1049 return (0);
1050}
1051
1052/* wihap_check_tx()
1053 *
1054 * Determine if a station is assoc'ed, get its tx rate, and update
1055 * its activity.
1056 */
1057int
1058wihap_check_tx(struct wihap_info *whi, u_int8_t addr[], u_int8_t *txrate)
1059{
1060 struct wihap_sta_info *sta;
1061 static u_int8_t txratetable[] = { 10, 20, 55, 110 };
1062 int s;
1063
1064 if (addr[0] & 0x01) {
1065 *txrate = 0; /* XXX: multicast rate? */
1066 return (1);
1067 }
1068
1069 s = splsoftclock()splraise(0x4);
1070 sta = wihap_sta_find(whi, addr);
1071 if (sta != NULL((void *)0) && (sta->flags & WI_SIFLAGS_ASSOC0x0002)) {
1072 /* Keep it active. */
1073 timeout_add_sec(&sta->tmo, whi->inactivity_time);
1074 *txrate = txratetable[sta->tx_curr_rate];
1075 splx(s)spllower(s);
1076 return (1);
1077 }
1078 splx(s)spllower(s);
1079
1080 return (0);
1081}
1082
1083/*
1084 * wihap_data_input()
1085 *
1086 * Handle all data input on interface when in Host AP mode.
1087 * Some packets are destined for this machine, others are
1088 * repeated to other stations.
1089 *
1090 * If wihap_data_input() returns a non-zero, it has processed
1091 * the packet and will free the mbuf.
1092 */
1093int
1094wihap_data_input(struct wi_softc *sc, struct wi_frame *rxfrm, struct mbuf *m)
1095{
1096 struct ifnet *ifp = &sc->sc_ic.ic_ific_ac.ac_if;
1097 struct wihap_info *whi = &sc->wi_hostap_info;
1098 struct wihap_sta_info *sta;
1099 int mcast, s;
1100 u_int16_t fctl;
1101
1102 /*
1103 * TODS flag must be set. However, Lucent cards set NULLFUNC but
1104 * not TODS when probing an AP to see if it is alive after it has
1105 * been down for a while. We accept these probe packets and send a
1106 * disassoc packet later on if the station is not already associated.
1107 */
1108 fctl = letoh16(rxfrm->wi_frame_ctl)((__uint16_t)(rxfrm->wi_frame_ctl));
1109 if (!(fctl & WI_FCTL_TODS0x0100) && !(fctl & WI_STYPE_NULLFUNC0x0040)) {
1110 if (ifp->if_flags & IFF_DEBUG0x4)
1111 printf("wihap_data_input: no TODS src=%s, fctl=0x%x\n",
1112 ether_sprintf(rxfrm->wi_addr2), fctl);
1113 m_freem(m);
1114 return (1);
1115 }
1116
1117 /* Check BSSID. (Is this necessary?) */
1118 if (!addr_cmp(rxfrm->wi_addr1, sc->sc_ic.ic_myaddr)) {
1119 if (ifp->if_flags & IFF_DEBUG0x4)
1120 printf("wihap_data_input: incorrect bss: %s\n",
1121 ether_sprintf(rxfrm->wi_addr1));
1122 m_freem(m);
1123 return (1);
1124 }
1125
1126 s = splsoftclock()splraise(0x4);
1127
1128 /* Find source station. */
1129 sta = wihap_sta_find(whi, rxfrm->wi_addr2);
1130
1131 /* Source station must be associated. */
1132 if (sta == NULL((void *)0) || !(sta->flags & WI_SIFLAGS_ASSOC0x0002)) {
1133 if (ifp->if_flags & IFF_DEBUG0x4)
1134 printf("wihap_data_input: dropping unassoc src %s\n",
1135 ether_sprintf(rxfrm->wi_addr2));
1136 wihap_sta_disassoc(sc, rxfrm->wi_addr2,
1137 IEEE80211_REASON_ASSOC_LEAVE);
1138 splx(s)spllower(s);
1139 m_freem(m);
1140 return (1);
1141 }
1142
1143 timeout_add_sec(&sta->tmo, whi->inactivity_time);
1144 sta->sig_info = letoh16(rxfrm->wi_q_info)((__uint16_t)(rxfrm->wi_q_info));
1145
1146 splx(s)spllower(s);
1147
1148 /* Repeat this packet to BSS? */
1149 mcast = (rxfrm->wi_addr3[0] & 0x01) != 0;
1150 if (mcast || wihap_sta_is_assoc(whi, rxfrm->wi_addr3)) {
1151
1152 /* If it's multicast, make a copy.
1153 */
1154 if (mcast) {
1155 m = m_copym(m, 0, M_COPYALL1000000000, M_DONTWAIT0x0002);
1156 if (m == NULL((void *)0))
1157 return (0);
1158 m->m_flagsm_hdr.mh_flags |= M_MCAST0x0200; /* XXX */
1159 }
1160
1161 /* Queue up for repeating.
1162 */
1163 if_enqueue(ifp, m);
1164 return (!mcast);
1165 }
1166
1167 return (0);
1168}
1169
1170/* wihap_ioctl()
1171 *
1172 * Handle Host AP specific ioctls. Called from wi_ioctl().
1173 */
1174int
1175wihap_ioctl(struct wi_softc *sc, u_long command, caddr_t data)
1176{
1177 struct proc *p = curproc({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r"
(__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self)));
__ci;})->ci_curproc
;
1178 struct ifreq *ifr = (struct ifreq *) data;
1179 struct wihap_info *whi = &sc->wi_hostap_info;
1180 struct wihap_sta_info *sta;
1181 struct hostap_getall reqall;
1182 struct hostap_sta reqsta;
1183 struct hostap_sta stabuf;
1184 int s, error = 0, n, flag;
1185
1186 struct ieee80211_nodereq nr;
1187 struct ieee80211_nodereq_all *na;
1188
1189 if (!(sc->sc_ic.ic_ific_ac.ac_if.if_flags & IFF_RUNNING0x40))
1190 return ENODEV19;
1191
1192 switch (command) {
1193 case SIOCHOSTAP_DEL(((unsigned long)0x80000000|(unsigned long)0x40000000) | ((sizeof
(struct ifreq) & 0x1fff) << 16) | ((('i')) <<
8) | ((202)))
:
1194 if ((error = suser(p)))
1195 break;
1196 if ((error = copyin(ifr->ifr_dataifr_ifru.ifru_data, &reqsta, sizeof(reqsta))))
1197 break;
1198 s = splnet()splraise(0x7);
1199 sta = wihap_sta_find(whi, reqsta.addr);
1200 if (sta == NULL((void *)0))
1201 error = ENOENT2;
1202 else {
1203 /* Disassociate station. */
1204 if (sta->flags & WI_SIFLAGS_ASSOC0x0002)
1205 wihap_sta_disassoc(sc, sta->addr,
1206 IEEE80211_REASON_ASSOC_LEAVE);
1207 /* Deauth station. */
1208 if (sta->flags & WI_SIFLAGS_AUTHEN0x0001)
1209 wihap_sta_deauth(sc, sta->addr,
1210 IEEE80211_REASON_AUTH_LEAVE);
1211
1212 wihap_sta_delete(sta);
1213 }
1214 splx(s)spllower(s);
1215 break;
1216
1217 case SIOCHOSTAP_GET(((unsigned long)0x80000000|(unsigned long)0x40000000) | ((sizeof
(struct ifreq) & 0x1fff) << 16) | ((('i')) <<
8) | ((200)))
:
1218 if ((error = copyin(ifr->ifr_dataifr_ifru.ifru_data, &reqsta, sizeof(reqsta))))
1219 break;
1220 s = splnet()splraise(0x7);
1221 sta = wihap_sta_find(whi, reqsta.addr);
1222 if (sta == NULL((void *)0))
1223 error = ENOENT2;
1224 else {
1225 reqsta.flags = sta->flags;
1226 reqsta.asid = sta->asid;
1227 reqsta.capinfo = sta->capinfo;
1228 reqsta.sig_info = sta->sig_info;
1229 reqsta.rates = sta->rates;
1230
1231 error = copyout(&reqsta, ifr->ifr_dataifr_ifru.ifru_data,
1232 sizeof(reqsta));
1233 }
1234 splx(s)spllower(s);
1235 break;
1236
1237 case SIOCHOSTAP_ADD(((unsigned long)0x80000000|(unsigned long)0x40000000) | ((sizeof
(struct ifreq) & 0x1fff) << 16) | ((('i')) <<
8) | ((201)))
:
1238 if ((error = suser(p)))
1239 break;
1240 if ((error = copyin(ifr->ifr_dataifr_ifru.ifru_data, &reqsta, sizeof(reqsta))))
1241 break;
1242 s = splnet()splraise(0x7);
1243 sta = wihap_sta_find(whi, reqsta.addr);
1244 if (sta != NULL((void *)0)) {
1245 error = EEXIST17;
1246 splx(s)spllower(s);
1247 break;
1248 }
1249 if (whi->n_stations >= WIHAP_MAX_STATIONS1800) {
1250 error = ENOSPC28;
1251 splx(s)spllower(s);
1252 break;
1253 }
1254 sta = wihap_sta_alloc(sc, reqsta.addr);
1255 sta->flags = reqsta.flags;
1256 timeout_add_sec(&sta->tmo, whi->inactivity_time);
1257 splx(s)spllower(s);
1258 break;
1259
1260 case SIOCHOSTAP_SFLAGS(((unsigned long)0x80000000|(unsigned long)0x40000000) | ((sizeof
(struct ifreq) & 0x1fff) << 16) | ((('i')) <<
8) | ((205)))
:
1261 if ((error = suser(p)))
1262 break;
1263 if ((error = copyin(ifr->ifr_dataifr_ifru.ifru_data, &flag, sizeof(int))))
1264 break;
1265
1266 whi->apflags = (whi->apflags & WIHAPFL_CANTCHANGE(0x0001)) |
1267 (flag & ~WIHAPFL_CANTCHANGE(0x0001));
1268 break;
1269
1270 case SIOCHOSTAP_GFLAGS(((unsigned long)0x80000000|(unsigned long)0x40000000) | ((sizeof
(struct ifreq) & 0x1fff) << 16) | ((('i')) <<
8) | ((204)))
:
1271 flag = (int) whi->apflags;
1272 error = copyout(&flag, ifr->ifr_dataifr_ifru.ifru_data, sizeof(int));
1273 break;
1274
1275 case SIOCHOSTAP_GETALL(((unsigned long)0x80000000|(unsigned long)0x40000000) | ((sizeof
(struct ifreq) & 0x1fff) << 16) | ((('i')) <<
8) | ((203)))
:
1276 if ((error = copyin(ifr->ifr_dataifr_ifru.ifru_data, &reqall, sizeof(reqall))))
1277 break;
1278
1279 reqall.nstations = whi->n_stations;
1280 n = 0;
1281 s = splnet()splraise(0x7);
1282 sta = TAILQ_FIRST(&whi->sta_list)((&whi->sta_list)->tqh_first);
1283 while (sta && reqall.size >= n+sizeof(struct hostap_sta)) {
1284
1285 bcopy(sta->addr, stabuf.addr, ETHER_ADDR_LEN6);
1286 stabuf.asid = sta->asid;
1287 stabuf.flags = sta->flags;
1288 stabuf.capinfo = sta->capinfo;
1289 stabuf.sig_info = sta->sig_info;
1290 stabuf.rates = sta->rates;
1291
1292 error = copyout(&stabuf, (caddr_t) reqall.addr + n,
1293 sizeof(struct hostap_sta));
1294 if (error)
1295 break;
1296
1297 sta = TAILQ_NEXT(sta, list)((sta)->list.tqe_next);
1298 n += sizeof(struct hostap_sta);
1299 }
1300 splx(s)spllower(s);
1301
1302 if (!error)
1303 error = copyout(&reqall, ifr->ifr_dataifr_ifru.ifru_data,
1304 sizeof(reqall));
1305 break;
1306
1307 case SIOCG80211ALLNODES(((unsigned long)0x80000000|(unsigned long)0x40000000) | ((sizeof
(struct ieee80211_nodereq_all) & 0x1fff) << 16) | (
(('i')) << 8) | ((214)))
:
1308 na = (struct ieee80211_nodereq_all *)data;
1309 na->na_nodes = n = 0;
1310 s = splnet()splraise(0x7);
1311 sta = TAILQ_FIRST(&whi->sta_list)((&whi->sta_list)->tqh_first);
1312 while (sta && na->na_size >=
1313 n + sizeof(struct ieee80211_nodereq)) {
1314 bzero(&nr, sizeof(nr))__builtin_bzero((&nr), (sizeof(nr)));
1315 IEEE80211_ADDR_COPY(nr.nr_macaddr, sta->addr)__builtin_memcpy((nr.nr_macaddr), (sta->addr), (6));
1316 IEEE80211_ADDR_COPY(nr.nr_bssid,__builtin_memcpy((nr.nr_bssid), (&sc->sc_ic.ic_myaddr)
, (6))
1317 &sc->sc_ic.ic_myaddr)__builtin_memcpy((nr.nr_bssid), (&sc->sc_ic.ic_myaddr)
, (6))
;
1318 nr.nr_channel = sc->wi_channel;
1319 nr.nr_chan_flags = IEEE80211_CHAN_B(0x0080 | 0x0020);
1320 nr.nr_associd = sta->asid;
1321 nr.nr_rssi = sta->sig_info >> 8;
1322 nr.nr_max_rssi = 0;
1323 nr.nr_capinfo = sta->capinfo;
1324 nr.nr_nrates = 0;
1325 if (sta->rates & WI_SUPPRATES_1M0x0001)
1326 nr.nr_rates[nr.nr_nrates++] = 2;
1327 if (sta->rates & WI_SUPPRATES_2M0x0002)
1328 nr.nr_rates[nr.nr_nrates++] = 4;
1329 if (sta->rates & WI_SUPPRATES_5M0x0004)
1330 nr.nr_rates[nr.nr_nrates++] = 11;
1331 if (sta->rates & WI_SUPPRATES_11M0x0008)
1332 nr.nr_rates[nr.nr_nrates++] = 22;
1333
1334 error = copyout(&nr, (caddr_t)na->na_node + n,
1335 sizeof(struct ieee80211_nodereq));
1336 if (error)
1337 break;
1338 n += sizeof(struct ieee80211_nodereq);
1339 na->na_nodes++;
1340 sta = TAILQ_NEXT(sta, list)((sta)->list.tqe_next);
1341 }
1342 splx(s)spllower(s);
1343 break;
1344
1345 default:
1346 printf("wihap_ioctl: i shouldn't get other ioctls!\n");
1347 error = EINVAL22;
1348 }
1349
1350 return (error);
1351}
1352
1353#else
1354void
1355wihap_init(struct wi_softc *sc)
1356{
1357 return;
1358}
1359
1360void
1361wihap_shutdown(struct wi_softc *sc)
1362{
1363 return;
1364}
1365
1366void
1367wihap_mgmt_input(struct wi_softc *sc, struct wi_frame *rxfrm, struct mbuf *m)
1368{
1369 return;
1370}
1371
1372int
1373wihap_data_input(struct wi_softc *sc, struct wi_frame *rxfrm, struct mbuf *m)
1374{
1375 return (0);
1376}
1377
1378int
1379wihap_ioctl(struct wi_softc *sc, u_long command, caddr_t data)
1380{
1381 return (EINVAL22);
1382}
1383
1384int
1385wihap_check_tx(struct wihap_info *whi, u_int8_t addr[], u_int8_t *txrate)
1386{
1387 return (0);
1388}
1389#endif