ieee80211_output.c revision 1.2 1 /*-
2 * Copyright (c) 2001 Atsushi Onoe
3 * Copyright (c) 2002, 2003 Sam Leffler, Errno Consulting
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * Alternatively, this software may be distributed under the terms of the
18 * GNU General Public License ("GPL") version 2 as published by the Free
19 * Software Foundation.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
33 #include <sys/cdefs.h>
34 __FBSDID("$FreeBSD: src/sys/net80211/ieee80211_output.c,v 1.4 2003/08/19 22:17:03 sam Exp $");
35
36 #include "opt_inet.h"
37
38 #include <sys/param.h>
39 #include <sys/systm.h>
40 #include <sys/mbuf.h>
41 #include <sys/malloc.h>
42 #include <sys/kernel.h>
43 #include <sys/socket.h>
44 #include <sys/sockio.h>
45 #include <sys/endian.h>
46 #include <sys/errno.h>
47 #include <sys/bus.h>
48 #include <sys/proc.h>
49 #include <sys/sysctl.h>
50
51 #ifdef __FreeBSD__
52 #include <machine/atomic.h>
53 #endif
54
55 #include <net/if.h>
56 #include <net/if_dl.h>
57 #include <net/if_media.h>
58 #include <net/if_arp.h>
59 #ifdef __FreeBSD__
60 #include <net/ethernet.h>
61 #endif
62 #include <net/if_llc.h>
63
64 #include <net80211/ieee80211_compat.h>
65 #include <net80211/ieee80211_var.h>
66
67 #include <net/bpf.h>
68
69 #ifdef INET
70 #include <netinet/in.h>
71 #include <netinet/if_ether.h>
72 #endif
73
74 /*
75 * Send a management frame to the specified node. The node pointer
76 * must have a reference as the pointer will be passed to the driver
77 * and potentially held for a long time. If the frame is successfully
78 * dispatched to the driver, then it is responsible for freeing the
79 * reference (and potentially free'ing up any associated storage).
80 */
81 static int
82 ieee80211_mgmt_output(struct ifnet *ifp, struct ieee80211_node *ni,
83 struct mbuf *m, int type)
84 {
85 struct ieee80211com *ic = (void *)ifp;
86 struct ieee80211_frame *wh;
87
88 KASSERT(ni != NULL, ("null node"));
89 ni->ni_inact = 0;
90
91 /*
92 * Yech, hack alert! We want to pass the node down to the
93 * driver's start routine. If we don't do so then the start
94 * routine must immediately look it up again and that can
95 * cause a lock order reversal if, for example, this frame
96 * is being sent because the station is being timedout and
97 * the frame being sent is a DEAUTH message. We could stick
98 * this in an m_tag and tack that on to the mbuf. However
99 * that's rather expensive to do for every frame so instead
100 * we stuff it in the rcvif field since outbound frames do
101 * not (presently) use this.
102 */
103 M_PREPEND(m, sizeof(struct ieee80211_frame), M_DONTWAIT);
104 if (m == NULL)
105 return ENOMEM;
106 KASSERT(m->m_pkthdr.rcvif == NULL, ("rcvif not null"));
107 m->m_pkthdr.rcvif = (void *)ni;
108
109 wh = mtod(m, struct ieee80211_frame *);
110 wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_MGT | type;
111 wh->i_fc[1] = IEEE80211_FC1_DIR_NODS;
112 *(u_int16_t *)&wh->i_dur[0] = 0;
113 *(u_int16_t *)&wh->i_seq[0] =
114 htole16(ni->ni_txseq << IEEE80211_SEQ_SEQ_SHIFT);
115 ni->ni_txseq++;
116 IEEE80211_ADDR_COPY(wh->i_addr1, ni->ni_macaddr);
117 IEEE80211_ADDR_COPY(wh->i_addr2, ic->ic_myaddr);
118 IEEE80211_ADDR_COPY(wh->i_addr3, ni->ni_bssid);
119
120 if (ifp->if_flags & IFF_DEBUG) {
121 /* avoid to print too many frames */
122 if (ic->ic_opmode == IEEE80211_M_IBSS ||
123 #ifdef IEEE80211_DEBUG
124 ieee80211_debug > 1 ||
125 #endif
126 (type & IEEE80211_FC0_SUBTYPE_MASK) !=
127 IEEE80211_FC0_SUBTYPE_PROBE_RESP)
128 if_printf(ifp, "sending %s to %s on channel %u\n",
129 ieee80211_mgt_subtype_name[
130 (type & IEEE80211_FC0_SUBTYPE_MASK)
131 >> IEEE80211_FC0_SUBTYPE_SHIFT],
132 ether_sprintf(ni->ni_macaddr),
133 ieee80211_chan2ieee(ic, ni->ni_chan));
134 }
135
136 IF_ENQUEUE(&ic->ic_mgtq, m);
137 ifp->if_timer = 1;
138 (*ifp->if_start)(ifp);
139 return 0;
140 }
141
142 /*
143 * Encapsulate an outbound data frame. The mbuf chain is updated and
144 * a reference to the destination node is returned. If an error is
145 * encountered NULL is returned and the node reference will also be NULL.
146 *
147 * NB: The caller is responsible for free'ing a returned node reference.
148 * The convention is ic_bss is not reference counted; the caller must
149 * maintain that.
150 */
151 struct mbuf *
152 ieee80211_encap(struct ifnet *ifp, struct mbuf *m, struct ieee80211_node **pni)
153 {
154 struct ieee80211com *ic = (void *)ifp;
155 struct ether_header eh;
156 struct ieee80211_frame *wh;
157 struct ieee80211_node *ni = NULL;
158 struct llc *llc;
159
160 if (m->m_len < sizeof(struct ether_header)) {
161 m = m_pullup(m, sizeof(struct ether_header));
162 if (m == NULL) {
163 /* XXX statistic */
164 goto bad;
165 }
166 }
167 memcpy(&eh, mtod(m, caddr_t), sizeof(struct ether_header));
168
169 if (ic->ic_opmode != IEEE80211_M_STA) {
170 ni = ieee80211_find_node(ic, eh.ether_dhost);
171 if (ni == NULL) {
172 /*
173 * When not in station mode the
174 * destination address should always be
175 * in the node table unless this is a
176 * multicast/broadcast frame.
177 */
178 if (!IEEE80211_IS_MULTICAST(eh.ether_dhost)) {
179 /* ic->ic_stats.st_tx_nonode++; XXX statistic */
180 goto bad;
181 }
182 ni = ic->ic_bss;
183 }
184 } else
185 ni = ic->ic_bss;
186 ni->ni_inact = 0;
187
188 m_adj(m, sizeof(struct ether_header) - sizeof(struct llc));
189 llc = mtod(m, struct llc *);
190 llc->llc_dsap = llc->llc_ssap = LLC_SNAP_LSAP;
191 llc->llc_control = LLC_UI;
192 llc->llc_snap.org_code[0] = 0;
193 llc->llc_snap.org_code[1] = 0;
194 llc->llc_snap.org_code[2] = 0;
195 llc->llc_snap.ether_type = eh.ether_type;
196 M_PREPEND(m, sizeof(struct ieee80211_frame), M_DONTWAIT);
197 if (m == NULL)
198 goto bad;
199 wh = mtod(m, struct ieee80211_frame *);
200 wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_DATA;
201 *(u_int16_t *)&wh->i_dur[0] = 0;
202 *(u_int16_t *)&wh->i_seq[0] =
203 htole16(ni->ni_txseq << IEEE80211_SEQ_SEQ_SHIFT);
204 ni->ni_txseq++;
205 switch (ic->ic_opmode) {
206 case IEEE80211_M_STA:
207 wh->i_fc[1] = IEEE80211_FC1_DIR_TODS;
208 IEEE80211_ADDR_COPY(wh->i_addr1, ni->ni_bssid);
209 IEEE80211_ADDR_COPY(wh->i_addr2, eh.ether_shost);
210 IEEE80211_ADDR_COPY(wh->i_addr3, eh.ether_dhost);
211 break;
212 case IEEE80211_M_IBSS:
213 case IEEE80211_M_AHDEMO:
214 wh->i_fc[1] = IEEE80211_FC1_DIR_NODS;
215 IEEE80211_ADDR_COPY(wh->i_addr1, eh.ether_dhost);
216 IEEE80211_ADDR_COPY(wh->i_addr2, eh.ether_shost);
217 IEEE80211_ADDR_COPY(wh->i_addr3, ni->ni_bssid);
218 break;
219 case IEEE80211_M_HOSTAP:
220 wh->i_fc[1] = IEEE80211_FC1_DIR_FROMDS;
221 IEEE80211_ADDR_COPY(wh->i_addr1, eh.ether_dhost);
222 IEEE80211_ADDR_COPY(wh->i_addr2, ni->ni_bssid);
223 IEEE80211_ADDR_COPY(wh->i_addr3, eh.ether_shost);
224 break;
225 case IEEE80211_M_MONITOR:
226 goto bad;
227 }
228 *pni = ni;
229 return m;
230 bad:
231 if (m != NULL)
232 m_freem(m);
233 if (ni && ni != ic->ic_bss)
234 ieee80211_free_node(ic, ni);
235 *pni = NULL;
236 return NULL;
237 }
238
239 /*
240 * Add a supported rates element id to a frame.
241 */
242 u_int8_t *
243 ieee80211_add_rates(u_int8_t *frm, const struct ieee80211_rateset *rs)
244 {
245 int nrates;
246
247 *frm++ = IEEE80211_ELEMID_RATES;
248 nrates = rs->rs_nrates;
249 if (nrates > IEEE80211_RATE_SIZE)
250 nrates = IEEE80211_RATE_SIZE;
251 *frm++ = nrates;
252 memcpy(frm, rs->rs_rates, nrates);
253 return frm + nrates;
254 }
255
256 /*
257 * Add an extended supported rates element id to a frame.
258 */
259 u_int8_t *
260 ieee80211_add_xrates(u_int8_t *frm, const struct ieee80211_rateset *rs)
261 {
262 /*
263 * Add an extended supported rates element if operating in 11g mode.
264 */
265 if (rs->rs_nrates > IEEE80211_RATE_SIZE) {
266 int nrates = rs->rs_nrates - IEEE80211_RATE_SIZE;
267 *frm++ = IEEE80211_ELEMID_XRATES;
268 *frm++ = nrates;
269 memcpy(frm, rs->rs_rates + IEEE80211_RATE_SIZE, nrates);
270 frm += nrates;
271 }
272 return frm;
273 }
274
275 /*
276 * Add an ssid elemet to a frame.
277 */
278 static u_int8_t *
279 ieee80211_add_ssid(u_int8_t *frm, const u_int8_t *ssid, u_int len)
280 {
281 *frm++ = IEEE80211_ELEMID_SSID;
282 *frm++ = len;
283 memcpy(frm, ssid, len);
284 return frm + len;
285 }
286
287 static struct mbuf *
288 ieee80211_getmbuf(int flags, int type, u_int pktlen)
289 {
290 struct mbuf *m;
291
292 #ifdef __FreeBSD__
293 if (pktlen > MHLEN)
294 MGETHDR(m, flags, type);
295 else
296 m = m_getcl(flags, type, M_PKTHDR);
297 #else
298 MGETHDR(m, flags, type);
299 if (m != NULL && pktlen > MHLEN)
300 MCLGET(m, flags);
301 #endif
302 return m;
303 }
304
305 /*
306 * Send a management frame. The node is for the destination (or ic_bss
307 * when in station mode). Nodes other than ic_bss have their reference
308 * count bumped to reflect our use for an indeterminant time.
309 */
310 int
311 ieee80211_send_mgmt(struct ieee80211com *ic, struct ieee80211_node *ni,
312 int type, int arg)
313 {
314 #define senderr(_x) do { ret = _x; goto bad; } while (0)
315 struct ifnet *ifp = &ic->ic_if;
316 struct mbuf *m;
317 u_int8_t *frm;
318 enum ieee80211_phymode mode;
319 u_int16_t capinfo;
320 int ret, timer;
321
322 KASSERT(ni != NULL, ("null node"));
323
324 /*
325 * Hold a reference on the node so it doesn't go away until after
326 * the xmit is complete all the way in the driver. On error we
327 * will remove our reference.
328 */
329 if (ni != ic->ic_bss)
330 ieee80211_ref_node(ni);
331 timer = 0;
332 switch (type) {
333 case IEEE80211_FC0_SUBTYPE_PROBE_REQ:
334 /*
335 * prreq frame format
336 * [tlv] ssid
337 * [tlv] supported rates
338 * [tlv] extended supported rates
339 */
340 m = ieee80211_getmbuf(M_DONTWAIT, MT_DATA,
341 2 + ic->ic_des_esslen
342 + 2 + IEEE80211_RATE_SIZE
343 + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE));
344 if (m == NULL)
345 senderr(ENOMEM);
346 m->m_data += sizeof(struct ieee80211_frame);
347 frm = mtod(m, u_int8_t *);
348 frm = ieee80211_add_ssid(frm, ic->ic_des_essid, ic->ic_des_esslen);
349 mode = ieee80211_chan2mode(ic, ni->ni_chan);
350 frm = ieee80211_add_rates(frm, &ic->ic_sup_rates[mode]);
351 frm = ieee80211_add_xrates(frm, &ic->ic_sup_rates[mode]);
352 m->m_pkthdr.len = m->m_len = frm - mtod(m, u_int8_t *);
353
354 timer = IEEE80211_TRANS_WAIT;
355 break;
356
357 case IEEE80211_FC0_SUBTYPE_PROBE_RESP:
358 /*
359 * probe response frame format
360 * [8] time stamp
361 * [2] beacon interval
362 * [2] cabability information
363 * [tlv] ssid
364 * [tlv] supported rates
365 * [tlv] parameter set (IBSS)
366 * [tlv] extended supported rates
367 */
368 m = ieee80211_getmbuf(M_DONTWAIT, MT_DATA,
369 8 + 2 + 2 + 2
370 + 2 + ni->ni_esslen
371 + 2 + IEEE80211_RATE_SIZE
372 + 6
373 + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE));
374 if (m == NULL)
375 senderr(ENOMEM);
376 m->m_data += sizeof(struct ieee80211_frame);
377 frm = mtod(m, u_int8_t *);
378
379 memset(frm, 0, 8); /* timestamp should be filled later */
380 frm += 8;
381 *(u_int16_t *)frm = htole16(ic->ic_bss->ni_intval);
382 frm += 2;
383 if (ic->ic_opmode == IEEE80211_M_IBSS)
384 capinfo = IEEE80211_CAPINFO_IBSS;
385 else
386 capinfo = IEEE80211_CAPINFO_ESS;
387 if (ic->ic_flags & IEEE80211_F_WEPON)
388 capinfo |= IEEE80211_CAPINFO_PRIVACY;
389 *(u_int16_t *)frm = htole16(capinfo);
390 frm += 2;
391
392 frm = ieee80211_add_ssid(frm, ic->ic_bss->ni_essid,
393 ic->ic_bss->ni_esslen);
394 frm = ieee80211_add_rates(frm, &ic->ic_bss->ni_rates);
395
396 if (ic->ic_opmode == IEEE80211_M_IBSS) {
397 *frm++ = IEEE80211_ELEMID_IBSSPARMS;
398 *frm++ = 2;
399 *frm++ = 0; *frm++ = 0; /* TODO: ATIM window */
400 } else { /* IEEE80211_M_HOSTAP */
401 /* TODO: TIM */
402 *frm++ = IEEE80211_ELEMID_TIM;
403 *frm++ = 4; /* length */
404 *frm++ = 0; /* DTIM count */
405 *frm++ = 1; /* DTIM period */
406 *frm++ = 0; /* bitmap control */
407 *frm++ = 0; /* Partial Virtual Bitmap (variable length) */
408 }
409 frm = ieee80211_add_xrates(frm, &ic->ic_bss->ni_rates);
410 m->m_pkthdr.len = m->m_len = frm - mtod(m, u_int8_t *);
411 break;
412
413 case IEEE80211_FC0_SUBTYPE_AUTH:
414 MGETHDR(m, M_DONTWAIT, MT_DATA);
415 if (m == NULL)
416 senderr(ENOMEM);
417 MH_ALIGN(m, 2 * 3);
418 m->m_pkthdr.len = m->m_len = 6;
419 frm = mtod(m, u_int8_t *);
420 /* TODO: shared key auth */
421 ((u_int16_t *)frm)[0] = htole16(IEEE80211_AUTH_ALG_OPEN);
422 ((u_int16_t *)frm)[1] = htole16(arg); /* sequence number */
423 ((u_int16_t *)frm)[2] = 0; /* status */
424 if (ic->ic_opmode == IEEE80211_M_STA)
425 timer = IEEE80211_TRANS_WAIT;
426 break;
427
428 case IEEE80211_FC0_SUBTYPE_DEAUTH:
429 if (ifp->if_flags & IFF_DEBUG)
430 if_printf(ifp, "station %s deauthenticate (reason %d)\n",
431 ether_sprintf(ni->ni_macaddr), arg);
432 MGETHDR(m, M_DONTWAIT, MT_DATA);
433 if (m == NULL)
434 senderr(ENOMEM);
435 MH_ALIGN(m, 2);
436 m->m_pkthdr.len = m->m_len = 2;
437 *mtod(m, u_int16_t *) = htole16(arg); /* reason */
438 break;
439
440 case IEEE80211_FC0_SUBTYPE_ASSOC_REQ:
441 case IEEE80211_FC0_SUBTYPE_REASSOC_REQ:
442 /*
443 * asreq frame format
444 * [2] capability information
445 * [2] listen interval
446 * [6*] current AP address (reassoc only)
447 * [tlv] ssid
448 * [tlv] supported rates
449 * [tlv] extended supported rates
450 */
451 m = ieee80211_getmbuf(M_DONTWAIT, MT_DATA,
452 sizeof(capinfo)
453 + sizeof(u_int16_t)
454 + IEEE80211_ADDR_LEN
455 + 2 + ni->ni_esslen
456 + 2 + IEEE80211_RATE_SIZE
457 + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE));
458 if (m == NULL)
459 senderr(ENOMEM);
460 m->m_data += sizeof(struct ieee80211_frame);
461 frm = mtod(m, u_int8_t *);
462
463 capinfo = 0;
464 if (ic->ic_opmode == IEEE80211_M_IBSS)
465 capinfo |= IEEE80211_CAPINFO_IBSS;
466 else /* IEEE80211_M_STA */
467 capinfo |= IEEE80211_CAPINFO_ESS;
468 if (ic->ic_flags & IEEE80211_F_WEPON)
469 capinfo |= IEEE80211_CAPINFO_PRIVACY;
470 if (ic->ic_flags & IEEE80211_F_SHPREAMBLE)
471 capinfo |= IEEE80211_CAPINFO_SHORT_PREAMBLE;
472 if (ic->ic_flags & IEEE80211_F_SHSLOT)
473 capinfo |= IEEE80211_CAPINFO_SHORT_SLOTTIME;
474 *(u_int16_t *)frm = htole16(capinfo);
475 frm += 2;
476
477 *(u_int16_t *)frm = htole16(ic->ic_lintval);
478 frm += 2;
479
480 if (type == IEEE80211_FC0_SUBTYPE_REASSOC_REQ) {
481 IEEE80211_ADDR_COPY(frm, ic->ic_bss->ni_bssid);
482 frm += IEEE80211_ADDR_LEN;
483 }
484
485 frm = ieee80211_add_ssid(frm, ni->ni_essid, ni->ni_esslen);
486 frm = ieee80211_add_rates(frm, &ni->ni_rates);
487 frm = ieee80211_add_xrates(frm, &ni->ni_rates);
488 m->m_pkthdr.len = m->m_len = frm - mtod(m, u_int8_t *);
489
490 timer = IEEE80211_TRANS_WAIT;
491 break;
492
493 case IEEE80211_FC0_SUBTYPE_ASSOC_RESP:
494 case IEEE80211_FC0_SUBTYPE_REASSOC_RESP:
495 /*
496 * asreq frame format
497 * [2] capability information
498 * [2] status
499 * [2] association ID
500 * [tlv] supported rates
501 * [tlv] extended supported rates
502 */
503 m = ieee80211_getmbuf(M_DONTWAIT, MT_DATA,
504 sizeof(capinfo)
505 + sizeof(u_int16_t)
506 + sizeof(u_int16_t)
507 + 2 + IEEE80211_RATE_SIZE
508 + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE));
509 if (m == NULL)
510 senderr(ENOMEM);
511 m->m_data += sizeof(struct ieee80211_frame);
512 frm = mtod(m, u_int8_t *);
513
514 capinfo = IEEE80211_CAPINFO_ESS;
515 if (ic->ic_flags & IEEE80211_F_WEPON)
516 capinfo |= IEEE80211_CAPINFO_PRIVACY;
517 *(u_int16_t *)frm = htole16(capinfo);
518 frm += 2;
519
520 *(u_int16_t *)frm = htole16(arg); /* status */
521 frm += 2;
522
523 if (arg == IEEE80211_STATUS_SUCCESS)
524 *(u_int16_t *)frm = htole16(ni->ni_associd);
525 frm += 2;
526
527 frm = ieee80211_add_rates(frm, &ni->ni_rates);
528 frm = ieee80211_add_xrates(frm, &ni->ni_rates);
529 m->m_pkthdr.len = m->m_len = frm - mtod(m, u_int8_t *);
530 break;
531
532 case IEEE80211_FC0_SUBTYPE_DISASSOC:
533 if (ifp->if_flags & IFF_DEBUG)
534 if_printf(ifp, "station %s disassociate (reason %d)\n",
535 ether_sprintf(ni->ni_macaddr), arg);
536 MGETHDR(m, M_DONTWAIT, MT_DATA);
537 if (m == NULL)
538 senderr(ENOMEM);
539 MH_ALIGN(m, 2);
540 m->m_pkthdr.len = m->m_len = 2;
541 *mtod(m, u_int16_t *) = htole16(arg); /* reason */
542 break;
543
544 default:
545 IEEE80211_DPRINTF(("%s: invalid mgmt frame type %u\n",
546 __func__, type));
547 senderr(EINVAL);
548 /* NOTREACHED */
549 }
550
551 ret = ieee80211_mgmt_output(ifp, ni, m, type);
552 if (ret == 0) {
553 if (timer)
554 ic->ic_mgt_timer = timer;
555 } else {
556 bad:
557 if (ni != ic->ic_bss) /* remove ref we added */
558 ieee80211_free_node(ic, ni);
559 }
560 return ret;
561 #undef senderr
562 }
563