10ba2cbe9Sxc151355 /* 219d332feSfei feng - Sun Microsystems - Beijing China * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 30ba2cbe9Sxc151355 * Use is subject to license terms. 40ba2cbe9Sxc151355 */ 50ba2cbe9Sxc151355 60ba2cbe9Sxc151355 /* 70ba2cbe9Sxc151355 * Copyright (c) 2001 Atsushi Onoe 819d332feSfei feng - Sun Microsystems - Beijing China * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting 90ba2cbe9Sxc151355 * All rights reserved. 100ba2cbe9Sxc151355 * 110ba2cbe9Sxc151355 * Redistribution and use in source and binary forms, with or without 120ba2cbe9Sxc151355 * modification, are permitted provided that the following conditions 130ba2cbe9Sxc151355 * are met: 140ba2cbe9Sxc151355 * 1. Redistributions of source code must retain the above copyright 150ba2cbe9Sxc151355 * notice, this list of conditions and the following disclaimer. 160ba2cbe9Sxc151355 * 2. Redistributions in binary form must reproduce the above copyright 170ba2cbe9Sxc151355 * notice, this list of conditions and the following disclaimer in the 180ba2cbe9Sxc151355 * documentation and/or other materials provided with the distribution. 190ba2cbe9Sxc151355 * 3. The name of the author may not be used to endorse or promote products 200ba2cbe9Sxc151355 * derived from this software without specific prior written permission. 210ba2cbe9Sxc151355 * 220ba2cbe9Sxc151355 * Alternatively, this software may be distributed under the terms of the 230ba2cbe9Sxc151355 * GNU General Public License ("GPL") version 2 as published by the Free 240ba2cbe9Sxc151355 * Software Foundation. 250ba2cbe9Sxc151355 * 260ba2cbe9Sxc151355 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 270ba2cbe9Sxc151355 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 280ba2cbe9Sxc151355 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 290ba2cbe9Sxc151355 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 300ba2cbe9Sxc151355 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 310ba2cbe9Sxc151355 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 320ba2cbe9Sxc151355 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 330ba2cbe9Sxc151355 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 340ba2cbe9Sxc151355 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 350ba2cbe9Sxc151355 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 360ba2cbe9Sxc151355 */ 370ba2cbe9Sxc151355 380ba2cbe9Sxc151355 /* 390ba2cbe9Sxc151355 * Send out 802.11 frames 400ba2cbe9Sxc151355 */ 410ba2cbe9Sxc151355 420ba2cbe9Sxc151355 #include <sys/byteorder.h> 430ba2cbe9Sxc151355 #include <sys/strsun.h> 440ba2cbe9Sxc151355 #include "net80211_impl.h" 450ba2cbe9Sxc151355 460ba2cbe9Sxc151355 /* 470ba2cbe9Sxc151355 * Set the direction field and address fields of an outgoing 480ba2cbe9Sxc151355 * non-QoS frame. Note this should be called early on in 490ba2cbe9Sxc151355 * constructing a frame as it sets i_fc[1]; other bits can 500ba2cbe9Sxc151355 * then be or'd in. 510ba2cbe9Sxc151355 */ 520ba2cbe9Sxc151355 static void 530ba2cbe9Sxc151355 ieee80211_send_setup(ieee80211com_t *ic, ieee80211_node_t *in, 540ba2cbe9Sxc151355 struct ieee80211_frame *wh, int type, const uint8_t *sa, const uint8_t *da, 550ba2cbe9Sxc151355 const uint8_t *bssid) 560ba2cbe9Sxc151355 { 570ba2cbe9Sxc151355 wh->i_fc[0] = (uint8_t)(IEEE80211_FC0_VERSION_0 | type); 580ba2cbe9Sxc151355 if ((type & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_DATA) { 590ba2cbe9Sxc151355 switch (ic->ic_opmode) { 600ba2cbe9Sxc151355 case IEEE80211_M_STA: 610ba2cbe9Sxc151355 wh->i_fc[1] = IEEE80211_FC1_DIR_TODS; 620ba2cbe9Sxc151355 IEEE80211_ADDR_COPY(wh->i_addr1, bssid); 630ba2cbe9Sxc151355 IEEE80211_ADDR_COPY(wh->i_addr2, sa); 640ba2cbe9Sxc151355 IEEE80211_ADDR_COPY(wh->i_addr3, da); 650ba2cbe9Sxc151355 break; 660ba2cbe9Sxc151355 case IEEE80211_M_IBSS: 670ba2cbe9Sxc151355 case IEEE80211_M_AHDEMO: 680ba2cbe9Sxc151355 wh->i_fc[1] = IEEE80211_FC1_DIR_NODS; 690ba2cbe9Sxc151355 IEEE80211_ADDR_COPY(wh->i_addr1, da); 700ba2cbe9Sxc151355 IEEE80211_ADDR_COPY(wh->i_addr2, sa); 710ba2cbe9Sxc151355 IEEE80211_ADDR_COPY(wh->i_addr3, bssid); 720ba2cbe9Sxc151355 break; 730ba2cbe9Sxc151355 default: 740ba2cbe9Sxc151355 ieee80211_err("ieee80211_send_setup: " 750ba2cbe9Sxc151355 "Invalid mode %u\n", ic->ic_opmode); 760ba2cbe9Sxc151355 return; 770ba2cbe9Sxc151355 } 780ba2cbe9Sxc151355 } else { 790ba2cbe9Sxc151355 wh->i_fc[1] = IEEE80211_FC1_DIR_NODS; 800ba2cbe9Sxc151355 IEEE80211_ADDR_COPY(wh->i_addr1, da); 810ba2cbe9Sxc151355 IEEE80211_ADDR_COPY(wh->i_addr2, sa); 820ba2cbe9Sxc151355 IEEE80211_ADDR_COPY(wh->i_addr3, bssid); 830ba2cbe9Sxc151355 } 840ba2cbe9Sxc151355 *(uint16_t *)&wh->i_dur[0] = 0; /* set duration */ 85*e2cf88acSQuaker Fang /* NB: use non-QoS tid */ 86*e2cf88acSQuaker Fang *(uint16_t *)&wh->i_seq[0] = 87*e2cf88acSQuaker Fang LE_16(in->in_txseqs[IEEE80211_NONQOS_TID] << 88*e2cf88acSQuaker Fang IEEE80211_SEQ_SEQ_SHIFT); 89*e2cf88acSQuaker Fang in->in_txseqs[IEEE80211_NONQOS_TID]++; 900ba2cbe9Sxc151355 } 910ba2cbe9Sxc151355 920ba2cbe9Sxc151355 /* 930ba2cbe9Sxc151355 * Send a management frame to the specified node. The node pointer 940ba2cbe9Sxc151355 * must have a reference as the pointer will be passed to the driver 950ba2cbe9Sxc151355 * and potentially held for a long time. If the frame is successfully 960ba2cbe9Sxc151355 * dispatched to the driver, then it is responsible for freeing the 970ba2cbe9Sxc151355 * reference (and potentially free'ing up any associated storage). 980ba2cbe9Sxc151355 * 990ba2cbe9Sxc151355 * Return 0 on success 1000ba2cbe9Sxc151355 */ 101*e2cf88acSQuaker Fang int 1020ba2cbe9Sxc151355 ieee80211_mgmt_output(ieee80211com_t *ic, ieee80211_node_t *in, mblk_t *mp, 1030ba2cbe9Sxc151355 int type, int timer) 1040ba2cbe9Sxc151355 { 1050ba2cbe9Sxc151355 ieee80211_impl_t *im = ic->ic_private; 1060ba2cbe9Sxc151355 struct ieee80211_frame *wh; 1070ba2cbe9Sxc151355 1080ba2cbe9Sxc151355 ASSERT(in != NULL); 1090ba2cbe9Sxc151355 1100ba2cbe9Sxc151355 wh = (struct ieee80211_frame *)mp->b_rptr; 1110ba2cbe9Sxc151355 ieee80211_send_setup(ic, in, wh, IEEE80211_FC0_TYPE_MGT | type, 1120ba2cbe9Sxc151355 ic->ic_macaddr, in->in_macaddr, in->in_bssid); 1130ba2cbe9Sxc151355 if (in->in_challenge != NULL) 1140ba2cbe9Sxc151355 wh->i_fc[1] |= IEEE80211_FC1_WEP; 1150ba2cbe9Sxc151355 1160ba2cbe9Sxc151355 if (timer > 0) { 1170ba2cbe9Sxc151355 /* 1180ba2cbe9Sxc151355 * Set the mgt frame timeout. 1190ba2cbe9Sxc151355 */ 1200ba2cbe9Sxc151355 im->im_mgt_timer = timer; 1210ba2cbe9Sxc151355 ieee80211_start_watchdog(ic, 1); 1220ba2cbe9Sxc151355 } 1230ba2cbe9Sxc151355 return ((*ic->ic_xmit)(ic, mp, IEEE80211_FC0_TYPE_MGT)); 1240ba2cbe9Sxc151355 } 1250ba2cbe9Sxc151355 1260ba2cbe9Sxc151355 /* 1270ba2cbe9Sxc151355 * Send a null data frame to the specified node. 1280ba2cbe9Sxc151355 * 1290ba2cbe9Sxc151355 * NB: the caller is assumed to have setup a node reference 1300ba2cbe9Sxc151355 * for use; this is necessary to deal with a race condition 1310ba2cbe9Sxc151355 * when probing for inactive stations. 1320ba2cbe9Sxc151355 */ 1330ba2cbe9Sxc151355 int 1340ba2cbe9Sxc151355 ieee80211_send_nulldata(ieee80211_node_t *in) 1350ba2cbe9Sxc151355 { 1360ba2cbe9Sxc151355 ieee80211com_t *ic = in->in_ic; 1370ba2cbe9Sxc151355 mblk_t *m; 1380ba2cbe9Sxc151355 struct ieee80211_frame *wh; 1390ba2cbe9Sxc151355 uint8_t *frm; 1400ba2cbe9Sxc151355 1410ba2cbe9Sxc151355 m = ieee80211_getmgtframe(&frm, 0); 1420ba2cbe9Sxc151355 if (m == NULL) { 1430ba2cbe9Sxc151355 ic->ic_stats.is_tx_nobuf++; 1440ba2cbe9Sxc151355 return (ENOMEM); 1450ba2cbe9Sxc151355 } 1460ba2cbe9Sxc151355 1470ba2cbe9Sxc151355 wh = (struct ieee80211_frame *)m->b_rptr; 1480ba2cbe9Sxc151355 ieee80211_send_setup(ic, in, wh, 1490ba2cbe9Sxc151355 IEEE80211_FC0_TYPE_DATA | IEEE80211_FC0_SUBTYPE_NODATA, 1500ba2cbe9Sxc151355 ic->ic_macaddr, in->in_macaddr, in->in_bssid); 1510ba2cbe9Sxc151355 /* NB: power management bit is never sent by an AP */ 1520ba2cbe9Sxc151355 if ((in->in_flags & IEEE80211_NODE_PWR_MGT) && 1530ba2cbe9Sxc151355 ic->ic_opmode != IEEE80211_M_HOSTAP) 1540ba2cbe9Sxc151355 wh->i_fc[1] |= IEEE80211_FC1_PWR_MGT; 1550ba2cbe9Sxc151355 m->b_wptr = m->b_rptr + sizeof (struct ieee80211_frame); 1560ba2cbe9Sxc151355 1570ba2cbe9Sxc151355 ieee80211_dbg(IEEE80211_MSG_DEBUG | IEEE80211_MSG_DUMPPKTS, "net80211: " 1580ba2cbe9Sxc151355 "send null data frame on channel %u, pwr mgt %s\n", 1590ba2cbe9Sxc151355 ieee80211_macaddr_sprintf(in->in_macaddr), 1600ba2cbe9Sxc151355 ieee80211_chan2ieee(ic, ic->ic_curchan), 1610ba2cbe9Sxc151355 wh->i_fc[1] & IEEE80211_FC1_PWR_MGT ? "ena" : "dis"); 1620ba2cbe9Sxc151355 1630ba2cbe9Sxc151355 (void) (*ic->ic_xmit)(ic, m, IEEE80211_FC0_TYPE_MGT); 1640ba2cbe9Sxc151355 1650ba2cbe9Sxc151355 return (0); 1660ba2cbe9Sxc151355 } 1670ba2cbe9Sxc151355 1680ba2cbe9Sxc151355 /* 1690ba2cbe9Sxc151355 * Encapsulate an outbound data frame for GLDv3 based driver. 1700ba2cbe9Sxc151355 * Fill in the variable part of the 80211 frame 1710ba2cbe9Sxc151355 */ 1720ba2cbe9Sxc151355 /* ARGSUSED */ 1730ba2cbe9Sxc151355 mblk_t * 1740ba2cbe9Sxc151355 ieee80211_encap(ieee80211com_t *ic, mblk_t *mp, ieee80211_node_t *in) 1750ba2cbe9Sxc151355 { 1760ba2cbe9Sxc151355 struct ieee80211_frame *wh; 177a399b765Szf162725 struct ieee80211_key *key; 178*e2cf88acSQuaker Fang int addqos, ac, tid; 1790ba2cbe9Sxc151355 1800ba2cbe9Sxc151355 ASSERT(mp != NULL && MBLKL(mp) >= sizeof (struct ieee80211_frame)); 181*e2cf88acSQuaker Fang /* 182*e2cf88acSQuaker Fang * Some ap's don't handle QoS-encapsulated EAPOL 183*e2cf88acSQuaker Fang * frames so suppress use. This may be an issue if other 184*e2cf88acSQuaker Fang * ap's require all data frames to be QoS-encapsulated 185*e2cf88acSQuaker Fang * once negotiated in which case we'll need to make this 186*e2cf88acSQuaker Fang * configurable. 187*e2cf88acSQuaker Fang */ 188*e2cf88acSQuaker Fang addqos = in->in_flags & (IEEE80211_NODE_QOS | IEEE80211_NODE_HT); 1890ba2cbe9Sxc151355 wh = (struct ieee80211_frame *)mp->b_rptr; 1900ba2cbe9Sxc151355 *(uint16_t *)wh->i_dur = 0; 191*e2cf88acSQuaker Fang if (addqos) { 192*e2cf88acSQuaker Fang struct ieee80211_qosframe *qwh = 193*e2cf88acSQuaker Fang (struct ieee80211_qosframe *)wh; 194*e2cf88acSQuaker Fang 195*e2cf88acSQuaker Fang ac = ieee80211_classify(ic, mp, in); 196*e2cf88acSQuaker Fang /* map from access class/queue to 11e header priorty value */ 197*e2cf88acSQuaker Fang tid = WME_AC_TO_TID(ac); 198*e2cf88acSQuaker Fang qwh->i_qos[0] = tid & IEEE80211_QOS_TID; 199*e2cf88acSQuaker Fang /* 200*e2cf88acSQuaker Fang * Check if A-MPDU tx aggregation is setup or if we 201*e2cf88acSQuaker Fang * should try to enable it. The sta must be associated 202*e2cf88acSQuaker Fang * with HT and A-MPDU enabled for use. On the first 203*e2cf88acSQuaker Fang * frame that goes out We issue an ADDBA request and 204*e2cf88acSQuaker Fang * wait for a reply. The frame being encapsulated 205*e2cf88acSQuaker Fang * will go out w/o using A-MPDU, or possibly it might 206*e2cf88acSQuaker Fang * be collected by the driver and held/retransmit. 207*e2cf88acSQuaker Fang * ieee80211_ampdu_request handles staggering requests 208*e2cf88acSQuaker Fang * in case the receiver NAK's us or we are otherwise 209*e2cf88acSQuaker Fang * unable to establish a BA stream. 210*e2cf88acSQuaker Fang */ 211*e2cf88acSQuaker Fang if ((in->in_flags & IEEE80211_NODE_AMPDU_TX) && 212*e2cf88acSQuaker Fang (ic->ic_flags_ext & IEEE80211_FEXT_AMPDU_TX)) { 213*e2cf88acSQuaker Fang struct ieee80211_tx_ampdu *tap = &in->in_tx_ampdu[ac]; 214*e2cf88acSQuaker Fang 215*e2cf88acSQuaker Fang if (IEEE80211_AMPDU_RUNNING(tap)) { 216*e2cf88acSQuaker Fang /* 217*e2cf88acSQuaker Fang * Operational, mark frame for aggregation. 218*e2cf88acSQuaker Fang */ 219*e2cf88acSQuaker Fang qwh->i_qos[0] |= IEEE80211_QOS_ACKPOLICY_BA; 220*e2cf88acSQuaker Fang } else if (!IEEE80211_AMPDU_REQUESTED(tap)) { 221*e2cf88acSQuaker Fang /* 222*e2cf88acSQuaker Fang * Not negotiated yet, request service. 223*e2cf88acSQuaker Fang */ 224*e2cf88acSQuaker Fang (void) ieee80211_ampdu_request(in, tap); 225*e2cf88acSQuaker Fang } 226*e2cf88acSQuaker Fang } 227*e2cf88acSQuaker Fang /* works even when BA marked above */ 228*e2cf88acSQuaker Fang if (ic->ic_wme.wme_wmeChanParams.cap_wmeParams[ac]. 229*e2cf88acSQuaker Fang wmep_noackPolicy) { 230*e2cf88acSQuaker Fang qwh->i_qos[0] |= IEEE80211_QOS_ACKPOLICY_NOACK; 231*e2cf88acSQuaker Fang } 232*e2cf88acSQuaker Fang 2330ba2cbe9Sxc151355 *(uint16_t *)wh->i_seq = 234*e2cf88acSQuaker Fang LE_16(in->in_txseqs[tid] << IEEE80211_SEQ_SEQ_SHIFT); 235*e2cf88acSQuaker Fang in->in_txseqs[tid]++; 236*e2cf88acSQuaker Fang } else { 237*e2cf88acSQuaker Fang *(uint16_t *)wh->i_seq = 238*e2cf88acSQuaker Fang LE_16(in->in_txseqs[IEEE80211_NONQOS_TID] << 239*e2cf88acSQuaker Fang IEEE80211_SEQ_SEQ_SHIFT); 240*e2cf88acSQuaker Fang in->in_txseqs[IEEE80211_NONQOS_TID]++; 241*e2cf88acSQuaker Fang } 2420ba2cbe9Sxc151355 243a399b765Szf162725 if (ic->ic_flags & IEEE80211_F_PRIVACY) 244a399b765Szf162725 key = ieee80211_crypto_getkey(ic); 245a399b765Szf162725 else 246a399b765Szf162725 key = NULL; 247a399b765Szf162725 248a399b765Szf162725 /* 249a399b765Szf162725 * IEEE 802.1X: send EAPOL frames always in the clear. 250a399b765Szf162725 * WPA/WPA2: encrypt EAPOL keys when pairwise keys are set. 251a399b765Szf162725 */ 252a399b765Szf162725 if (key != NULL && (ic->ic_flags & IEEE80211_F_WPA)) { 253a399b765Szf162725 wh->i_fc[1] |= IEEE80211_FC1_WEP; 254*e2cf88acSQuaker Fang if (!ieee80211_crypto_enmic(isc, key, mp, 0)) 255a399b765Szf162725 ieee80211_err("ieee80211_crypto_enmic failed.\n"); 256a399b765Szf162725 } 257a399b765Szf162725 2580ba2cbe9Sxc151355 return (mp); 2590ba2cbe9Sxc151355 } 2600ba2cbe9Sxc151355 2610ba2cbe9Sxc151355 /* 2620ba2cbe9Sxc151355 * Add supported rates information element to a frame. 2630ba2cbe9Sxc151355 */ 2640ba2cbe9Sxc151355 static uint8_t * 2650ba2cbe9Sxc151355 ieee80211_add_rates(uint8_t *frm, const struct ieee80211_rateset *rs) 2660ba2cbe9Sxc151355 { 2670ba2cbe9Sxc151355 uint8_t nrates; 2680ba2cbe9Sxc151355 2690ba2cbe9Sxc151355 *frm++ = IEEE80211_ELEMID_RATES; 2700ba2cbe9Sxc151355 nrates = rs->ir_nrates; 2710ba2cbe9Sxc151355 if (nrates > IEEE80211_RATE_SIZE) 2720ba2cbe9Sxc151355 nrates = IEEE80211_RATE_SIZE; 2730ba2cbe9Sxc151355 *frm++ = nrates; 2740ba2cbe9Sxc151355 bcopy(rs->ir_rates, frm, nrates); 2750ba2cbe9Sxc151355 return (frm + nrates); 2760ba2cbe9Sxc151355 } 2770ba2cbe9Sxc151355 2780ba2cbe9Sxc151355 /* 2790ba2cbe9Sxc151355 * Add extended supported rates element to a frame, usually for 11g mode 2800ba2cbe9Sxc151355 */ 2810ba2cbe9Sxc151355 static uint8_t * 2820ba2cbe9Sxc151355 ieee80211_add_xrates(uint8_t *frm, const struct ieee80211_rateset *rs) 2830ba2cbe9Sxc151355 { 2840ba2cbe9Sxc151355 if (rs->ir_nrates > IEEE80211_RATE_SIZE) { 2850ba2cbe9Sxc151355 uint8_t nrates = rs->ir_nrates - IEEE80211_RATE_SIZE; 2860ba2cbe9Sxc151355 2870ba2cbe9Sxc151355 *frm++ = IEEE80211_ELEMID_XRATES; 2880ba2cbe9Sxc151355 *frm++ = nrates; 2890ba2cbe9Sxc151355 bcopy(rs->ir_rates + IEEE80211_RATE_SIZE, frm, nrates); 2900ba2cbe9Sxc151355 frm += nrates; 2910ba2cbe9Sxc151355 } 2920ba2cbe9Sxc151355 return (frm); 2930ba2cbe9Sxc151355 } 2940ba2cbe9Sxc151355 295*e2cf88acSQuaker Fang #define WME_OUI_BYTES 0x00, 0x50, 0xf2 296*e2cf88acSQuaker Fang /* 297*e2cf88acSQuaker Fang * Add a WME information element to a frame. 298*e2cf88acSQuaker Fang */ 299*e2cf88acSQuaker Fang /* ARGSUSED */ 300*e2cf88acSQuaker Fang static uint8_t * 301*e2cf88acSQuaker Fang ieee80211_add_wme_info(uint8_t *frm, struct ieee80211_wme_state *wme) 302*e2cf88acSQuaker Fang { 303*e2cf88acSQuaker Fang static const struct ieee80211_wme_info info = { 304*e2cf88acSQuaker Fang .wme_id = IEEE80211_ELEMID_VENDOR, 305*e2cf88acSQuaker Fang .wme_len = sizeof (struct ieee80211_wme_info) - 2, 306*e2cf88acSQuaker Fang .wme_oui = { WME_OUI_BYTES }, 307*e2cf88acSQuaker Fang .wme_type = WME_OUI_TYPE, 308*e2cf88acSQuaker Fang .wme_subtype = WME_INFO_OUI_SUBTYPE, 309*e2cf88acSQuaker Fang .wme_version = WME_VERSION, 310*e2cf88acSQuaker Fang .wme_info = 0, 311*e2cf88acSQuaker Fang }; 312*e2cf88acSQuaker Fang (void) memcpy(frm, &info, sizeof (info)); 313*e2cf88acSQuaker Fang return (frm + sizeof (info)); 314*e2cf88acSQuaker Fang } 315*e2cf88acSQuaker Fang 316*e2cf88acSQuaker Fang /* 317*e2cf88acSQuaker Fang * Add a WME parameters element to a frame. 318*e2cf88acSQuaker Fang */ 319*e2cf88acSQuaker Fang static uint8_t * 320*e2cf88acSQuaker Fang ieee80211_add_wme_param(uint8_t *frm, struct ieee80211_wme_state *wme) 321*e2cf88acSQuaker Fang { 322*e2cf88acSQuaker Fang #define SM(_v, _f) (((_v) << _f##_S) & _f) 323*e2cf88acSQuaker Fang #define ADDSHORT(frm, v) do { \ 324*e2cf88acSQuaker Fang _NOTE(CONSTCOND) \ 325*e2cf88acSQuaker Fang frm[0] = (v) & 0xff; \ 326*e2cf88acSQuaker Fang frm[1] = (v) >> 8; \ 327*e2cf88acSQuaker Fang frm += 2; \ 328*e2cf88acSQuaker Fang _NOTE(CONSTCOND) \ 329*e2cf88acSQuaker Fang } while (0) 330*e2cf88acSQuaker Fang /* NB: this works 'cuz a param has an info at the front */ 331*e2cf88acSQuaker Fang static const struct ieee80211_wme_info param = { 332*e2cf88acSQuaker Fang .wme_id = IEEE80211_ELEMID_VENDOR, 333*e2cf88acSQuaker Fang .wme_len = sizeof (struct ieee80211_wme_param) - 2, 334*e2cf88acSQuaker Fang .wme_oui = { WME_OUI_BYTES }, 335*e2cf88acSQuaker Fang .wme_type = WME_OUI_TYPE, 336*e2cf88acSQuaker Fang .wme_subtype = WME_PARAM_OUI_SUBTYPE, 337*e2cf88acSQuaker Fang .wme_version = WME_VERSION, 338*e2cf88acSQuaker Fang }; 339*e2cf88acSQuaker Fang int i; 340*e2cf88acSQuaker Fang 341*e2cf88acSQuaker Fang (void) memcpy(frm, ¶m, sizeof (param)); 342*e2cf88acSQuaker Fang frm += offsetof(struct ieee80211_wme_info, wme_info); 343*e2cf88acSQuaker Fang *frm++ = wme->wme_bssChanParams.cap_info; /* AC info */ 344*e2cf88acSQuaker Fang *frm++ = 0; /* reserved field */ 345*e2cf88acSQuaker Fang for (i = 0; i < WME_NUM_AC; i++) { 346*e2cf88acSQuaker Fang const struct wmeParams *ac = 347*e2cf88acSQuaker Fang &wme->wme_bssChanParams.cap_wmeParams[i]; 348*e2cf88acSQuaker Fang *frm++ = SM(i, WME_PARAM_ACI) 349*e2cf88acSQuaker Fang | SM(ac->wmep_acm, WME_PARAM_ACM) 350*e2cf88acSQuaker Fang | SM(ac->wmep_aifsn, WME_PARAM_AIFSN); 351*e2cf88acSQuaker Fang *frm++ = SM(ac->wmep_logcwmax, WME_PARAM_LOGCWMAX) 352*e2cf88acSQuaker Fang | SM(ac->wmep_logcwmin, WME_PARAM_LOGCWMIN); 353*e2cf88acSQuaker Fang ADDSHORT(frm, ac->wmep_txopLimit); 354*e2cf88acSQuaker Fang } 355*e2cf88acSQuaker Fang return (frm); 356*e2cf88acSQuaker Fang #undef SM 357*e2cf88acSQuaker Fang #undef ADDSHORT 358*e2cf88acSQuaker Fang } 359*e2cf88acSQuaker Fang #undef WME_OUI_BYTES 360*e2cf88acSQuaker Fang 3610ba2cbe9Sxc151355 /* 3620ba2cbe9Sxc151355 * Add SSID element to a frame 3630ba2cbe9Sxc151355 */ 3640ba2cbe9Sxc151355 static uint8_t * 3650ba2cbe9Sxc151355 ieee80211_add_ssid(uint8_t *frm, const uint8_t *ssid, uint32_t len) 3660ba2cbe9Sxc151355 { 3670ba2cbe9Sxc151355 *frm++ = IEEE80211_ELEMID_SSID; 3680ba2cbe9Sxc151355 *frm++ = (uint8_t)len; 3690ba2cbe9Sxc151355 bcopy(ssid, frm, len); 3700ba2cbe9Sxc151355 return (frm + len); 3710ba2cbe9Sxc151355 } 3720ba2cbe9Sxc151355 3730ba2cbe9Sxc151355 /* 3740ba2cbe9Sxc151355 * Add an erp element to a frame. 3750ba2cbe9Sxc151355 */ 3760ba2cbe9Sxc151355 static uint8_t * 3770ba2cbe9Sxc151355 ieee80211_add_erp(uint8_t *frm, ieee80211com_t *ic) 3780ba2cbe9Sxc151355 { 3790ba2cbe9Sxc151355 uint8_t erp; 3800ba2cbe9Sxc151355 3810ba2cbe9Sxc151355 *frm++ = IEEE80211_ELEMID_ERP; 3820ba2cbe9Sxc151355 *frm++ = 1; 3830ba2cbe9Sxc151355 erp = 0; 3840ba2cbe9Sxc151355 if (ic->ic_flags & IEEE80211_F_USEPROT) 3850ba2cbe9Sxc151355 erp |= IEEE80211_ERP_USE_PROTECTION; 3860ba2cbe9Sxc151355 if (ic->ic_flags & IEEE80211_F_USEBARKER) 3870ba2cbe9Sxc151355 erp |= IEEE80211_ERP_LONG_PREAMBLE; 3880ba2cbe9Sxc151355 *frm++ = erp; 3890ba2cbe9Sxc151355 return (frm); 3900ba2cbe9Sxc151355 } 3910ba2cbe9Sxc151355 3920ba2cbe9Sxc151355 /* 3930ba2cbe9Sxc151355 * Get capability information from the interface softc, ic. 3940ba2cbe9Sxc151355 */ 3950ba2cbe9Sxc151355 static uint16_t 3960ba2cbe9Sxc151355 ieee80211_get_capinfo(ieee80211com_t *ic) 3970ba2cbe9Sxc151355 { 3980ba2cbe9Sxc151355 uint16_t capinfo; 3990ba2cbe9Sxc151355 4000ba2cbe9Sxc151355 if (ic->ic_opmode == IEEE80211_M_IBSS) 4010ba2cbe9Sxc151355 capinfo = IEEE80211_CAPINFO_IBSS; 4020ba2cbe9Sxc151355 else 4030ba2cbe9Sxc151355 capinfo = IEEE80211_CAPINFO_ESS; 4040ba2cbe9Sxc151355 if (ic->ic_flags & IEEE80211_F_PRIVACY) 4050ba2cbe9Sxc151355 capinfo |= IEEE80211_CAPINFO_PRIVACY; 4060ba2cbe9Sxc151355 if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) && 4070ba2cbe9Sxc151355 IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) { 4080ba2cbe9Sxc151355 capinfo |= IEEE80211_CAPINFO_SHORT_PREAMBLE; 4090ba2cbe9Sxc151355 } 4100ba2cbe9Sxc151355 if (ic->ic_flags & IEEE80211_F_SHSLOT) 4110ba2cbe9Sxc151355 capinfo |= IEEE80211_CAPINFO_SHORT_SLOTTIME; 4120ba2cbe9Sxc151355 4130ba2cbe9Sxc151355 return (capinfo); 4140ba2cbe9Sxc151355 } 4150ba2cbe9Sxc151355 4160ba2cbe9Sxc151355 /* 4170ba2cbe9Sxc151355 * Send a probe request frame with the specified ssid 4180ba2cbe9Sxc151355 * and any optional information element data. 4190ba2cbe9Sxc151355 */ 4200ba2cbe9Sxc151355 int 4210ba2cbe9Sxc151355 ieee80211_send_probereq(ieee80211_node_t *in, 4220ba2cbe9Sxc151355 const uint8_t *sa, const uint8_t *da, const uint8_t *bssid, 4230ba2cbe9Sxc151355 const uint8_t *ssid, size_t ssidlen, const void *optie, size_t optielen) 4240ba2cbe9Sxc151355 { 4250ba2cbe9Sxc151355 mblk_t *mp; 4260ba2cbe9Sxc151355 ieee80211com_t *ic = in->in_ic; 4270ba2cbe9Sxc151355 enum ieee80211_phymode mode; 4280ba2cbe9Sxc151355 struct ieee80211_frame *wh; 4290ba2cbe9Sxc151355 uint8_t *frm; 4300ba2cbe9Sxc151355 4310ba2cbe9Sxc151355 /* 4320ba2cbe9Sxc151355 * prreq frame format ([tlv] - 1 byte element ID + 1 byte length) 4330ba2cbe9Sxc151355 * [tlv] ssid 4340ba2cbe9Sxc151355 * [tlv] supported rates 4350ba2cbe9Sxc151355 * [tlv] extended supported rates 4360ba2cbe9Sxc151355 * [tlv] user-specified ie's 4370ba2cbe9Sxc151355 */ 4380ba2cbe9Sxc151355 mp = ieee80211_getmgtframe(&frm, 4390ba2cbe9Sxc151355 2 + IEEE80211_NWID_LEN 4400ba2cbe9Sxc151355 + 2 + IEEE80211_RATE_SIZE + 4410ba2cbe9Sxc151355 + 2 + IEEE80211_XRATE_SIZE 4420ba2cbe9Sxc151355 + optielen); 4430ba2cbe9Sxc151355 if (mp == NULL) 4440ba2cbe9Sxc151355 return (ENOMEM); 4450ba2cbe9Sxc151355 4460ba2cbe9Sxc151355 frm = ieee80211_add_ssid(frm, ssid, ssidlen); 4470ba2cbe9Sxc151355 mode = ieee80211_chan2mode(ic, ic->ic_curchan); 4480ba2cbe9Sxc151355 frm = ieee80211_add_rates(frm, &ic->ic_sup_rates[mode]); 4490ba2cbe9Sxc151355 frm = ieee80211_add_xrates(frm, &ic->ic_sup_rates[mode]); 4500ba2cbe9Sxc151355 if (optie != NULL) { 4510ba2cbe9Sxc151355 (void) memcpy(frm, optie, optielen); 4520ba2cbe9Sxc151355 frm += optielen; 4530ba2cbe9Sxc151355 } 4540ba2cbe9Sxc151355 mp->b_wptr = frm; 4550ba2cbe9Sxc151355 4560ba2cbe9Sxc151355 wh = (struct ieee80211_frame *)mp->b_rptr; 4570ba2cbe9Sxc151355 ieee80211_send_setup(ic, in, wh, 4580ba2cbe9Sxc151355 IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_PROBE_REQ, 4590ba2cbe9Sxc151355 sa, da, bssid); 4600ba2cbe9Sxc151355 4610ba2cbe9Sxc151355 ieee80211_dbg(IEEE80211_MSG_DEBUG | IEEE80211_MSG_DUMPPKTS, 4620ba2cbe9Sxc151355 "[%s] send probe req on channel %u\n", 4630ba2cbe9Sxc151355 ieee80211_macaddr_sprintf(wh->i_addr1), 4640ba2cbe9Sxc151355 ieee80211_chan2ieee(ic, ic->ic_curchan)); 4650ba2cbe9Sxc151355 4660ba2cbe9Sxc151355 (void) (*ic->ic_xmit)(ic, mp, IEEE80211_FC0_TYPE_MGT); 4670ba2cbe9Sxc151355 return (0); 4680ba2cbe9Sxc151355 } 4690ba2cbe9Sxc151355 4700ba2cbe9Sxc151355 /* 4710ba2cbe9Sxc151355 * Send a management frame. The node is for the destination (or ic_bss 4720ba2cbe9Sxc151355 * when in station mode). Nodes other than ic_bss have their reference 4730ba2cbe9Sxc151355 * count bumped to reflect our use for an indeterminant time. 4740ba2cbe9Sxc151355 */ 4750ba2cbe9Sxc151355 int 4760ba2cbe9Sxc151355 ieee80211_send_mgmt(ieee80211com_t *ic, ieee80211_node_t *in, int type, int arg) 4770ba2cbe9Sxc151355 { 4780ba2cbe9Sxc151355 mblk_t *mp; 4790ba2cbe9Sxc151355 uint8_t *frm; 4800ba2cbe9Sxc151355 uint16_t capinfo; 4810ba2cbe9Sxc151355 struct ieee80211_key *key; 4820ba2cbe9Sxc151355 boolean_t has_challenge; 4830ba2cbe9Sxc151355 boolean_t is_shared_key; 4840ba2cbe9Sxc151355 int ret; 4850ba2cbe9Sxc151355 int timer; 4860ba2cbe9Sxc151355 int status; 4870ba2cbe9Sxc151355 4880ba2cbe9Sxc151355 ASSERT(in != NULL); 4890ba2cbe9Sxc151355 4900ba2cbe9Sxc151355 timer = 0; 4910ba2cbe9Sxc151355 switch (type) { 4920ba2cbe9Sxc151355 case IEEE80211_FC0_SUBTYPE_PROBE_RESP: 4930ba2cbe9Sxc151355 /* 4940ba2cbe9Sxc151355 * probe response frame format 4950ba2cbe9Sxc151355 * [8] time stamp 4960ba2cbe9Sxc151355 * [2] beacon interval 4970ba2cbe9Sxc151355 * [2] capability information 4980ba2cbe9Sxc151355 * [tlv] ssid 4990ba2cbe9Sxc151355 * [tlv] supported rates 5000ba2cbe9Sxc151355 * [tlv] parameter set (FH/DS) 5010ba2cbe9Sxc151355 * [tlv] parameter set (IBSS) 5020ba2cbe9Sxc151355 * [tlv] extended rate phy (ERP) 5030ba2cbe9Sxc151355 * [tlv] extended supported rates 5040ba2cbe9Sxc151355 * [tlv] WPA 5050ba2cbe9Sxc151355 * [tlv] WME (optional) 506*e2cf88acSQuaker Fang * [tlv] HT capabilities 507*e2cf88acSQuaker Fang * [tlv] HT information 508*e2cf88acSQuaker Fang * [tlv] Vendor OUI HT capabilities (optional) 509*e2cf88acSQuaker Fang * [tlv] Vendor OUI HT information (optional) 5100ba2cbe9Sxc151355 */ 5110ba2cbe9Sxc151355 mp = ieee80211_getmgtframe(&frm, 5120ba2cbe9Sxc151355 8 /* time stamp */ 5130ba2cbe9Sxc151355 + sizeof (uint16_t) /* beacon interval */ 5140ba2cbe9Sxc151355 + sizeof (uint16_t) /* capability */ 5150ba2cbe9Sxc151355 + 2 + IEEE80211_NWID_LEN 5160ba2cbe9Sxc151355 + 2 + IEEE80211_RATE_SIZE 5170ba2cbe9Sxc151355 + 2 + IEEE80211_FH_LEN 5180ba2cbe9Sxc151355 + 2 + IEEE80211_IBSS_LEN 5190ba2cbe9Sxc151355 + 2 + IEEE80211_ERP_LEN 5200ba2cbe9Sxc151355 + 2 + IEEE80211_XRATE_SIZE 5210ba2cbe9Sxc151355 + (ic->ic_flags & IEEE80211_F_WPA ? 5220ba2cbe9Sxc151355 2 * sizeof (struct ieee80211_ie_wpa) : 0) 5230ba2cbe9Sxc151355 /* [tlv] WPA */ 5240ba2cbe9Sxc151355 + (ic->ic_flags & IEEE80211_F_WME ? 525*e2cf88acSQuaker Fang sizeof (struct ieee80211_wme_param) : 0) 5260ba2cbe9Sxc151355 /* [tlv] WME */ 527*e2cf88acSQuaker Fang /* check for cluster requirement */ 528*e2cf88acSQuaker Fang + 2 * sizeof (struct ieee80211_ie_htcap) + 4 529*e2cf88acSQuaker Fang + 2 * sizeof (struct ieee80211_ie_htinfo) + 4); 530*e2cf88acSQuaker Fang 5310ba2cbe9Sxc151355 if (mp == NULL) 5320ba2cbe9Sxc151355 return (ENOMEM); 5330ba2cbe9Sxc151355 53419d332feSfei feng - Sun Microsystems - Beijing China bzero(frm, 8); /* timestamp should be filled later */ 5350ba2cbe9Sxc151355 frm += 8; 53619d332feSfei feng - Sun Microsystems - Beijing China *(uint16_t *)frm = LE_16(ic->ic_bss->in_intval); 5370ba2cbe9Sxc151355 frm += 2; 5380ba2cbe9Sxc151355 capinfo = ieee80211_get_capinfo(ic); 5390ba2cbe9Sxc151355 *(uint16_t *)frm = LE_16(capinfo); 5400ba2cbe9Sxc151355 frm += 2; 5410ba2cbe9Sxc151355 54219d332feSfei feng - Sun Microsystems - Beijing China /* ssid */ 54319d332feSfei feng - Sun Microsystems - Beijing China frm = ieee80211_add_ssid(frm, ic->ic_bss->in_essid, 54419d332feSfei feng - Sun Microsystems - Beijing China ic->ic_bss->in_esslen); 54519d332feSfei feng - Sun Microsystems - Beijing China /* supported rates */ 5460ba2cbe9Sxc151355 frm = ieee80211_add_rates(frm, &in->in_rates); 5470ba2cbe9Sxc151355 54819d332feSfei feng - Sun Microsystems - Beijing China if (IEEE80211_IS_CHAN_FHSS(ic->ic_curchan)) { 5490ba2cbe9Sxc151355 *frm++ = IEEE80211_ELEMID_FHPARMS; 5500ba2cbe9Sxc151355 *frm++ = IEEE80211_FH_LEN; 5510ba2cbe9Sxc151355 *frm++ = in->in_fhdwell & 0x00ff; 5520ba2cbe9Sxc151355 *frm++ = (in->in_fhdwell >> 8) & 0x00ff; 5530ba2cbe9Sxc151355 *frm++ = IEEE80211_FH_CHANSET( 5540ba2cbe9Sxc151355 ieee80211_chan2ieee(ic, ic->ic_curchan)); 5550ba2cbe9Sxc151355 *frm++ = IEEE80211_FH_CHANPAT( 5560ba2cbe9Sxc151355 ieee80211_chan2ieee(ic, ic->ic_curchan)); 5570ba2cbe9Sxc151355 *frm++ = in->in_fhindex; 5580ba2cbe9Sxc151355 } else { 5590ba2cbe9Sxc151355 *frm++ = IEEE80211_ELEMID_DSPARMS; 5600ba2cbe9Sxc151355 *frm++ = IEEE80211_DS_LEN; 5610ba2cbe9Sxc151355 *frm++ = ieee80211_chan2ieee(ic, ic->ic_curchan); 5620ba2cbe9Sxc151355 } 5630ba2cbe9Sxc151355 5640ba2cbe9Sxc151355 if (ic->ic_opmode == IEEE80211_M_IBSS) { 5650ba2cbe9Sxc151355 *frm++ = IEEE80211_ELEMID_IBSSPARMS; 5660ba2cbe9Sxc151355 *frm++ = IEEE80211_IBSS_LEN; 5670ba2cbe9Sxc151355 *frm++ = 0; *frm++ = 0; /* ATIM window */ 5680ba2cbe9Sxc151355 } 56919d332feSfei feng - Sun Microsystems - Beijing China if (IEEE80211_IS_CHAN_ANYG(ic->ic_curchan)) 57019d332feSfei feng - Sun Microsystems - Beijing China frm = ieee80211_add_erp(frm, ic); 5710ba2cbe9Sxc151355 frm = ieee80211_add_xrates(frm, &in->in_rates); 572*e2cf88acSQuaker Fang /* 573*e2cf88acSQuaker Fang * NB: legacy 11b clients do not get certain ie's. 574*e2cf88acSQuaker Fang * The caller identifies such clients by passing 575*e2cf88acSQuaker Fang * a token in arg to us. Could expand this to be 576*e2cf88acSQuaker Fang * any legacy client for stuff like HT ie's. 577*e2cf88acSQuaker Fang */ 578*e2cf88acSQuaker Fang if (IEEE80211_IS_CHAN_HT(ic->ic_curchan) && 579*e2cf88acSQuaker Fang arg != IEEE80211_SEND_LEGACY_11B) { 580*e2cf88acSQuaker Fang frm = ieee80211_add_htcap(frm, in); 581*e2cf88acSQuaker Fang frm = ieee80211_add_htinfo(frm, in); 582*e2cf88acSQuaker Fang } 583*e2cf88acSQuaker Fang if (ic->ic_flags & IEEE80211_F_WME) 584*e2cf88acSQuaker Fang frm = ieee80211_add_wme_param(frm, &ic->ic_wme); 585*e2cf88acSQuaker Fang if (IEEE80211_IS_CHAN_HT(ic->ic_curchan) && 586*e2cf88acSQuaker Fang (ic->ic_flags_ext & IEEE80211_FEXT_HTCOMPAT) && 587*e2cf88acSQuaker Fang arg != IEEE80211_SEND_LEGACY_11B) { 588*e2cf88acSQuaker Fang frm = ieee80211_add_htcap_vendor(frm, in); 589*e2cf88acSQuaker Fang frm = ieee80211_add_htinfo_vendor(frm, in); 590*e2cf88acSQuaker Fang } 591*e2cf88acSQuaker Fang mp->b_wptr = frm; /* allocated is greater than used */ 592*e2cf88acSQuaker Fang 5930ba2cbe9Sxc151355 break; 5940ba2cbe9Sxc151355 5950ba2cbe9Sxc151355 case IEEE80211_FC0_SUBTYPE_AUTH: 5960ba2cbe9Sxc151355 status = arg >> 16; 5970ba2cbe9Sxc151355 arg &= 0xffff; 5980ba2cbe9Sxc151355 has_challenge = ((arg == IEEE80211_AUTH_SHARED_CHALLENGE || 5990ba2cbe9Sxc151355 arg == IEEE80211_AUTH_SHARED_RESPONSE) && 6000ba2cbe9Sxc151355 in->in_challenge != NULL); 6010ba2cbe9Sxc151355 6020ba2cbe9Sxc151355 /* 6030ba2cbe9Sxc151355 * Deduce whether we're doing open authentication or 6040ba2cbe9Sxc151355 * shared key authentication. We do the latter if 6050ba2cbe9Sxc151355 * we're in the middle of a shared key authentication 6060ba2cbe9Sxc151355 * handshake or if we're initiating an authentication 6070ba2cbe9Sxc151355 * request and configured to use shared key. 6080ba2cbe9Sxc151355 */ 6090ba2cbe9Sxc151355 is_shared_key = has_challenge || 6100ba2cbe9Sxc151355 arg >= IEEE80211_AUTH_SHARED_RESPONSE || 6110ba2cbe9Sxc151355 (arg == IEEE80211_AUTH_SHARED_REQUEST && 6120ba2cbe9Sxc151355 ic->ic_bss->in_authmode == IEEE80211_AUTH_SHARED); 6130ba2cbe9Sxc151355 6140ba2cbe9Sxc151355 if (has_challenge && status == IEEE80211_STATUS_SUCCESS) 6150ba2cbe9Sxc151355 key = ieee80211_crypto_getkey(ic); 6160ba2cbe9Sxc151355 else 6170ba2cbe9Sxc151355 key = NULL; 6180ba2cbe9Sxc151355 6190ba2cbe9Sxc151355 mp = ieee80211_getmgtframe(&frm, 6200ba2cbe9Sxc151355 3 * sizeof (uint16_t) 6210ba2cbe9Sxc151355 + (has_challenge && status == IEEE80211_STATUS_SUCCESS ? 6220ba2cbe9Sxc151355 sizeof (uint16_t) + IEEE80211_CHALLENGE_LEN : 0) 6230ba2cbe9Sxc151355 + (key != NULL ? key->wk_cipher->ic_header : 0)); 6240ba2cbe9Sxc151355 if (mp == NULL) 6250ba2cbe9Sxc151355 return (ENOMEM); 6260ba2cbe9Sxc151355 6270ba2cbe9Sxc151355 if (key != NULL) 6280ba2cbe9Sxc151355 frm += key->wk_cipher->ic_header; 6290ba2cbe9Sxc151355 6300ba2cbe9Sxc151355 ((uint16_t *)frm)[0] = 6310ba2cbe9Sxc151355 (is_shared_key) ? LE_16(IEEE80211_AUTH_ALG_SHARED) 6320ba2cbe9Sxc151355 : LE_16(IEEE80211_AUTH_ALG_OPEN); 6330ba2cbe9Sxc151355 ((uint16_t *)frm)[1] = LE_16(arg); /* sequence number */ 6340ba2cbe9Sxc151355 ((uint16_t *)frm)[2] = LE_16(status); /* status */ 6350ba2cbe9Sxc151355 6360ba2cbe9Sxc151355 if (has_challenge && status == IEEE80211_STATUS_SUCCESS) { 6370ba2cbe9Sxc151355 frm += IEEE80211_AUTH_ELEM_MIN; 6380ba2cbe9Sxc151355 *frm = IEEE80211_ELEMID_CHALLENGE; 6390ba2cbe9Sxc151355 frm++; 6400ba2cbe9Sxc151355 *frm = IEEE80211_CHALLENGE_LEN; 6410ba2cbe9Sxc151355 frm++; 6420ba2cbe9Sxc151355 bcopy(in->in_challenge, frm, IEEE80211_CHALLENGE_LEN); 6430ba2cbe9Sxc151355 } 6440ba2cbe9Sxc151355 6450ba2cbe9Sxc151355 if (ic->ic_opmode == IEEE80211_M_STA) 6460ba2cbe9Sxc151355 timer = IEEE80211_TRANS_WAIT; 6470ba2cbe9Sxc151355 break; 6480ba2cbe9Sxc151355 6490ba2cbe9Sxc151355 case IEEE80211_FC0_SUBTYPE_DEAUTH: 6500ba2cbe9Sxc151355 mp = ieee80211_getmgtframe(&frm, sizeof (uint16_t)); 6510ba2cbe9Sxc151355 if (mp == NULL) 6520ba2cbe9Sxc151355 return (ENOMEM); 6530ba2cbe9Sxc151355 6540ba2cbe9Sxc151355 *(uint16_t *)frm = LE_16(arg); /* reason */ 6550ba2cbe9Sxc151355 6560ba2cbe9Sxc151355 ieee80211_node_unauthorize(in); /* port closed */ 6570ba2cbe9Sxc151355 break; 6580ba2cbe9Sxc151355 6590ba2cbe9Sxc151355 case IEEE80211_FC0_SUBTYPE_ASSOC_REQ: 6600ba2cbe9Sxc151355 case IEEE80211_FC0_SUBTYPE_REASSOC_REQ: 6610ba2cbe9Sxc151355 /* 6620ba2cbe9Sxc151355 * asreq frame format 6630ba2cbe9Sxc151355 * [2] capability information 6640ba2cbe9Sxc151355 * [2] listen interval 6650ba2cbe9Sxc151355 * [6*] current AP address (reassoc only) 6660ba2cbe9Sxc151355 * [tlv] ssid 6670ba2cbe9Sxc151355 * [tlv] supported rates 6680ba2cbe9Sxc151355 * [tlv] extended supported rates 6690ba2cbe9Sxc151355 * [tlv] WME 670*e2cf88acSQuaker Fang * [tlv] HT capabilities 671*e2cf88acSQuaker Fang * [tlv] Vendor OUI HT capabilities (optional) 6720ba2cbe9Sxc151355 * [tlv] user-specified ie's 6730ba2cbe9Sxc151355 */ 6740ba2cbe9Sxc151355 mp = ieee80211_getmgtframe(&frm, 6750ba2cbe9Sxc151355 sizeof (uint16_t) 6760ba2cbe9Sxc151355 + sizeof (uint16_t) + IEEE80211_ADDR_LEN 6770ba2cbe9Sxc151355 + 2 + IEEE80211_NWID_LEN 6780ba2cbe9Sxc151355 + 2 + IEEE80211_RATE_SIZE 6790ba2cbe9Sxc151355 + 2 + IEEE80211_XRATE_SIZE 680*e2cf88acSQuaker Fang + sizeof (struct ieee80211_wme_info) 681*e2cf88acSQuaker Fang + 2 * sizeof (struct ieee80211_ie_htcap) + 4 6820ba2cbe9Sxc151355 + ic->ic_opt_ie_len); 6830ba2cbe9Sxc151355 if (mp == NULL) 6840ba2cbe9Sxc151355 return (ENOMEM); 6850ba2cbe9Sxc151355 6860ba2cbe9Sxc151355 capinfo = ieee80211_get_capinfo(ic); 6870ba2cbe9Sxc151355 if (!(in->in_capinfo & IEEE80211_CAPINFO_SHORT_SLOTTIME) || 6880ba2cbe9Sxc151355 !(ic->ic_caps & IEEE80211_C_SHSLOT)) { 6890ba2cbe9Sxc151355 capinfo &= ~IEEE80211_CAPINFO_SHORT_SLOTTIME; 690c1500db9Szf162725 } else { 691c1500db9Szf162725 capinfo |= IEEE80211_CAPINFO_SHORT_SLOTTIME; 6920ba2cbe9Sxc151355 } 693239e91abShx147065 if (!(in->in_capinfo & IEEE80211_CAPINFO_SHORT_PREAMBLE) || 694239e91abShx147065 !(ic->ic_caps & IEEE80211_C_SHPREAMBLE)) { 695239e91abShx147065 capinfo &= ~IEEE80211_CAPINFO_SHORT_PREAMBLE; 696239e91abShx147065 } else { 697239e91abShx147065 capinfo |= IEEE80211_CAPINFO_SHORT_PREAMBLE; 698239e91abShx147065 } 6990ba2cbe9Sxc151355 *(uint16_t *)frm = LE_16(capinfo); 7000ba2cbe9Sxc151355 frm += 2; 7010ba2cbe9Sxc151355 7020ba2cbe9Sxc151355 *(uint16_t *)frm = LE_16(ic->ic_lintval); 7030ba2cbe9Sxc151355 frm += 2; 7040ba2cbe9Sxc151355 7050ba2cbe9Sxc151355 if (type == IEEE80211_FC0_SUBTYPE_REASSOC_REQ) { 7060ba2cbe9Sxc151355 IEEE80211_ADDR_COPY(frm, ic->ic_bss->in_bssid); 7070ba2cbe9Sxc151355 frm += IEEE80211_ADDR_LEN; 7080ba2cbe9Sxc151355 } 7090ba2cbe9Sxc151355 7100ba2cbe9Sxc151355 frm = ieee80211_add_ssid(frm, in->in_essid, in->in_esslen); 7110ba2cbe9Sxc151355 frm = ieee80211_add_rates(frm, &in->in_rates); 7120ba2cbe9Sxc151355 frm = ieee80211_add_xrates(frm, &in->in_rates); 713*e2cf88acSQuaker Fang if ((ic->ic_flags_ext & IEEE80211_FEXT_HT) && 714*e2cf88acSQuaker Fang in->in_htcap_ie != NULL && 715*e2cf88acSQuaker Fang in->in_htcap_ie[0] == IEEE80211_ELEMID_HTCAP) 716*e2cf88acSQuaker Fang frm = ieee80211_add_htcap(frm, in); 717*e2cf88acSQuaker Fang if ((ic->ic_flags & IEEE80211_F_WME) && in->in_wme_ie != NULL) 718*e2cf88acSQuaker Fang frm = ieee80211_add_wme_info(frm, &ic->ic_wme); 719*e2cf88acSQuaker Fang if ((ic->ic_flags_ext & IEEE80211_FEXT_HT) && 720*e2cf88acSQuaker Fang in->in_htcap_ie != NULL && 721*e2cf88acSQuaker Fang in->in_htcap_ie[0] == IEEE80211_ELEMID_VENDOR) 722*e2cf88acSQuaker Fang frm = ieee80211_add_htcap_vendor(frm, in); 7230ba2cbe9Sxc151355 if (ic->ic_opt_ie != NULL) { 7240ba2cbe9Sxc151355 bcopy(ic->ic_opt_ie, frm, ic->ic_opt_ie_len); 7250ba2cbe9Sxc151355 frm += ic->ic_opt_ie_len; 7260ba2cbe9Sxc151355 } 7270ba2cbe9Sxc151355 mp->b_wptr = frm; /* allocated is greater than used */ 7280ba2cbe9Sxc151355 7290ba2cbe9Sxc151355 timer = IEEE80211_TRANS_WAIT; 7300ba2cbe9Sxc151355 break; 7310ba2cbe9Sxc151355 7320ba2cbe9Sxc151355 case IEEE80211_FC0_SUBTYPE_ASSOC_RESP: 7330ba2cbe9Sxc151355 case IEEE80211_FC0_SUBTYPE_REASSOC_RESP: 7340ba2cbe9Sxc151355 /* 7350ba2cbe9Sxc151355 * asreq frame format 7360ba2cbe9Sxc151355 * [2] capability information 7370ba2cbe9Sxc151355 * [2] status 7380ba2cbe9Sxc151355 * [2] association ID 7390ba2cbe9Sxc151355 * [tlv] supported rates 7400ba2cbe9Sxc151355 * [tlv] extended supported rates 7410ba2cbe9Sxc151355 * [tlv] WME (if enabled and STA enabled) 742*e2cf88acSQuaker Fang * [tlv] HT capabilities (standard or vendor OUI) 743*e2cf88acSQuaker Fang * [tlv] HT information (standard or vendor OUI) 7440ba2cbe9Sxc151355 */ 7450ba2cbe9Sxc151355 mp = ieee80211_getmgtframe(&frm, 7460ba2cbe9Sxc151355 3 * sizeof (uint16_t) 7470ba2cbe9Sxc151355 + 2 + IEEE80211_RATE_SIZE 7480ba2cbe9Sxc151355 + 2 + IEEE80211_XRATE_SIZE); 7490ba2cbe9Sxc151355 if (mp == NULL) 7500ba2cbe9Sxc151355 return (ENOMEM); 7510ba2cbe9Sxc151355 7520ba2cbe9Sxc151355 capinfo = ieee80211_get_capinfo(ic); 7530ba2cbe9Sxc151355 *(uint16_t *)frm = LE_16(capinfo); 7540ba2cbe9Sxc151355 frm += 2; 7550ba2cbe9Sxc151355 7560ba2cbe9Sxc151355 *(uint16_t *)frm = LE_16(arg); /* status */ 7570ba2cbe9Sxc151355 frm += 2; 7580ba2cbe9Sxc151355 7590ba2cbe9Sxc151355 if (arg == IEEE80211_STATUS_SUCCESS) 7600ba2cbe9Sxc151355 *(uint16_t *)frm = LE_16(in->in_associd); 7610ba2cbe9Sxc151355 else 7620ba2cbe9Sxc151355 *(uint16_t *)frm = LE_16(0); 7630ba2cbe9Sxc151355 frm += 2; 7640ba2cbe9Sxc151355 7650ba2cbe9Sxc151355 frm = ieee80211_add_rates(frm, &in->in_rates); 7660ba2cbe9Sxc151355 frm = ieee80211_add_xrates(frm, &in->in_rates); 76719d332feSfei feng - Sun Microsystems - Beijing China mp->b_wptr = frm; 7680ba2cbe9Sxc151355 break; 7690ba2cbe9Sxc151355 7700ba2cbe9Sxc151355 case IEEE80211_FC0_SUBTYPE_DISASSOC: 7710ba2cbe9Sxc151355 mp = ieee80211_getmgtframe(&frm, sizeof (uint16_t)); 7720ba2cbe9Sxc151355 if (mp == NULL) 7730ba2cbe9Sxc151355 return (ENOMEM); 7740ba2cbe9Sxc151355 *(uint16_t *)frm = LE_16(arg); /* reason */ 7750ba2cbe9Sxc151355 break; 7760ba2cbe9Sxc151355 7770ba2cbe9Sxc151355 default: 7780ba2cbe9Sxc151355 ieee80211_dbg(IEEE80211_MSG_ANY, 7790ba2cbe9Sxc151355 "[%s] invalid mgmt frame type %u\n", 7800ba2cbe9Sxc151355 ieee80211_macaddr_sprintf(in->in_macaddr), type); 7810ba2cbe9Sxc151355 return (EINVAL); 7820ba2cbe9Sxc151355 } /* type */ 7830ba2cbe9Sxc151355 ret = ieee80211_mgmt_output(ic, in, mp, type, timer); 7840ba2cbe9Sxc151355 return (ret); 7850ba2cbe9Sxc151355 } 7860ba2cbe9Sxc151355 7870ba2cbe9Sxc151355 /* 7880ba2cbe9Sxc151355 * Allocate a beacon frame and fillin the appropriate bits. 7890ba2cbe9Sxc151355 */ 7900ba2cbe9Sxc151355 mblk_t * 7910ba2cbe9Sxc151355 ieee80211_beacon_alloc(ieee80211com_t *ic, ieee80211_node_t *in, 7920ba2cbe9Sxc151355 struct ieee80211_beacon_offsets *bo) 7930ba2cbe9Sxc151355 { 7940ba2cbe9Sxc151355 struct ieee80211_frame *wh; 7950ba2cbe9Sxc151355 struct ieee80211_rateset *rs; 7960ba2cbe9Sxc151355 mblk_t *m; 7970ba2cbe9Sxc151355 uint8_t *frm; 7980ba2cbe9Sxc151355 int pktlen; 7990ba2cbe9Sxc151355 uint16_t capinfo; 8000ba2cbe9Sxc151355 8010ba2cbe9Sxc151355 IEEE80211_LOCK(ic); 8020ba2cbe9Sxc151355 /* 8030ba2cbe9Sxc151355 * beacon frame format 8040ba2cbe9Sxc151355 * [8] time stamp 8050ba2cbe9Sxc151355 * [2] beacon interval 8060ba2cbe9Sxc151355 * [2] cabability information 8070ba2cbe9Sxc151355 * [tlv] ssid 8080ba2cbe9Sxc151355 * [tlv] supported rates 8090ba2cbe9Sxc151355 * [3] parameter set (DS) 8100ba2cbe9Sxc151355 * [tlv] parameter set (IBSS/TIM) 8110ba2cbe9Sxc151355 * [tlv] extended rate phy (ERP) 8120ba2cbe9Sxc151355 * [tlv] extended supported rates 8130ba2cbe9Sxc151355 * [tlv] WME parameters 8140ba2cbe9Sxc151355 * [tlv] WPA/RSN parameters 815*e2cf88acSQuaker Fang * [tlv] HT capabilities 816*e2cf88acSQuaker Fang * [tlv] HT information 817*e2cf88acSQuaker Fang * [tlv] Vendor OUI HT capabilities (optional) 818*e2cf88acSQuaker Fang * [tlv] Vendor OUI HT information (optional) 8190ba2cbe9Sxc151355 * Vendor-specific OIDs (e.g. Atheros) 8200ba2cbe9Sxc151355 * NB: we allocate the max space required for the TIM bitmap. 8210ba2cbe9Sxc151355 */ 8220ba2cbe9Sxc151355 rs = &in->in_rates; 8230ba2cbe9Sxc151355 pktlen = 8 /* time stamp */ 8240ba2cbe9Sxc151355 + sizeof (uint16_t) /* beacon interval */ 8250ba2cbe9Sxc151355 + sizeof (uint16_t) /* capabilities */ 8260ba2cbe9Sxc151355 + 2 + in->in_esslen /* ssid */ 8270ba2cbe9Sxc151355 + 2 + IEEE80211_RATE_SIZE /* supported rates */ 8280ba2cbe9Sxc151355 + 2 + 1 /* DS parameters */ 8290ba2cbe9Sxc151355 + 2 + 4 + ic->ic_tim_len /* DTIM/IBSSPARMS */ 8300ba2cbe9Sxc151355 + 2 + 1 /* ERP */ 831*e2cf88acSQuaker Fang + 2 + IEEE80211_XRATE_SIZE 832*e2cf88acSQuaker Fang + (ic->ic_caps & IEEE80211_C_WME ? /* WME */ 833*e2cf88acSQuaker Fang sizeof (struct ieee80211_wme_param) : 0) 834*e2cf88acSQuaker Fang /* conditional? */ 835*e2cf88acSQuaker Fang + 4 + 2 * sizeof (struct ieee80211_ie_htcap) /* HT caps */ 836*e2cf88acSQuaker Fang + 4 + 2 * sizeof (struct ieee80211_ie_htinfo); /* HT info */ 837*e2cf88acSQuaker Fang 8380ba2cbe9Sxc151355 m = ieee80211_getmgtframe(&frm, pktlen); 8390ba2cbe9Sxc151355 if (m == NULL) { 8400ba2cbe9Sxc151355 ieee80211_dbg(IEEE80211_MSG_ANY, "ieee80211_beacon_alloc: " 8410ba2cbe9Sxc151355 "cannot get buf; size %u\n", pktlen); 8420ba2cbe9Sxc151355 IEEE80211_UNLOCK(ic); 8430ba2cbe9Sxc151355 return (NULL); 8440ba2cbe9Sxc151355 } 8450ba2cbe9Sxc151355 8460ba2cbe9Sxc151355 /* timestamp is set by hardware/driver */ 8470ba2cbe9Sxc151355 (void) memset(frm, 0, 8); 8480ba2cbe9Sxc151355 frm += 8; 8490ba2cbe9Sxc151355 *(uint16_t *)frm = LE_16(in->in_intval); 8500ba2cbe9Sxc151355 frm += 2; 8510ba2cbe9Sxc151355 capinfo = ieee80211_get_capinfo(ic); 8520ba2cbe9Sxc151355 bo->bo_caps = (uint16_t *)frm; 8530ba2cbe9Sxc151355 *(uint16_t *)frm = LE_16(capinfo); 8540ba2cbe9Sxc151355 frm += 2; 8550ba2cbe9Sxc151355 *frm++ = IEEE80211_ELEMID_SSID; 8560ba2cbe9Sxc151355 if (!(ic->ic_flags & IEEE80211_F_HIDESSID)) { 8570ba2cbe9Sxc151355 *frm++ = in->in_esslen; 8580ba2cbe9Sxc151355 bcopy(in->in_essid, frm, in->in_esslen); 8590ba2cbe9Sxc151355 frm += in->in_esslen; 8600ba2cbe9Sxc151355 } else { 8610ba2cbe9Sxc151355 *frm++ = 0; 8620ba2cbe9Sxc151355 } 8630ba2cbe9Sxc151355 frm = ieee80211_add_rates(frm, rs); 8640ba2cbe9Sxc151355 if (ic->ic_curmode != IEEE80211_MODE_FH) { 8650ba2cbe9Sxc151355 *frm++ = IEEE80211_ELEMID_DSPARMS; 8660ba2cbe9Sxc151355 *frm++ = 1; 8670ba2cbe9Sxc151355 *frm++ = ieee80211_chan2ieee(ic, in->in_chan); 8680ba2cbe9Sxc151355 } 8690ba2cbe9Sxc151355 bo->bo_tim = frm; 8700ba2cbe9Sxc151355 if (ic->ic_opmode == IEEE80211_M_IBSS) { 8710ba2cbe9Sxc151355 *frm++ = IEEE80211_ELEMID_IBSSPARMS; 8720ba2cbe9Sxc151355 *frm++ = 2; 8730ba2cbe9Sxc151355 *frm++ = 0; *frm++ = 0; /* TODO: ATIM window */ 8740ba2cbe9Sxc151355 bo->bo_tim_len = 0; 8750ba2cbe9Sxc151355 } else { 8760ba2cbe9Sxc151355 struct ieee80211_tim_ie *tie = 8770ba2cbe9Sxc151355 (struct ieee80211_tim_ie *)frm; 8780ba2cbe9Sxc151355 8790ba2cbe9Sxc151355 tie->tim_ie = IEEE80211_ELEMID_TIM; 8800ba2cbe9Sxc151355 tie->tim_len = 4; /* length */ 8810ba2cbe9Sxc151355 tie->tim_count = 0; /* DTIM count */ 8820ba2cbe9Sxc151355 tie->tim_period = IEEE80211_DTIM_DEFAULT; 8830ba2cbe9Sxc151355 tie->tim_bitctl = 0; /* bitmap control */ 8840ba2cbe9Sxc151355 tie->tim_bitmap[0] = 0; /* Partial Virtual Bitmap */ 8850ba2cbe9Sxc151355 frm += sizeof (struct ieee80211_tim_ie); 8860ba2cbe9Sxc151355 bo->bo_tim_len = 1; 8870ba2cbe9Sxc151355 } 8880ba2cbe9Sxc151355 bo->bo_trailer = frm; 8890ba2cbe9Sxc151355 8900ba2cbe9Sxc151355 if (ic->ic_curmode == IEEE80211_MODE_11G) { 8910ba2cbe9Sxc151355 bo->bo_erp = frm; 8920ba2cbe9Sxc151355 frm = ieee80211_add_erp(frm, ic); 8930ba2cbe9Sxc151355 } 894*e2cf88acSQuaker Fang frm = ieee80211_add_xrates(frm, rs); 895*e2cf88acSQuaker Fang if (IEEE80211_IS_CHAN_HT(ic->ic_curchan)) { 896*e2cf88acSQuaker Fang frm = ieee80211_add_htcap(frm, in); 897*e2cf88acSQuaker Fang bo->bo_htinfo = frm; 898*e2cf88acSQuaker Fang frm = ieee80211_add_htinfo(frm, in); 899*e2cf88acSQuaker Fang } 900*e2cf88acSQuaker Fang if (ic->ic_flags & IEEE80211_F_WME) { 901*e2cf88acSQuaker Fang bo->bo_wme = frm; 902*e2cf88acSQuaker Fang frm = ieee80211_add_wme_param(frm, &ic->ic_wme); 903*e2cf88acSQuaker Fang } 904*e2cf88acSQuaker Fang if (IEEE80211_IS_CHAN_HT(ic->ic_curchan) && 905*e2cf88acSQuaker Fang (ic->ic_flags_ext & IEEE80211_FEXT_HTCOMPAT)) { 906*e2cf88acSQuaker Fang frm = ieee80211_add_htcap_vendor(frm, in); 907*e2cf88acSQuaker Fang frm = ieee80211_add_htinfo_vendor(frm, in); 908*e2cf88acSQuaker Fang } 909*e2cf88acSQuaker Fang bo->bo_trailer_len = _PTRDIFF(frm, bo->bo_trailer); 910*e2cf88acSQuaker Fang m->b_wptr = frm; 9110ba2cbe9Sxc151355 9120ba2cbe9Sxc151355 wh = (struct ieee80211_frame *)m->b_rptr; 9130ba2cbe9Sxc151355 wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_MGT | 9140ba2cbe9Sxc151355 IEEE80211_FC0_SUBTYPE_BEACON; 9150ba2cbe9Sxc151355 wh->i_fc[1] = IEEE80211_FC1_DIR_NODS; 9160ba2cbe9Sxc151355 *(uint16_t *)wh->i_dur = 0; 9170ba2cbe9Sxc151355 IEEE80211_ADDR_COPY(wh->i_addr1, wifi_bcastaddr); 9180ba2cbe9Sxc151355 IEEE80211_ADDR_COPY(wh->i_addr2, ic->ic_macaddr); 9190ba2cbe9Sxc151355 IEEE80211_ADDR_COPY(wh->i_addr3, in->in_bssid); 9200ba2cbe9Sxc151355 *(uint16_t *)wh->i_seq = 0; 9210ba2cbe9Sxc151355 9220ba2cbe9Sxc151355 IEEE80211_UNLOCK(ic); 9230ba2cbe9Sxc151355 return (m); 9240ba2cbe9Sxc151355 } 9250ba2cbe9Sxc151355 9260ba2cbe9Sxc151355 /* 9270ba2cbe9Sxc151355 * Update the dynamic parts of a beacon frame based on the current state. 9280ba2cbe9Sxc151355 */ 9290ba2cbe9Sxc151355 /* ARGSUSED */ 9300ba2cbe9Sxc151355 int 9310ba2cbe9Sxc151355 ieee80211_beacon_update(ieee80211com_t *ic, ieee80211_node_t *in, 9320ba2cbe9Sxc151355 struct ieee80211_beacon_offsets *bo, mblk_t *mp, int mcast) 9330ba2cbe9Sxc151355 { 9340ba2cbe9Sxc151355 uint16_t capinfo; 9350ba2cbe9Sxc151355 9360ba2cbe9Sxc151355 IEEE80211_LOCK(ic); 9370ba2cbe9Sxc151355 9380ba2cbe9Sxc151355 capinfo = ieee80211_get_capinfo(ic); 9390ba2cbe9Sxc151355 *bo->bo_caps = LE_16(capinfo); 9400ba2cbe9Sxc151355 9410ba2cbe9Sxc151355 IEEE80211_UNLOCK(ic); 9420ba2cbe9Sxc151355 return (0); 9430ba2cbe9Sxc151355 } 944*e2cf88acSQuaker Fang 945*e2cf88acSQuaker Fang /* 946*e2cf88acSQuaker Fang * Assign priority to a frame based on any vlan tag assigned 947*e2cf88acSQuaker Fang * to the station and/or any Diffserv setting in an IP header. 948*e2cf88acSQuaker Fang * Finally, if an ACM policy is setup (in station mode) it's 949*e2cf88acSQuaker Fang * applied. 950*e2cf88acSQuaker Fang */ 951*e2cf88acSQuaker Fang int 952*e2cf88acSQuaker Fang ieee80211_classify(struct ieee80211com *ic, mblk_t *m, 953*e2cf88acSQuaker Fang struct ieee80211_node *ni) 954*e2cf88acSQuaker Fang /* ARGSUSED */ 955*e2cf88acSQuaker Fang { 956*e2cf88acSQuaker Fang int ac; 957*e2cf88acSQuaker Fang 958*e2cf88acSQuaker Fang if ((ni->in_flags & IEEE80211_NODE_QOS) == 0) 959*e2cf88acSQuaker Fang return (WME_AC_BE); 960*e2cf88acSQuaker Fang 961*e2cf88acSQuaker Fang /* Process VLan */ 962*e2cf88acSQuaker Fang /* Process IPQoS */ 963*e2cf88acSQuaker Fang 964*e2cf88acSQuaker Fang ac = WME_AC_BE; 965*e2cf88acSQuaker Fang 966*e2cf88acSQuaker Fang /* 967*e2cf88acSQuaker Fang * Apply ACM policy. 968*e2cf88acSQuaker Fang */ 969*e2cf88acSQuaker Fang if (ic->ic_opmode == IEEE80211_M_STA) { 970*e2cf88acSQuaker Fang static const int acmap[4] = { 971*e2cf88acSQuaker Fang WME_AC_BK, /* WME_AC_BE */ 972*e2cf88acSQuaker Fang WME_AC_BK, /* WME_AC_BK */ 973*e2cf88acSQuaker Fang WME_AC_BE, /* WME_AC_VI */ 974*e2cf88acSQuaker Fang WME_AC_VI, /* WME_AC_VO */ 975*e2cf88acSQuaker Fang }; 976*e2cf88acSQuaker Fang while (ac != WME_AC_BK && 977*e2cf88acSQuaker Fang ic->ic_wme.wme_wmeBssChanParams.cap_wmeParams[ac]. 978*e2cf88acSQuaker Fang wmep_acm) { 979*e2cf88acSQuaker Fang ac = acmap[ac]; 980*e2cf88acSQuaker Fang } 981*e2cf88acSQuaker Fang } 982*e2cf88acSQuaker Fang 983*e2cf88acSQuaker Fang return (ac); 984*e2cf88acSQuaker Fang } 985