Annotation of sys/net80211/ieee80211_proto.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: ieee80211_proto.c,v 1.20 2007/07/28 11:24:06 damien Exp $ */
2: /* $NetBSD: ieee80211_proto.c,v 1.8 2004/04/30 23:58:20 dyoung Exp $ */
3:
4: /*-
5: * Copyright (c) 2001 Atsushi Onoe
6: * Copyright (c) 2002, 2003 Sam Leffler, Errno Consulting
7: * All rights reserved.
8: *
9: * Redistribution and use in source and binary forms, with or without
10: * modification, are permitted provided that the following conditions
11: * are met:
12: * 1. Redistributions of source code must retain the above copyright
13: * notice, this list of conditions and the following disclaimer.
14: * 2. Redistributions in binary form must reproduce the above copyright
15: * notice, this list of conditions and the following disclaimer in the
16: * documentation and/or other materials provided with the distribution.
17: * 3. The name of the author may not be used to endorse or promote products
18: * derived from this software without specific prior written permission.
19: *
20: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
24: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30: */
31:
32: /*
33: * IEEE 802.11 protocol support.
34: */
35:
36: #include "bpfilter.h"
37:
38: #include <sys/param.h>
39: #include <sys/systm.h>
40: #include <sys/mbuf.h>
41: #include <sys/kernel.h>
42: #include <sys/socket.h>
43: #include <sys/sockio.h>
44: #include <sys/endian.h>
45: #include <sys/errno.h>
46: #include <sys/proc.h>
47: #include <sys/sysctl.h>
48:
49: #include <net/if.h>
50: #include <net/if_dl.h>
51: #include <net/if_media.h>
52: #include <net/if_arp.h>
53: #include <net/if_llc.h>
54:
55: #if NBPFILTER > 0
56: #include <net/bpf.h>
57: #endif
58:
59: #ifdef INET
60: #include <netinet/in.h>
61: #include <netinet/if_ether.h>
62: #endif
63:
64: #include <net80211/ieee80211_var.h>
65:
66: const char * const ieee80211_mgt_subtype_name[] = {
67: "assoc_req", "assoc_resp", "reassoc_req", "reassoc_resp",
68: "probe_req", "probe_resp", "reserved#6", "reserved#7",
69: "beacon", "atim", "disassoc", "auth",
70: "deauth", "action", "action_noack", "reserved#15"
71: };
72: const char * const ieee80211_state_name[IEEE80211_S_MAX] = {
73: "INIT", /* IEEE80211_S_INIT */
74: "SCAN", /* IEEE80211_S_SCAN */
75: "AUTH", /* IEEE80211_S_AUTH */
76: "ASSOC", /* IEEE80211_S_ASSOC */
77: "RUN" /* IEEE80211_S_RUN */
78: };
79: const char * const ieee80211_phymode_name[] = {
80: "auto", /* IEEE80211_MODE_AUTO */
81: "11a", /* IEEE80211_MODE_11A */
82: "11b", /* IEEE80211_MODE_11B */
83: "11g", /* IEEE80211_MODE_11G */
84: "fh", /* IEEE80211_MODE_FH */
85: "turbo", /* IEEE80211_MODE_TURBO */
86: };
87:
88: int ieee80211_newstate(struct ieee80211com *, enum ieee80211_state, int);
89:
90: void
91: ieee80211_proto_attach(struct ifnet *ifp)
92: {
93: struct ieee80211com *ic = (void *)ifp;
94:
95: ifp->if_hdrlen = sizeof(struct ieee80211_frame);
96:
97: #ifdef notdef
98: ic->ic_rtsthreshold = IEEE80211_RTS_DEFAULT;
99: #else
100: ic->ic_rtsthreshold = IEEE80211_RTS_MAX;
101: #endif
102: ic->ic_fragthreshold = 2346; /* XXX not used yet */
103: ic->ic_fixed_rate = -1; /* no fixed rate */
104: ic->ic_protmode = IEEE80211_PROT_CTSONLY;
105:
106: /* protocol state change handler */
107: ic->ic_newstate = ieee80211_newstate;
108:
109: /* initialize management frame handlers */
110: ic->ic_recv_mgmt = ieee80211_recv_mgmt;
111: ic->ic_send_mgmt = ieee80211_send_mgmt;
112:
113: /* initialize EAPOL frame handler */
114: ic->ic_recv_eapol = ieee80211_recv_eapol;
115: }
116:
117: void
118: ieee80211_proto_detach(struct ifnet *ifp)
119: {
120: struct ieee80211com *ic = (void *)ifp;
121:
122: IF_PURGE(&ic->ic_mgtq);
123: IF_PURGE(&ic->ic_pwrsaveq);
124: }
125:
126: void
127: ieee80211_print_essid(const u_int8_t *essid, int len)
128: {
129: int i;
130: const u_int8_t *p;
131:
132: if (len > IEEE80211_NWID_LEN)
133: len = IEEE80211_NWID_LEN;
134: /* determine printable or not */
135: for (i = 0, p = essid; i < len; i++, p++) {
136: if (*p < ' ' || *p > 0x7e)
137: break;
138: }
139: if (i == len) {
140: printf("\"");
141: for (i = 0, p = essid; i < len; i++, p++)
142: printf("%c", *p);
143: printf("\"");
144: } else {
145: printf("0x");
146: for (i = 0, p = essid; i < len; i++, p++)
147: printf("%02x", *p);
148: }
149: }
150:
151: void
152: ieee80211_dump_pkt(const u_int8_t *buf, int len, int rate, int rssi)
153: {
154: struct ieee80211_frame *wh;
155: int i;
156:
157: wh = (struct ieee80211_frame *)buf;
158: switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) {
159: case IEEE80211_FC1_DIR_NODS:
160: printf("NODS %s", ether_sprintf(wh->i_addr2));
161: printf("->%s", ether_sprintf(wh->i_addr1));
162: printf("(%s)", ether_sprintf(wh->i_addr3));
163: break;
164: case IEEE80211_FC1_DIR_TODS:
165: printf("TODS %s", ether_sprintf(wh->i_addr2));
166: printf("->%s", ether_sprintf(wh->i_addr3));
167: printf("(%s)", ether_sprintf(wh->i_addr1));
168: break;
169: case IEEE80211_FC1_DIR_FROMDS:
170: printf("FRDS %s", ether_sprintf(wh->i_addr3));
171: printf("->%s", ether_sprintf(wh->i_addr1));
172: printf("(%s)", ether_sprintf(wh->i_addr2));
173: break;
174: case IEEE80211_FC1_DIR_DSTODS:
175: printf("DSDS %s", ether_sprintf((u_int8_t *)&wh[1]));
176: printf("->%s", ether_sprintf(wh->i_addr3));
177: printf("(%s", ether_sprintf(wh->i_addr2));
178: printf("->%s)", ether_sprintf(wh->i_addr1));
179: break;
180: }
181: switch (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) {
182: case IEEE80211_FC0_TYPE_DATA:
183: printf(" data");
184: break;
185: case IEEE80211_FC0_TYPE_MGT:
186: printf(" %s", ieee80211_mgt_subtype_name[
187: (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK)
188: >> IEEE80211_FC0_SUBTYPE_SHIFT]);
189: break;
190: default:
191: printf(" type#%d", wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK);
192: break;
193: }
194: if (wh->i_fc[1] & IEEE80211_FC1_WEP)
195: printf(" WEP");
196: if (rate >= 0)
197: printf(" %d%sM", rate / 2, (rate & 1) ? ".5" : "");
198: if (rssi >= 0)
199: printf(" +%d", rssi);
200: printf("\n");
201: if (len > 0) {
202: for (i = 0; i < len; i++) {
203: if ((i & 1) == 0)
204: printf(" ");
205: printf("%02x", buf[i]);
206: }
207: printf("\n");
208: }
209: }
210:
211: int
212: ieee80211_fix_rate(struct ieee80211com *ic, struct ieee80211_node *ni,
213: int flags)
214: {
215: #define RV(v) ((v) & IEEE80211_RATE_VAL)
216: int i, j, ignore, error;
217: int okrate, badrate, fixedrate;
218: const struct ieee80211_rateset *srs;
219: struct ieee80211_rateset *nrs;
220: u_int8_t r;
221:
222: /*
223: * If the fixed rate check was requested but no fixed rate has been
224: * defined then just remove the check.
225: */
226: if ((flags & IEEE80211_F_DOFRATE) && ic->ic_fixed_rate == -1)
227: flags &= ~IEEE80211_F_DOFRATE;
228:
229: error = 0;
230: okrate = badrate = fixedrate = 0;
231: srs = &ic->ic_sup_rates[ieee80211_chan2mode(ic, ni->ni_chan)];
232: nrs = &ni->ni_rates;
233: for (i = 0; i < nrs->rs_nrates; ) {
234: ignore = 0;
235: if (flags & IEEE80211_F_DOSORT) {
236: /*
237: * Sort rates.
238: */
239: for (j = i + 1; j < nrs->rs_nrates; j++) {
240: if (RV(nrs->rs_rates[i]) >
241: 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: * Check fixed rate is included.
253: */
254: if (r == RV(srs->rs_rates[ic->ic_fixed_rate]))
255: fixedrate = r;
256: }
257: if (flags & IEEE80211_F_DONEGO) {
258: /*
259: * Check against supported rates.
260: */
261: for (j = 0; j < srs->rs_nrates; j++) {
262: if (r == RV(srs->rs_rates[j])) {
263: /*
264: * Overwrite with the supported rate
265: * value so any basic rate bit is set.
266: * This insures that response we send
267: * to stations have the necessary basic
268: * rate bit set.
269: */
270: nrs->rs_rates[i] = srs->rs_rates[j];
271: break;
272: }
273: }
274: if (j == srs->rs_nrates) {
275: /*
276: * A rate in the node's rate set is not
277: * supported. If this is a basic rate and we
278: * are operating as an AP then this is an error.
279: * Otherwise we just discard/ignore the rate.
280: * Note that this is important for 11b stations
281: * when they want to associate with an 11g AP.
282: */
283: if (ic->ic_opmode == IEEE80211_M_HOSTAP &&
284: (nrs->rs_rates[i] & IEEE80211_RATE_BASIC))
285: error++;
286: ignore++;
287: }
288: }
289: if (flags & IEEE80211_F_DODEL) {
290: /*
291: * Delete unacceptable rates.
292: */
293: if (ignore) {
294: nrs->rs_nrates--;
295: for (j = i; j < nrs->rs_nrates; j++)
296: nrs->rs_rates[j] = nrs->rs_rates[j + 1];
297: nrs->rs_rates[j] = 0;
298: continue;
299: }
300: }
301: if (!ignore)
302: okrate = nrs->rs_rates[i];
303: i++;
304: }
305: if (okrate == 0 || error != 0 ||
306: ((flags & IEEE80211_F_DOFRATE) && fixedrate == 0))
307: return badrate | IEEE80211_RATE_BASIC;
308: else
309: return RV(okrate);
310: #undef RV
311: }
312:
313: /*
314: * Reset 11g-related state.
315: */
316: void
317: ieee80211_reset_erp(struct ieee80211com *ic)
318: {
319: ic->ic_flags &= ~IEEE80211_F_USEPROT;
320: ic->ic_nonerpsta = 0;
321: ic->ic_longslotsta = 0;
322:
323: /*
324: * Enable short slot time iff:
325: * - we're operating in 802.11a or
326: * - we're operating in 802.11g and we're not in IBSS mode and
327: * the device supports short slot time
328: */
329: ieee80211_set_shortslottime(ic,
330: ic->ic_curmode == IEEE80211_MODE_11A ||
331: (ic->ic_curmode == IEEE80211_MODE_11G &&
332: ic->ic_opmode == IEEE80211_M_HOSTAP &&
333: (ic->ic_caps & IEEE80211_C_SHSLOT)));
334:
335: if (ic->ic_curmode == IEEE80211_MODE_11A ||
336: (ic->ic_caps & IEEE80211_C_SHPREAMBLE))
337: ic->ic_flags |= IEEE80211_F_SHPREAMBLE;
338: else
339: ic->ic_flags &= ~IEEE80211_F_SHPREAMBLE;
340: }
341:
342: /*
343: * Set the short slot time state and notify the driver.
344: */
345: void
346: ieee80211_set_shortslottime(struct ieee80211com *ic, int on)
347: {
348: if (on)
349: ic->ic_flags |= IEEE80211_F_SHSLOT;
350: else
351: ic->ic_flags &= ~IEEE80211_F_SHSLOT;
352:
353: /* notify the driver */
354: if (ic->ic_updateslot != NULL)
355: ic->ic_updateslot(ic);
356: }
357:
358: int
359: ieee80211_newstate(struct ieee80211com *ic, enum ieee80211_state nstate,
360: int mgt)
361: {
362: struct ifnet *ifp = &ic->ic_if;
363: struct ieee80211_node *ni;
364: enum ieee80211_state ostate;
365: u_int rate;
366: int s;
367:
368: ostate = ic->ic_state;
369: IEEE80211_DPRINTF(("%s: %s -> %s\n", __func__,
370: ieee80211_state_name[ostate], ieee80211_state_name[nstate]));
371: ic->ic_state = nstate; /* state transition */
372: ni = ic->ic_bss; /* NB: no reference held */
373: switch (nstate) {
374: case IEEE80211_S_INIT:
375: switch (ostate) {
376: case IEEE80211_S_INIT:
377: break;
378: case IEEE80211_S_RUN:
379: switch (ic->ic_opmode) {
380: case IEEE80211_M_STA:
381: IEEE80211_SEND_MGMT(ic, ni,
382: IEEE80211_FC0_SUBTYPE_DISASSOC,
383: IEEE80211_REASON_ASSOC_LEAVE);
384: break;
385: case IEEE80211_M_HOSTAP:
386: s = splnet();
387: RB_FOREACH(ni, ieee80211_tree, &ic->ic_tree) {
388: if (ni->ni_associd == 0)
389: continue;
390: IEEE80211_SEND_MGMT(ic, ni,
391: IEEE80211_FC0_SUBTYPE_DISASSOC,
392: IEEE80211_REASON_ASSOC_LEAVE);
393: }
394: splx(s);
395: break;
396: default:
397: break;
398: }
399: /* FALLTHROUGH */
400: case IEEE80211_S_ASSOC:
401: switch (ic->ic_opmode) {
402: case IEEE80211_M_STA:
403: IEEE80211_SEND_MGMT(ic, ni,
404: IEEE80211_FC0_SUBTYPE_DEAUTH,
405: IEEE80211_REASON_AUTH_LEAVE);
406: break;
407: case IEEE80211_M_HOSTAP:
408: s = splnet();
409: RB_FOREACH(ni, ieee80211_tree, &ic->ic_tree) {
410: IEEE80211_SEND_MGMT(ic, ni,
411: IEEE80211_FC0_SUBTYPE_DEAUTH,
412: IEEE80211_REASON_AUTH_LEAVE);
413: }
414: splx(s);
415: break;
416: default:
417: break;
418: }
419: /* FALLTHROUGH */
420: case IEEE80211_S_AUTH:
421: case IEEE80211_S_SCAN:
422: ic->ic_mgt_timer = 0;
423: IF_PURGE(&ic->ic_mgtq);
424: IF_PURGE(&ic->ic_pwrsaveq);
425: if (ic->ic_wep_ctx != NULL) {
426: free(ic->ic_wep_ctx, M_DEVBUF);
427: ic->ic_wep_ctx = NULL;
428: }
429: ieee80211_free_allnodes(ic);
430: break;
431: }
432: break;
433: case IEEE80211_S_SCAN:
434: ic->ic_flags &= ~IEEE80211_F_SIBSS;
435: /* initialize bss for probe request */
436: IEEE80211_ADDR_COPY(ni->ni_macaddr, etherbroadcastaddr);
437: IEEE80211_ADDR_COPY(ni->ni_bssid, etherbroadcastaddr);
438: ni->ni_rates = ic->ic_sup_rates[
439: ieee80211_chan2mode(ic, ni->ni_chan)];
440: ni->ni_associd = 0;
441: ni->ni_rstamp = 0;
442: switch (ostate) {
443: case IEEE80211_S_INIT:
444: if (ic->ic_opmode == IEEE80211_M_HOSTAP &&
445: ic->ic_des_chan != IEEE80211_CHAN_ANYC) {
446: /*
447: * AP operation and we already have a channel;
448: * bypass the scan and startup immediately.
449: */
450: ieee80211_create_ibss(ic, ic->ic_des_chan);
451: } else {
452: ieee80211_begin_scan(ifp);
453: }
454: break;
455: case IEEE80211_S_SCAN:
456: /* scan next */
457: if (ic->ic_flags & IEEE80211_F_ASCAN) {
458: IEEE80211_SEND_MGMT(ic, ni,
459: IEEE80211_FC0_SUBTYPE_PROBE_REQ, 0);
460: }
461: break;
462: case IEEE80211_S_RUN:
463: /* beacon miss */
464: if (ifp->if_flags & IFF_DEBUG) {
465: /* XXX bssid clobbered above */
466: printf("%s: no recent beacons from %s;"
467: " rescanning\n", ifp->if_xname,
468: ether_sprintf(ic->ic_bss->ni_bssid));
469: }
470: ieee80211_free_allnodes(ic);
471: /* FALLTHROUGH */
472: case IEEE80211_S_AUTH:
473: case IEEE80211_S_ASSOC:
474: /* timeout restart scan */
475: ni = ieee80211_find_node(ic, ic->ic_bss->ni_macaddr);
476: if (ni != NULL)
477: ni->ni_fails++;
478: ieee80211_begin_scan(ifp);
479: break;
480: }
481: break;
482: case IEEE80211_S_AUTH:
483: switch (ostate) {
484: case IEEE80211_S_INIT:
485: IEEE80211_DPRINTF(("%s: invalid transition\n",
486: __func__));
487: break;
488: case IEEE80211_S_SCAN:
489: IEEE80211_SEND_MGMT(ic, ni,
490: IEEE80211_FC0_SUBTYPE_AUTH, 1);
491: break;
492: case IEEE80211_S_AUTH:
493: case IEEE80211_S_ASSOC:
494: switch (mgt) {
495: case IEEE80211_FC0_SUBTYPE_AUTH:
496: /* ??? */
497: IEEE80211_SEND_MGMT(ic, ni,
498: IEEE80211_FC0_SUBTYPE_AUTH, 2);
499: break;
500: case IEEE80211_FC0_SUBTYPE_DEAUTH:
501: /* ignore and retry scan on timeout */
502: break;
503: }
504: break;
505: case IEEE80211_S_RUN:
506: switch (mgt) {
507: case IEEE80211_FC0_SUBTYPE_AUTH:
508: IEEE80211_SEND_MGMT(ic, ni,
509: IEEE80211_FC0_SUBTYPE_AUTH, 2);
510: ic->ic_state = ostate; /* stay RUN */
511: break;
512: case IEEE80211_FC0_SUBTYPE_DEAUTH:
513: /* try to reauth */
514: IEEE80211_SEND_MGMT(ic, ni,
515: IEEE80211_FC0_SUBTYPE_AUTH, 1);
516: break;
517: }
518: break;
519: }
520: break;
521: case IEEE80211_S_ASSOC:
522: switch (ostate) {
523: case IEEE80211_S_INIT:
524: case IEEE80211_S_SCAN:
525: case IEEE80211_S_ASSOC:
526: IEEE80211_DPRINTF(("%s: invalid transition\n",
527: __func__));
528: break;
529: case IEEE80211_S_AUTH:
530: IEEE80211_SEND_MGMT(ic, ni,
531: IEEE80211_FC0_SUBTYPE_ASSOC_REQ, 0);
532: break;
533: case IEEE80211_S_RUN:
534: IEEE80211_SEND_MGMT(ic, ni,
535: IEEE80211_FC0_SUBTYPE_ASSOC_REQ, 1);
536: break;
537: }
538: break;
539: case IEEE80211_S_RUN:
540: switch (ostate) {
541: case IEEE80211_S_INIT:
542: case IEEE80211_S_AUTH:
543: case IEEE80211_S_RUN:
544: IEEE80211_DPRINTF(("%s: invalid transition\n",
545: __func__));
546: break;
547: case IEEE80211_S_SCAN: /* adhoc/hostap mode */
548: case IEEE80211_S_ASSOC: /* infra mode */
549: if (ni->ni_txrate >= ni->ni_rates.rs_nrates)
550: panic("%s: bogus xmit rate %u setup\n",
551: __func__, ni->ni_txrate);
552: if (ifp->if_flags & IFF_DEBUG) {
553: printf("%s: %s with %s ssid ",
554: ifp->if_xname,
555: ic->ic_opmode == IEEE80211_M_STA ?
556: "associated" : "synchronized",
557: ether_sprintf(ni->ni_bssid));
558: ieee80211_print_essid(ic->ic_bss->ni_essid,
559: ni->ni_esslen);
560: rate = ni->ni_rates.rs_rates[ni->ni_txrate] &
561: IEEE80211_RATE_VAL;
562: printf(" channel %d start %u%sMb",
563: ieee80211_chan2ieee(ic, ni->ni_chan),
564: rate / 2, (rate & 1) ? ".5" : "");
565: printf(" %s preamble %s slot time%s\n",
566: (ic->ic_flags & IEEE80211_F_SHPREAMBLE) ?
567: "short" : "long",
568: (ic->ic_flags & IEEE80211_F_SHSLOT) ?
569: "short" : "long",
570: (ic->ic_flags & IEEE80211_F_USEPROT) ?
571: " protection enabled" : "");
572: }
573: ic->ic_mgt_timer = 0;
574: (*ifp->if_start)(ifp);
575: break;
576: }
577: break;
578: }
579: return 0;
580: }
CVSweb