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