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 /* NB: use non-QoS tid */ 86 *(uint16_t *)&wh->i_seq[0] = 87 LE_16(in->in_txseqs[IEEE80211_NONQOS_TID] << 88 IEEE80211_SEQ_SEQ_SHIFT); 89 in->in_txseqs[IEEE80211_NONQOS_TID]++; 90 } 91 92 /* 93 * Send a management frame to the specified node. The node pointer 94 * must have a reference as the pointer will be passed to the driver 95 * and potentially held for a long time. If the frame is successfully 96 * dispatched to the driver, then it is responsible for freeing the 97 * reference (and potentially free'ing up any associated storage). 98 * 99 * Return 0 on success 100 */ 101 int 102 ieee80211_mgmt_output(ieee80211com_t *ic, ieee80211_node_t *in, mblk_t *mp, 103 int type, int timer) 104 { 105 ieee80211_impl_t *im = ic->ic_private; 106 struct ieee80211_frame *wh; 107 108 ASSERT(in != NULL); 109 110 wh = (struct ieee80211_frame *)mp->b_rptr; 111 ieee80211_send_setup(ic, in, wh, IEEE80211_FC0_TYPE_MGT | type, 112 ic->ic_macaddr, in->in_macaddr, in->in_bssid); 113 if (in->in_challenge != NULL) 114 wh->i_fc[1] |= IEEE80211_FC1_WEP; 115 116 if (timer > 0) { 117 /* 118 * Set the mgt frame timeout. 119 */ 120 im->im_mgt_timer = timer; 121 ieee80211_start_watchdog(ic, 1); 122 } 123 return ((*ic->ic_xmit)(ic, mp, IEEE80211_FC0_TYPE_MGT)); 124 } 125 126 /* 127 * Send a null data frame to the specified node. 128 * 129 * NB: the caller is assumed to have setup a node reference 130 * for use; this is necessary to deal with a race condition 131 * when probing for inactive stations. 132 */ 133 int 134 ieee80211_send_nulldata(ieee80211_node_t *in) 135 { 136 ieee80211com_t *ic = in->in_ic; 137 mblk_t *m; 138 struct ieee80211_frame *wh; 139 uint8_t *frm; 140 141 m = ieee80211_getmgtframe(&frm, 0); 142 if (m == NULL) { 143 ic->ic_stats.is_tx_nobuf++; 144 return (ENOMEM); 145 } 146 147 wh = (struct ieee80211_frame *)m->b_rptr; 148 ieee80211_send_setup(ic, in, wh, 149 IEEE80211_FC0_TYPE_DATA | IEEE80211_FC0_SUBTYPE_NODATA, 150 ic->ic_macaddr, in->in_macaddr, in->in_bssid); 151 /* NB: power management bit is never sent by an AP */ 152 if ((in->in_flags & IEEE80211_NODE_PWR_MGT) && 153 ic->ic_opmode != IEEE80211_M_HOSTAP) 154 wh->i_fc[1] |= IEEE80211_FC1_PWR_MGT; 155 m->b_wptr = m->b_rptr + sizeof (struct ieee80211_frame); 156 157 ieee80211_dbg(IEEE80211_MSG_DEBUG | IEEE80211_MSG_DUMPPKTS, "net80211: " 158 "send null data frame on channel %u, pwr mgt %s\n", 159 ieee80211_macaddr_sprintf(in->in_macaddr), 160 ieee80211_chan2ieee(ic, ic->ic_curchan), 161 wh->i_fc[1] & IEEE80211_FC1_PWR_MGT ? "ena" : "dis"); 162 163 (void) (*ic->ic_xmit)(ic, m, IEEE80211_FC0_TYPE_MGT); 164 165 return (0); 166 } 167 168 /* 169 * Encapsulate an outbound data frame for GLDv3 based driver. 170 * Fill in the variable part of the 80211 frame 171 */ 172 /* ARGSUSED */ 173 mblk_t * 174 ieee80211_encap(ieee80211com_t *ic, mblk_t *mp, ieee80211_node_t *in) 175 { 176 struct ieee80211_frame *wh; 177 struct ieee80211_key *key; 178 int addqos, ac, tid; 179 180 ASSERT(mp != NULL && MBLKL(mp) >= sizeof (struct ieee80211_frame)); 181 /* 182 * Some ap's don't handle QoS-encapsulated EAPOL 183 * frames so suppress use. This may be an issue if other 184 * ap's require all data frames to be QoS-encapsulated 185 * once negotiated in which case we'll need to make this 186 * configurable. 187 */ 188 addqos = in->in_flags & (IEEE80211_NODE_QOS | IEEE80211_NODE_HT); 189 wh = (struct ieee80211_frame *)mp->b_rptr; 190 *(uint16_t *)wh->i_dur = 0; 191 if (addqos) { 192 struct ieee80211_qosframe *qwh = 193 (struct ieee80211_qosframe *)wh; 194 195 ac = ieee80211_classify(ic, mp, in); 196 /* map from access class/queue to 11e header priorty value */ 197 tid = WME_AC_TO_TID(ac); 198 qwh->i_qos[0] = tid & IEEE80211_QOS_TID; 199 /* 200 * Check if A-MPDU tx aggregation is setup or if we 201 * should try to enable it. The sta must be associated 202 * with HT and A-MPDU enabled for use. On the first 203 * frame that goes out We issue an ADDBA request and 204 * wait for a reply. The frame being encapsulated 205 * will go out w/o using A-MPDU, or possibly it might 206 * be collected by the driver and held/retransmit. 207 * ieee80211_ampdu_request handles staggering requests 208 * in case the receiver NAK's us or we are otherwise 209 * unable to establish a BA stream. 210 */ 211 if ((in->in_flags & IEEE80211_NODE_AMPDU_TX) && 212 (ic->ic_flags_ext & IEEE80211_FEXT_AMPDU_TX)) { 213 struct ieee80211_tx_ampdu *tap = &in->in_tx_ampdu[ac]; 214 215 if (IEEE80211_AMPDU_RUNNING(tap)) { 216 /* 217 * Operational, mark frame for aggregation. 218 */ 219 qwh->i_qos[0] |= IEEE80211_QOS_ACKPOLICY_BA; 220 } else if (!IEEE80211_AMPDU_REQUESTED(tap)) { 221 /* 222 * Not negotiated yet, request service. 223 */ 224 (void) ieee80211_ampdu_request(in, tap); 225 } 226 } 227 /* works even when BA marked above */ 228 if (ic->ic_wme.wme_wmeChanParams.cap_wmeParams[ac]. 229 wmep_noackPolicy) { 230 qwh->i_qos[0] |= IEEE80211_QOS_ACKPOLICY_NOACK; 231 } 232 233 *(uint16_t *)wh->i_seq = 234 LE_16(in->in_txseqs[tid] << IEEE80211_SEQ_SEQ_SHIFT); 235 in->in_txseqs[tid]++; 236 } else { 237 *(uint16_t *)wh->i_seq = 238 LE_16(in->in_txseqs[IEEE80211_NONQOS_TID] << 239 IEEE80211_SEQ_SEQ_SHIFT); 240 in->in_txseqs[IEEE80211_NONQOS_TID]++; 241 } 242 243 if (ic->ic_flags & IEEE80211_F_PRIVACY) 244 key = ieee80211_crypto_getkey(ic); 245 else 246 key = NULL; 247 248 /* 249 * IEEE 802.1X: send EAPOL frames always in the clear. 250 * WPA/WPA2: encrypt EAPOL keys when pairwise keys are set. 251 */ 252 if (key != NULL && (ic->ic_flags & IEEE80211_F_WPA)) { 253 wh->i_fc[1] |= IEEE80211_FC1_WEP; 254 if (!ieee80211_crypto_enmic(isc, key, mp, 0)) 255 ieee80211_err("ieee80211_crypto_enmic failed.\n"); 256 } 257 258 return (mp); 259 } 260 261 /* 262 * Add supported rates information element to a frame. 263 */ 264 static uint8_t * 265 ieee80211_add_rates(uint8_t *frm, const struct ieee80211_rateset *rs) 266 { 267 uint8_t nrates; 268 269 *frm++ = IEEE80211_ELEMID_RATES; 270 nrates = rs->ir_nrates; 271 if (nrates > IEEE80211_RATE_SIZE) 272 nrates = IEEE80211_RATE_SIZE; 273 *frm++ = nrates; 274 bcopy(rs->ir_rates, frm, nrates); 275 return (frm + nrates); 276 } 277 278 /* 279 * Add extended supported rates element to a frame, usually for 11g mode 280 */ 281 static uint8_t * 282 ieee80211_add_xrates(uint8_t *frm, const struct ieee80211_rateset *rs) 283 { 284 if (rs->ir_nrates > IEEE80211_RATE_SIZE) { 285 uint8_t nrates = rs->ir_nrates - IEEE80211_RATE_SIZE; 286 287 *frm++ = IEEE80211_ELEMID_XRATES; 288 *frm++ = nrates; 289 bcopy(rs->ir_rates + IEEE80211_RATE_SIZE, frm, nrates); 290 frm += nrates; 291 } 292 return (frm); 293 } 294 295 #define WME_OUI_BYTES 0x00, 0x50, 0xf2 296 /* 297 * Add a WME information element to a frame. 298 */ 299 /* ARGSUSED */ 300 static uint8_t * 301 ieee80211_add_wme_info(uint8_t *frm, struct ieee80211_wme_state *wme) 302 { 303 static const struct ieee80211_wme_info info = { 304 .wme_id = IEEE80211_ELEMID_VENDOR, 305 .wme_len = sizeof (struct ieee80211_wme_info) - 2, 306 .wme_oui = { WME_OUI_BYTES }, 307 .wme_type = WME_OUI_TYPE, 308 .wme_subtype = WME_INFO_OUI_SUBTYPE, 309 .wme_version = WME_VERSION, 310 .wme_info = 0, 311 }; 312 (void) memcpy(frm, &info, sizeof (info)); 313 return (frm + sizeof (info)); 314 } 315 316 /* 317 * Add a WME parameters element to a frame. 318 */ 319 static uint8_t * 320 ieee80211_add_wme_param(uint8_t *frm, struct ieee80211_wme_state *wme) 321 { 322 #define SM(_v, _f) (((_v) << _f##_S) & _f) 323 #define ADDSHORT(frm, v) do { \ 324 _NOTE(CONSTCOND) \ 325 frm[0] = (v) & 0xff; \ 326 frm[1] = (v) >> 8; \ 327 frm += 2; \ 328 _NOTE(CONSTCOND) \ 329 } while (0) 330 /* NB: this works 'cuz a param has an info at the front */ 331 static const struct ieee80211_wme_info param = { 332 .wme_id = IEEE80211_ELEMID_VENDOR, 333 .wme_len = sizeof (struct ieee80211_wme_param) - 2, 334 .wme_oui = { WME_OUI_BYTES }, 335 .wme_type = WME_OUI_TYPE, 336 .wme_subtype = WME_PARAM_OUI_SUBTYPE, 337 .wme_version = WME_VERSION, 338 }; 339 int i; 340 341 (void) memcpy(frm, ¶m, sizeof (param)); 342 frm += offsetof(struct ieee80211_wme_info, wme_info); 343 *frm++ = wme->wme_bssChanParams.cap_info; /* AC info */ 344 *frm++ = 0; /* reserved field */ 345 for (i = 0; i < WME_NUM_AC; i++) { 346 const struct wmeParams *ac = 347 &wme->wme_bssChanParams.cap_wmeParams[i]; 348 *frm++ = SM(i, WME_PARAM_ACI) 349 | SM(ac->wmep_acm, WME_PARAM_ACM) 350 | SM(ac->wmep_aifsn, WME_PARAM_AIFSN); 351 *frm++ = SM(ac->wmep_logcwmax, WME_PARAM_LOGCWMAX) 352 | SM(ac->wmep_logcwmin, WME_PARAM_LOGCWMIN); 353 ADDSHORT(frm, ac->wmep_txopLimit); 354 } 355 return (frm); 356 #undef SM 357 #undef ADDSHORT 358 } 359 #undef WME_OUI_BYTES 360 361 /* 362 * Add SSID element to a frame 363 */ 364 static uint8_t * 365 ieee80211_add_ssid(uint8_t *frm, const uint8_t *ssid, uint32_t len) 366 { 367 *frm++ = IEEE80211_ELEMID_SSID; 368 *frm++ = (uint8_t)len; 369 bcopy(ssid, frm, len); 370 return (frm + len); 371 } 372 373 /* 374 * Add an erp element to a frame. 375 */ 376 static uint8_t * 377 ieee80211_add_erp(uint8_t *frm, ieee80211com_t *ic) 378 { 379 uint8_t erp; 380 381 *frm++ = IEEE80211_ELEMID_ERP; 382 *frm++ = 1; 383 erp = 0; 384 if (ic->ic_flags & IEEE80211_F_USEPROT) 385 erp |= IEEE80211_ERP_USE_PROTECTION; 386 if (ic->ic_flags & IEEE80211_F_USEBARKER) 387 erp |= IEEE80211_ERP_LONG_PREAMBLE; 388 *frm++ = erp; 389 return (frm); 390 } 391 392 /* 393 * Get capability information from the interface softc, ic. 394 */ 395 static uint16_t 396 ieee80211_get_capinfo(ieee80211com_t *ic) 397 { 398 uint16_t capinfo; 399 400 if (ic->ic_opmode == IEEE80211_M_IBSS) 401 capinfo = IEEE80211_CAPINFO_IBSS; 402 else 403 capinfo = IEEE80211_CAPINFO_ESS; 404 if (ic->ic_flags & IEEE80211_F_PRIVACY) 405 capinfo |= IEEE80211_CAPINFO_PRIVACY; 406 if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) && 407 IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) { 408 capinfo |= IEEE80211_CAPINFO_SHORT_PREAMBLE; 409 } 410 if (ic->ic_flags & IEEE80211_F_SHSLOT) 411 capinfo |= IEEE80211_CAPINFO_SHORT_SLOTTIME; 412 413 return (capinfo); 414 } 415 416 /* 417 * Send a probe request frame with the specified ssid 418 * and any optional information element data. 419 */ 420 int 421 ieee80211_send_probereq(ieee80211_node_t *in, 422 const uint8_t *sa, const uint8_t *da, const uint8_t *bssid, 423 const uint8_t *ssid, size_t ssidlen, const void *optie, size_t optielen) 424 { 425 mblk_t *mp; 426 ieee80211com_t *ic = in->in_ic; 427 enum ieee80211_phymode mode; 428 struct ieee80211_frame *wh; 429 uint8_t *frm; 430 431 /* 432 * prreq frame format ([tlv] - 1 byte element ID + 1 byte length) 433 * [tlv] ssid 434 * [tlv] supported rates 435 * [tlv] extended supported rates 436 * [tlv] user-specified ie's 437 */ 438 mp = ieee80211_getmgtframe(&frm, 439 2 + IEEE80211_NWID_LEN 440 + 2 + IEEE80211_RATE_SIZE + 441 + 2 + IEEE80211_XRATE_SIZE 442 + optielen); 443 if (mp == NULL) 444 return (ENOMEM); 445 446 frm = ieee80211_add_ssid(frm, ssid, ssidlen); 447 mode = ieee80211_chan2mode(ic, ic->ic_curchan); 448 frm = ieee80211_add_rates(frm, &ic->ic_sup_rates[mode]); 449 frm = ieee80211_add_xrates(frm, &ic->ic_sup_rates[mode]); 450 if (optie != NULL) { 451 (void) memcpy(frm, optie, optielen); 452 frm += optielen; 453 } 454 mp->b_wptr = frm; 455 456 wh = (struct ieee80211_frame *)mp->b_rptr; 457 ieee80211_send_setup(ic, in, wh, 458 IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_PROBE_REQ, 459 sa, da, bssid); 460 461 ieee80211_dbg(IEEE80211_MSG_DEBUG | IEEE80211_MSG_DUMPPKTS, 462 "[%s] send probe req on channel %u\n", 463 ieee80211_macaddr_sprintf(wh->i_addr1), 464 ieee80211_chan2ieee(ic, ic->ic_curchan)); 465 466 (void) (*ic->ic_xmit)(ic, mp, IEEE80211_FC0_TYPE_MGT); 467 return (0); 468 } 469 470 /* 471 * Send a management frame. The node is for the destination (or ic_bss 472 * when in station mode). Nodes other than ic_bss have their reference 473 * count bumped to reflect our use for an indeterminant time. 474 */ 475 int 476 ieee80211_send_mgmt(ieee80211com_t *ic, ieee80211_node_t *in, int type, int arg) 477 { 478 mblk_t *mp; 479 uint8_t *frm; 480 uint16_t capinfo; 481 struct ieee80211_key *key; 482 boolean_t has_challenge; 483 boolean_t is_shared_key; 484 int ret; 485 int timer; 486 int status; 487 488 ASSERT(in != NULL); 489 490 timer = 0; 491 switch (type) { 492 case IEEE80211_FC0_SUBTYPE_PROBE_RESP: 493 /* 494 * probe response frame format 495 * [8] time stamp 496 * [2] beacon interval 497 * [2] capability information 498 * [tlv] ssid 499 * [tlv] supported rates 500 * [tlv] parameter set (FH/DS) 501 * [tlv] parameter set (IBSS) 502 * [tlv] extended rate phy (ERP) 503 * [tlv] extended supported rates 504 * [tlv] WPA 505 * [tlv] WME (optional) 506 * [tlv] HT capabilities 507 * [tlv] HT information 508 * [tlv] Vendor OUI HT capabilities (optional) 509 * [tlv] Vendor OUI HT information (optional) 510 */ 511 mp = ieee80211_getmgtframe(&frm, 512 8 /* time stamp */ 513 + sizeof (uint16_t) /* beacon interval */ 514 + sizeof (uint16_t) /* capability */ 515 + 2 + IEEE80211_NWID_LEN 516 + 2 + IEEE80211_RATE_SIZE 517 + 2 + IEEE80211_FH_LEN 518 + 2 + IEEE80211_IBSS_LEN 519 + 2 + IEEE80211_ERP_LEN 520 + 2 + IEEE80211_XRATE_SIZE 521 + (ic->ic_flags & IEEE80211_F_WPA ? 522 2 * sizeof (struct ieee80211_ie_wpa) : 0) 523 /* [tlv] WPA */ 524 + (ic->ic_flags & IEEE80211_F_WME ? 525 sizeof (struct ieee80211_wme_param) : 0) 526 /* [tlv] WME */ 527 /* check for cluster requirement */ 528 + 2 * sizeof (struct ieee80211_ie_htcap) + 4 529 + 2 * sizeof (struct ieee80211_ie_htinfo) + 4); 530 531 if (mp == NULL) 532 return (ENOMEM); 533 534 bzero(frm, 8); /* timestamp should be filled later */ 535 frm += 8; 536 *(uint16_t *)frm = LE_16(ic->ic_bss->in_intval); 537 frm += 2; 538 capinfo = ieee80211_get_capinfo(ic); 539 *(uint16_t *)frm = LE_16(capinfo); 540 frm += 2; 541 542 /* ssid */ 543 frm = ieee80211_add_ssid(frm, ic->ic_bss->in_essid, 544 ic->ic_bss->in_esslen); 545 /* supported rates */ 546 frm = ieee80211_add_rates(frm, &in->in_rates); 547 548 if (IEEE80211_IS_CHAN_FHSS(ic->ic_curchan)) { 549 *frm++ = IEEE80211_ELEMID_FHPARMS; 550 *frm++ = IEEE80211_FH_LEN; 551 *frm++ = in->in_fhdwell & 0x00ff; 552 *frm++ = (in->in_fhdwell >> 8) & 0x00ff; 553 *frm++ = IEEE80211_FH_CHANSET( 554 ieee80211_chan2ieee(ic, ic->ic_curchan)); 555 *frm++ = IEEE80211_FH_CHANPAT( 556 ieee80211_chan2ieee(ic, ic->ic_curchan)); 557 *frm++ = in->in_fhindex; 558 } else { 559 *frm++ = IEEE80211_ELEMID_DSPARMS; 560 *frm++ = IEEE80211_DS_LEN; 561 *frm++ = ieee80211_chan2ieee(ic, ic->ic_curchan); 562 } 563 564 if (ic->ic_opmode == IEEE80211_M_IBSS) { 565 *frm++ = IEEE80211_ELEMID_IBSSPARMS; 566 *frm++ = IEEE80211_IBSS_LEN; 567 *frm++ = 0; *frm++ = 0; /* ATIM window */ 568 } 569 if (IEEE80211_IS_CHAN_ANYG(ic->ic_curchan)) 570 frm = ieee80211_add_erp(frm, ic); 571 frm = ieee80211_add_xrates(frm, &in->in_rates); 572 /* 573 * NB: legacy 11b clients do not get certain ie's. 574 * The caller identifies such clients by passing 575 * a token in arg to us. Could expand this to be 576 * any legacy client for stuff like HT ie's. 577 */ 578 if (IEEE80211_IS_CHAN_HT(ic->ic_curchan) && 579 arg != IEEE80211_SEND_LEGACY_11B) { 580 frm = ieee80211_add_htcap(frm, in); 581 frm = ieee80211_add_htinfo(frm, in); 582 } 583 if (ic->ic_flags & IEEE80211_F_WME) 584 frm = ieee80211_add_wme_param(frm, &ic->ic_wme); 585 if (IEEE80211_IS_CHAN_HT(ic->ic_curchan) && 586 (ic->ic_flags_ext & IEEE80211_FEXT_HTCOMPAT) && 587 arg != IEEE80211_SEND_LEGACY_11B) { 588 frm = ieee80211_add_htcap_vendor(frm, in); 589 frm = ieee80211_add_htinfo_vendor(frm, in); 590 } 591 mp->b_wptr = frm; /* allocated is greater than used */ 592 593 break; 594 595 case IEEE80211_FC0_SUBTYPE_AUTH: 596 status = arg >> 16; 597 arg &= 0xffff; 598 has_challenge = ((arg == IEEE80211_AUTH_SHARED_CHALLENGE || 599 arg == IEEE80211_AUTH_SHARED_RESPONSE) && 600 in->in_challenge != NULL); 601 602 /* 603 * Deduce whether we're doing open authentication or 604 * shared key authentication. We do the latter if 605 * we're in the middle of a shared key authentication 606 * handshake or if we're initiating an authentication 607 * request and configured to use shared key. 608 */ 609 is_shared_key = has_challenge || 610 arg >= IEEE80211_AUTH_SHARED_RESPONSE || 611 (arg == IEEE80211_AUTH_SHARED_REQUEST && 612 ic->ic_bss->in_authmode == IEEE80211_AUTH_SHARED); 613 614 if (has_challenge && status == IEEE80211_STATUS_SUCCESS) 615 key = ieee80211_crypto_getkey(ic); 616 else 617 key = NULL; 618 619 mp = ieee80211_getmgtframe(&frm, 620 3 * sizeof (uint16_t) 621 + (has_challenge && status == IEEE80211_STATUS_SUCCESS ? 622 sizeof (uint16_t) + IEEE80211_CHALLENGE_LEN : 0) 623 + (key != NULL ? key->wk_cipher->ic_header : 0)); 624 if (mp == NULL) 625 return (ENOMEM); 626 627 if (key != NULL) 628 frm += key->wk_cipher->ic_header; 629 630 ((uint16_t *)frm)[0] = 631 (is_shared_key) ? LE_16(IEEE80211_AUTH_ALG_SHARED) 632 : LE_16(IEEE80211_AUTH_ALG_OPEN); 633 ((uint16_t *)frm)[1] = LE_16(arg); /* sequence number */ 634 ((uint16_t *)frm)[2] = LE_16(status); /* status */ 635 636 if (has_challenge && status == IEEE80211_STATUS_SUCCESS) { 637 frm += IEEE80211_AUTH_ELEM_MIN; 638 *frm = IEEE80211_ELEMID_CHALLENGE; 639 frm++; 640 *frm = IEEE80211_CHALLENGE_LEN; 641 frm++; 642 bcopy(in->in_challenge, frm, IEEE80211_CHALLENGE_LEN); 643 } 644 645 if (ic->ic_opmode == IEEE80211_M_STA) 646 timer = IEEE80211_TRANS_WAIT; 647 break; 648 649 case IEEE80211_FC0_SUBTYPE_DEAUTH: 650 mp = ieee80211_getmgtframe(&frm, sizeof (uint16_t)); 651 if (mp == NULL) 652 return (ENOMEM); 653 654 *(uint16_t *)frm = LE_16(arg); /* reason */ 655 656 ieee80211_node_unauthorize(in); /* port closed */ 657 break; 658 659 case IEEE80211_FC0_SUBTYPE_ASSOC_REQ: 660 case IEEE80211_FC0_SUBTYPE_REASSOC_REQ: 661 /* 662 * asreq frame format 663 * [2] capability information 664 * [2] listen interval 665 * [6*] current AP address (reassoc only) 666 * [tlv] ssid 667 * [tlv] supported rates 668 * [tlv] extended supported rates 669 * [tlv] WME 670 * [tlv] HT capabilities 671 * [tlv] Vendor OUI HT capabilities (optional) 672 * [tlv] user-specified ie's 673 */ 674 mp = ieee80211_getmgtframe(&frm, 675 sizeof (uint16_t) 676 + sizeof (uint16_t) + IEEE80211_ADDR_LEN 677 + 2 + IEEE80211_NWID_LEN 678 + 2 + IEEE80211_RATE_SIZE 679 + 2 + IEEE80211_XRATE_SIZE 680 + sizeof (struct ieee80211_wme_info) 681 + 2 * sizeof (struct ieee80211_ie_htcap) + 4 682 + ic->ic_opt_ie_len); 683 if (mp == NULL) 684 return (ENOMEM); 685 686 capinfo = ieee80211_get_capinfo(ic); 687 if (!(in->in_capinfo & IEEE80211_CAPINFO_SHORT_SLOTTIME) || 688 !(ic->ic_caps & IEEE80211_C_SHSLOT)) { 689 capinfo &= ~IEEE80211_CAPINFO_SHORT_SLOTTIME; 690 } else { 691 capinfo |= IEEE80211_CAPINFO_SHORT_SLOTTIME; 692 } 693 if (!(in->in_capinfo & IEEE80211_CAPINFO_SHORT_PREAMBLE) || 694 !(ic->ic_caps & IEEE80211_C_SHPREAMBLE)) { 695 capinfo &= ~IEEE80211_CAPINFO_SHORT_PREAMBLE; 696 } else { 697 capinfo |= IEEE80211_CAPINFO_SHORT_PREAMBLE; 698 } 699 *(uint16_t *)frm = LE_16(capinfo); 700 frm += 2; 701 702 *(uint16_t *)frm = LE_16(ic->ic_lintval); 703 frm += 2; 704 705 if (type == IEEE80211_FC0_SUBTYPE_REASSOC_REQ) { 706 IEEE80211_ADDR_COPY(frm, ic->ic_bss->in_bssid); 707 frm += IEEE80211_ADDR_LEN; 708 } 709 710 frm = ieee80211_add_ssid(frm, in->in_essid, in->in_esslen); 711 frm = ieee80211_add_rates(frm, &in->in_rates); 712 frm = ieee80211_add_xrates(frm, &in->in_rates); 713 if ((ic->ic_flags_ext & IEEE80211_FEXT_HT) && 714 in->in_htcap_ie != NULL && 715 in->in_htcap_ie[0] == IEEE80211_ELEMID_HTCAP) 716 frm = ieee80211_add_htcap(frm, in); 717 if ((ic->ic_flags & IEEE80211_F_WME) && in->in_wme_ie != NULL) 718 frm = ieee80211_add_wme_info(frm, &ic->ic_wme); 719 if ((ic->ic_flags_ext & IEEE80211_FEXT_HT) && 720 in->in_htcap_ie != NULL && 721 in->in_htcap_ie[0] == IEEE80211_ELEMID_VENDOR) 722 frm = ieee80211_add_htcap_vendor(frm, in); 723 if (ic->ic_opt_ie != NULL) { 724 bcopy(ic->ic_opt_ie, frm, ic->ic_opt_ie_len); 725 frm += ic->ic_opt_ie_len; 726 } 727 mp->b_wptr = frm; /* allocated is greater than used */ 728 729 timer = IEEE80211_TRANS_WAIT; 730 break; 731 732 case IEEE80211_FC0_SUBTYPE_ASSOC_RESP: 733 case IEEE80211_FC0_SUBTYPE_REASSOC_RESP: 734 /* 735 * asreq frame format 736 * [2] capability information 737 * [2] status 738 * [2] association ID 739 * [tlv] supported rates 740 * [tlv] extended supported rates 741 * [tlv] WME (if enabled and STA enabled) 742 * [tlv] HT capabilities (standard or vendor OUI) 743 * [tlv] HT information (standard or vendor OUI) 744 */ 745 mp = ieee80211_getmgtframe(&frm, 746 3 * sizeof (uint16_t) 747 + 2 + IEEE80211_RATE_SIZE 748 + 2 + IEEE80211_XRATE_SIZE); 749 if (mp == NULL) 750 return (ENOMEM); 751 752 capinfo = ieee80211_get_capinfo(ic); 753 *(uint16_t *)frm = LE_16(capinfo); 754 frm += 2; 755 756 *(uint16_t *)frm = LE_16(arg); /* status */ 757 frm += 2; 758 759 if (arg == IEEE80211_STATUS_SUCCESS) 760 *(uint16_t *)frm = LE_16(in->in_associd); 761 else 762 *(uint16_t *)frm = LE_16(0); 763 frm += 2; 764 765 frm = ieee80211_add_rates(frm, &in->in_rates); 766 frm = ieee80211_add_xrates(frm, &in->in_rates); 767 mp->b_wptr = frm; 768 break; 769 770 case IEEE80211_FC0_SUBTYPE_DISASSOC: 771 mp = ieee80211_getmgtframe(&frm, sizeof (uint16_t)); 772 if (mp == NULL) 773 return (ENOMEM); 774 *(uint16_t *)frm = LE_16(arg); /* reason */ 775 break; 776 777 default: 778 ieee80211_dbg(IEEE80211_MSG_ANY, 779 "[%s] invalid mgmt frame type %u\n", 780 ieee80211_macaddr_sprintf(in->in_macaddr), type); 781 return (EINVAL); 782 } /* type */ 783 ret = ieee80211_mgmt_output(ic, in, mp, type, timer); 784 return (ret); 785 } 786 787 /* 788 * Allocate a beacon frame and fillin the appropriate bits. 789 */ 790 mblk_t * 791 ieee80211_beacon_alloc(ieee80211com_t *ic, ieee80211_node_t *in, 792 struct ieee80211_beacon_offsets *bo) 793 { 794 struct ieee80211_frame *wh; 795 struct ieee80211_rateset *rs; 796 mblk_t *m; 797 uint8_t *frm; 798 int pktlen; 799 uint16_t capinfo; 800 801 IEEE80211_LOCK(ic); 802 /* 803 * beacon frame format 804 * [8] time stamp 805 * [2] beacon interval 806 * [2] cabability information 807 * [tlv] ssid 808 * [tlv] supported rates 809 * [3] parameter set (DS) 810 * [tlv] parameter set (IBSS/TIM) 811 * [tlv] extended rate phy (ERP) 812 * [tlv] extended supported rates 813 * [tlv] WME parameters 814 * [tlv] WPA/RSN parameters 815 * [tlv] HT capabilities 816 * [tlv] HT information 817 * [tlv] Vendor OUI HT capabilities (optional) 818 * [tlv] Vendor OUI HT information (optional) 819 * Vendor-specific OIDs (e.g. Atheros) 820 * NB: we allocate the max space required for the TIM bitmap. 821 */ 822 rs = &in->in_rates; 823 pktlen = 8 /* time stamp */ 824 + sizeof (uint16_t) /* beacon interval */ 825 + sizeof (uint16_t) /* capabilities */ 826 + 2 + in->in_esslen /* ssid */ 827 + 2 + IEEE80211_RATE_SIZE /* supported rates */ 828 + 2 + 1 /* DS parameters */ 829 + 2 + 4 + ic->ic_tim_len /* DTIM/IBSSPARMS */ 830 + 2 + 1 /* ERP */ 831 + 2 + IEEE80211_XRATE_SIZE 832 + (ic->ic_caps & IEEE80211_C_WME ? /* WME */ 833 sizeof (struct ieee80211_wme_param) : 0) 834 /* conditional? */ 835 + 4 + 2 * sizeof (struct ieee80211_ie_htcap) /* HT caps */ 836 + 4 + 2 * sizeof (struct ieee80211_ie_htinfo); /* HT info */ 837 838 m = ieee80211_getmgtframe(&frm, pktlen); 839 if (m == NULL) { 840 ieee80211_dbg(IEEE80211_MSG_ANY, "ieee80211_beacon_alloc: " 841 "cannot get buf; size %u\n", pktlen); 842 IEEE80211_UNLOCK(ic); 843 return (NULL); 844 } 845 846 /* timestamp is set by hardware/driver */ 847 (void) memset(frm, 0, 8); 848 frm += 8; 849 *(uint16_t *)frm = LE_16(in->in_intval); 850 frm += 2; 851 capinfo = ieee80211_get_capinfo(ic); 852 bo->bo_caps = (uint16_t *)frm; 853 *(uint16_t *)frm = LE_16(capinfo); 854 frm += 2; 855 *frm++ = IEEE80211_ELEMID_SSID; 856 if (!(ic->ic_flags & IEEE80211_F_HIDESSID)) { 857 *frm++ = in->in_esslen; 858 bcopy(in->in_essid, frm, in->in_esslen); 859 frm += in->in_esslen; 860 } else { 861 *frm++ = 0; 862 } 863 frm = ieee80211_add_rates(frm, rs); 864 if (ic->ic_curmode != IEEE80211_MODE_FH) { 865 *frm++ = IEEE80211_ELEMID_DSPARMS; 866 *frm++ = 1; 867 *frm++ = ieee80211_chan2ieee(ic, in->in_chan); 868 } 869 bo->bo_tim = frm; 870 if (ic->ic_opmode == IEEE80211_M_IBSS) { 871 *frm++ = IEEE80211_ELEMID_IBSSPARMS; 872 *frm++ = 2; 873 *frm++ = 0; *frm++ = 0; /* TODO: ATIM window */ 874 bo->bo_tim_len = 0; 875 } else { 876 struct ieee80211_tim_ie *tie = 877 (struct ieee80211_tim_ie *)frm; 878 879 tie->tim_ie = IEEE80211_ELEMID_TIM; 880 tie->tim_len = 4; /* length */ 881 tie->tim_count = 0; /* DTIM count */ 882 tie->tim_period = IEEE80211_DTIM_DEFAULT; 883 tie->tim_bitctl = 0; /* bitmap control */ 884 tie->tim_bitmap[0] = 0; /* Partial Virtual Bitmap */ 885 frm += sizeof (struct ieee80211_tim_ie); 886 bo->bo_tim_len = 1; 887 } 888 bo->bo_trailer = frm; 889 890 if (ic->ic_curmode == IEEE80211_MODE_11G) { 891 bo->bo_erp = frm; 892 frm = ieee80211_add_erp(frm, ic); 893 } 894 frm = ieee80211_add_xrates(frm, rs); 895 if (IEEE80211_IS_CHAN_HT(ic->ic_curchan)) { 896 frm = ieee80211_add_htcap(frm, in); 897 bo->bo_htinfo = frm; 898 frm = ieee80211_add_htinfo(frm, in); 899 } 900 if (ic->ic_flags & IEEE80211_F_WME) { 901 bo->bo_wme = frm; 902 frm = ieee80211_add_wme_param(frm, &ic->ic_wme); 903 } 904 if (IEEE80211_IS_CHAN_HT(ic->ic_curchan) && 905 (ic->ic_flags_ext & IEEE80211_FEXT_HTCOMPAT)) { 906 frm = ieee80211_add_htcap_vendor(frm, in); 907 frm = ieee80211_add_htinfo_vendor(frm, in); 908 } 909 bo->bo_trailer_len = _PTRDIFF(frm, bo->bo_trailer); 910 m->b_wptr = frm; 911 912 wh = (struct ieee80211_frame *)m->b_rptr; 913 wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_MGT | 914 IEEE80211_FC0_SUBTYPE_BEACON; 915 wh->i_fc[1] = IEEE80211_FC1_DIR_NODS; 916 *(uint16_t *)wh->i_dur = 0; 917 IEEE80211_ADDR_COPY(wh->i_addr1, wifi_bcastaddr); 918 IEEE80211_ADDR_COPY(wh->i_addr2, ic->ic_macaddr); 919 IEEE80211_ADDR_COPY(wh->i_addr3, in->in_bssid); 920 *(uint16_t *)wh->i_seq = 0; 921 922 IEEE80211_UNLOCK(ic); 923 return (m); 924 } 925 926 /* 927 * Update the dynamic parts of a beacon frame based on the current state. 928 */ 929 /* ARGSUSED */ 930 int 931 ieee80211_beacon_update(ieee80211com_t *ic, ieee80211_node_t *in, 932 struct ieee80211_beacon_offsets *bo, mblk_t *mp, int mcast) 933 { 934 uint16_t capinfo; 935 936 IEEE80211_LOCK(ic); 937 938 capinfo = ieee80211_get_capinfo(ic); 939 *bo->bo_caps = LE_16(capinfo); 940 941 IEEE80211_UNLOCK(ic); 942 return (0); 943 } 944 945 /* 946 * Assign priority to a frame based on any vlan tag assigned 947 * to the station and/or any Diffserv setting in an IP header. 948 * Finally, if an ACM policy is setup (in station mode) it's 949 * applied. 950 */ 951 int 952 ieee80211_classify(struct ieee80211com *ic, mblk_t *m, 953 struct ieee80211_node *ni) 954 /* ARGSUSED */ 955 { 956 int ac; 957 958 if ((ni->in_flags & IEEE80211_NODE_QOS) == 0) 959 return (WME_AC_BE); 960 961 /* Process VLan */ 962 /* Process IPQoS */ 963 964 ac = WME_AC_BE; 965 966 /* 967 * Apply ACM policy. 968 */ 969 if (ic->ic_opmode == IEEE80211_M_STA) { 970 static const int acmap[4] = { 971 WME_AC_BK, /* WME_AC_BE */ 972 WME_AC_BK, /* WME_AC_BK */ 973 WME_AC_BE, /* WME_AC_VI */ 974 WME_AC_VI, /* WME_AC_VO */ 975 }; 976 while (ac != WME_AC_BK && 977 ic->ic_wme.wme_wmeBssChanParams.cap_wmeParams[ac]. 978 wmep_acm) { 979 ac = acmap[ac]; 980 } 981 } 982 983 return (ac); 984 } 985