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
ieee80211_send_setup(ieee80211com_t * ic,ieee80211_node_t * in,struct ieee80211_frame * wh,int type,const uint8_t * sa,const uint8_t * da,const uint8_t * bssid)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
ieee80211_mgmt_output(ieee80211com_t * ic,ieee80211_node_t * in,mblk_t * mp,int type,int timer)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
ieee80211_send_nulldata(ieee80211_node_t * in)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 *
ieee80211_encap(ieee80211com_t * ic,mblk_t * mp,ieee80211_node_t * in)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 *
ieee80211_add_rates(uint8_t * frm,const struct ieee80211_rateset * rs)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 *
ieee80211_add_xrates(uint8_t * frm,const struct ieee80211_rateset * rs)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 *
ieee80211_add_wme_info(uint8_t * frm,struct ieee80211_wme_state * wme)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 *
ieee80211_add_wme_param(uint8_t * frm,struct ieee80211_wme_state * wme)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 *
ieee80211_add_ssid(uint8_t * frm,const uint8_t * ssid,uint32_t len)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 *
ieee80211_add_erp(uint8_t * frm,ieee80211com_t * ic)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
ieee80211_get_capinfo(ieee80211com_t * ic)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
ieee80211_send_probereq(ieee80211_node_t * in,const uint8_t * sa,const uint8_t * da,const uint8_t * bssid,const uint8_t * ssid,size_t ssidlen,const void * optie,size_t optielen)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
ieee80211_send_mgmt(ieee80211com_t * ic,ieee80211_node_t * in,int type,int arg)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 *
ieee80211_beacon_alloc(ieee80211com_t * ic,ieee80211_node_t * in,struct ieee80211_beacon_offsets * bo)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
ieee80211_beacon_update(ieee80211com_t * ic,ieee80211_node_t * in,struct ieee80211_beacon_offsets * bo,mblk_t * mp,int mcast)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
ieee80211_classify(struct ieee80211com * ic,mblk_t * m,struct ieee80211_node * ni)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