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: stable/11/sys/net80211/ieee80211_input.h 330241 2018-03-01 15:21:52Z eadler $
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, 			\
65298376Savos			    ieee80211_mgt_subtype_name(subtype),	\
66178354Ssam				wh->i_addr2, _ssid);			\
67178354Ssam		vap->iv_stats.is_rx_ssidmismatch++;			\
68178354Ssam		_action;						\
69178354Ssam	}								\
70178354Ssam} while (0)
71178354Ssam#else /* !IEEE80211_DEBUG */
72178354Ssam#define	IEEE80211_VERIFY_SSID(_ni, _ssid, _action) do {			\
73178354Ssam	if ((_ssid)[1] != 0 &&						\
74178354Ssam	    ((_ssid)[1] != (_ni)->ni_esslen ||				\
75178354Ssam	    memcmp((_ssid) + 2, (_ni)->ni_essid, (_ssid)[1]) != 0)) {	\
76178354Ssam		vap->iv_stats.is_rx_ssidmismatch++;			\
77178354Ssam		_action;						\
78178354Ssam	}								\
79178354Ssam} while (0)
80178354Ssam#endif /* !IEEE80211_DEBUG */
81178354Ssam
82298359Savos#include <sys/endian.h>		/* For le16toh() / le32dec() */
83178354Ssam
84178354Ssamstatic __inline int
85178354Ssamiswpaoui(const uint8_t *frm)
86178354Ssam{
87298359Savos	return frm[1] > 3 && le32dec(frm+2) == ((WPA_OUI_TYPE<<24)|WPA_OUI);
88178354Ssam}
89178354Ssam
90178354Ssamstatic __inline int
91178354Ssamiswmeoui(const uint8_t *frm)
92178354Ssam{
93298359Savos	return frm[1] > 3 && le32dec(frm+2) == ((WME_OUI_TYPE<<24)|WME_OUI);
94178354Ssam}
95178354Ssam
96178354Ssamstatic __inline int
97178354Ssamiswmeparam(const uint8_t *frm)
98178354Ssam{
99298359Savos	return frm[1] > 5 && le32dec(frm+2) == ((WME_OUI_TYPE<<24)|WME_OUI) &&
100178354Ssam		frm[6] == WME_PARAM_OUI_SUBTYPE;
101178354Ssam}
102178354Ssam
103178354Ssamstatic __inline int
104178354Ssamiswmeinfo(const uint8_t *frm)
105178354Ssam{
106298359Savos	return frm[1] > 5 && le32dec(frm+2) == ((WME_OUI_TYPE<<24)|WME_OUI) &&
107178354Ssam		frm[6] == WME_INFO_OUI_SUBTYPE;
108178354Ssam}
109178354Ssam
110178354Ssamstatic __inline int
111178354Ssamisatherosoui(const uint8_t *frm)
112178354Ssam{
113298359Savos	return frm[1] > 3 && le32dec(frm+2) == ((ATH_OUI_TYPE<<24)|ATH_OUI);
114178354Ssam}
115178354Ssam
116178354Ssamstatic __inline int
117186904Ssamistdmaoui(const uint8_t *frm)
118186904Ssam{
119298359Savos	return frm[1] > 3 && le32dec(frm+2) == ((TDMA_OUI_TYPE<<24)|TDMA_OUI);
120186904Ssam}
121186904Ssam
122186904Ssamstatic __inline int
123178354Ssamishtcapoui(const uint8_t *frm)
124178354Ssam{
125298359Savos	return frm[1] > 3 && le32dec(frm+2) == ((BCM_OUI_HTCAP<<24)|BCM_OUI);
126178354Ssam}
127178354Ssam
128178354Ssamstatic __inline int
129178354Ssamishtinfooui(const uint8_t *frm)
130178354Ssam{
131298359Savos	return frm[1] > 3 && le32dec(frm+2) == ((BCM_OUI_HTINFO<<24)|BCM_OUI);
132178354Ssam}
133178354Ssam
134221418Sadrian/*
135221418Sadrian * Check the current frame sequence number against the current TID
136221418Sadrian * state and return whether it's in sequence or should be dropped.
137221418Sadrian *
138221418Sadrian * Since out of order packet and duplicate packet eliminations should
139221418Sadrian * be done by the AMPDU RX code, this routine blindly accepts all
140221418Sadrian * frames from a HT station w/ a TID that is currently doing AMPDU-RX.
141221418Sadrian * HT stations without WME or where the TID is not doing AMPDU-RX
142221418Sadrian * are checked like non-HT stations.
143221418Sadrian *
144221418Sadrian * The routine only eliminates packets whose sequence/fragment
145221418Sadrian * match or are less than the last seen sequence/fragment number
146221418Sadrian * AND are retransmits It doesn't try to eliminate out of order packets.
147221418Sadrian *
148221418Sadrian * Since all frames after sequence number 4095 will be less than 4095
149221418Sadrian * (as the seqnum wraps), handle that special case so packets aren't
150221418Sadrian * incorrectly dropped - ie, if the next packet is sequence number 0
151221418Sadrian * but a retransmit since the initial packet didn't make it.
152221418Sadrian */
153221418Sadrianstatic __inline int
154296254Savosieee80211_check_rxseq(struct ieee80211_node *ni, struct ieee80211_frame *wh,
155296254Savos    uint8_t *bssid)
156221418Sadrian{
157221418Sadrian#define	SEQ_LEQ(a,b)	((int)((a)-(b)) <= 0)
158221418Sadrian#define	SEQ_EQ(a,b)	((int)((a)-(b)) == 0)
159221418Sadrian#define	SEQNO(a)	((a) >> IEEE80211_SEQ_SEQ_SHIFT)
160221418Sadrian#define	FRAGNO(a)	((a) & IEEE80211_SEQ_FRAG_MASK)
161296254Savos	struct ieee80211vap *vap = ni->ni_vap;
162221418Sadrian	uint16_t rxseq;
163282820Sadrian	uint8_t type, subtype;
164221418Sadrian	uint8_t tid;
165221418Sadrian	struct ieee80211_rx_ampdu *rap;
166221418Sadrian
167221418Sadrian	rxseq = le16toh(*(uint16_t *)wh->i_seq);
168221418Sadrian	type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
169282820Sadrian	subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK;
170221418Sadrian
171282820Sadrian	/*
172282820Sadrian	 * Types with no sequence number (or QoS (+)Null frames)
173282820Sadrian	 * are always treated valid.
174282820Sadrian	 */
175282820Sadrian	if (! IEEE80211_HAS_SEQ(type, subtype))
176221418Sadrian		return 1;
177221418Sadrian
178221418Sadrian	tid = ieee80211_gettid(wh);
179221418Sadrian
180221418Sadrian	/*
181221418Sadrian	 * Only do the HT AMPDU check for WME stations; non-WME HT stations
182221418Sadrian	 * shouldn't exist outside of debugging. We should at least
183221418Sadrian	 * handle that.
184221418Sadrian	 */
185221418Sadrian	if (tid < WME_NUM_TID) {
186221418Sadrian		rap = &ni->ni_rx_ampdu[tid];
187221418Sadrian		/* HT nodes currently doing RX AMPDU are always valid */
188221418Sadrian		if ((ni->ni_flags & IEEE80211_NODE_HT) &&
189221418Sadrian		    (rap->rxa_flags & IEEE80211_AGGR_RUNNING))
190296254Savos			goto ok;
191221418Sadrian	}
192221418Sadrian
193221418Sadrian	/*
194221418Sadrian	 * Otherwise, retries for packets below or equal to the last
195221418Sadrian	 * seen sequence number should be dropped.
196221418Sadrian	 */
197221418Sadrian
198221418Sadrian	/*
199221418Sadrian	 * Treat frame seqnum 4095 as special due to boundary
200221418Sadrian	 * wrapping conditions.
201221418Sadrian	 */
202221418Sadrian	if (SEQNO(ni->ni_rxseqs[tid]) == 4095) {
203221418Sadrian		/*
204221418Sadrian		 * Drop retransmits on seqnum 4095/current fragment for itself.
205221418Sadrian		 */
206221418Sadrian		if (SEQ_EQ(rxseq, ni->ni_rxseqs[tid]) &&
207221418Sadrian		    (wh->i_fc[1] & IEEE80211_FC1_RETRY))
208296254Savos			goto fail;
209221418Sadrian		/*
210221418Sadrian		 * Treat any subsequent frame as fine if the last seen frame
211221418Sadrian		 * is 4095 and it's not a retransmit for the same sequence
212221418Sadrian		 * number. However, this doesn't capture incorrectly ordered
213221418Sadrian	 	 * fragments w/ sequence number 4095. It shouldn't be seen
214221418Sadrian		 * in practice, but see the comment above for further info.
215221418Sadrian		 */
216296254Savos		goto ok;
217221418Sadrian	}
218221418Sadrian
219221418Sadrian	/*
220221418Sadrian	 * At this point we assume that retransmitted seq/frag numbers below
221221418Sadrian	 * the current can simply be eliminated.
222221418Sadrian	 */
223221418Sadrian	if ((wh->i_fc[1] & IEEE80211_FC1_RETRY) &&
224221418Sadrian	    SEQ_LEQ(rxseq, ni->ni_rxseqs[tid]))
225296254Savos		goto fail;
226221418Sadrian
227296254Savosok:
228330241Seadler	ni->ni_rxseqs[tid] = rxseq;
229296254Savos
230221418Sadrian	return 1;
231296254Savos
232296254Savosfail:
233296254Savos	/* duplicate, discard */
234296254Savos	IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_INPUT, bssid, "duplicate",
235296254Savos	    "seqno <%u,%u> fragno <%u,%u> tid %u",
236296254Savos	     SEQNO(rxseq),  SEQNO(ni->ni_rxseqs[tid]),
237296254Savos	    FRAGNO(rxseq), FRAGNO(ni->ni_rxseqs[tid]), tid);
238296254Savos	vap->iv_stats.is_rx_dup++;
239296254Savos	IEEE80211_NODE_STAT(ni, rx_dup);
240296254Savos
241296254Savos	return 0;
242221418Sadrian#undef	SEQ_LEQ
243221418Sadrian#undef	SEQ_EQ
244221418Sadrian#undef	SEQNO
245221418Sadrian#undef	FRAGNO
246221418Sadrian}
247221418Sadrian
248178354Ssamvoid	ieee80211_deliver_data(struct ieee80211vap *,
249178354Ssam		struct ieee80211_node *, struct mbuf *);
250178354Ssamstruct mbuf *ieee80211_defrag(struct ieee80211_node *,
251178354Ssam		struct mbuf *, int);
252195757Ssamstruct mbuf *ieee80211_realign(struct ieee80211vap *, struct mbuf *, size_t);
253178354Ssamstruct mbuf *ieee80211_decap(struct ieee80211vap *, struct mbuf *, int);
254178354Ssamstruct mbuf *ieee80211_decap1(struct mbuf *, int *);
255178354Ssamint	ieee80211_setup_rates(struct ieee80211_node *ni,
256178354Ssam		const uint8_t *rates, const uint8_t *xrates, int flags);
257178354Ssamvoid ieee80211_send_error(struct ieee80211_node *,
258178354Ssam		const uint8_t mac[IEEE80211_ADDR_LEN], int subtype, int arg);
259178354Ssamint	ieee80211_alloc_challenge(struct ieee80211_node *);
260178354Ssamint	ieee80211_parse_beacon(struct ieee80211_node *, struct mbuf *,
261283535Sadrian		struct ieee80211_channel *,
262178354Ssam		struct ieee80211_scanparams *);
263178354Ssamint	ieee80211_parse_action(struct ieee80211_node *, struct mbuf *);
264178354Ssam#endif /* _NET80211_IEEE80211_INPUT_H_ */
265