1178354Ssam/*-
2186904Ssam * Copyright (c) 2007-2009 Sam Leffler, Errno Consulting
3178354Ssam * All rights reserved.
4178354Ssam *
5178354Ssam * Redistribution and use in source and binary forms, with or without
6178354Ssam * modification, are permitted provided that the following conditions
7178354Ssam * are met:
8178354Ssam * 1. Redistributions of source code must retain the above copyright
9178354Ssam *    notice, this list of conditions and the following disclaimer.
10178354Ssam * 2. Redistributions in binary form must reproduce the above copyright
11178354Ssam *    notice, this list of conditions and the following disclaimer in the
12178354Ssam *    documentation and/or other materials provided with the distribution.
13178354Ssam *
14178354Ssam * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15178354Ssam * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16178354Ssam * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17178354Ssam * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18178354Ssam * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19178354Ssam * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20178354Ssam * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21178354Ssam * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22178354Ssam * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23178354Ssam * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24178354Ssam *
25178354Ssam * $FreeBSD$
26178354Ssam */
27178354Ssam#ifndef _NET80211_IEEE80211_INPUT_H_
28178354Ssam#define _NET80211_IEEE80211_INPUT_H_
29178354Ssam
30178354Ssam/* Verify the existence and length of __elem or get out. */
31178354Ssam#define IEEE80211_VERIFY_ELEMENT(__elem, __maxlen, _action) do {	\
32178354Ssam	if ((__elem) == NULL) {						\
33178354Ssam		IEEE80211_DISCARD(vap, IEEE80211_MSG_ELEMID,		\
34178354Ssam		    wh, NULL, "%s", "no " #__elem );			\
35178354Ssam		vap->iv_stats.is_rx_elem_missing++;			\
36178354Ssam		_action;						\
37178354Ssam	} else if ((__elem)[1] > (__maxlen)) {				\
38178354Ssam		IEEE80211_DISCARD(vap, IEEE80211_MSG_ELEMID,		\
39178354Ssam		    wh, NULL, "bad " #__elem " len %d", (__elem)[1]);	\
40178354Ssam		vap->iv_stats.is_rx_elem_toobig++;			\
41178354Ssam		_action;						\
42178354Ssam	}								\
43178354Ssam} while (0)
44178354Ssam
45178354Ssam#define	IEEE80211_VERIFY_LENGTH(_len, _minlen, _action) do {		\
46178354Ssam	if ((_len) < (_minlen)) {					\
47178354Ssam		IEEE80211_DISCARD(vap, IEEE80211_MSG_ELEMID,		\
48178354Ssam		    wh, NULL, "ie too short, got %d, expected %d",	\
49178354Ssam		    (_len), (_minlen));					\
50178354Ssam		vap->iv_stats.is_rx_elem_toosmall++;			\
51178354Ssam		_action;						\
52178354Ssam	}								\
53178354Ssam} while (0)
54178354Ssam
55178354Ssam#ifdef IEEE80211_DEBUG
56178354Ssamvoid	ieee80211_ssid_mismatch(struct ieee80211vap *, const char *tag,
57178354Ssam	uint8_t mac[IEEE80211_ADDR_LEN], uint8_t *ssid);
58178354Ssam
59178354Ssam#define	IEEE80211_VERIFY_SSID(_ni, _ssid, _action) do {			\
60178354Ssam	if ((_ssid)[1] != 0 &&						\
61178354Ssam	    ((_ssid)[1] != (_ni)->ni_esslen ||				\
62178354Ssam	    memcmp((_ssid) + 2, (_ni)->ni_essid, (_ssid)[1]) != 0)) {	\
63178354Ssam		if (ieee80211_msg_input(vap))				\
64178354Ssam			ieee80211_ssid_mismatch(vap, 			\
65178354Ssam			    ieee80211_mgt_subtype_name[subtype >>	\
66178354Ssam				IEEE80211_FC0_SUBTYPE_SHIFT],		\
67178354Ssam				wh->i_addr2, _ssid);			\
68178354Ssam		vap->iv_stats.is_rx_ssidmismatch++;			\
69178354Ssam		_action;						\
70178354Ssam	}								\
71178354Ssam} while (0)
72178354Ssam#else /* !IEEE80211_DEBUG */
73178354Ssam#define	IEEE80211_VERIFY_SSID(_ni, _ssid, _action) do {			\
74178354Ssam	if ((_ssid)[1] != 0 &&						\
75178354Ssam	    ((_ssid)[1] != (_ni)->ni_esslen ||				\
76178354Ssam	    memcmp((_ssid) + 2, (_ni)->ni_essid, (_ssid)[1]) != 0)) {	\
77178354Ssam		vap->iv_stats.is_rx_ssidmismatch++;			\
78178354Ssam		_action;						\
79178354Ssam	}								\
80178354Ssam} while (0)
81178354Ssam#endif /* !IEEE80211_DEBUG */
82178354Ssam
83178354Ssam/* unalligned little endian access */
84178354Ssam#define LE_READ_2(p)					\
85178354Ssam	((uint16_t)					\
86178354Ssam	 ((((const uint8_t *)(p))[0]      ) |		\
87178354Ssam	  (((const uint8_t *)(p))[1] <<  8)))
88178354Ssam#define LE_READ_4(p)					\
89178354Ssam	((uint32_t)					\
90178354Ssam	 ((((const uint8_t *)(p))[0]      ) |		\
91178354Ssam	  (((const uint8_t *)(p))[1] <<  8) |		\
92178354Ssam	  (((const uint8_t *)(p))[2] << 16) |		\
93178354Ssam	  (((const uint8_t *)(p))[3] << 24)))
94178354Ssam
95178354Ssamstatic __inline int
96178354Ssamiswpaoui(const uint8_t *frm)
97178354Ssam{
98178354Ssam	return frm[1] > 3 && LE_READ_4(frm+2) == ((WPA_OUI_TYPE<<24)|WPA_OUI);
99178354Ssam}
100178354Ssam
101178354Ssamstatic __inline int
102178354Ssamiswmeoui(const uint8_t *frm)
103178354Ssam{
104178354Ssam	return frm[1] > 3 && LE_READ_4(frm+2) == ((WME_OUI_TYPE<<24)|WME_OUI);
105178354Ssam}
106178354Ssam
107178354Ssamstatic __inline int
108178354Ssamiswmeparam(const uint8_t *frm)
109178354Ssam{
110178354Ssam	return frm[1] > 5 && LE_READ_4(frm+2) == ((WME_OUI_TYPE<<24)|WME_OUI) &&
111178354Ssam		frm[6] == WME_PARAM_OUI_SUBTYPE;
112178354Ssam}
113178354Ssam
114178354Ssamstatic __inline int
115178354Ssamiswmeinfo(const uint8_t *frm)
116178354Ssam{
117178354Ssam	return frm[1] > 5 && LE_READ_4(frm+2) == ((WME_OUI_TYPE<<24)|WME_OUI) &&
118178354Ssam		frm[6] == WME_INFO_OUI_SUBTYPE;
119178354Ssam}
120178354Ssam
121178354Ssamstatic __inline int
122178354Ssamisatherosoui(const uint8_t *frm)
123178354Ssam{
124178354Ssam	return frm[1] > 3 && LE_READ_4(frm+2) == ((ATH_OUI_TYPE<<24)|ATH_OUI);
125178354Ssam}
126178354Ssam
127178354Ssamstatic __inline int
128186904Ssamistdmaoui(const uint8_t *frm)
129186904Ssam{
130186904Ssam	return frm[1] > 3 && LE_READ_4(frm+2) == ((TDMA_OUI_TYPE<<24)|TDMA_OUI);
131186904Ssam}
132186904Ssam
133186904Ssamstatic __inline int
134178354Ssamishtcapoui(const uint8_t *frm)
135178354Ssam{
136178354Ssam	return frm[1] > 3 && LE_READ_4(frm+2) == ((BCM_OUI_HTCAP<<24)|BCM_OUI);
137178354Ssam}
138178354Ssam
139178354Ssamstatic __inline int
140178354Ssamishtinfooui(const uint8_t *frm)
141178354Ssam{
142178354Ssam	return frm[1] > 3 && LE_READ_4(frm+2) == ((BCM_OUI_HTINFO<<24)|BCM_OUI);
143178354Ssam}
144178354Ssam
145221418Sadrian#include <sys/endian.h>		/* For le16toh() */
146221418Sadrian
147221418Sadrian/*
148221418Sadrian * Check the current frame sequence number against the current TID
149221418Sadrian * state and return whether it's in sequence or should be dropped.
150221418Sadrian *
151221418Sadrian * Since out of order packet and duplicate packet eliminations should
152221418Sadrian * be done by the AMPDU RX code, this routine blindly accepts all
153221418Sadrian * frames from a HT station w/ a TID that is currently doing AMPDU-RX.
154221418Sadrian * HT stations without WME or where the TID is not doing AMPDU-RX
155221418Sadrian * are checked like non-HT stations.
156221418Sadrian *
157221418Sadrian * The routine only eliminates packets whose sequence/fragment
158221418Sadrian * match or are less than the last seen sequence/fragment number
159221418Sadrian * AND are retransmits It doesn't try to eliminate out of order packets.
160221418Sadrian *
161221418Sadrian * Since all frames after sequence number 4095 will be less than 4095
162221418Sadrian * (as the seqnum wraps), handle that special case so packets aren't
163221418Sadrian * incorrectly dropped - ie, if the next packet is sequence number 0
164221418Sadrian * but a retransmit since the initial packet didn't make it.
165221418Sadrian */
166221418Sadrianstatic __inline int
167221418Sadrianieee80211_check_rxseq(struct ieee80211_node *ni, struct ieee80211_frame *wh)
168221418Sadrian{
169221418Sadrian#define	SEQ_LEQ(a,b)	((int)((a)-(b)) <= 0)
170221418Sadrian#define	SEQ_EQ(a,b)	((int)((a)-(b)) == 0)
171221418Sadrian#define	HAS_SEQ(type)	((type & 0x4) == 0)
172221418Sadrian#define	SEQNO(a)	((a) >> IEEE80211_SEQ_SEQ_SHIFT)
173221418Sadrian#define	FRAGNO(a)	((a) & IEEE80211_SEQ_FRAG_MASK)
174221418Sadrian	uint16_t rxseq;
175221418Sadrian	uint8_t type;
176221418Sadrian	uint8_t tid;
177221418Sadrian	struct ieee80211_rx_ampdu *rap;
178221418Sadrian
179221418Sadrian	rxseq = le16toh(*(uint16_t *)wh->i_seq);
180221418Sadrian	type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
181221418Sadrian
182221418Sadrian	/* Types with no sequence number are always treated valid */
183221418Sadrian	if (! HAS_SEQ(type))
184221418Sadrian		return 1;
185221418Sadrian
186221418Sadrian	tid = ieee80211_gettid(wh);
187221418Sadrian
188221418Sadrian	/*
189221418Sadrian	 * Only do the HT AMPDU check for WME stations; non-WME HT stations
190221418Sadrian	 * shouldn't exist outside of debugging. We should at least
191221418Sadrian	 * handle that.
192221418Sadrian	 */
193221418Sadrian	if (tid < WME_NUM_TID) {
194221418Sadrian		rap = &ni->ni_rx_ampdu[tid];
195221418Sadrian		/* HT nodes currently doing RX AMPDU are always valid */
196221418Sadrian		if ((ni->ni_flags & IEEE80211_NODE_HT) &&
197221418Sadrian		    (rap->rxa_flags & IEEE80211_AGGR_RUNNING))
198221418Sadrian			return 1;
199221418Sadrian	}
200221418Sadrian
201221418Sadrian	/*
202221418Sadrian	 * Otherwise, retries for packets below or equal to the last
203221418Sadrian	 * seen sequence number should be dropped.
204221418Sadrian	 */
205221418Sadrian
206221418Sadrian	/*
207221418Sadrian	 * Treat frame seqnum 4095 as special due to boundary
208221418Sadrian	 * wrapping conditions.
209221418Sadrian	 */
210221418Sadrian	if (SEQNO(ni->ni_rxseqs[tid]) == 4095) {
211221418Sadrian		/*
212221418Sadrian		 * Drop retransmits on seqnum 4095/current fragment for itself.
213221418Sadrian		 */
214221418Sadrian		if (SEQ_EQ(rxseq, ni->ni_rxseqs[tid]) &&
215221418Sadrian		    (wh->i_fc[1] & IEEE80211_FC1_RETRY))
216221418Sadrian			return 0;
217221418Sadrian		/*
218221418Sadrian		 * Treat any subsequent frame as fine if the last seen frame
219221418Sadrian		 * is 4095 and it's not a retransmit for the same sequence
220221418Sadrian		 * number. However, this doesn't capture incorrectly ordered
221221418Sadrian	 	 * fragments w/ sequence number 4095. It shouldn't be seen
222221418Sadrian		 * in practice, but see the comment above for further info.
223221418Sadrian		 */
224221418Sadrian		return 1;
225221418Sadrian	}
226221418Sadrian
227221418Sadrian	/*
228221418Sadrian	 * At this point we assume that retransmitted seq/frag numbers below
229221418Sadrian	 * the current can simply be eliminated.
230221418Sadrian	 */
231221418Sadrian	if ((wh->i_fc[1] & IEEE80211_FC1_RETRY) &&
232221418Sadrian	    SEQ_LEQ(rxseq, ni->ni_rxseqs[tid]))
233221418Sadrian		return 0;
234221418Sadrian
235221418Sadrian	return 1;
236221418Sadrian#undef	SEQ_LEQ
237221418Sadrian#undef	SEQ_EQ
238221418Sadrian#undef	HAS_SEQ
239221418Sadrian#undef	SEQNO
240221418Sadrian#undef	FRAGNO
241221418Sadrian}
242221418Sadrian
243178354Ssamvoid	ieee80211_deliver_data(struct ieee80211vap *,
244178354Ssam		struct ieee80211_node *, struct mbuf *);
245178354Ssamstruct mbuf *ieee80211_defrag(struct ieee80211_node *,
246178354Ssam		struct mbuf *, int);
247195757Ssamstruct mbuf *ieee80211_realign(struct ieee80211vap *, struct mbuf *, size_t);
248178354Ssamstruct mbuf *ieee80211_decap(struct ieee80211vap *, struct mbuf *, int);
249178354Ssamstruct mbuf *ieee80211_decap1(struct mbuf *, int *);
250178354Ssamint	ieee80211_setup_rates(struct ieee80211_node *ni,
251178354Ssam		const uint8_t *rates, const uint8_t *xrates, int flags);
252178354Ssamvoid ieee80211_send_error(struct ieee80211_node *,
253178354Ssam		const uint8_t mac[IEEE80211_ADDR_LEN], int subtype, int arg);
254178354Ssamint	ieee80211_alloc_challenge(struct ieee80211_node *);
255178354Ssamint	ieee80211_parse_beacon(struct ieee80211_node *, struct mbuf *,
256178354Ssam		struct ieee80211_scanparams *);
257178354Ssamint	ieee80211_parse_action(struct ieee80211_node *, struct mbuf *);
258178354Ssam#endif /* _NET80211_IEEE80211_INPUT_H_ */
259