ieee80211_output.c revision 116904
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 116904 2003-06-27 05:13:52Z 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	}
176	ieee80211_unref_node(&ni);
177	return m;
178}
179
180/*
181 * Add a supported rates element id to a frame.
182 */
183u_int8_t *
184ieee80211_add_rates(u_int8_t *frm, const struct ieee80211_rateset *rs)
185{
186	int nrates;
187
188	*frm++ = IEEE80211_ELEMID_RATES;
189	nrates = rs->rs_nrates;
190	if (nrates > IEEE80211_RATE_SIZE)
191		nrates = IEEE80211_RATE_SIZE;
192	*frm++ = nrates;
193	memcpy(frm, rs->rs_rates, nrates);
194	return frm + nrates;
195}
196
197/*
198 * Add an extended supported rates element id to a frame.
199 */
200u_int8_t *
201ieee80211_add_xrates(u_int8_t *frm, const struct ieee80211_rateset *rs)
202{
203	/*
204	 * Add an extended supported rates element if operating in 11g mode.
205	 */
206	if (rs->rs_nrates > IEEE80211_RATE_SIZE) {
207		int nrates = rs->rs_nrates - IEEE80211_RATE_SIZE;
208		*frm++ = IEEE80211_ELEMID_XRATES;
209		*frm++ = nrates;
210		memcpy(frm, rs->rs_rates + IEEE80211_RATE_SIZE, nrates);
211		frm += nrates;
212	}
213	return frm;
214}
215
216/*
217 * Add an ssid elemet to a frame.
218 */
219static u_int8_t *
220ieee80211_add_ssid(u_int8_t *frm, const u_int8_t *ssid, u_int len)
221{
222	*frm++ = IEEE80211_ELEMID_SSID;
223	*frm++ = len;
224	memcpy(frm, ssid, len);
225	return frm + len;
226}
227
228static struct mbuf *
229ieee80211_getmbuf(int flags, int type, u_int pktlen)
230{
231	struct mbuf *m;
232
233	if (pktlen > MHLEN)
234		MGETHDR(m, flags, type);
235	else
236		m = m_getcl(flags, type, M_PKTHDR);
237	return m;
238}
239
240int
241ieee80211_send_mgmt(struct ieee80211com *ic, struct ieee80211_node *ni,
242	int type, int arg)
243{
244	struct ifnet *ifp = &ic->ic_if;
245	struct mbuf *m;
246	u_int8_t *frm;
247	enum ieee80211_phymode mode;
248	u_int16_t capinfo;
249	int ret, timer;
250
251	timer = 0;
252	switch (type) {
253	case IEEE80211_FC0_SUBTYPE_PROBE_REQ:
254		/*
255		 * prreq frame format
256		 *	[tlv] ssid
257		 *	[tlv] supported rates
258		 *	[tlv] extended supported rates
259		 */
260		m = ieee80211_getmbuf(M_DONTWAIT, MT_DATA,
261			 2 + ic->ic_des_esslen
262		       + 2 + IEEE80211_RATE_SIZE
263		       + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE));
264		if (m == NULL)
265			return ENOMEM;
266		m->m_data += sizeof(struct ieee80211_frame);
267		frm = mtod(m, u_int8_t *);
268		frm = ieee80211_add_ssid(frm, ic->ic_des_essid, ic->ic_des_esslen);
269		mode = ieee80211_chan2mode(ic, ni->ni_chan);
270		frm = ieee80211_add_rates(frm, &ic->ic_sup_rates[mode]);
271		frm = ieee80211_add_xrates(frm, &ic->ic_sup_rates[mode]);
272		m->m_pkthdr.len = m->m_len = frm - mtod(m, u_int8_t *);
273
274		timer = IEEE80211_TRANS_WAIT;
275		break;
276
277	case IEEE80211_FC0_SUBTYPE_PROBE_RESP:
278		/*
279		 * probe response frame format
280		 *	[8] time stamp
281		 *	[2] beacon interval
282		 *	[2] cabability information
283		 *	[tlv] ssid
284		 *	[tlv] supported rates
285		 *	[tlv] parameter set (IBSS)
286		 *	[tlv] extended supported rates
287		 */
288		m = ieee80211_getmbuf(M_DONTWAIT, MT_DATA,
289			 8 + 2 + 2 + 2
290		       + 2 + ni->ni_esslen
291		       + 2 + IEEE80211_RATE_SIZE
292		       + 6
293		       + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE));
294		if (m == NULL)
295			return ENOMEM;
296		m->m_data += sizeof(struct ieee80211_frame);
297		frm = mtod(m, u_int8_t *);
298
299		memset(frm, 0, 8);	/* timestamp should be filled later */
300		frm += 8;
301		*(u_int16_t *)frm = htole16(ic->ic_bss->ni_intval);
302		frm += 2;
303		if (ic->ic_opmode == IEEE80211_M_IBSS)
304			capinfo = IEEE80211_CAPINFO_IBSS;
305		else
306			capinfo = IEEE80211_CAPINFO_ESS;
307		if (ic->ic_flags & IEEE80211_F_WEPON)
308			capinfo |= IEEE80211_CAPINFO_PRIVACY;
309		*(u_int16_t *)frm = htole16(capinfo);
310		frm += 2;
311
312		frm = ieee80211_add_ssid(frm, ic->ic_bss->ni_essid,
313				ic->ic_bss->ni_esslen);
314		frm = ieee80211_add_rates(frm, &ic->ic_bss->ni_rates);
315
316		if (ic->ic_opmode == IEEE80211_M_IBSS) {
317			*frm++ = IEEE80211_ELEMID_IBSSPARMS;
318			*frm++ = 2;
319			*frm++ = 0; *frm++ = 0;		/* TODO: ATIM window */
320		} else {	/* IEEE80211_M_HOSTAP */
321			/* TODO: TIM */
322			*frm++ = IEEE80211_ELEMID_TIM;
323			*frm++ = 4;	/* length */
324			*frm++ = 0;	/* DTIM count */
325			*frm++ = 1;	/* DTIM period */
326			*frm++ = 0;	/* bitmap control */
327			*frm++ = 0;	/* Partial Virtual Bitmap (variable length) */
328		}
329		frm = ieee80211_add_xrates(frm, &ic->ic_bss->ni_rates);
330		m->m_pkthdr.len = m->m_len = frm - mtod(m, u_int8_t *);
331		break;
332
333	case IEEE80211_FC0_SUBTYPE_AUTH:
334		MGETHDR(m, M_DONTWAIT, MT_DATA);
335		if (m == NULL)
336			return ENOMEM;
337		MH_ALIGN(m, 2 * 3);
338		m->m_pkthdr.len = m->m_len = 6;
339		frm = mtod(m, u_int8_t *);
340		/* TODO: shared key auth */
341		((u_int16_t *)frm)[0] = htole16(IEEE80211_AUTH_ALG_OPEN);
342		((u_int16_t *)frm)[1] = htole16(arg);	/* sequence number */
343		((u_int16_t *)frm)[2] = 0;		/* status */
344		if (ic->ic_opmode == IEEE80211_M_STA)
345			timer = IEEE80211_TRANS_WAIT;
346		break;
347
348	case IEEE80211_FC0_SUBTYPE_DEAUTH:
349		if (ifp->if_flags & IFF_DEBUG)
350			if_printf(ifp, "station %s deauthenticate (reason %d)\n",
351			    ether_sprintf(ni->ni_macaddr), arg);
352		MGETHDR(m, M_DONTWAIT, MT_DATA);
353		if (m == NULL)
354			return ENOMEM;
355		MH_ALIGN(m, 2);
356		m->m_pkthdr.len = m->m_len = 2;
357		*mtod(m, u_int16_t *) = htole16(arg);	/* reason */
358		break;
359
360	case IEEE80211_FC0_SUBTYPE_ASSOC_REQ:
361	case IEEE80211_FC0_SUBTYPE_REASSOC_REQ:
362		/*
363		 * asreq frame format
364		 *	[2] capability information
365		 *	[2] listen interval
366		 *	[6*] current AP address (reassoc only)
367		 *	[tlv] ssid
368		 *	[tlv] supported rates
369		 *	[tlv] extended supported rates
370		 */
371		m = ieee80211_getmbuf(M_DONTWAIT, MT_DATA,
372			 sizeof(capinfo)
373		       + sizeof(u_int16_t)
374		       + IEEE80211_ADDR_LEN
375		       + 2 + ni->ni_esslen
376		       + 2 + IEEE80211_RATE_SIZE
377		       + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE));
378		if (m == NULL)
379			return ENOMEM;
380		m->m_data += sizeof(struct ieee80211_frame);
381		frm = mtod(m, u_int8_t *);
382
383		capinfo = 0;
384		if (ic->ic_opmode == IEEE80211_M_IBSS)
385			capinfo |= IEEE80211_CAPINFO_IBSS;
386		else		/* IEEE80211_M_STA */
387			capinfo |= IEEE80211_CAPINFO_ESS;
388		if (ic->ic_flags & IEEE80211_F_WEPON)
389			capinfo |= IEEE80211_CAPINFO_PRIVACY;
390		if (ic->ic_flags & IEEE80211_F_SHPREAMBLE)
391			capinfo |= IEEE80211_CAPINFO_SHORT_PREAMBLE;
392		if (ic->ic_flags & IEEE80211_F_SHSLOT)
393			capinfo |= IEEE80211_CAPINFO_SHORT_SLOTTIME;
394		*(u_int16_t *)frm = htole16(capinfo);
395		frm += 2;
396
397		*(u_int16_t *)frm = htole16(ic->ic_lintval);
398		frm += 2;
399
400		if (type == IEEE80211_FC0_SUBTYPE_REASSOC_REQ) {
401			IEEE80211_ADDR_COPY(frm, ic->ic_bss->ni_bssid);
402			frm += IEEE80211_ADDR_LEN;
403		}
404
405		frm = ieee80211_add_ssid(frm, ni->ni_essid, ni->ni_esslen);
406		frm = ieee80211_add_rates(frm, &ni->ni_rates);
407		frm = ieee80211_add_xrates(frm, &ni->ni_rates);
408		m->m_pkthdr.len = m->m_len = frm - mtod(m, u_int8_t *);
409
410		timer = IEEE80211_TRANS_WAIT;
411		break;
412
413	case IEEE80211_FC0_SUBTYPE_ASSOC_RESP:
414	case IEEE80211_FC0_SUBTYPE_REASSOC_RESP:
415		/*
416		 * asreq frame format
417		 *	[2] capability information
418		 *	[2] status
419		 *	[2] association ID
420		 *	[tlv] supported rates
421		 *	[tlv] extended supported rates
422		 */
423		m = ieee80211_getmbuf(M_DONTWAIT, MT_DATA,
424			 sizeof(capinfo)
425		       + sizeof(u_int16_t)
426		       + sizeof(u_int16_t)
427		       + 2 + IEEE80211_RATE_SIZE
428		       + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE));
429		if (m == NULL)
430			return ENOMEM;
431		m->m_data += sizeof(struct ieee80211_frame);
432		frm = mtod(m, u_int8_t *);
433
434		capinfo = IEEE80211_CAPINFO_ESS;
435		if (ic->ic_flags & IEEE80211_F_WEPON)
436			capinfo |= IEEE80211_CAPINFO_PRIVACY;
437		*(u_int16_t *)frm = htole16(capinfo);
438		frm += 2;
439
440		*(u_int16_t *)frm = htole16(arg);	/* status */
441		frm += 2;
442
443		if (arg == IEEE80211_STATUS_SUCCESS && ni != NULL)
444			*(u_int16_t *)frm = htole16(ni->ni_associd);
445		else
446			*(u_int16_t *)frm = htole16(0);
447		frm += 2;
448
449		if (ni != NULL) {
450			frm = ieee80211_add_rates(frm, &ni->ni_rates);
451			frm = ieee80211_add_xrates(frm, &ni->ni_rates);
452		} else {
453			frm = ieee80211_add_rates(frm, &ic->ic_bss->ni_rates);
454			frm = ieee80211_add_xrates(frm, &ic->ic_bss->ni_rates);
455		}
456		m->m_pkthdr.len = m->m_len = frm - mtod(m, u_int8_t *);
457		break;
458
459	case IEEE80211_FC0_SUBTYPE_DISASSOC:
460		if (ifp->if_flags & IFF_DEBUG)
461			if_printf(ifp, "station %s disassociate (reason %d)\n",
462			    ether_sprintf(ni->ni_macaddr), arg);
463		MGETHDR(m, M_DONTWAIT, MT_DATA);
464		if (m == NULL)
465			return ENOMEM;
466		MH_ALIGN(m, 2);
467		m->m_pkthdr.len = m->m_len = 2;
468		*mtod(m, u_int16_t *) = htole16(arg);	/* reason */
469		break;
470
471	default:
472		IEEE80211_DPRINTF(("%s: invalid mgmt frame type %u\n",
473			__func__, type));
474		return EINVAL;
475	}
476
477	ret = ieee80211_mgmt_output(ifp, ni, m, type);
478	if (ret == 0 && timer)
479		ic->ic_mgt_timer = timer;
480	return ret;
481}
482