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