1 /* 2 * Copyright 2006 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 179 ASSERT(mp != NULL && MBLKL(mp) >= sizeof (struct ieee80211_frame)); 180 wh = (struct ieee80211_frame *)mp->b_rptr; 181 *(uint16_t *)wh->i_dur = 0; 182 *(uint16_t *)wh->i_seq = 183 LE_16(in->in_txseqs[0] << IEEE80211_SEQ_SEQ_SHIFT); 184 in->in_txseqs[0]++; 185 186 return (mp); 187 } 188 189 /* 190 * Add supported rates information element to a frame. 191 */ 192 static uint8_t * 193 ieee80211_add_rates(uint8_t *frm, const struct ieee80211_rateset *rs) 194 { 195 uint8_t nrates; 196 197 *frm++ = IEEE80211_ELEMID_RATES; 198 nrates = rs->ir_nrates; 199 if (nrates > IEEE80211_RATE_SIZE) 200 nrates = IEEE80211_RATE_SIZE; 201 *frm++ = nrates; 202 bcopy(rs->ir_rates, frm, nrates); 203 return (frm + nrates); 204 } 205 206 /* 207 * Add extended supported rates element to a frame, usually for 11g mode 208 */ 209 static uint8_t * 210 ieee80211_add_xrates(uint8_t *frm, const struct ieee80211_rateset *rs) 211 { 212 if (rs->ir_nrates > IEEE80211_RATE_SIZE) { 213 uint8_t nrates = rs->ir_nrates - IEEE80211_RATE_SIZE; 214 215 *frm++ = IEEE80211_ELEMID_XRATES; 216 *frm++ = nrates; 217 bcopy(rs->ir_rates + IEEE80211_RATE_SIZE, frm, nrates); 218 frm += nrates; 219 } 220 return (frm); 221 } 222 223 /* 224 * Add SSID element to a frame 225 */ 226 static uint8_t * 227 ieee80211_add_ssid(uint8_t *frm, const uint8_t *ssid, uint32_t len) 228 { 229 *frm++ = IEEE80211_ELEMID_SSID; 230 *frm++ = (uint8_t)len; 231 bcopy(ssid, frm, len); 232 return (frm + len); 233 } 234 235 /* 236 * Add an erp element to a frame. 237 */ 238 static uint8_t * 239 ieee80211_add_erp(uint8_t *frm, ieee80211com_t *ic) 240 { 241 uint8_t erp; 242 243 *frm++ = IEEE80211_ELEMID_ERP; 244 *frm++ = 1; 245 erp = 0; 246 if (ic->ic_flags & IEEE80211_F_USEPROT) 247 erp |= IEEE80211_ERP_USE_PROTECTION; 248 if (ic->ic_flags & IEEE80211_F_USEBARKER) 249 erp |= IEEE80211_ERP_LONG_PREAMBLE; 250 *frm++ = erp; 251 return (frm); 252 } 253 254 /* 255 * Get capability information from the interface softc, ic. 256 */ 257 static uint16_t 258 ieee80211_get_capinfo(ieee80211com_t *ic) 259 { 260 uint16_t capinfo; 261 262 if (ic->ic_opmode == IEEE80211_M_IBSS) 263 capinfo = IEEE80211_CAPINFO_IBSS; 264 else 265 capinfo = IEEE80211_CAPINFO_ESS; 266 if (ic->ic_flags & IEEE80211_F_PRIVACY) 267 capinfo |= IEEE80211_CAPINFO_PRIVACY; 268 if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) && 269 IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) { 270 capinfo |= IEEE80211_CAPINFO_SHORT_PREAMBLE; 271 } 272 if (ic->ic_flags & IEEE80211_F_SHSLOT) 273 capinfo |= IEEE80211_CAPINFO_SHORT_SLOTTIME; 274 275 return (capinfo); 276 } 277 278 /* 279 * Send a probe request frame with the specified ssid 280 * and any optional information element data. 281 */ 282 int 283 ieee80211_send_probereq(ieee80211_node_t *in, 284 const uint8_t *sa, const uint8_t *da, const uint8_t *bssid, 285 const uint8_t *ssid, size_t ssidlen, const void *optie, size_t optielen) 286 { 287 mblk_t *mp; 288 ieee80211com_t *ic = in->in_ic; 289 enum ieee80211_phymode mode; 290 struct ieee80211_frame *wh; 291 uint8_t *frm; 292 293 /* 294 * prreq frame format ([tlv] - 1 byte element ID + 1 byte length) 295 * [tlv] ssid 296 * [tlv] supported rates 297 * [tlv] extended supported rates 298 * [tlv] user-specified ie's 299 */ 300 mp = ieee80211_getmgtframe(&frm, 301 2 + IEEE80211_NWID_LEN 302 + 2 + IEEE80211_RATE_SIZE + 303 + 2 + IEEE80211_XRATE_SIZE 304 + optielen); 305 if (mp == NULL) 306 return (ENOMEM); 307 308 frm = ieee80211_add_ssid(frm, ssid, ssidlen); 309 mode = ieee80211_chan2mode(ic, ic->ic_curchan); 310 frm = ieee80211_add_rates(frm, &ic->ic_sup_rates[mode]); 311 frm = ieee80211_add_xrates(frm, &ic->ic_sup_rates[mode]); 312 if (optie != NULL) { 313 (void) memcpy(frm, optie, optielen); 314 frm += optielen; 315 } 316 mp->b_wptr = frm; 317 318 wh = (struct ieee80211_frame *)mp->b_rptr; 319 ieee80211_send_setup(ic, in, wh, 320 IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_PROBE_REQ, 321 sa, da, bssid); 322 323 ieee80211_dbg(IEEE80211_MSG_DEBUG | IEEE80211_MSG_DUMPPKTS, 324 "[%s] send probe req on channel %u\n", 325 ieee80211_macaddr_sprintf(wh->i_addr1), 326 ieee80211_chan2ieee(ic, ic->ic_curchan)); 327 328 (void) (*ic->ic_xmit)(ic, mp, IEEE80211_FC0_TYPE_MGT); 329 return (0); 330 } 331 332 /* 333 * Send a management frame. The node is for the destination (or ic_bss 334 * when in station mode). Nodes other than ic_bss have their reference 335 * count bumped to reflect our use for an indeterminant time. 336 */ 337 int 338 ieee80211_send_mgmt(ieee80211com_t *ic, ieee80211_node_t *in, int type, int arg) 339 { 340 mblk_t *mp; 341 uint8_t *frm; 342 uint16_t capinfo; 343 struct ieee80211_key *key; 344 boolean_t has_challenge; 345 boolean_t is_shared_key; 346 int ret; 347 int timer; 348 int status; 349 350 ASSERT(in != NULL); 351 352 timer = 0; 353 switch (type) { 354 case IEEE80211_FC0_SUBTYPE_PROBE_RESP: 355 /* 356 * probe response frame format 357 * [8] time stamp 358 * [2] beacon interval 359 * [2] capability information 360 * [tlv] ssid 361 * [tlv] supported rates 362 * [tlv] parameter set (FH/DS) 363 * [tlv] parameter set (IBSS) 364 * [tlv] extended rate phy (ERP) 365 * [tlv] extended supported rates 366 * [tlv] WPA 367 * [tlv] WME (optional) 368 */ 369 mp = ieee80211_getmgtframe(&frm, 370 8 /* time stamp */ 371 + sizeof (uint16_t) /* beacon interval */ 372 + sizeof (uint16_t) /* capability */ 373 + 2 + IEEE80211_NWID_LEN 374 + 2 + IEEE80211_RATE_SIZE 375 + 2 + IEEE80211_FH_LEN 376 + 2 + IEEE80211_IBSS_LEN 377 + 2 + IEEE80211_ERP_LEN 378 + 2 + IEEE80211_XRATE_SIZE 379 + (ic->ic_flags & IEEE80211_F_WPA ? 380 2 * sizeof (struct ieee80211_ie_wpa) : 0) 381 /* [tlv] WPA */ 382 + (ic->ic_flags & IEEE80211_F_WME ? 383 sizeof (struct ieee80211_wme_param) : 0)); 384 /* [tlv] WME */ 385 if (mp == NULL) 386 return (ENOMEM); 387 388 bzero(frm, 8); /* timestamp is set by hardware/driver */ 389 frm += 8; 390 *(uint16_t *)frm = LE_16(in->in_intval); 391 frm += 2; 392 capinfo = ieee80211_get_capinfo(ic); 393 *(uint16_t *)frm = LE_16(capinfo); 394 frm += 2; 395 396 frm = ieee80211_add_ssid(frm, in->in_essid, in->in_esslen); 397 frm = ieee80211_add_rates(frm, &in->in_rates); 398 399 if (ic->ic_phytype == IEEE80211_T_FH) { 400 *frm++ = IEEE80211_ELEMID_FHPARMS; 401 *frm++ = IEEE80211_FH_LEN; 402 *frm++ = in->in_fhdwell & 0x00ff; 403 *frm++ = (in->in_fhdwell >> 8) & 0x00ff; 404 *frm++ = IEEE80211_FH_CHANSET( 405 ieee80211_chan2ieee(ic, ic->ic_curchan)); 406 *frm++ = IEEE80211_FH_CHANPAT( 407 ieee80211_chan2ieee(ic, ic->ic_curchan)); 408 *frm++ = in->in_fhindex; 409 } else { 410 *frm++ = IEEE80211_ELEMID_DSPARMS; 411 *frm++ = IEEE80211_DS_LEN; 412 *frm++ = ieee80211_chan2ieee(ic, ic->ic_curchan); 413 } 414 415 if (ic->ic_opmode == IEEE80211_M_IBSS) { 416 *frm++ = IEEE80211_ELEMID_IBSSPARMS; 417 *frm++ = IEEE80211_IBSS_LEN; 418 *frm++ = 0; *frm++ = 0; /* ATIM window */ 419 } 420 frm = ieee80211_add_xrates(frm, &in->in_rates); 421 break; 422 423 case IEEE80211_FC0_SUBTYPE_AUTH: 424 status = arg >> 16; 425 arg &= 0xffff; 426 has_challenge = ((arg == IEEE80211_AUTH_SHARED_CHALLENGE || 427 arg == IEEE80211_AUTH_SHARED_RESPONSE) && 428 in->in_challenge != NULL); 429 430 /* 431 * Deduce whether we're doing open authentication or 432 * shared key authentication. We do the latter if 433 * we're in the middle of a shared key authentication 434 * handshake or if we're initiating an authentication 435 * request and configured to use shared key. 436 */ 437 is_shared_key = has_challenge || 438 arg >= IEEE80211_AUTH_SHARED_RESPONSE || 439 (arg == IEEE80211_AUTH_SHARED_REQUEST && 440 ic->ic_bss->in_authmode == IEEE80211_AUTH_SHARED); 441 442 if (has_challenge && status == IEEE80211_STATUS_SUCCESS) 443 key = ieee80211_crypto_getkey(ic); 444 else 445 key = NULL; 446 447 mp = ieee80211_getmgtframe(&frm, 448 3 * sizeof (uint16_t) 449 + (has_challenge && status == IEEE80211_STATUS_SUCCESS ? 450 sizeof (uint16_t) + IEEE80211_CHALLENGE_LEN : 0) 451 + (key != NULL ? key->wk_cipher->ic_header : 0)); 452 if (mp == NULL) 453 return (ENOMEM); 454 455 if (key != NULL) 456 frm += key->wk_cipher->ic_header; 457 458 ((uint16_t *)frm)[0] = 459 (is_shared_key) ? LE_16(IEEE80211_AUTH_ALG_SHARED) 460 : LE_16(IEEE80211_AUTH_ALG_OPEN); 461 ((uint16_t *)frm)[1] = LE_16(arg); /* sequence number */ 462 ((uint16_t *)frm)[2] = LE_16(status); /* status */ 463 464 if (has_challenge && status == IEEE80211_STATUS_SUCCESS) { 465 frm += IEEE80211_AUTH_ELEM_MIN; 466 *frm = IEEE80211_ELEMID_CHALLENGE; 467 frm++; 468 *frm = IEEE80211_CHALLENGE_LEN; 469 frm++; 470 bcopy(in->in_challenge, frm, IEEE80211_CHALLENGE_LEN); 471 } 472 473 if (ic->ic_opmode == IEEE80211_M_STA) 474 timer = IEEE80211_TRANS_WAIT; 475 break; 476 477 case IEEE80211_FC0_SUBTYPE_DEAUTH: 478 mp = ieee80211_getmgtframe(&frm, sizeof (uint16_t)); 479 if (mp == NULL) 480 return (ENOMEM); 481 482 *(uint16_t *)frm = LE_16(arg); /* reason */ 483 484 ieee80211_node_unauthorize(in); /* port closed */ 485 break; 486 487 case IEEE80211_FC0_SUBTYPE_ASSOC_REQ: 488 case IEEE80211_FC0_SUBTYPE_REASSOC_REQ: 489 /* 490 * asreq frame format 491 * [2] capability information 492 * [2] listen interval 493 * [6*] current AP address (reassoc only) 494 * [tlv] ssid 495 * [tlv] supported rates 496 * [tlv] extended supported rates 497 * [tlv] WME 498 * [tlv] user-specified ie's 499 */ 500 mp = ieee80211_getmgtframe(&frm, 501 sizeof (uint16_t) 502 + sizeof (uint16_t) + IEEE80211_ADDR_LEN 503 + 2 + IEEE80211_NWID_LEN 504 + 2 + IEEE80211_RATE_SIZE 505 + 2 + IEEE80211_XRATE_SIZE 506 + ic->ic_opt_ie_len); 507 if (mp == NULL) 508 return (ENOMEM); 509 510 capinfo = ieee80211_get_capinfo(ic); 511 if (!(in->in_capinfo & IEEE80211_CAPINFO_SHORT_SLOTTIME) || 512 !(ic->ic_caps & IEEE80211_C_SHSLOT)) { 513 capinfo &= ~IEEE80211_CAPINFO_SHORT_SLOTTIME; 514 } 515 *(uint16_t *)frm = LE_16(capinfo); 516 frm += 2; 517 518 *(uint16_t *)frm = LE_16(ic->ic_lintval); 519 frm += 2; 520 521 if (type == IEEE80211_FC0_SUBTYPE_REASSOC_REQ) { 522 IEEE80211_ADDR_COPY(frm, ic->ic_bss->in_bssid); 523 frm += IEEE80211_ADDR_LEN; 524 } 525 526 frm = ieee80211_add_ssid(frm, in->in_essid, in->in_esslen); 527 frm = ieee80211_add_rates(frm, &in->in_rates); 528 frm = ieee80211_add_xrates(frm, &in->in_rates); 529 if (ic->ic_opt_ie != NULL) { 530 bcopy(ic->ic_opt_ie, frm, ic->ic_opt_ie_len); 531 frm += ic->ic_opt_ie_len; 532 } 533 mp->b_wptr = frm; /* allocated is greater than used */ 534 535 timer = IEEE80211_TRANS_WAIT; 536 break; 537 538 case IEEE80211_FC0_SUBTYPE_ASSOC_RESP: 539 case IEEE80211_FC0_SUBTYPE_REASSOC_RESP: 540 /* 541 * asreq frame format 542 * [2] capability information 543 * [2] status 544 * [2] association ID 545 * [tlv] supported rates 546 * [tlv] extended supported rates 547 * [tlv] WME (if enabled and STA enabled) 548 */ 549 mp = ieee80211_getmgtframe(&frm, 550 3 * sizeof (uint16_t) 551 + 2 + IEEE80211_RATE_SIZE 552 + 2 + IEEE80211_XRATE_SIZE); 553 if (mp == NULL) 554 return (ENOMEM); 555 556 capinfo = ieee80211_get_capinfo(ic); 557 *(uint16_t *)frm = LE_16(capinfo); 558 frm += 2; 559 560 *(uint16_t *)frm = LE_16(arg); /* status */ 561 frm += 2; 562 563 if (arg == IEEE80211_STATUS_SUCCESS) 564 *(uint16_t *)frm = LE_16(in->in_associd); 565 else 566 *(uint16_t *)frm = LE_16(0); 567 frm += 2; 568 569 frm = ieee80211_add_rates(frm, &in->in_rates); 570 frm = ieee80211_add_xrates(frm, &in->in_rates); 571 break; 572 573 case IEEE80211_FC0_SUBTYPE_DISASSOC: 574 mp = ieee80211_getmgtframe(&frm, sizeof (uint16_t)); 575 if (mp == NULL) 576 return (ENOMEM); 577 *(uint16_t *)frm = LE_16(arg); /* reason */ 578 break; 579 580 default: 581 ieee80211_dbg(IEEE80211_MSG_ANY, 582 "[%s] invalid mgmt frame type %u\n", 583 ieee80211_macaddr_sprintf(in->in_macaddr), type); 584 return (EINVAL); 585 } /* type */ 586 ret = ieee80211_mgmt_output(ic, in, mp, type, timer); 587 return (ret); 588 } 589 590 /* 591 * Allocate a beacon frame and fillin the appropriate bits. 592 */ 593 mblk_t * 594 ieee80211_beacon_alloc(ieee80211com_t *ic, ieee80211_node_t *in, 595 struct ieee80211_beacon_offsets *bo) 596 { 597 struct ieee80211_frame *wh; 598 struct ieee80211_rateset *rs; 599 mblk_t *m; 600 uint8_t *frm; 601 uint8_t *efrm; 602 int pktlen; 603 uint16_t capinfo; 604 605 IEEE80211_LOCK(ic); 606 /* 607 * beacon frame format 608 * [8] time stamp 609 * [2] beacon interval 610 * [2] cabability information 611 * [tlv] ssid 612 * [tlv] supported rates 613 * [3] parameter set (DS) 614 * [tlv] parameter set (IBSS/TIM) 615 * [tlv] extended rate phy (ERP) 616 * [tlv] extended supported rates 617 * [tlv] WME parameters 618 * [tlv] WPA/RSN parameters 619 * Vendor-specific OIDs (e.g. Atheros) 620 * NB: we allocate the max space required for the TIM bitmap. 621 */ 622 rs = &in->in_rates; 623 pktlen = 8 /* time stamp */ 624 + sizeof (uint16_t) /* beacon interval */ 625 + sizeof (uint16_t) /* capabilities */ 626 + 2 + in->in_esslen /* ssid */ 627 + 2 + IEEE80211_RATE_SIZE /* supported rates */ 628 + 2 + 1 /* DS parameters */ 629 + 2 + 4 + ic->ic_tim_len /* DTIM/IBSSPARMS */ 630 + 2 + 1 /* ERP */ 631 + 2 + IEEE80211_XRATE_SIZE; 632 m = ieee80211_getmgtframe(&frm, pktlen); 633 if (m == NULL) { 634 ieee80211_dbg(IEEE80211_MSG_ANY, "ieee80211_beacon_alloc: " 635 "cannot get buf; size %u\n", pktlen); 636 IEEE80211_UNLOCK(ic); 637 return (NULL); 638 } 639 640 /* timestamp is set by hardware/driver */ 641 (void) memset(frm, 0, 8); 642 frm += 8; 643 *(uint16_t *)frm = LE_16(in->in_intval); 644 frm += 2; 645 capinfo = ieee80211_get_capinfo(ic); 646 bo->bo_caps = (uint16_t *)frm; 647 *(uint16_t *)frm = LE_16(capinfo); 648 frm += 2; 649 *frm++ = IEEE80211_ELEMID_SSID; 650 if (!(ic->ic_flags & IEEE80211_F_HIDESSID)) { 651 *frm++ = in->in_esslen; 652 bcopy(in->in_essid, frm, in->in_esslen); 653 frm += in->in_esslen; 654 } else { 655 *frm++ = 0; 656 } 657 frm = ieee80211_add_rates(frm, rs); 658 if (ic->ic_curmode != IEEE80211_MODE_FH) { 659 *frm++ = IEEE80211_ELEMID_DSPARMS; 660 *frm++ = 1; 661 *frm++ = ieee80211_chan2ieee(ic, in->in_chan); 662 } 663 bo->bo_tim = frm; 664 if (ic->ic_opmode == IEEE80211_M_IBSS) { 665 *frm++ = IEEE80211_ELEMID_IBSSPARMS; 666 *frm++ = 2; 667 *frm++ = 0; *frm++ = 0; /* TODO: ATIM window */ 668 bo->bo_tim_len = 0; 669 } else { 670 struct ieee80211_tim_ie *tie = 671 (struct ieee80211_tim_ie *)frm; 672 673 tie->tim_ie = IEEE80211_ELEMID_TIM; 674 tie->tim_len = 4; /* length */ 675 tie->tim_count = 0; /* DTIM count */ 676 tie->tim_period = IEEE80211_DTIM_DEFAULT; 677 tie->tim_bitctl = 0; /* bitmap control */ 678 tie->tim_bitmap[0] = 0; /* Partial Virtual Bitmap */ 679 frm += sizeof (struct ieee80211_tim_ie); 680 bo->bo_tim_len = 1; 681 } 682 bo->bo_trailer = frm; 683 684 if (ic->ic_curmode == IEEE80211_MODE_11G) { 685 bo->bo_erp = frm; 686 frm = ieee80211_add_erp(frm, ic); 687 } 688 efrm = ieee80211_add_xrates(frm, rs); 689 bo->bo_trailer_len = efrm - bo->bo_trailer; 690 m->b_wptr = efrm; 691 692 wh = (struct ieee80211_frame *)m->b_rptr; 693 wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_MGT | 694 IEEE80211_FC0_SUBTYPE_BEACON; 695 wh->i_fc[1] = IEEE80211_FC1_DIR_NODS; 696 *(uint16_t *)wh->i_dur = 0; 697 IEEE80211_ADDR_COPY(wh->i_addr1, wifi_bcastaddr); 698 IEEE80211_ADDR_COPY(wh->i_addr2, ic->ic_macaddr); 699 IEEE80211_ADDR_COPY(wh->i_addr3, in->in_bssid); 700 *(uint16_t *)wh->i_seq = 0; 701 702 IEEE80211_UNLOCK(ic); 703 return (m); 704 } 705 706 /* 707 * Update the dynamic parts of a beacon frame based on the current state. 708 */ 709 /* ARGSUSED */ 710 int 711 ieee80211_beacon_update(ieee80211com_t *ic, ieee80211_node_t *in, 712 struct ieee80211_beacon_offsets *bo, mblk_t *mp, int mcast) 713 { 714 uint16_t capinfo; 715 716 IEEE80211_LOCK(ic); 717 718 capinfo = ieee80211_get_capinfo(ic); 719 *bo->bo_caps = LE_16(capinfo); 720 721 IEEE80211_UNLOCK(ic); 722 return (0); 723 } 724