ieee80211_proto.c revision 117811
12061Sjkh/*- 250479Speter * Copyright (c) 2001 Atsushi Onoe 32061Sjkh * Copyright (c) 2002, 2003 Sam Leffler, Errno Consulting 438666Sjb * All rights reserved. 532427Sjb * 638666Sjb * Redistribution and use in source and binary forms, with or without 738666Sjb * modification, are permitted provided that the following conditions 838666Sjb * are met: 938666Sjb * 1. Redistributions of source code must retain the above copyright 1064049Salex * notice, this list of conditions and the following disclaimer. 1164049Salex * 2. Redistributions in binary form must reproduce the above copyright 1266071Smarkm * notice, this list of conditions and the following disclaimer in the 1369491Sjkh * documentation and/or other materials provided with the distribution. 1438666Sjb * 3. The name of the author may not be used to endorse or promote products 1544918Sjkh * derived from this software without specific prior written permission. 1638666Sjb * 1738666Sjb * Alternatively, this software may be distributed under the terms of the 1838666Sjb * GNU General Public License ("GPL") version 2 as published by the Free 1938666Sjb * Software Foundation. 2038666Sjb * 2138666Sjb * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 2238666Sjb * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 2338978Sjb * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 2438978Sjb * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 2532427Sjb * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2638666Sjb * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2738666Sjb * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2838666Sjb * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2938666Sjb * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 3038666Sjb * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 3138666Sjb */ 3217308Speter 3338666Sjb#include <sys/cdefs.h> 3438666Sjb__FBSDID("$FreeBSD: head/sys/net80211/ieee80211_proto.c 117811 2003-07-20 21:36:08Z sam $"); 3538666Sjb 3619175Sbde/* 3738666Sjb * IEEE 802.11 protocol support. 3838666Sjb */ 3938042Sbde 4039726Sjb#include "opt_inet.h" 4138666Sjb 4238666Sjb#include <sys/param.h> 4338042Sbde#include <sys/systm.h> 4438666Sjb#include <sys/mbuf.h> 4549315Shoek#include <sys/malloc.h> 4617308Speter#include <sys/kernel.h> 4738666Sjb#include <sys/socket.h> 4838666Sjb#include <sys/sockio.h> 4938666Sjb#include <sys/endian.h> 5038666Sjb#include <sys/errno.h> 5117308Speter#include <sys/bus.h> 5245108Sobrien#include <sys/proc.h> 5342128Speter#include <sys/sysctl.h> 5442128Speter 5538666Sjb#include <machine/atomic.h> 5651361Sjb 5738666Sjb#include <net/if.h> 5817308Speter#include <net/if_dl.h> 5938666Sjb#include <net/if_media.h> 6017308Speter#include <net/if_arp.h> 6138666Sjb#include <net/ethernet.h> 6217308Speter#include <net/if_llc.h> 6327910Sasami 6443226Sjkh#include <net80211/ieee80211_var.h> 6543226Sjkh 6643226Sjkh#include <net/bpf.h> 6738666Sjb 6827910Sasami#ifdef INET 6938666Sjb#include <netinet/in.h> 7038666Sjb#include <netinet/if_ether.h> 7138666Sjb#endif 7227910Sasami 7338666Sjb#define IEEE80211_RATE2MBS(r) (((r) & IEEE80211_RATE_VAL) / 2) 7438666Sjb 7543226Sjkhconst char *ieee80211_mgt_subtype_name[] = { 7643226Sjkh "assoc_req", "assoc_resp", "reassoc_req", "reassoc_resp", 7727910Sasami "probe_req", "probe_resp", "reserved#6", "reserved#7", 7838666Sjb "beacon", "atim", "disassoc", "auth", 7938666Sjb "deauth", "reserved#13", "reserved#14", "reserved#15" 8027910Sasami}; 8138666Sjbconst char *ieee80211_state_name[IEEE80211_S_MAX] = { 8227910Sasami "INIT", /* IEEE80211_S_INIT */ 8317308Speter "SCAN", /* IEEE80211_S_SCAN */ 8438666Sjb "AUTH", /* IEEE80211_S_AUTH */ 8538666Sjb "ASSOC", /* IEEE80211_S_ASSOC */ 8617308Speter "RUN" /* IEEE80211_S_RUN */ 8755678Smarcel}; 8868987Smarcel 8969496Sjkhstatic int ieee80211_newstate(struct ieee80211com *, enum ieee80211_state, int); 9069496Sjkh 9169496Sjkhvoid 922061Sjkhieee80211_proto_attach(struct ifnet *ifp) 9355026Smarcel{ 9455026Smarcel struct ieee80211com *ic = (void *)ifp; 9554324Smarcel 9617308Speter ifp->if_hdrlen = sizeof(struct ieee80211_frame); 9738666Sjb 9817308Speter#ifdef notdef 9955678Smarcel ic->ic_rtsthreshold = IEEE80211_RTS_DEFAULT; 10038666Sjb#else 10154324Smarcel ic->ic_rtsthreshold = IEEE80211_RTS_MAX; 1022302Spaul#endif 10339206Sjkh ic->ic_fragthreshold = 2346; /* XXX not used yet */ 10439206Sjkh ic->ic_fixed_rate = -1; /* no fixed rate */ 10539206Sjkh 10669659Sobrien mtx_init(&ic->ic_mgtq.ifq_mtx, ifp->if_name, "mgmt send q", MTX_DEF); 10717308Speter 10854324Smarcel /* protocol state change handler */ 10954324Smarcel ic->ic_newstate = ieee80211_newstate; 11054324Smarcel 11154324Smarcel /* initialize management frame handlers */ 11254324Smarcel ic->ic_recv_mgmt = ieee80211_recv_mgmt; 11354324Smarcel ic->ic_send_mgmt = ieee80211_send_mgmt; 11454324Smarcel} 11569659Sobrien 11654324Smarcelvoid 11754324Smarcelieee80211_proto_detach(struct ifnet *ifp) 11854324Smarcel{ 11954324Smarcel struct ieee80211com *ic = (void *)ifp; 12054324Smarcel 12154324Smarcel IF_DRAIN(&ic->ic_mgtq); 12254324Smarcel mtx_destroy(&ic->ic_mgtq.ifq_mtx); 12354324Smarcel} 12454324Smarcel 12554324Smarcelvoid 12654324Smarcelieee80211_print_essid(u_int8_t *essid, int len) 12754324Smarcel{ 12854324Smarcel int i; 12954324Smarcel u_int8_t *p; 13054324Smarcel 13154324Smarcel if (len > IEEE80211_NWID_LEN) 13254324Smarcel len = IEEE80211_NWID_LEN; 13354324Smarcel /* determine printable or not */ 13454324Smarcel for (i = 0, p = essid; i < len; i++, p++) { 13569659Sobrien if (*p < ' ' || *p > 0x7e) 13654324Smarcel break; 13754324Smarcel } 13854324Smarcel if (i == len) { 13938666Sjb printf("\""); 14038666Sjb for (i = 0, p = essid; i < len; i++, p++) 14117308Speter printf("%c", *p); 14238666Sjb printf("\""); 14338666Sjb } else { 14438666Sjb printf("0x"); 14517308Speter for (i = 0, p = essid; i < len; i++, p++) 14655678Smarcel printf("%02x", *p); 14755678Smarcel } 14855678Smarcel} 14955678Smarcel 15055678Smarcelvoid 1512061Sjkhieee80211_dump_pkt(u_int8_t *buf, int len, int rate, int rssi) 15217308Speter{ 15338666Sjb struct ieee80211_frame *wh; 15438666Sjb int i; 15517308Speter 15655678Smarcel wh = (struct ieee80211_frame *)buf; 1573626Swollman switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) { 15817308Speter case IEEE80211_FC1_DIR_NODS: 15955678Smarcel printf("NODS %s", ether_sprintf(wh->i_addr2)); 16055678Smarcel printf("->%s", ether_sprintf(wh->i_addr1)); 16155678Smarcel printf("(%s)", ether_sprintf(wh->i_addr3)); 16255678Smarcel break; 16355678Smarcel case IEEE80211_FC1_DIR_TODS: 16455678Smarcel printf("TODS %s", ether_sprintf(wh->i_addr2)); 16555678Smarcel printf("->%s", ether_sprintf(wh->i_addr3)); 16655678Smarcel printf("(%s)", ether_sprintf(wh->i_addr1)); 16755678Smarcel break; 16855678Smarcel case IEEE80211_FC1_DIR_FROMDS: 16955678Smarcel printf("FRDS %s", ether_sprintf(wh->i_addr3)); 17055678Smarcel printf("->%s", ether_sprintf(wh->i_addr1)); 17155678Smarcel printf("(%s)", ether_sprintf(wh->i_addr2)); 17238666Sjb break; 17338666Sjb case IEEE80211_FC1_DIR_DSTODS: 17417308Speter printf("DSDS %s", ether_sprintf((u_int8_t *)&wh[1])); 17555678Smarcel printf("->%s", ether_sprintf(wh->i_addr3)); 17638978Sjb printf("(%s", ether_sprintf(wh->i_addr2)); 1773626Swollman printf("->%s)", ether_sprintf(wh->i_addr1)); 17817308Speter break; 17938666Sjb } 18017308Speter switch (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) { 18143226Sjkh case IEEE80211_FC0_TYPE_DATA: 18243226Sjkh printf(" data"); 18343226Sjkh break; 18438666Sjb case IEEE80211_FC0_TYPE_MGT: 18538666Sjb printf(" %s", ieee80211_mgt_subtype_name[ 18644103Smsmith (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) 187 >> IEEE80211_FC0_SUBTYPE_SHIFT]); 188 break; 189 default: 190 printf(" type#%d", wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK); 191 break; 192 } 193 if (wh->i_fc[1] & IEEE80211_FC1_WEP) 194 printf(" WEP"); 195 if (rate >= 0) 196 printf(" %dM", rate / 2); 197 if (rssi >= 0) 198 printf(" +%d", rssi); 199 printf("\n"); 200 if (len > 0) { 201 for (i = 0; i < len; i++) { 202 if ((i & 1) == 0) 203 printf(" "); 204 printf("%02x", buf[i]); 205 } 206 printf("\n"); 207 } 208} 209 210int 211ieee80211_fix_rate(struct ieee80211com *ic, struct ieee80211_node *ni, int flags) 212{ 213#define RV(v) ((v) & IEEE80211_RATE_VAL) 214 int i, j, ignore, error; 215 int okrate, badrate; 216 struct ieee80211_rateset *srs, *nrs; 217 u_int8_t r; 218 219 error = 0; 220 okrate = badrate = 0; 221 srs = &ic->ic_sup_rates[ieee80211_chan2mode(ic, ni->ni_chan)]; 222 nrs = &ni->ni_rates; 223 for (i = 0; i < ni->ni_rates.rs_nrates; ) { 224 ignore = 0; 225 if (flags & IEEE80211_F_DOSORT) { 226 /* 227 * Sort rates. 228 */ 229 for (j = i + 1; j < nrs->rs_nrates; j++) { 230 if (RV(nrs->rs_rates[i]) > RV(nrs->rs_rates[j])) { 231 r = nrs->rs_rates[i]; 232 nrs->rs_rates[i] = nrs->rs_rates[j]; 233 nrs->rs_rates[j] = r; 234 } 235 } 236 } 237 r = nrs->rs_rates[i] & IEEE80211_RATE_VAL; 238 badrate = r; 239 if (flags & IEEE80211_F_DOFRATE) { 240 /* 241 * Apply fixed rate constraint. Note that we do 242 * not apply the constraint to basic rates as 243 * otherwise we may not be able to associate if 244 * the rate set we submit to the AP is invalid 245 * (e.g. fix rate at 36Mb/s which is not a basic 246 * rate for 11a operation). 247 */ 248 if ((nrs->rs_rates[i] & IEEE80211_RATE_BASIC) == 0 && 249 ic->ic_fixed_rate >= 0 && 250 r != RV(srs->rs_rates[ic->ic_fixed_rate])) 251 ignore++; 252 } 253 if (flags & IEEE80211_F_DONEGO) { 254 /* 255 * Check against supported rates. 256 */ 257 for (j = 0; j < srs->rs_nrates; j++) { 258 if (r == RV(srs->rs_rates[j])) 259 break; 260 } 261 if (j == srs->rs_nrates) { 262 if (nrs->rs_rates[i] & IEEE80211_RATE_BASIC) 263 error++; 264 ignore++; 265 } 266 } 267 if (flags & IEEE80211_F_DODEL) { 268 /* 269 * Delete unacceptable rates. 270 */ 271 if (ignore) { 272 nrs->rs_nrates--; 273 for (j = i; j < nrs->rs_nrates; j++) 274 nrs->rs_rates[j] = nrs->rs_rates[j + 1]; 275 nrs->rs_rates[j] = 0; 276 continue; 277 } 278 } 279 if (!ignore) 280 okrate = nrs->rs_rates[i]; 281 i++; 282 } 283 if (okrate == 0 || error != 0) 284 return badrate | IEEE80211_RATE_BASIC; 285 else 286 return RV(okrate); 287#undef RV 288} 289 290static int 291ieee80211_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int mgt) 292{ 293 struct ifnet *ifp = &ic->ic_if; 294 struct ieee80211_node *ni; 295 enum ieee80211_state ostate; 296 297 ostate = ic->ic_state; 298 IEEE80211_DPRINTF(("%s: %s -> %s\n", __func__, 299 ieee80211_state_name[ostate], ieee80211_state_name[nstate])); 300 ic->ic_state = nstate; /* state transition */ 301 ni = ic->ic_bss; /* NB: no reference held */ 302 switch (nstate) { 303 case IEEE80211_S_INIT: 304 switch (ostate) { 305 case IEEE80211_S_INIT: 306 break; 307 case IEEE80211_S_RUN: 308 switch (ic->ic_opmode) { 309 case IEEE80211_M_STA: 310 IEEE80211_SEND_MGMT(ic, ni, 311 IEEE80211_FC0_SUBTYPE_DISASSOC, 312 IEEE80211_REASON_ASSOC_LEAVE); 313 break; 314 case IEEE80211_M_HOSTAP: 315 mtx_lock(&ic->ic_nodelock); 316 TAILQ_FOREACH(ni, &ic->ic_node, ni_list) { 317 if (ni->ni_associd == 0) 318 continue; 319 IEEE80211_SEND_MGMT(ic, ni, 320 IEEE80211_FC0_SUBTYPE_DISASSOC, 321 IEEE80211_REASON_ASSOC_LEAVE); 322 } 323 mtx_unlock(&ic->ic_nodelock); 324 break; 325 default: 326 break; 327 } 328 /* FALLTHRU */ 329 case IEEE80211_S_ASSOC: 330 switch (ic->ic_opmode) { 331 case IEEE80211_M_STA: 332 IEEE80211_SEND_MGMT(ic, ni, 333 IEEE80211_FC0_SUBTYPE_DEAUTH, 334 IEEE80211_REASON_AUTH_LEAVE); 335 break; 336 case IEEE80211_M_HOSTAP: 337 mtx_lock(&ic->ic_nodelock); 338 TAILQ_FOREACH(ni, &ic->ic_node, ni_list) { 339 IEEE80211_SEND_MGMT(ic, ni, 340 IEEE80211_FC0_SUBTYPE_DEAUTH, 341 IEEE80211_REASON_AUTH_LEAVE); 342 } 343 mtx_unlock(&ic->ic_nodelock); 344 break; 345 default: 346 break; 347 } 348 /* FALLTHRU */ 349 case IEEE80211_S_AUTH: 350 case IEEE80211_S_SCAN: 351 ic->ic_mgt_timer = 0; 352 IF_DRAIN(&ic->ic_mgtq); 353 if (ic->ic_wep_ctx != NULL) { 354 free(ic->ic_wep_ctx, M_DEVBUF); 355 ic->ic_wep_ctx = NULL; 356 } 357 ieee80211_free_allnodes(ic); 358 break; 359 } 360 break; 361 case IEEE80211_S_SCAN: 362 ic->ic_flags &= ~IEEE80211_F_SIBSS; 363 /* initialize bss for probe request */ 364 IEEE80211_ADDR_COPY(ni->ni_macaddr, ifp->if_broadcastaddr); 365 IEEE80211_ADDR_COPY(ni->ni_bssid, ifp->if_broadcastaddr); 366 ni->ni_rates = ic->ic_sup_rates[ 367 ieee80211_chan2mode(ic, ni->ni_chan)]; 368 ni->ni_associd = 0; 369 ni->ni_rstamp = 0; 370 switch (ostate) { 371 case IEEE80211_S_INIT: 372 if (ic->ic_opmode == IEEE80211_M_HOSTAP && 373 ic->ic_des_chan != IEEE80211_CHAN_ANYC) { 374 /* 375 * AP operation and we already have a channel; 376 * bypass the scan and startup immediately. 377 */ 378 ieee80211_create_ibss(ic, ic->ic_des_chan); 379 } else { 380 ieee80211_begin_scan(ifp); 381 } 382 break; 383 case IEEE80211_S_SCAN: 384 /* scan next */ 385 if (ic->ic_flags & IEEE80211_F_ASCAN) { 386 IEEE80211_SEND_MGMT(ic, ni, 387 IEEE80211_FC0_SUBTYPE_PROBE_REQ, 0); 388 } 389 break; 390 case IEEE80211_S_RUN: 391 /* beacon miss */ 392 if (ifp->if_flags & IFF_DEBUG) { 393 /* XXX bssid clobbered above */ 394 if_printf(ifp, "no recent beacons from %s;" 395 " rescanning\n", 396 ether_sprintf(ic->ic_bss->ni_bssid)); 397 } 398 ieee80211_free_allnodes(ic); 399 /* FALLTHRU */ 400 case IEEE80211_S_AUTH: 401 case IEEE80211_S_ASSOC: 402 /* timeout restart scan */ 403 ni = ieee80211_find_node(ic, ic->ic_bss->ni_macaddr); 404 if (ni != NULL) { 405 ni->ni_fails++; 406 ieee80211_unref_node(&ni); 407 } 408 ieee80211_begin_scan(ifp); 409 break; 410 } 411 break; 412 case IEEE80211_S_AUTH: 413 switch (ostate) { 414 case IEEE80211_S_INIT: 415 IEEE80211_DPRINTF(("%s: invalid transition\n", 416 __func__)); 417 break; 418 case IEEE80211_S_SCAN: 419 IEEE80211_SEND_MGMT(ic, ni, 420 IEEE80211_FC0_SUBTYPE_AUTH, 1); 421 break; 422 case IEEE80211_S_AUTH: 423 case IEEE80211_S_ASSOC: 424 switch (mgt) { 425 case IEEE80211_FC0_SUBTYPE_AUTH: 426 /* ??? */ 427 IEEE80211_SEND_MGMT(ic, ni, 428 IEEE80211_FC0_SUBTYPE_AUTH, 2); 429 break; 430 case IEEE80211_FC0_SUBTYPE_DEAUTH: 431 /* ignore and retry scan on timeout */ 432 break; 433 } 434 break; 435 case IEEE80211_S_RUN: 436 switch (mgt) { 437 case IEEE80211_FC0_SUBTYPE_AUTH: 438 IEEE80211_SEND_MGMT(ic, ni, 439 IEEE80211_FC0_SUBTYPE_AUTH, 2); 440 ic->ic_state = ostate; /* stay RUN */ 441 break; 442 case IEEE80211_FC0_SUBTYPE_DEAUTH: 443 /* try to reauth */ 444 IEEE80211_SEND_MGMT(ic, ni, 445 IEEE80211_FC0_SUBTYPE_AUTH, 1); 446 break; 447 } 448 break; 449 } 450 break; 451 case IEEE80211_S_ASSOC: 452 switch (ostate) { 453 case IEEE80211_S_INIT: 454 case IEEE80211_S_SCAN: 455 case IEEE80211_S_ASSOC: 456 IEEE80211_DPRINTF(("%s: invalid transition\n", 457 __func__)); 458 break; 459 case IEEE80211_S_AUTH: 460 IEEE80211_SEND_MGMT(ic, ni, 461 IEEE80211_FC0_SUBTYPE_ASSOC_REQ, 0); 462 break; 463 case IEEE80211_S_RUN: 464 IEEE80211_SEND_MGMT(ic, ni, 465 IEEE80211_FC0_SUBTYPE_ASSOC_REQ, 1); 466 break; 467 } 468 break; 469 case IEEE80211_S_RUN: 470 switch (ostate) { 471 case IEEE80211_S_INIT: 472 case IEEE80211_S_AUTH: 473 case IEEE80211_S_RUN: 474 IEEE80211_DPRINTF(("%s: invalid transition\n", 475 __func__)); 476 break; 477 case IEEE80211_S_SCAN: /* adhoc/hostap mode */ 478 case IEEE80211_S_ASSOC: /* infra mode */ 479 KASSERT(ni->ni_txrate < ni->ni_rates.rs_nrates, 480 ("%s: bogus xmit rate %u setup\n", __func__, 481 ni->ni_txrate)); 482 if (ifp->if_flags & IFF_DEBUG) { 483 if_printf(ifp, " "); 484 if (ic->ic_opmode == IEEE80211_M_STA) 485 printf("associated "); 486 else 487 printf("synchronized "); 488 printf("with %s ssid ", 489 ether_sprintf(ni->ni_bssid)); 490 ieee80211_print_essid(ic->ic_bss->ni_essid, 491 ni->ni_esslen); 492 printf(" channel %d start %uMb\n", 493 ieee80211_chan2ieee(ic, ni->ni_chan), 494 IEEE80211_RATE2MBS(ni->ni_rates.rs_rates[ni->ni_txrate])); 495 } 496 ic->ic_mgt_timer = 0; 497 (*ifp->if_start)(ifp); 498 break; 499 } 500 break; 501 } 502 return 0; 503} 504