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