1 /* 2 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 6 /* 7 * Copyright (c) 2001 Atsushi Onoe 8 * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting 9 * All rights reserved. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. The name of the author may not be used to endorse or promote products 20 * derived from this software without specific prior written permission. 21 * 22 * Alternatively, this software may be distributed under the terms of the 23 * GNU General Public License ("GPL") version 2 as published by the Free 24 * Software Foundation. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 27 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 28 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 29 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 30 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 31 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 32 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 35 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 */ 37 38 #pragma ident "%Z%%M% %I% %E% SMI" 39 40 41 /* 42 * Send out 802.11 frames 43 */ 44 45 #include <sys/byteorder.h> 46 #include <sys/strsun.h> 47 #include "net80211_impl.h" 48 49 /* 50 * Set the direction field and address fields of an outgoing 51 * non-QoS frame. Note this should be called early on in 52 * constructing a frame as it sets i_fc[1]; other bits can 53 * then be or'd in. 54 */ 55 static void 56 ieee80211_send_setup(ieee80211com_t *ic, ieee80211_node_t *in, 57 struct ieee80211_frame *wh, int type, const uint8_t *sa, const uint8_t *da, 58 const uint8_t *bssid) 59 { 60 wh->i_fc[0] = (uint8_t)(IEEE80211_FC0_VERSION_0 | type); 61 if ((type & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_DATA) { 62 switch (ic->ic_opmode) { 63 case IEEE80211_M_STA: 64 wh->i_fc[1] = IEEE80211_FC1_DIR_TODS; 65 IEEE80211_ADDR_COPY(wh->i_addr1, bssid); 66 IEEE80211_ADDR_COPY(wh->i_addr2, sa); 67 IEEE80211_ADDR_COPY(wh->i_addr3, da); 68 break; 69 case IEEE80211_M_IBSS: 70 case IEEE80211_M_AHDEMO: 71 wh->i_fc[1] = IEEE80211_FC1_DIR_NODS; 72 IEEE80211_ADDR_COPY(wh->i_addr1, da); 73 IEEE80211_ADDR_COPY(wh->i_addr2, sa); 74 IEEE80211_ADDR_COPY(wh->i_addr3, bssid); 75 break; 76 default: 77 ieee80211_err("ieee80211_send_setup: " 78 "Invalid mode %u\n", ic->ic_opmode); 79 return; 80 } 81 } else { 82 wh->i_fc[1] = IEEE80211_FC1_DIR_NODS; 83 IEEE80211_ADDR_COPY(wh->i_addr1, da); 84 IEEE80211_ADDR_COPY(wh->i_addr2, sa); 85 IEEE80211_ADDR_COPY(wh->i_addr3, bssid); 86 } 87 *(uint16_t *)&wh->i_dur[0] = 0; /* set duration */ 88 *(uint16_t *)&wh->i_seq[0] = /* set sequence number */ 89 LE_16(in->in_txseqs[0] << IEEE80211_SEQ_SEQ_SHIFT); 90 in->in_txseqs[0]++; /* increase sequence number by 1 */ 91 } 92 93 /* 94 * Send a management frame to the specified node. The node pointer 95 * must have a reference as the pointer will be passed to the driver 96 * and potentially held for a long time. If the frame is successfully 97 * dispatched to the driver, then it is responsible for freeing the 98 * reference (and potentially free'ing up any associated storage). 99 * 100 * Return 0 on success 101 */ 102 static int 103 ieee80211_mgmt_output(ieee80211com_t *ic, ieee80211_node_t *in, mblk_t *mp, 104 int type, int timer) 105 { 106 ieee80211_impl_t *im = ic->ic_private; 107 struct ieee80211_frame *wh; 108 109 ASSERT(in != NULL); 110 111 wh = (struct ieee80211_frame *)mp->b_rptr; 112 ieee80211_send_setup(ic, in, wh, IEEE80211_FC0_TYPE_MGT | type, 113 ic->ic_macaddr, in->in_macaddr, in->in_bssid); 114 if (in->in_challenge != NULL) 115 wh->i_fc[1] |= IEEE80211_FC1_WEP; 116 117 if (timer > 0) { 118 /* 119 * Set the mgt frame timeout. 120 */ 121 im->im_mgt_timer = timer; 122 ieee80211_start_watchdog(ic, 1); 123 } 124 return ((*ic->ic_xmit)(ic, mp, IEEE80211_FC0_TYPE_MGT)); 125 } 126 127 /* 128 * Send a null data frame to the specified node. 129 * 130 * NB: the caller is assumed to have setup a node reference 131 * for use; this is necessary to deal with a race condition 132 * when probing for inactive stations. 133 */ 134 int 135 ieee80211_send_nulldata(ieee80211_node_t *in) 136 { 137 ieee80211com_t *ic = in->in_ic; 138 mblk_t *m; 139 struct ieee80211_frame *wh; 140 uint8_t *frm; 141 142 m = ieee80211_getmgtframe(&frm, 0); 143 if (m == NULL) { 144 ic->ic_stats.is_tx_nobuf++; 145 return (ENOMEM); 146 } 147 148 wh = (struct ieee80211_frame *)m->b_rptr; 149 ieee80211_send_setup(ic, in, wh, 150 IEEE80211_FC0_TYPE_DATA | IEEE80211_FC0_SUBTYPE_NODATA, 151 ic->ic_macaddr, in->in_macaddr, in->in_bssid); 152 /* NB: power management bit is never sent by an AP */ 153 if ((in->in_flags & IEEE80211_NODE_PWR_MGT) && 154 ic->ic_opmode != IEEE80211_M_HOSTAP) 155 wh->i_fc[1] |= IEEE80211_FC1_PWR_MGT; 156 m->b_wptr = m->b_rptr + sizeof (struct ieee80211_frame); 157 158 ieee80211_dbg(IEEE80211_MSG_DEBUG | IEEE80211_MSG_DUMPPKTS, "net80211: " 159 "send null data frame on channel %u, pwr mgt %s\n", 160 ieee80211_macaddr_sprintf(in->in_macaddr), 161 ieee80211_chan2ieee(ic, ic->ic_curchan), 162 wh->i_fc[1] & IEEE80211_FC1_PWR_MGT ? "ena" : "dis"); 163 164 (void) (*ic->ic_xmit)(ic, m, IEEE80211_FC0_TYPE_MGT); 165 166 return (0); 167 } 168 169 /* 170 * Encapsulate an outbound data frame for GLDv3 based driver. 171 * Fill in the variable part of the 80211 frame 172 */ 173 /* ARGSUSED */ 174 mblk_t * 175 ieee80211_encap(ieee80211com_t *ic, mblk_t *mp, ieee80211_node_t *in) 176 { 177 struct ieee80211_frame *wh; 178 struct ieee80211_key *key; 179 180 ASSERT(mp != NULL && MBLKL(mp) >= sizeof (struct ieee80211_frame)); 181 wh = (struct ieee80211_frame *)mp->b_rptr; 182 *(uint16_t *)wh->i_dur = 0; 183 *(uint16_t *)wh->i_seq = 184 LE_16(in->in_txseqs[0] << IEEE80211_SEQ_SEQ_SHIFT); 185 in->in_txseqs[0]++; 186 187 if (ic->ic_flags & IEEE80211_F_PRIVACY) 188 key = ieee80211_crypto_getkey(ic); 189 else 190 key = NULL; 191 192 /* 193 * IEEE 802.1X: send EAPOL frames always in the clear. 194 * WPA/WPA2: encrypt EAPOL keys when pairwise keys are set. 195 */ 196 if (key != NULL && (ic->ic_flags & IEEE80211_F_WPA)) { 197 wh->i_fc[1] |= IEEE80211_FC1_WEP; 198 if (!ieee80211_crypto_enmic(isc, key, mp, 0)) { 199 ieee80211_err("ieee80211_crypto_enmic failed.\n"); 200 } 201 } 202 203 return (mp); 204 } 205 206 /* 207 * Add supported rates information element to a frame. 208 */ 209 static uint8_t * 210 ieee80211_add_rates(uint8_t *frm, const struct ieee80211_rateset *rs) 211 { 212 uint8_t nrates; 213 214 *frm++ = IEEE80211_ELEMID_RATES; 215 nrates = rs->ir_nrates; 216 if (nrates > IEEE80211_RATE_SIZE) 217 nrates = IEEE80211_RATE_SIZE; 218 *frm++ = nrates; 219 bcopy(rs->ir_rates, frm, nrates); 220 return (frm + nrates); 221 } 222 223 /* 224 * Add extended supported rates element to a frame, usually for 11g mode 225 */ 226 static uint8_t * 227 ieee80211_add_xrates(uint8_t *frm, const struct ieee80211_rateset *rs) 228 { 229 if (rs->ir_nrates > IEEE80211_RATE_SIZE) { 230 uint8_t nrates = rs->ir_nrates - IEEE80211_RATE_SIZE; 231 232 *frm++ = IEEE80211_ELEMID_XRATES; 233 *frm++ = nrates; 234 bcopy(rs->ir_rates + IEEE80211_RATE_SIZE, frm, nrates); 235 frm += nrates; 236 } 237 return (frm); 238 } 239 240 /* 241 * Add SSID element to a frame 242 */ 243 static uint8_t * 244 ieee80211_add_ssid(uint8_t *frm, const uint8_t *ssid, uint32_t len) 245 { 246 *frm++ = IEEE80211_ELEMID_SSID; 247 *frm++ = (uint8_t)len; 248 bcopy(ssid, frm, len); 249 return (frm + len); 250 } 251 252 /* 253 * Add an erp element to a frame. 254 */ 255 static uint8_t * 256 ieee80211_add_erp(uint8_t *frm, ieee80211com_t *ic) 257 { 258 uint8_t erp; 259 260 *frm++ = IEEE80211_ELEMID_ERP; 261 *frm++ = 1; 262 erp = 0; 263 if (ic->ic_flags & IEEE80211_F_USEPROT) 264 erp |= IEEE80211_ERP_USE_PROTECTION; 265 if (ic->ic_flags & IEEE80211_F_USEBARKER) 266 erp |= IEEE80211_ERP_LONG_PREAMBLE; 267 *frm++ = erp; 268 return (frm); 269 } 270 271 /* 272 * Get capability information from the interface softc, ic. 273 */ 274 static uint16_t 275 ieee80211_get_capinfo(ieee80211com_t *ic) 276 { 277 uint16_t capinfo; 278 279 if (ic->ic_opmode == IEEE80211_M_IBSS) 280 capinfo = IEEE80211_CAPINFO_IBSS; 281 else 282 capinfo = IEEE80211_CAPINFO_ESS; 283 if (ic->ic_flags & IEEE80211_F_PRIVACY) 284 capinfo |= IEEE80211_CAPINFO_PRIVACY; 285 if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) && 286 IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) { 287 capinfo |= IEEE80211_CAPINFO_SHORT_PREAMBLE; 288 } 289 if (ic->ic_flags & IEEE80211_F_SHSLOT) 290 capinfo |= IEEE80211_CAPINFO_SHORT_SLOTTIME; 291 292 return (capinfo); 293 } 294 295 /* 296 * Send a probe request frame with the specified ssid 297 * and any optional information element data. 298 */ 299 int 300 ieee80211_send_probereq(ieee80211_node_t *in, 301 const uint8_t *sa, const uint8_t *da, const uint8_t *bssid, 302 const uint8_t *ssid, size_t ssidlen, const void *optie, size_t optielen) 303 { 304 mblk_t *mp; 305 ieee80211com_t *ic = in->in_ic; 306 enum ieee80211_phymode mode; 307 struct ieee80211_frame *wh; 308 uint8_t *frm; 309 310 /* 311 * prreq frame format ([tlv] - 1 byte element ID + 1 byte length) 312 * [tlv] ssid 313 * [tlv] supported rates 314 * [tlv] extended supported rates 315 * [tlv] user-specified ie's 316 */ 317 mp = ieee80211_getmgtframe(&frm, 318 2 + IEEE80211_NWID_LEN 319 + 2 + IEEE80211_RATE_SIZE + 320 + 2 + IEEE80211_XRATE_SIZE 321 + optielen); 322 if (mp == NULL) 323 return (ENOMEM); 324 325 frm = ieee80211_add_ssid(frm, ssid, ssidlen); 326 mode = ieee80211_chan2mode(ic, ic->ic_curchan); 327 frm = ieee80211_add_rates(frm, &ic->ic_sup_rates[mode]); 328 frm = ieee80211_add_xrates(frm, &ic->ic_sup_rates[mode]); 329 if (optie != NULL) { 330 (void) memcpy(frm, optie, optielen); 331 frm += optielen; 332 } 333 mp->b_wptr = frm; 334 335 wh = (struct ieee80211_frame *)mp->b_rptr; 336 ieee80211_send_setup(ic, in, wh, 337 IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_PROBE_REQ, 338 sa, da, bssid); 339 340 ieee80211_dbg(IEEE80211_MSG_DEBUG | IEEE80211_MSG_DUMPPKTS, 341 "[%s] send probe req on channel %u\n", 342 ieee80211_macaddr_sprintf(wh->i_addr1), 343 ieee80211_chan2ieee(ic, ic->ic_curchan)); 344 345 (void) (*ic->ic_xmit)(ic, mp, IEEE80211_FC0_TYPE_MGT); 346 return (0); 347 } 348 349 /* 350 * Send a management frame. The node is for the destination (or ic_bss 351 * when in station mode). Nodes other than ic_bss have their reference 352 * count bumped to reflect our use for an indeterminant time. 353 */ 354 int 355 ieee80211_send_mgmt(ieee80211com_t *ic, ieee80211_node_t *in, int type, int arg) 356 { 357 mblk_t *mp; 358 uint8_t *frm; 359 uint16_t capinfo; 360 struct ieee80211_key *key; 361 boolean_t has_challenge; 362 boolean_t is_shared_key; 363 int ret; 364 int timer; 365 int status; 366 367 ASSERT(in != NULL); 368 369 timer = 0; 370 switch (type) { 371 case IEEE80211_FC0_SUBTYPE_PROBE_RESP: 372 /* 373 * probe response frame format 374 * [8] time stamp 375 * [2] beacon interval 376 * [2] capability information 377 * [tlv] ssid 378 * [tlv] supported rates 379 * [tlv] parameter set (FH/DS) 380 * [tlv] parameter set (IBSS) 381 * [tlv] extended rate phy (ERP) 382 * [tlv] extended supported rates 383 * [tlv] WPA 384 * [tlv] WME (optional) 385 */ 386 mp = ieee80211_getmgtframe(&frm, 387 8 /* time stamp */ 388 + sizeof (uint16_t) /* beacon interval */ 389 + sizeof (uint16_t) /* capability */ 390 + 2 + IEEE80211_NWID_LEN 391 + 2 + IEEE80211_RATE_SIZE 392 + 2 + IEEE80211_FH_LEN 393 + 2 + IEEE80211_IBSS_LEN 394 + 2 + IEEE80211_ERP_LEN 395 + 2 + IEEE80211_XRATE_SIZE 396 + (ic->ic_flags & IEEE80211_F_WPA ? 397 2 * sizeof (struct ieee80211_ie_wpa) : 0) 398 /* [tlv] WPA */ 399 + (ic->ic_flags & IEEE80211_F_WME ? 400 sizeof (struct ieee80211_wme_param) : 0)); 401 /* [tlv] WME */ 402 if (mp == NULL) 403 return (ENOMEM); 404 405 bzero(frm, 8); /* timestamp is set by hardware/driver */ 406 frm += 8; 407 *(uint16_t *)frm = LE_16(in->in_intval); 408 frm += 2; 409 capinfo = ieee80211_get_capinfo(ic); 410 *(uint16_t *)frm = LE_16(capinfo); 411 frm += 2; 412 413 frm = ieee80211_add_ssid(frm, in->in_essid, in->in_esslen); 414 frm = ieee80211_add_rates(frm, &in->in_rates); 415 416 if (ic->ic_phytype == IEEE80211_T_FH) { 417 *frm++ = IEEE80211_ELEMID_FHPARMS; 418 *frm++ = IEEE80211_FH_LEN; 419 *frm++ = in->in_fhdwell & 0x00ff; 420 *frm++ = (in->in_fhdwell >> 8) & 0x00ff; 421 *frm++ = IEEE80211_FH_CHANSET( 422 ieee80211_chan2ieee(ic, ic->ic_curchan)); 423 *frm++ = IEEE80211_FH_CHANPAT( 424 ieee80211_chan2ieee(ic, ic->ic_curchan)); 425 *frm++ = in->in_fhindex; 426 } else { 427 *frm++ = IEEE80211_ELEMID_DSPARMS; 428 *frm++ = IEEE80211_DS_LEN; 429 *frm++ = ieee80211_chan2ieee(ic, ic->ic_curchan); 430 } 431 432 if (ic->ic_opmode == IEEE80211_M_IBSS) { 433 *frm++ = IEEE80211_ELEMID_IBSSPARMS; 434 *frm++ = IEEE80211_IBSS_LEN; 435 *frm++ = 0; *frm++ = 0; /* ATIM window */ 436 } 437 frm = ieee80211_add_xrates(frm, &in->in_rates); 438 break; 439 440 case IEEE80211_FC0_SUBTYPE_AUTH: 441 status = arg >> 16; 442 arg &= 0xffff; 443 has_challenge = ((arg == IEEE80211_AUTH_SHARED_CHALLENGE || 444 arg == IEEE80211_AUTH_SHARED_RESPONSE) && 445 in->in_challenge != NULL); 446 447 /* 448 * Deduce whether we're doing open authentication or 449 * shared key authentication. We do the latter if 450 * we're in the middle of a shared key authentication 451 * handshake or if we're initiating an authentication 452 * request and configured to use shared key. 453 */ 454 is_shared_key = has_challenge || 455 arg >= IEEE80211_AUTH_SHARED_RESPONSE || 456 (arg == IEEE80211_AUTH_SHARED_REQUEST && 457 ic->ic_bss->in_authmode == IEEE80211_AUTH_SHARED); 458 459 if (has_challenge && status == IEEE80211_STATUS_SUCCESS) 460 key = ieee80211_crypto_getkey(ic); 461 else 462 key = NULL; 463 464 mp = ieee80211_getmgtframe(&frm, 465 3 * sizeof (uint16_t) 466 + (has_challenge && status == IEEE80211_STATUS_SUCCESS ? 467 sizeof (uint16_t) + IEEE80211_CHALLENGE_LEN : 0) 468 + (key != NULL ? key->wk_cipher->ic_header : 0)); 469 if (mp == NULL) 470 return (ENOMEM); 471 472 if (key != NULL) 473 frm += key->wk_cipher->ic_header; 474 475 ((uint16_t *)frm)[0] = 476 (is_shared_key) ? LE_16(IEEE80211_AUTH_ALG_SHARED) 477 : LE_16(IEEE80211_AUTH_ALG_OPEN); 478 ((uint16_t *)frm)[1] = LE_16(arg); /* sequence number */ 479 ((uint16_t *)frm)[2] = LE_16(status); /* status */ 480 481 if (has_challenge && status == IEEE80211_STATUS_SUCCESS) { 482 frm += IEEE80211_AUTH_ELEM_MIN; 483 *frm = IEEE80211_ELEMID_CHALLENGE; 484 frm++; 485 *frm = IEEE80211_CHALLENGE_LEN; 486 frm++; 487 bcopy(in->in_challenge, frm, IEEE80211_CHALLENGE_LEN); 488 } 489 490 if (ic->ic_opmode == IEEE80211_M_STA) 491 timer = IEEE80211_TRANS_WAIT; 492 break; 493 494 case IEEE80211_FC0_SUBTYPE_DEAUTH: 495 mp = ieee80211_getmgtframe(&frm, sizeof (uint16_t)); 496 if (mp == NULL) 497 return (ENOMEM); 498 499 *(uint16_t *)frm = LE_16(arg); /* reason */ 500 501 ieee80211_node_unauthorize(in); /* port closed */ 502 break; 503 504 case IEEE80211_FC0_SUBTYPE_ASSOC_REQ: 505 case IEEE80211_FC0_SUBTYPE_REASSOC_REQ: 506 /* 507 * asreq frame format 508 * [2] capability information 509 * [2] listen interval 510 * [6*] current AP address (reassoc only) 511 * [tlv] ssid 512 * [tlv] supported rates 513 * [tlv] extended supported rates 514 * [tlv] WME 515 * [tlv] user-specified ie's 516 */ 517 mp = ieee80211_getmgtframe(&frm, 518 sizeof (uint16_t) 519 + sizeof (uint16_t) + IEEE80211_ADDR_LEN 520 + 2 + IEEE80211_NWID_LEN 521 + 2 + IEEE80211_RATE_SIZE 522 + 2 + IEEE80211_XRATE_SIZE 523 + ic->ic_opt_ie_len); 524 if (mp == NULL) 525 return (ENOMEM); 526 527 capinfo = ieee80211_get_capinfo(ic); 528 if (!(in->in_capinfo & IEEE80211_CAPINFO_SHORT_SLOTTIME) || 529 !(ic->ic_caps & IEEE80211_C_SHSLOT)) { 530 capinfo &= ~IEEE80211_CAPINFO_SHORT_SLOTTIME; 531 } else { 532 capinfo |= IEEE80211_CAPINFO_SHORT_SLOTTIME; 533 } 534 *(uint16_t *)frm = LE_16(capinfo); 535 frm += 2; 536 537 *(uint16_t *)frm = LE_16(ic->ic_lintval); 538 frm += 2; 539 540 if (type == IEEE80211_FC0_SUBTYPE_REASSOC_REQ) { 541 IEEE80211_ADDR_COPY(frm, ic->ic_bss->in_bssid); 542 frm += IEEE80211_ADDR_LEN; 543 } 544 545 frm = ieee80211_add_ssid(frm, in->in_essid, in->in_esslen); 546 frm = ieee80211_add_rates(frm, &in->in_rates); 547 frm = ieee80211_add_xrates(frm, &in->in_rates); 548 if (ic->ic_opt_ie != NULL) { 549 bcopy(ic->ic_opt_ie, frm, ic->ic_opt_ie_len); 550 frm += ic->ic_opt_ie_len; 551 } 552 mp->b_wptr = frm; /* allocated is greater than used */ 553 554 timer = IEEE80211_TRANS_WAIT; 555 break; 556 557 case IEEE80211_FC0_SUBTYPE_ASSOC_RESP: 558 case IEEE80211_FC0_SUBTYPE_REASSOC_RESP: 559 /* 560 * asreq frame format 561 * [2] capability information 562 * [2] status 563 * [2] association ID 564 * [tlv] supported rates 565 * [tlv] extended supported rates 566 * [tlv] WME (if enabled and STA enabled) 567 */ 568 mp = ieee80211_getmgtframe(&frm, 569 3 * sizeof (uint16_t) 570 + 2 + IEEE80211_RATE_SIZE 571 + 2 + IEEE80211_XRATE_SIZE); 572 if (mp == NULL) 573 return (ENOMEM); 574 575 capinfo = ieee80211_get_capinfo(ic); 576 *(uint16_t *)frm = LE_16(capinfo); 577 frm += 2; 578 579 *(uint16_t *)frm = LE_16(arg); /* status */ 580 frm += 2; 581 582 if (arg == IEEE80211_STATUS_SUCCESS) 583 *(uint16_t *)frm = LE_16(in->in_associd); 584 else 585 *(uint16_t *)frm = LE_16(0); 586 frm += 2; 587 588 frm = ieee80211_add_rates(frm, &in->in_rates); 589 frm = ieee80211_add_xrates(frm, &in->in_rates); 590 break; 591 592 case IEEE80211_FC0_SUBTYPE_DISASSOC: 593 mp = ieee80211_getmgtframe(&frm, sizeof (uint16_t)); 594 if (mp == NULL) 595 return (ENOMEM); 596 *(uint16_t *)frm = LE_16(arg); /* reason */ 597 break; 598 599 default: 600 ieee80211_dbg(IEEE80211_MSG_ANY, 601 "[%s] invalid mgmt frame type %u\n", 602 ieee80211_macaddr_sprintf(in->in_macaddr), type); 603 return (EINVAL); 604 } /* type */ 605 ret = ieee80211_mgmt_output(ic, in, mp, type, timer); 606 return (ret); 607 } 608 609 /* 610 * Allocate a beacon frame and fillin the appropriate bits. 611 */ 612 mblk_t * 613 ieee80211_beacon_alloc(ieee80211com_t *ic, ieee80211_node_t *in, 614 struct ieee80211_beacon_offsets *bo) 615 { 616 struct ieee80211_frame *wh; 617 struct ieee80211_rateset *rs; 618 mblk_t *m; 619 uint8_t *frm; 620 uint8_t *efrm; 621 int pktlen; 622 uint16_t capinfo; 623 624 IEEE80211_LOCK(ic); 625 /* 626 * beacon frame format 627 * [8] time stamp 628 * [2] beacon interval 629 * [2] cabability information 630 * [tlv] ssid 631 * [tlv] supported rates 632 * [3] parameter set (DS) 633 * [tlv] parameter set (IBSS/TIM) 634 * [tlv] extended rate phy (ERP) 635 * [tlv] extended supported rates 636 * [tlv] WME parameters 637 * [tlv] WPA/RSN parameters 638 * Vendor-specific OIDs (e.g. Atheros) 639 * NB: we allocate the max space required for the TIM bitmap. 640 */ 641 rs = &in->in_rates; 642 pktlen = 8 /* time stamp */ 643 + sizeof (uint16_t) /* beacon interval */ 644 + sizeof (uint16_t) /* capabilities */ 645 + 2 + in->in_esslen /* ssid */ 646 + 2 + IEEE80211_RATE_SIZE /* supported rates */ 647 + 2 + 1 /* DS parameters */ 648 + 2 + 4 + ic->ic_tim_len /* DTIM/IBSSPARMS */ 649 + 2 + 1 /* ERP */ 650 + 2 + IEEE80211_XRATE_SIZE; 651 m = ieee80211_getmgtframe(&frm, pktlen); 652 if (m == NULL) { 653 ieee80211_dbg(IEEE80211_MSG_ANY, "ieee80211_beacon_alloc: " 654 "cannot get buf; size %u\n", pktlen); 655 IEEE80211_UNLOCK(ic); 656 return (NULL); 657 } 658 659 /* timestamp is set by hardware/driver */ 660 (void) memset(frm, 0, 8); 661 frm += 8; 662 *(uint16_t *)frm = LE_16(in->in_intval); 663 frm += 2; 664 capinfo = ieee80211_get_capinfo(ic); 665 bo->bo_caps = (uint16_t *)frm; 666 *(uint16_t *)frm = LE_16(capinfo); 667 frm += 2; 668 *frm++ = IEEE80211_ELEMID_SSID; 669 if (!(ic->ic_flags & IEEE80211_F_HIDESSID)) { 670 *frm++ = in->in_esslen; 671 bcopy(in->in_essid, frm, in->in_esslen); 672 frm += in->in_esslen; 673 } else { 674 *frm++ = 0; 675 } 676 frm = ieee80211_add_rates(frm, rs); 677 if (ic->ic_curmode != IEEE80211_MODE_FH) { 678 *frm++ = IEEE80211_ELEMID_DSPARMS; 679 *frm++ = 1; 680 *frm++ = ieee80211_chan2ieee(ic, in->in_chan); 681 } 682 bo->bo_tim = frm; 683 if (ic->ic_opmode == IEEE80211_M_IBSS) { 684 *frm++ = IEEE80211_ELEMID_IBSSPARMS; 685 *frm++ = 2; 686 *frm++ = 0; *frm++ = 0; /* TODO: ATIM window */ 687 bo->bo_tim_len = 0; 688 } else { 689 struct ieee80211_tim_ie *tie = 690 (struct ieee80211_tim_ie *)frm; 691 692 tie->tim_ie = IEEE80211_ELEMID_TIM; 693 tie->tim_len = 4; /* length */ 694 tie->tim_count = 0; /* DTIM count */ 695 tie->tim_period = IEEE80211_DTIM_DEFAULT; 696 tie->tim_bitctl = 0; /* bitmap control */ 697 tie->tim_bitmap[0] = 0; /* Partial Virtual Bitmap */ 698 frm += sizeof (struct ieee80211_tim_ie); 699 bo->bo_tim_len = 1; 700 } 701 bo->bo_trailer = frm; 702 703 if (ic->ic_curmode == IEEE80211_MODE_11G) { 704 bo->bo_erp = frm; 705 frm = ieee80211_add_erp(frm, ic); 706 } 707 efrm = ieee80211_add_xrates(frm, rs); 708 bo->bo_trailer_len = efrm - bo->bo_trailer; 709 m->b_wptr = efrm; 710 711 wh = (struct ieee80211_frame *)m->b_rptr; 712 wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_MGT | 713 IEEE80211_FC0_SUBTYPE_BEACON; 714 wh->i_fc[1] = IEEE80211_FC1_DIR_NODS; 715 *(uint16_t *)wh->i_dur = 0; 716 IEEE80211_ADDR_COPY(wh->i_addr1, wifi_bcastaddr); 717 IEEE80211_ADDR_COPY(wh->i_addr2, ic->ic_macaddr); 718 IEEE80211_ADDR_COPY(wh->i_addr3, in->in_bssid); 719 *(uint16_t *)wh->i_seq = 0; 720 721 IEEE80211_UNLOCK(ic); 722 return (m); 723 } 724 725 /* 726 * Update the dynamic parts of a beacon frame based on the current state. 727 */ 728 /* ARGSUSED */ 729 int 730 ieee80211_beacon_update(ieee80211com_t *ic, ieee80211_node_t *in, 731 struct ieee80211_beacon_offsets *bo, mblk_t *mp, int mcast) 732 { 733 uint16_t capinfo; 734 735 IEEE80211_LOCK(ic); 736 737 capinfo = ieee80211_get_capinfo(ic); 738 *bo->bo_caps = LE_16(capinfo); 739 740 IEEE80211_UNLOCK(ic); 741 return (0); 742 } 743