ieee80211_input.h revision 298359
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: head/sys/net80211/ieee80211_input.h 298359 2016-04-20 18:29:30Z avos $
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
83298359Savos#include <sys/endian.h>		/* For le16toh() / le32dec() */
84178354Ssam
85178354Ssamstatic __inline int
86178354Ssamiswpaoui(const uint8_t *frm)
87178354Ssam{
88298359Savos	return frm[1] > 3 && le32dec(frm+2) == ((WPA_OUI_TYPE<<24)|WPA_OUI);
89178354Ssam}
90178354Ssam
91178354Ssamstatic __inline int
92178354Ssamiswmeoui(const uint8_t *frm)
93178354Ssam{
94298359Savos	return frm[1] > 3 && le32dec(frm+2) == ((WME_OUI_TYPE<<24)|WME_OUI);
95178354Ssam}
96178354Ssam
97178354Ssamstatic __inline int
98178354Ssamiswmeparam(const uint8_t *frm)
99178354Ssam{
100298359Savos	return frm[1] > 5 && le32dec(frm+2) == ((WME_OUI_TYPE<<24)|WME_OUI) &&
101178354Ssam		frm[6] == WME_PARAM_OUI_SUBTYPE;
102178354Ssam}
103178354Ssam
104178354Ssamstatic __inline int
105178354Ssamiswmeinfo(const uint8_t *frm)
106178354Ssam{
107298359Savos	return frm[1] > 5 && le32dec(frm+2) == ((WME_OUI_TYPE<<24)|WME_OUI) &&
108178354Ssam		frm[6] == WME_INFO_OUI_SUBTYPE;
109178354Ssam}
110178354Ssam
111178354Ssamstatic __inline int
112178354Ssamisatherosoui(const uint8_t *frm)
113178354Ssam{
114298359Savos	return frm[1] > 3 && le32dec(frm+2) == ((ATH_OUI_TYPE<<24)|ATH_OUI);
115178354Ssam}
116178354Ssam
117178354Ssamstatic __inline int
118186904Ssamistdmaoui(const uint8_t *frm)
119186904Ssam{
120298359Savos	return frm[1] > 3 && le32dec(frm+2) == ((TDMA_OUI_TYPE<<24)|TDMA_OUI);
121186904Ssam}
122186904Ssam
123186904Ssamstatic __inline int
124178354Ssamishtcapoui(const uint8_t *frm)
125178354Ssam{
126298359Savos	return frm[1] > 3 && le32dec(frm+2) == ((BCM_OUI_HTCAP<<24)|BCM_OUI);
127178354Ssam}
128178354Ssam
129178354Ssamstatic __inline int
130178354Ssamishtinfooui(const uint8_t *frm)
131178354Ssam{
132298359Savos	return frm[1] > 3 && le32dec(frm+2) == ((BCM_OUI_HTINFO<<24)|BCM_OUI);
133178354Ssam}
134178354Ssam
135221418Sadrian/*
136221418Sadrian * Check the current frame sequence number against the current TID
137221418Sadrian * state and return whether it's in sequence or should be dropped.
138221418Sadrian *
139221418Sadrian * Since out of order packet and duplicate packet eliminations should
140221418Sadrian * be done by the AMPDU RX code, this routine blindly accepts all
141221418Sadrian * frames from a HT station w/ a TID that is currently doing AMPDU-RX.
142221418Sadrian * HT stations without WME or where the TID is not doing AMPDU-RX
143221418Sadrian * are checked like non-HT stations.
144221418Sadrian *
145221418Sadrian * The routine only eliminates packets whose sequence/fragment
146221418Sadrian * match or are less than the last seen sequence/fragment number
147221418Sadrian * AND are retransmits It doesn't try to eliminate out of order packets.
148221418Sadrian *
149221418Sadrian * Since all frames after sequence number 4095 will be less than 4095
150221418Sadrian * (as the seqnum wraps), handle that special case so packets aren't
151221418Sadrian * incorrectly dropped - ie, if the next packet is sequence number 0
152221418Sadrian * but a retransmit since the initial packet didn't make it.
153221418Sadrian */
154221418Sadrianstatic __inline int
155296254Savosieee80211_check_rxseq(struct ieee80211_node *ni, struct ieee80211_frame *wh,
156296254Savos    uint8_t *bssid)
157221418Sadrian{
158221418Sadrian#define	SEQ_LEQ(a,b)	((int)((a)-(b)) <= 0)
159221418Sadrian#define	SEQ_EQ(a,b)	((int)((a)-(b)) == 0)
160221418Sadrian#define	SEQNO(a)	((a) >> IEEE80211_SEQ_SEQ_SHIFT)
161221418Sadrian#define	FRAGNO(a)	((a) & IEEE80211_SEQ_FRAG_MASK)
162296254Savos	struct ieee80211vap *vap = ni->ni_vap;
163221418Sadrian	uint16_t rxseq;
164282820Sadrian	uint8_t type, subtype;
165221418Sadrian	uint8_t tid;
166221418Sadrian	struct ieee80211_rx_ampdu *rap;
167221418Sadrian
168221418Sadrian	rxseq = le16toh(*(uint16_t *)wh->i_seq);
169221418Sadrian	type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
170282820Sadrian	subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK;
171221418Sadrian
172282820Sadrian	/*
173282820Sadrian	 * Types with no sequence number (or QoS (+)Null frames)
174282820Sadrian	 * are always treated valid.
175282820Sadrian	 */
176282820Sadrian	if (! IEEE80211_HAS_SEQ(type, subtype))
177221418Sadrian		return 1;
178221418Sadrian
179221418Sadrian	tid = ieee80211_gettid(wh);
180221418Sadrian
181221418Sadrian	/*
182221418Sadrian	 * Only do the HT AMPDU check for WME stations; non-WME HT stations
183221418Sadrian	 * shouldn't exist outside of debugging. We should at least
184221418Sadrian	 * handle that.
185221418Sadrian	 */
186221418Sadrian	if (tid < WME_NUM_TID) {
187221418Sadrian		rap = &ni->ni_rx_ampdu[tid];
188221418Sadrian		/* HT nodes currently doing RX AMPDU are always valid */
189221418Sadrian		if ((ni->ni_flags & IEEE80211_NODE_HT) &&
190221418Sadrian		    (rap->rxa_flags & IEEE80211_AGGR_RUNNING))
191296254Savos			goto ok;
192221418Sadrian	}
193221418Sadrian
194221418Sadrian	/*
195221418Sadrian	 * Otherwise, retries for packets below or equal to the last
196221418Sadrian	 * seen sequence number should be dropped.
197221418Sadrian	 */
198221418Sadrian
199221418Sadrian	/*
200221418Sadrian	 * Treat frame seqnum 4095 as special due to boundary
201221418Sadrian	 * wrapping conditions.
202221418Sadrian	 */
203221418Sadrian	if (SEQNO(ni->ni_rxseqs[tid]) == 4095) {
204221418Sadrian		/*
205221418Sadrian		 * Drop retransmits on seqnum 4095/current fragment for itself.
206221418Sadrian		 */
207221418Sadrian		if (SEQ_EQ(rxseq, ni->ni_rxseqs[tid]) &&
208221418Sadrian		    (wh->i_fc[1] & IEEE80211_FC1_RETRY))
209296254Savos			goto fail;
210221418Sadrian		/*
211221418Sadrian		 * Treat any subsequent frame as fine if the last seen frame
212221418Sadrian		 * is 4095 and it's not a retransmit for the same sequence
213221418Sadrian		 * number. However, this doesn't capture incorrectly ordered
214221418Sadrian	 	 * fragments w/ sequence number 4095. It shouldn't be seen
215221418Sadrian		 * in practice, but see the comment above for further info.
216221418Sadrian		 */
217296254Savos		goto ok;
218221418Sadrian	}
219221418Sadrian
220221418Sadrian	/*
221221418Sadrian	 * At this point we assume that retransmitted seq/frag numbers below
222221418Sadrian	 * the current can simply be eliminated.
223221418Sadrian	 */
224221418Sadrian	if ((wh->i_fc[1] & IEEE80211_FC1_RETRY) &&
225221418Sadrian	    SEQ_LEQ(rxseq, ni->ni_rxseqs[tid]))
226296254Savos		goto fail;
227221418Sadrian
228296254Savosok:
229296254Savos	ni->ni_rxseqs[tid] = rxseq;
230296254Savos
231221418Sadrian	return 1;
232296254Savos
233296254Savosfail:
234296254Savos	/* duplicate, discard */
235296254Savos	IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_INPUT, bssid, "duplicate",
236296254Savos	    "seqno <%u,%u> fragno <%u,%u> tid %u",
237296254Savos	     SEQNO(rxseq),  SEQNO(ni->ni_rxseqs[tid]),
238296254Savos	    FRAGNO(rxseq), FRAGNO(ni->ni_rxseqs[tid]), tid);
239296254Savos	vap->iv_stats.is_rx_dup++;
240296254Savos	IEEE80211_NODE_STAT(ni, rx_dup);
241296254Savos
242296254Savos	return 0;
243221418Sadrian#undef	SEQ_LEQ
244221418Sadrian#undef	SEQ_EQ
245221418Sadrian#undef	SEQNO
246221418Sadrian#undef	FRAGNO
247221418Sadrian}
248221418Sadrian
249178354Ssamvoid	ieee80211_deliver_data(struct ieee80211vap *,
250178354Ssam		struct ieee80211_node *, struct mbuf *);
251178354Ssamstruct mbuf *ieee80211_defrag(struct ieee80211_node *,
252178354Ssam		struct mbuf *, int);
253195757Ssamstruct mbuf *ieee80211_realign(struct ieee80211vap *, struct mbuf *, size_t);
254178354Ssamstruct mbuf *ieee80211_decap(struct ieee80211vap *, struct mbuf *, int);
255178354Ssamstruct mbuf *ieee80211_decap1(struct mbuf *, int *);
256178354Ssamint	ieee80211_setup_rates(struct ieee80211_node *ni,
257178354Ssam		const uint8_t *rates, const uint8_t *xrates, int flags);
258178354Ssamvoid ieee80211_send_error(struct ieee80211_node *,
259178354Ssam		const uint8_t mac[IEEE80211_ADDR_LEN], int subtype, int arg);
260178354Ssamint	ieee80211_alloc_challenge(struct ieee80211_node *);
261178354Ssamint	ieee80211_parse_beacon(struct ieee80211_node *, struct mbuf *,
262283535Sadrian		struct ieee80211_channel *,
263178354Ssam		struct ieee80211_scanparams *);
264178354Ssamint	ieee80211_parse_action(struct ieee80211_node *, struct mbuf *);
265178354Ssam#endif /* _NET80211_IEEE80211_INPUT_H_ */
266