ieee80211_proto.c revision 1.3 1 /* $NetBSD: ieee80211_proto.c,v 1.3 2003/09/14 01:14:55 dyoung Exp $ */
2 /*-
3 * Copyright (c) 2001 Atsushi Onoe
4 * Copyright (c) 2002, 2003 Sam Leffler, Errno Consulting
5 * 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. The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * Alternatively, this software may be distributed under the terms of the
19 * GNU General Public License ("GPL") version 2 as published by the Free
20 * Software Foundation.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33
34 #include <sys/cdefs.h>
35 #ifdef __FreeBSD__
36 __FBSDID("$FreeBSD: src/sys/net80211/ieee80211_proto.c,v 1.3 2003/07/20 21:36:08 sam Exp $");
37 #else
38 __KERNEL_RCSID(0, "$NetBSD: ieee80211_proto.c,v 1.3 2003/09/14 01:14:55 dyoung Exp $");
39 #endif
40
41 /*
42 * IEEE 802.11 protocol support.
43 */
44
45 #include "opt_inet.h"
46
47 #include <sys/param.h>
48 #include <sys/systm.h>
49 #include <sys/mbuf.h>
50 #include <sys/malloc.h>
51 #include <sys/kernel.h>
52 #include <sys/socket.h>
53 #include <sys/sockio.h>
54 #include <sys/endian.h>
55 #include <sys/errno.h>
56 #include <sys/bus.h>
57 #include <sys/proc.h>
58 #include <sys/sysctl.h>
59
60 #ifdef __FreeBSD__
61 #include <machine/atomic.h>
62 #endif
63
64 #include <net/if.h>
65 #include <net/if_dl.h>
66 #include <net/if_media.h>
67 #include <net/if_arp.h>
68 #ifdef __FreeBSD__
69 #include <net/ethernet.h>
70 #endif
71 #include <net/if_llc.h>
72
73 #include <net80211/ieee80211_var.h>
74
75 #include <net/bpf.h>
76
77 #ifdef INET
78 #include <netinet/in.h>
79 #include <netinet/if_ether.h>
80 #endif
81
82 #define IEEE80211_RATE2MBS(r) (((r) & IEEE80211_RATE_VAL) / 2)
83
84 const char *ieee80211_mgt_subtype_name[] = {
85 "assoc_req", "assoc_resp", "reassoc_req", "reassoc_resp",
86 "probe_req", "probe_resp", "reserved#6", "reserved#7",
87 "beacon", "atim", "disassoc", "auth",
88 "deauth", "reserved#13", "reserved#14", "reserved#15"
89 };
90 const char *ieee80211_state_name[IEEE80211_S_MAX] = {
91 "INIT", /* IEEE80211_S_INIT */
92 "SCAN", /* IEEE80211_S_SCAN */
93 "AUTH", /* IEEE80211_S_AUTH */
94 "ASSOC", /* IEEE80211_S_ASSOC */
95 "RUN" /* IEEE80211_S_RUN */
96 };
97
98 static int ieee80211_newstate(struct ieee80211com *, enum ieee80211_state, int);
99
100 void
101 ieee80211_proto_attach(struct ifnet *ifp)
102 {
103 struct ieee80211com *ic = (void *)ifp;
104
105 ifp->if_hdrlen = sizeof(struct ieee80211_frame);
106
107 #ifdef notdef
108 ic->ic_rtsthreshold = IEEE80211_RTS_DEFAULT;
109 #else
110 ic->ic_rtsthreshold = IEEE80211_RTS_MAX;
111 #endif
112 ic->ic_fragthreshold = 2346; /* XXX not used yet */
113 ic->ic_fixed_rate = -1; /* no fixed rate */
114
115 #ifdef __FreeBSD__
116 mtx_init(&ic->ic_mgtq.ifq_mtx, ifp->if_name, "mgmt send q", MTX_DEF);
117 #endif
118
119 /* protocol state change handler */
120 ic->ic_newstate = ieee80211_newstate;
121
122 /* initialize management frame handlers */
123 ic->ic_recv_mgmt = ieee80211_recv_mgmt;
124 ic->ic_send_mgmt = ieee80211_send_mgmt;
125 }
126
127 void
128 ieee80211_proto_detach(struct ifnet *ifp)
129 {
130 struct ieee80211com *ic = (void *)ifp;
131
132 IF_DRAIN(&ic->ic_mgtq);
133 mtx_destroy(&ic->ic_mgtq.ifq_mtx);
134 }
135
136 void
137 ieee80211_print_essid(u_int8_t *essid, int len)
138 {
139 int i;
140 u_int8_t *p;
141
142 if (len > IEEE80211_NWID_LEN)
143 len = IEEE80211_NWID_LEN;
144 /* determine printable or not */
145 for (i = 0, p = essid; i < len; i++, p++) {
146 if (*p < ' ' || *p > 0x7e)
147 break;
148 }
149 if (i == len) {
150 printf("\"");
151 for (i = 0, p = essid; i < len; i++, p++)
152 printf("%c", *p);
153 printf("\"");
154 } else {
155 printf("0x");
156 for (i = 0, p = essid; i < len; i++, p++)
157 printf("%02x", *p);
158 }
159 }
160
161 void
162 ieee80211_dump_pkt(u_int8_t *buf, int len, int rate, int rssi)
163 {
164 struct ieee80211_frame *wh;
165 int i;
166
167 wh = (struct ieee80211_frame *)buf;
168 switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) {
169 case IEEE80211_FC1_DIR_NODS:
170 printf("NODS %s", ether_sprintf(wh->i_addr2));
171 printf("->%s", ether_sprintf(wh->i_addr1));
172 printf("(%s)", ether_sprintf(wh->i_addr3));
173 break;
174 case IEEE80211_FC1_DIR_TODS:
175 printf("TODS %s", ether_sprintf(wh->i_addr2));
176 printf("->%s", ether_sprintf(wh->i_addr3));
177 printf("(%s)", ether_sprintf(wh->i_addr1));
178 break;
179 case IEEE80211_FC1_DIR_FROMDS:
180 printf("FRDS %s", ether_sprintf(wh->i_addr3));
181 printf("->%s", ether_sprintf(wh->i_addr1));
182 printf("(%s)", ether_sprintf(wh->i_addr2));
183 break;
184 case IEEE80211_FC1_DIR_DSTODS:
185 printf("DSDS %s", ether_sprintf((u_int8_t *)&wh[1]));
186 printf("->%s", ether_sprintf(wh->i_addr3));
187 printf("(%s", ether_sprintf(wh->i_addr2));
188 printf("->%s)", ether_sprintf(wh->i_addr1));
189 break;
190 }
191 switch (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) {
192 case IEEE80211_FC0_TYPE_DATA:
193 printf(" data");
194 break;
195 case IEEE80211_FC0_TYPE_MGT:
196 printf(" %s", ieee80211_mgt_subtype_name[
197 (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK)
198 >> IEEE80211_FC0_SUBTYPE_SHIFT]);
199 break;
200 default:
201 printf(" type#%d", wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK);
202 break;
203 }
204 if (wh->i_fc[1] & IEEE80211_FC1_WEP)
205 printf(" WEP");
206 if (rate >= 0)
207 printf(" %dM", rate / 2);
208 if (rssi >= 0)
209 printf(" +%d", rssi);
210 printf("\n");
211 if (len > 0) {
212 for (i = 0; i < len; i++) {
213 if ((i & 1) == 0)
214 printf(" ");
215 printf("%02x", buf[i]);
216 }
217 printf("\n");
218 }
219 }
220
221 int
222 ieee80211_fix_rate(struct ieee80211com *ic, struct ieee80211_node *ni, int flags)
223 {
224 #define RV(v) ((v) & IEEE80211_RATE_VAL)
225 int i, j, ignore, error;
226 int okrate, badrate;
227 struct ieee80211_rateset *srs, *nrs;
228 u_int8_t r;
229
230 error = 0;
231 okrate = badrate = 0;
232 srs = &ic->ic_sup_rates[ieee80211_chan2mode(ic, ni->ni_chan)];
233 nrs = &ni->ni_rates;
234 for (i = 0; i < ni->ni_rates.rs_nrates; ) {
235 ignore = 0;
236 if (flags & IEEE80211_F_DOSORT) {
237 /*
238 * Sort rates.
239 */
240 for (j = i + 1; j < nrs->rs_nrates; j++) {
241 if (RV(nrs->rs_rates[i]) > RV(nrs->rs_rates[j])) {
242 r = nrs->rs_rates[i];
243 nrs->rs_rates[i] = nrs->rs_rates[j];
244 nrs->rs_rates[j] = r;
245 }
246 }
247 }
248 r = nrs->rs_rates[i] & IEEE80211_RATE_VAL;
249 badrate = r;
250 if (flags & IEEE80211_F_DOFRATE) {
251 /*
252 * Apply fixed rate constraint. Note that we do
253 * not apply the constraint to basic rates as
254 * otherwise we may not be able to associate if
255 * the rate set we submit to the AP is invalid
256 * (e.g. fix rate at 36Mb/s which is not a basic
257 * rate for 11a operation).
258 */
259 if ((nrs->rs_rates[i] & IEEE80211_RATE_BASIC) == 0 &&
260 ic->ic_fixed_rate >= 0 &&
261 r != RV(srs->rs_rates[ic->ic_fixed_rate]))
262 ignore++;
263 }
264 if (flags & IEEE80211_F_DONEGO) {
265 /*
266 * Check against supported rates.
267 */
268 for (j = 0; j < srs->rs_nrates; j++) {
269 if (r == RV(srs->rs_rates[j]))
270 break;
271 }
272 if (j == srs->rs_nrates) {
273 if (nrs->rs_rates[i] & IEEE80211_RATE_BASIC)
274 error++;
275 ignore++;
276 }
277 }
278 if (flags & IEEE80211_F_DODEL) {
279 /*
280 * Delete unacceptable rates.
281 */
282 if (ignore) {
283 nrs->rs_nrates--;
284 for (j = i; j < nrs->rs_nrates; j++)
285 nrs->rs_rates[j] = nrs->rs_rates[j + 1];
286 nrs->rs_rates[j] = 0;
287 continue;
288 }
289 }
290 if (!ignore)
291 okrate = nrs->rs_rates[i];
292 i++;
293 }
294 if (okrate == 0 || error != 0)
295 return badrate | IEEE80211_RATE_BASIC;
296 else
297 return RV(okrate);
298 #undef RV
299 }
300
301 static int
302 ieee80211_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int mgt)
303 {
304 struct ifnet *ifp = &ic->ic_if;
305 struct ieee80211_node *ni;
306 enum ieee80211_state ostate;
307 ieee80211_node_critsec_decl(s);
308
309 ostate = ic->ic_state;
310 IEEE80211_DPRINTF(("%s: %s -> %s\n", __func__,
311 ieee80211_state_name[ostate], ieee80211_state_name[nstate]));
312 ic->ic_state = nstate; /* state transition */
313 ni = ic->ic_bss; /* NB: no reference held */
314 switch (nstate) {
315 case IEEE80211_S_INIT:
316 switch (ostate) {
317 case IEEE80211_S_INIT:
318 break;
319 case IEEE80211_S_RUN:
320 switch (ic->ic_opmode) {
321 case IEEE80211_M_STA:
322 IEEE80211_SEND_MGMT(ic, ni,
323 IEEE80211_FC0_SUBTYPE_DISASSOC,
324 IEEE80211_REASON_ASSOC_LEAVE);
325 break;
326 case IEEE80211_M_HOSTAP:
327 ieee80211_node_critsec_begin(ic, s);
328 TAILQ_FOREACH(ni, &ic->ic_node, ni_list) {
329 if (ni->ni_associd == 0)
330 continue;
331 IEEE80211_SEND_MGMT(ic, ni,
332 IEEE80211_FC0_SUBTYPE_DISASSOC,
333 IEEE80211_REASON_ASSOC_LEAVE);
334 }
335 ieee80211_node_critsec_end(ic, s);
336 break;
337 default:
338 break;
339 }
340 /* FALLTHRU */
341 case IEEE80211_S_ASSOC:
342 switch (ic->ic_opmode) {
343 case IEEE80211_M_STA:
344 IEEE80211_SEND_MGMT(ic, ni,
345 IEEE80211_FC0_SUBTYPE_DEAUTH,
346 IEEE80211_REASON_AUTH_LEAVE);
347 break;
348 case IEEE80211_M_HOSTAP:
349 ieee80211_node_critsec_begin(ic, s);
350 TAILQ_FOREACH(ni, &ic->ic_node, ni_list) {
351 IEEE80211_SEND_MGMT(ic, ni,
352 IEEE80211_FC0_SUBTYPE_DEAUTH,
353 IEEE80211_REASON_AUTH_LEAVE);
354 }
355 ieee80211_node_critsec_end(ic, s);
356 break;
357 default:
358 break;
359 }
360 /* FALLTHRU */
361 case IEEE80211_S_AUTH:
362 case IEEE80211_S_SCAN:
363 ic->ic_mgt_timer = 0;
364 IF_DRAIN(&ic->ic_mgtq);
365 if (ic->ic_wep_ctx != NULL) {
366 free(ic->ic_wep_ctx, M_DEVBUF);
367 ic->ic_wep_ctx = NULL;
368 }
369 ieee80211_free_allnodes(ic);
370 break;
371 }
372 break;
373 case IEEE80211_S_SCAN:
374 ic->ic_flags &= ~IEEE80211_F_SIBSS;
375 /* initialize bss for probe request */
376 IEEE80211_ADDR_COPY(ni->ni_macaddr, ifp->if_broadcastaddr);
377 IEEE80211_ADDR_COPY(ni->ni_bssid, ifp->if_broadcastaddr);
378 ni->ni_rates = ic->ic_sup_rates[
379 ieee80211_chan2mode(ic, ni->ni_chan)];
380 ni->ni_associd = 0;
381 ni->ni_rstamp = 0;
382 switch (ostate) {
383 case IEEE80211_S_INIT:
384 if (ic->ic_opmode == IEEE80211_M_HOSTAP &&
385 ic->ic_des_chan != IEEE80211_CHAN_ANYC) {
386 /*
387 * AP operation and we already have a channel;
388 * bypass the scan and startup immediately.
389 */
390 ieee80211_create_ibss(ic, ic->ic_des_chan);
391 } else {
392 ieee80211_begin_scan(ifp);
393 }
394 break;
395 case IEEE80211_S_SCAN:
396 /* scan next */
397 if (ic->ic_flags & IEEE80211_F_ASCAN) {
398 IEEE80211_SEND_MGMT(ic, ni,
399 IEEE80211_FC0_SUBTYPE_PROBE_REQ, 0);
400 }
401 break;
402 case IEEE80211_S_RUN:
403 /* beacon miss */
404 if (ifp->if_flags & IFF_DEBUG) {
405 /* XXX bssid clobbered above */
406 if_printf(ifp, "no recent beacons from %s;"
407 " rescanning\n",
408 ether_sprintf(ic->ic_bss->ni_bssid));
409 }
410 ieee80211_free_allnodes(ic);
411 /* FALLTHRU */
412 case IEEE80211_S_AUTH:
413 case IEEE80211_S_ASSOC:
414 /* timeout restart scan */
415 ni = ieee80211_find_node(ic, ic->ic_bss->ni_macaddr);
416 if (ni != NULL) {
417 ni->ni_fails++;
418 ieee80211_unref_node(&ni);
419 }
420 ieee80211_begin_scan(ifp);
421 break;
422 }
423 break;
424 case IEEE80211_S_AUTH:
425 switch (ostate) {
426 case IEEE80211_S_INIT:
427 IEEE80211_DPRINTF(("%s: invalid transition\n",
428 __func__));
429 break;
430 case IEEE80211_S_SCAN:
431 IEEE80211_SEND_MGMT(ic, ni,
432 IEEE80211_FC0_SUBTYPE_AUTH, 1);
433 break;
434 case IEEE80211_S_AUTH:
435 case IEEE80211_S_ASSOC:
436 switch (mgt) {
437 case IEEE80211_FC0_SUBTYPE_AUTH:
438 /* ??? */
439 IEEE80211_SEND_MGMT(ic, ni,
440 IEEE80211_FC0_SUBTYPE_AUTH, 2);
441 break;
442 case IEEE80211_FC0_SUBTYPE_DEAUTH:
443 /* ignore and retry scan on timeout */
444 break;
445 }
446 break;
447 case IEEE80211_S_RUN:
448 switch (mgt) {
449 case IEEE80211_FC0_SUBTYPE_AUTH:
450 IEEE80211_SEND_MGMT(ic, ni,
451 IEEE80211_FC0_SUBTYPE_AUTH, 2);
452 ic->ic_state = ostate; /* stay RUN */
453 break;
454 case IEEE80211_FC0_SUBTYPE_DEAUTH:
455 /* try to reauth */
456 IEEE80211_SEND_MGMT(ic, ni,
457 IEEE80211_FC0_SUBTYPE_AUTH, 1);
458 break;
459 }
460 break;
461 }
462 break;
463 case IEEE80211_S_ASSOC:
464 switch (ostate) {
465 case IEEE80211_S_INIT:
466 case IEEE80211_S_SCAN:
467 case IEEE80211_S_ASSOC:
468 IEEE80211_DPRINTF(("%s: invalid transition\n",
469 __func__));
470 break;
471 case IEEE80211_S_AUTH:
472 IEEE80211_SEND_MGMT(ic, ni,
473 IEEE80211_FC0_SUBTYPE_ASSOC_REQ, 0);
474 break;
475 case IEEE80211_S_RUN:
476 IEEE80211_SEND_MGMT(ic, ni,
477 IEEE80211_FC0_SUBTYPE_ASSOC_REQ, 1);
478 break;
479 }
480 break;
481 case IEEE80211_S_RUN:
482 switch (ostate) {
483 case IEEE80211_S_INIT:
484 case IEEE80211_S_AUTH:
485 case IEEE80211_S_RUN:
486 IEEE80211_DPRINTF(("%s: invalid transition\n",
487 __func__));
488 break;
489 case IEEE80211_S_SCAN: /* adhoc/hostap mode */
490 case IEEE80211_S_ASSOC: /* infra mode */
491 KASSERT(ni->ni_txrate < ni->ni_rates.rs_nrates,
492 ("%s: bogus xmit rate %u setup\n", __func__,
493 ni->ni_txrate));
494 if (ifp->if_flags & IFF_DEBUG) {
495 if_printf(ifp, " ");
496 if (ic->ic_opmode == IEEE80211_M_STA)
497 printf("associated ");
498 else
499 printf("synchronized ");
500 printf("with %s ssid ",
501 ether_sprintf(ni->ni_bssid));
502 ieee80211_print_essid(ic->ic_bss->ni_essid,
503 ni->ni_esslen);
504 printf(" channel %d start %uMb\n",
505 ieee80211_chan2ieee(ic, ni->ni_chan),
506 IEEE80211_RATE2MBS(ni->ni_rates.rs_rates[ni->ni_txrate]));
507 }
508 ic->ic_mgt_timer = 0;
509 (*ifp->if_start)(ifp);
510 break;
511 }
512 break;
513 }
514 return 0;
515 }
516