ieee80211_output.c revision 117817
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: head/sys/net80211/ieee80211_output.c 117817 2003-07-21 02:49:42Z sam $");
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#include <machine/atomic.h>
52
53#include <net/if.h>
54#include <net/if_dl.h>
55#include <net/if_media.h>
56#include <net/if_arp.h>
57#include <net/ethernet.h>
58#include <net/if_llc.h>
59
60#include <net80211/ieee80211_var.h>
61
62#include <net/bpf.h>
63
64#ifdef INET
65#include <netinet/in.h>
66#include <netinet/if_ether.h>
67#endif
68
69int
70ieee80211_mgmt_output(struct ifnet *ifp, struct ieee80211_node *ni,
71    struct mbuf *m, int type)
72{
73	struct ieee80211com *ic = (void *)ifp;
74	struct ieee80211_frame *wh;
75
76	/* XXX this probably shouldn't be permitted */
77	KASSERT(ni != NULL, ("%s: null node", __func__));
78	ni->ni_inact = 0;
79
80	M_PREPEND(m, sizeof(struct ieee80211_frame), M_DONTWAIT);
81	if (m == NULL)
82		return ENOMEM;
83	wh = mtod(m, struct ieee80211_frame *);
84	wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_MGT | type;
85	wh->i_fc[1] = IEEE80211_FC1_DIR_NODS;
86	*(u_int16_t *)wh->i_dur = 0;
87	*(u_int16_t *)wh->i_seq =
88	    htole16(ni->ni_txseq << IEEE80211_SEQ_SEQ_SHIFT);
89	ni->ni_txseq++;
90	IEEE80211_ADDR_COPY(wh->i_addr1, ni->ni_macaddr);
91	IEEE80211_ADDR_COPY(wh->i_addr2, ic->ic_myaddr);
92	IEEE80211_ADDR_COPY(wh->i_addr3, ni->ni_bssid);
93
94	if (ifp->if_flags & IFF_DEBUG) {
95		/* avoid to print too many frames */
96		if (ic->ic_opmode == IEEE80211_M_IBSS ||
97#ifdef IEEE80211_DEBUG
98		    ieee80211_debug > 1 ||
99#endif
100		    (type & IEEE80211_FC0_SUBTYPE_MASK) !=
101		    IEEE80211_FC0_SUBTYPE_PROBE_RESP)
102			if_printf(ifp, "sending %s to %s on channel %u\n",
103			    ieee80211_mgt_subtype_name[
104			    (type & IEEE80211_FC0_SUBTYPE_MASK)
105			    >> IEEE80211_FC0_SUBTYPE_SHIFT],
106			    ether_sprintf(ni->ni_macaddr),
107			    ieee80211_chan2ieee(ic, ni->ni_chan));
108	}
109	IF_ENQUEUE(&ic->ic_mgtq, m);
110	ifp->if_timer = 1;
111	(*ifp->if_start)(ifp);
112	return 0;
113}
114
115struct mbuf *
116ieee80211_encap(struct ifnet *ifp, struct mbuf *m)
117{
118	struct ieee80211com *ic = (void *)ifp;
119	struct ether_header eh;
120	struct ieee80211_frame *wh;
121	struct llc *llc;
122	struct ieee80211_node *ni;
123
124	if (m->m_len < sizeof(struct ether_header)) {
125		m = m_pullup(m, sizeof(struct ether_header));
126		if (m == NULL)
127			return NULL;
128	}
129	memcpy(&eh, mtod(m, caddr_t), sizeof(struct ether_header));
130
131	ni = ieee80211_find_node(ic, eh.ether_dhost);
132	if (ni == NULL)			/*ic_opmode?? XXX*/
133		ni = ieee80211_ref_node(ic->ic_bss);
134	ni->ni_inact = 0;
135
136	m_adj(m, sizeof(struct ether_header) - sizeof(struct llc));
137	llc = mtod(m, struct llc *);
138	llc->llc_dsap = llc->llc_ssap = LLC_SNAP_LSAP;
139	llc->llc_control = LLC_UI;
140	llc->llc_snap.org_code[0] = 0;
141	llc->llc_snap.org_code[1] = 0;
142	llc->llc_snap.org_code[2] = 0;
143	llc->llc_snap.ether_type = eh.ether_type;
144	M_PREPEND(m, sizeof(struct ieee80211_frame), M_DONTWAIT);
145	if (m == NULL) {
146		ieee80211_unref_node(&ni);
147		return NULL;
148	}
149	wh = mtod(m, struct ieee80211_frame *);
150	wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_DATA;
151	*(u_int16_t *)wh->i_dur = 0;
152	*(u_int16_t *)wh->i_seq =
153	    htole16(ni->ni_txseq << IEEE80211_SEQ_SEQ_SHIFT);
154	ni->ni_txseq++;
155	switch (ic->ic_opmode) {
156	case IEEE80211_M_STA:
157		wh->i_fc[1] = IEEE80211_FC1_DIR_TODS;
158		IEEE80211_ADDR_COPY(wh->i_addr1, ni->ni_bssid);
159		IEEE80211_ADDR_COPY(wh->i_addr2, eh.ether_shost);
160		IEEE80211_ADDR_COPY(wh->i_addr3, eh.ether_dhost);
161		break;
162	case IEEE80211_M_IBSS:
163	case IEEE80211_M_AHDEMO:
164		wh->i_fc[1] = IEEE80211_FC1_DIR_NODS;
165		IEEE80211_ADDR_COPY(wh->i_addr1, eh.ether_dhost);
166		IEEE80211_ADDR_COPY(wh->i_addr2, eh.ether_shost);
167		IEEE80211_ADDR_COPY(wh->i_addr3, ni->ni_bssid);
168		break;
169	case IEEE80211_M_HOSTAP:
170		wh->i_fc[1] = IEEE80211_FC1_DIR_FROMDS;
171		IEEE80211_ADDR_COPY(wh->i_addr1, eh.ether_dhost);
172		IEEE80211_ADDR_COPY(wh->i_addr2, ni->ni_bssid);
173		IEEE80211_ADDR_COPY(wh->i_addr3, eh.ether_shost);
174		break;
175	case IEEE80211_M_MONITOR:
176		m_freem(m), m = NULL;
177		break;
178	}
179	ieee80211_unref_node(&ni);
180	return m;
181}
182
183/*
184 * Add a supported rates element id to a frame.
185 */
186u_int8_t *
187ieee80211_add_rates(u_int8_t *frm, const struct ieee80211_rateset *rs)
188{
189	int nrates;
190
191	*frm++ = IEEE80211_ELEMID_RATES;
192	nrates = rs->rs_nrates;
193	if (nrates > IEEE80211_RATE_SIZE)
194		nrates = IEEE80211_RATE_SIZE;
195	*frm++ = nrates;
196	memcpy(frm, rs->rs_rates, nrates);
197	return frm + nrates;
198}
199
200/*
201 * Add an extended supported rates element id to a frame.
202 */
203u_int8_t *
204ieee80211_add_xrates(u_int8_t *frm, const struct ieee80211_rateset *rs)
205{
206	/*
207	 * Add an extended supported rates element if operating in 11g mode.
208	 */
209	if (rs->rs_nrates > IEEE80211_RATE_SIZE) {
210		int nrates = rs->rs_nrates - IEEE80211_RATE_SIZE;
211		*frm++ = IEEE80211_ELEMID_XRATES;
212		*frm++ = nrates;
213		memcpy(frm, rs->rs_rates + IEEE80211_RATE_SIZE, nrates);
214		frm += nrates;
215	}
216	return frm;
217}
218
219/*
220 * Add an ssid elemet to a frame.
221 */
222static u_int8_t *
223ieee80211_add_ssid(u_int8_t *frm, const u_int8_t *ssid, u_int len)
224{
225	*frm++ = IEEE80211_ELEMID_SSID;
226	*frm++ = len;
227	memcpy(frm, ssid, len);
228	return frm + len;
229}
230
231static struct mbuf *
232ieee80211_getmbuf(int flags, int type, u_int pktlen)
233{
234	struct mbuf *m;
235
236	if (pktlen > MHLEN)
237		MGETHDR(m, flags, type);
238	else
239		m = m_getcl(flags, type, M_PKTHDR);
240	return m;
241}
242
243int
244ieee80211_send_mgmt(struct ieee80211com *ic, struct ieee80211_node *ni,
245	int type, int arg)
246{
247	struct ifnet *ifp = &ic->ic_if;
248	struct mbuf *m;
249	u_int8_t *frm;
250	enum ieee80211_phymode mode;
251	u_int16_t capinfo;
252	int ret, timer;
253
254	timer = 0;
255	switch (type) {
256	case IEEE80211_FC0_SUBTYPE_PROBE_REQ:
257		/*
258		 * prreq frame format
259		 *	[tlv] ssid
260		 *	[tlv] supported rates
261		 *	[tlv] extended supported rates
262		 */
263		m = ieee80211_getmbuf(M_DONTWAIT, MT_DATA,
264			 2 + ic->ic_des_esslen
265		       + 2 + IEEE80211_RATE_SIZE
266		       + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE));
267		if (m == NULL)
268			return ENOMEM;
269		m->m_data += sizeof(struct ieee80211_frame);
270		frm = mtod(m, u_int8_t *);
271		frm = ieee80211_add_ssid(frm, ic->ic_des_essid, ic->ic_des_esslen);
272		mode = ieee80211_chan2mode(ic, ni->ni_chan);
273		frm = ieee80211_add_rates(frm, &ic->ic_sup_rates[mode]);
274		frm = ieee80211_add_xrates(frm, &ic->ic_sup_rates[mode]);
275		m->m_pkthdr.len = m->m_len = frm - mtod(m, u_int8_t *);
276
277		timer = IEEE80211_TRANS_WAIT;
278		break;
279
280	case IEEE80211_FC0_SUBTYPE_PROBE_RESP:
281		/*
282		 * probe response frame format
283		 *	[8] time stamp
284		 *	[2] beacon interval
285		 *	[2] cabability information
286		 *	[tlv] ssid
287		 *	[tlv] supported rates
288		 *	[tlv] parameter set (IBSS)
289		 *	[tlv] extended supported rates
290		 */
291		m = ieee80211_getmbuf(M_DONTWAIT, MT_DATA,
292			 8 + 2 + 2 + 2
293		       + 2 + ni->ni_esslen
294		       + 2 + IEEE80211_RATE_SIZE
295		       + 6
296		       + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE));
297		if (m == NULL)
298			return ENOMEM;
299		m->m_data += sizeof(struct ieee80211_frame);
300		frm = mtod(m, u_int8_t *);
301
302		memset(frm, 0, 8);	/* timestamp should be filled later */
303		frm += 8;
304		*(u_int16_t *)frm = htole16(ic->ic_bss->ni_intval);
305		frm += 2;
306		if (ic->ic_opmode == IEEE80211_M_IBSS)
307			capinfo = IEEE80211_CAPINFO_IBSS;
308		else
309			capinfo = IEEE80211_CAPINFO_ESS;
310		if (ic->ic_flags & IEEE80211_F_WEPON)
311			capinfo |= IEEE80211_CAPINFO_PRIVACY;
312		*(u_int16_t *)frm = htole16(capinfo);
313		frm += 2;
314
315		frm = ieee80211_add_ssid(frm, ic->ic_bss->ni_essid,
316				ic->ic_bss->ni_esslen);
317		frm = ieee80211_add_rates(frm, &ic->ic_bss->ni_rates);
318
319		if (ic->ic_opmode == IEEE80211_M_IBSS) {
320			*frm++ = IEEE80211_ELEMID_IBSSPARMS;
321			*frm++ = 2;
322			*frm++ = 0; *frm++ = 0;		/* TODO: ATIM window */
323		} else {	/* IEEE80211_M_HOSTAP */
324			/* TODO: TIM */
325			*frm++ = IEEE80211_ELEMID_TIM;
326			*frm++ = 4;	/* length */
327			*frm++ = 0;	/* DTIM count */
328			*frm++ = 1;	/* DTIM period */
329			*frm++ = 0;	/* bitmap control */
330			*frm++ = 0;	/* Partial Virtual Bitmap (variable length) */
331		}
332		frm = ieee80211_add_xrates(frm, &ic->ic_bss->ni_rates);
333		m->m_pkthdr.len = m->m_len = frm - mtod(m, u_int8_t *);
334		break;
335
336	case IEEE80211_FC0_SUBTYPE_AUTH:
337		MGETHDR(m, M_DONTWAIT, MT_DATA);
338		if (m == NULL)
339			return ENOMEM;
340		MH_ALIGN(m, 2 * 3);
341		m->m_pkthdr.len = m->m_len = 6;
342		frm = mtod(m, u_int8_t *);
343		/* TODO: shared key auth */
344		((u_int16_t *)frm)[0] = htole16(IEEE80211_AUTH_ALG_OPEN);
345		((u_int16_t *)frm)[1] = htole16(arg);	/* sequence number */
346		((u_int16_t *)frm)[2] = 0;		/* status */
347		if (ic->ic_opmode == IEEE80211_M_STA)
348			timer = IEEE80211_TRANS_WAIT;
349		break;
350
351	case IEEE80211_FC0_SUBTYPE_DEAUTH:
352		if (ifp->if_flags & IFF_DEBUG)
353			if_printf(ifp, "station %s deauthenticate (reason %d)\n",
354			    ether_sprintf(ni->ni_macaddr), arg);
355		MGETHDR(m, M_DONTWAIT, MT_DATA);
356		if (m == NULL)
357			return ENOMEM;
358		MH_ALIGN(m, 2);
359		m->m_pkthdr.len = m->m_len = 2;
360		*mtod(m, u_int16_t *) = htole16(arg);	/* reason */
361		break;
362
363	case IEEE80211_FC0_SUBTYPE_ASSOC_REQ:
364	case IEEE80211_FC0_SUBTYPE_REASSOC_REQ:
365		/*
366		 * asreq frame format
367		 *	[2] capability information
368		 *	[2] listen interval
369		 *	[6*] current AP address (reassoc only)
370		 *	[tlv] ssid
371		 *	[tlv] supported rates
372		 *	[tlv] extended supported rates
373		 */
374		m = ieee80211_getmbuf(M_DONTWAIT, MT_DATA,
375			 sizeof(capinfo)
376		       + sizeof(u_int16_t)
377		       + IEEE80211_ADDR_LEN
378		       + 2 + ni->ni_esslen
379		       + 2 + IEEE80211_RATE_SIZE
380		       + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE));
381		if (m == NULL)
382			return ENOMEM;
383		m->m_data += sizeof(struct ieee80211_frame);
384		frm = mtod(m, u_int8_t *);
385
386		capinfo = 0;
387		if (ic->ic_opmode == IEEE80211_M_IBSS)
388			capinfo |= IEEE80211_CAPINFO_IBSS;
389		else		/* IEEE80211_M_STA */
390			capinfo |= IEEE80211_CAPINFO_ESS;
391		if (ic->ic_flags & IEEE80211_F_WEPON)
392			capinfo |= IEEE80211_CAPINFO_PRIVACY;
393		if (ic->ic_flags & IEEE80211_F_SHPREAMBLE)
394			capinfo |= IEEE80211_CAPINFO_SHORT_PREAMBLE;
395		if (ic->ic_flags & IEEE80211_F_SHSLOT)
396			capinfo |= IEEE80211_CAPINFO_SHORT_SLOTTIME;
397		*(u_int16_t *)frm = htole16(capinfo);
398		frm += 2;
399
400		*(u_int16_t *)frm = htole16(ic->ic_lintval);
401		frm += 2;
402
403		if (type == IEEE80211_FC0_SUBTYPE_REASSOC_REQ) {
404			IEEE80211_ADDR_COPY(frm, ic->ic_bss->ni_bssid);
405			frm += IEEE80211_ADDR_LEN;
406		}
407
408		frm = ieee80211_add_ssid(frm, ni->ni_essid, ni->ni_esslen);
409		frm = ieee80211_add_rates(frm, &ni->ni_rates);
410		frm = ieee80211_add_xrates(frm, &ni->ni_rates);
411		m->m_pkthdr.len = m->m_len = frm - mtod(m, u_int8_t *);
412
413		timer = IEEE80211_TRANS_WAIT;
414		break;
415
416	case IEEE80211_FC0_SUBTYPE_ASSOC_RESP:
417	case IEEE80211_FC0_SUBTYPE_REASSOC_RESP:
418		/*
419		 * asreq frame format
420		 *	[2] capability information
421		 *	[2] status
422		 *	[2] association ID
423		 *	[tlv] supported rates
424		 *	[tlv] extended supported rates
425		 */
426		m = ieee80211_getmbuf(M_DONTWAIT, MT_DATA,
427			 sizeof(capinfo)
428		       + sizeof(u_int16_t)
429		       + sizeof(u_int16_t)
430		       + 2 + IEEE80211_RATE_SIZE
431		       + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE));
432		if (m == NULL)
433			return ENOMEM;
434		m->m_data += sizeof(struct ieee80211_frame);
435		frm = mtod(m, u_int8_t *);
436
437		capinfo = IEEE80211_CAPINFO_ESS;
438		if (ic->ic_flags & IEEE80211_F_WEPON)
439			capinfo |= IEEE80211_CAPINFO_PRIVACY;
440		*(u_int16_t *)frm = htole16(capinfo);
441		frm += 2;
442
443		*(u_int16_t *)frm = htole16(arg);	/* status */
444		frm += 2;
445
446		if (arg == IEEE80211_STATUS_SUCCESS && ni != NULL)
447			*(u_int16_t *)frm = htole16(ni->ni_associd);
448		else
449			*(u_int16_t *)frm = htole16(0);
450		frm += 2;
451
452		if (ni != NULL) {
453			frm = ieee80211_add_rates(frm, &ni->ni_rates);
454			frm = ieee80211_add_xrates(frm, &ni->ni_rates);
455		} else {
456			frm = ieee80211_add_rates(frm, &ic->ic_bss->ni_rates);
457			frm = ieee80211_add_xrates(frm, &ic->ic_bss->ni_rates);
458		}
459		m->m_pkthdr.len = m->m_len = frm - mtod(m, u_int8_t *);
460		break;
461
462	case IEEE80211_FC0_SUBTYPE_DISASSOC:
463		if (ifp->if_flags & IFF_DEBUG)
464			if_printf(ifp, "station %s disassociate (reason %d)\n",
465			    ether_sprintf(ni->ni_macaddr), arg);
466		MGETHDR(m, M_DONTWAIT, MT_DATA);
467		if (m == NULL)
468			return ENOMEM;
469		MH_ALIGN(m, 2);
470		m->m_pkthdr.len = m->m_len = 2;
471		*mtod(m, u_int16_t *) = htole16(arg);	/* reason */
472		break;
473
474	default:
475		IEEE80211_DPRINTF(("%s: invalid mgmt frame type %u\n",
476			__func__, type));
477		return EINVAL;
478	}
479
480	ret = ieee80211_mgmt_output(ifp, ni, m, type);
481	if (ret == 0 && timer)
482		ic->ic_mgt_timer = timer;
483	return ret;
484}
485