File: | dev/ic/if_wi_hostap.c |
Warning: | line 732, column 2 Value stored to 'lstintvl' is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
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 | |
71 | void wihap_timeout(void *v); |
72 | void wihap_sta_timeout(void *v); |
73 | struct wihap_sta_info *wihap_sta_alloc(struct wi_softc *sc, u_int8_t *addr); |
74 | void wihap_sta_delete(struct wihap_sta_info *sta); |
75 | struct wihap_sta_info *wihap_sta_find(struct wihap_info *whi, u_int8_t *addr); |
76 | int wihap_sta_is_assoc(struct wihap_info *whi, u_int8_t addr[]); |
77 | void wihap_auth_req(struct wi_softc *sc, struct wi_frame *rxfrm, |
78 | caddr_t pkt, int len); |
79 | void wihap_sta_deauth(struct wi_softc *sc, u_int8_t sta_addr[], |
80 | u_int16_t reason); |
81 | void wihap_deauth_req(struct wi_softc *sc, struct wi_frame *rxfrm, |
82 | caddr_t pkt, int len); |
83 | void wihap_assoc_req(struct wi_softc *sc, struct wi_frame *rxfrm, |
84 | caddr_t pkt, int len); |
85 | void wihap_sta_disassoc(struct wi_softc *sc, u_int8_t sta_addr[], |
86 | u_int16_t reason); |
87 | void 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 | */ |
97 | static __inline u_int16_t |
98 | take_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 | */ |
111 | static int |
112 | take_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 | */ |
135 | static __inline void |
136 | put_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 | */ |
145 | static void |
146 | put_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 | |
154 | static int |
155 | put_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 | */ |
178 | void |
179 | wihap_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 | */ |
206 | void |
207 | wihap_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 | */ |
235 | void |
236 | wihap_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 | */ |
264 | void |
265 | wihap_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(0x4); |
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 | */ |
312 | static __inline int |
313 | sta_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? */ |
319 | static __inline int |
320 | addr_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 */ |
328 | static __inline void |
329 | wihap_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 | |
336 | void |
337 | wihap_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(0x4); |
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 | |
396 | void |
397 | wihap_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(0x4); |
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 | */ |
422 | void |
423 | wihap_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 | */ |
446 | struct wihap_sta_info * |
447 | wihap_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 | */ |
482 | struct wihap_sta_info * |
483 | wihap_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 | |
496 | static __inline int |
497 | wihap_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 | */ |
536 | void |
537 | wihap_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); |
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(0x4); |
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 | |
682 | fail: |
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 | */ |
712 | void |
713 | wihap_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); |
Value stored to 'lstintvl' is never read | |
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 | |
825 | fail: |
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 | */ |
852 | void |
853 | wihap_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 | */ |
881 | void |
882 | wihap_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 | */ |
917 | static __inline void |
918 | wihap_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 | */ |
980 | void |
981 | wihap_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(0x1); |
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 | */ |
1037 | int |
1038 | wihap_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 | */ |
1057 | int |
1058 | wihap_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(0x1); |
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 | */ |
1093 | int |
1094 | wihap_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(0x1); |
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 | */ |
1174 | int |
1175 | wihap_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(0x4); |
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(0x4); |
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(0x4); |
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(0x4); |
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(0x4); |
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 |
1354 | void |
1355 | wihap_init(struct wi_softc *sc) |
1356 | { |
1357 | return; |
1358 | } |
1359 | |
1360 | void |
1361 | wihap_shutdown(struct wi_softc *sc) |
1362 | { |
1363 | return; |
1364 | } |
1365 | |
1366 | void |
1367 | wihap_mgmt_input(struct wi_softc *sc, struct wi_frame *rxfrm, struct mbuf *m) |
1368 | { |
1369 | return; |
1370 | } |
1371 | |
1372 | int |
1373 | wihap_data_input(struct wi_softc *sc, struct wi_frame *rxfrm, struct mbuf *m) |
1374 | { |
1375 | return (0); |
1376 | } |
1377 | |
1378 | int |
1379 | wihap_ioctl(struct wi_softc *sc, u_long command, caddr_t data) |
1380 | { |
1381 | return (EINVAL22); |
1382 | } |
1383 | |
1384 | int |
1385 | wihap_check_tx(struct wihap_info *whi, u_int8_t addr[], u_int8_t *txrate) |
1386 | { |
1387 | return (0); |
1388 | } |
1389 | #endif |