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