132176cfdSRui Paulo /*-
232176cfdSRui Paulo  * Copyright (c) 2007-2009 Sam Leffler, Errno Consulting
332176cfdSRui Paulo  * All rights reserved.
432176cfdSRui Paulo  *
532176cfdSRui Paulo  * Redistribution and use in source and binary forms, with or without
632176cfdSRui Paulo  * modification, are permitted provided that the following conditions
732176cfdSRui Paulo  * are met:
832176cfdSRui Paulo  * 1. Redistributions of source code must retain the above copyright
932176cfdSRui Paulo  *    notice, this list of conditions and the following disclaimer.
1032176cfdSRui Paulo  * 2. Redistributions in binary form must reproduce the above copyright
1132176cfdSRui Paulo  *    notice, this list of conditions and the following disclaimer in the
1232176cfdSRui Paulo  *    documentation and/or other materials provided with the distribution.
1332176cfdSRui Paulo  *
1432176cfdSRui Paulo  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1532176cfdSRui Paulo  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1632176cfdSRui Paulo  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1732176cfdSRui Paulo  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
1832176cfdSRui Paulo  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
1932176cfdSRui Paulo  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2032176cfdSRui Paulo  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2132176cfdSRui Paulo  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2232176cfdSRui Paulo  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2332176cfdSRui Paulo  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2432176cfdSRui Paulo  *
25085ff963SMatthew Dillon  * $FreeBSD$
2632176cfdSRui Paulo  */
2732176cfdSRui Paulo #ifndef _NET80211_IEEE80211_INPUT_H_
2832176cfdSRui Paulo #define _NET80211_IEEE80211_INPUT_H_
2932176cfdSRui Paulo 
3032176cfdSRui Paulo /* Verify the existence and length of __elem or get out. */
3132176cfdSRui Paulo #define IEEE80211_VERIFY_ELEMENT(__elem, __maxlen, _action) do {	\
3232176cfdSRui Paulo 	if ((__elem) == NULL) {						\
3332176cfdSRui Paulo 		IEEE80211_DISCARD(vap, IEEE80211_MSG_ELEMID,		\
3432176cfdSRui Paulo 		    wh, NULL, "%s", "no " #__elem );			\
3532176cfdSRui Paulo 		vap->iv_stats.is_rx_elem_missing++;			\
3632176cfdSRui Paulo 		_action;						\
3732176cfdSRui Paulo 	} else if ((__elem)[1] > (__maxlen)) {				\
3832176cfdSRui Paulo 		IEEE80211_DISCARD(vap, IEEE80211_MSG_ELEMID,		\
3932176cfdSRui Paulo 		    wh, NULL, "bad " #__elem " len %d", (__elem)[1]);	\
4032176cfdSRui Paulo 		vap->iv_stats.is_rx_elem_toobig++;			\
4132176cfdSRui Paulo 		_action;						\
4232176cfdSRui Paulo 	}								\
4332176cfdSRui Paulo } while (0)
4432176cfdSRui Paulo 
4532176cfdSRui Paulo #define	IEEE80211_VERIFY_LENGTH(_len, _minlen, _action) do {		\
4632176cfdSRui Paulo 	if ((_len) < (_minlen)) {					\
4732176cfdSRui Paulo 		IEEE80211_DISCARD(vap, IEEE80211_MSG_ELEMID,		\
482c7ccc4aSSascha Wildner 		    wh, NULL, "ie too short, got %ld, expected %ld",	\
492c7ccc4aSSascha Wildner 		    (long)(_len), (long)(_minlen));			\
5032176cfdSRui Paulo 		vap->iv_stats.is_rx_elem_toosmall++;			\
5132176cfdSRui Paulo 		_action;						\
5232176cfdSRui Paulo 	}								\
5332176cfdSRui Paulo } while (0)
5432176cfdSRui Paulo 
55085ff963SMatthew Dillon #ifdef IEEE80211_DEBUG
5632176cfdSRui Paulo void	ieee80211_ssid_mismatch(struct ieee80211vap *, const char *tag,
5732176cfdSRui Paulo 	uint8_t mac[IEEE80211_ADDR_LEN], uint8_t *ssid);
5832176cfdSRui Paulo 
5932176cfdSRui Paulo #define	IEEE80211_VERIFY_SSID(_ni, _ssid, _action) do {			\
6032176cfdSRui Paulo 	if ((_ssid)[1] != 0 &&						\
6132176cfdSRui Paulo 	    ((_ssid)[1] != (_ni)->ni_esslen ||				\
6232176cfdSRui Paulo 	    memcmp((_ssid) + 2, (_ni)->ni_essid, (_ssid)[1]) != 0)) {	\
6332176cfdSRui Paulo 		if (ieee80211_msg_input(vap))				\
6432176cfdSRui Paulo 			ieee80211_ssid_mismatch(vap, 			\
654f655ef5SMatthew Dillon 			    ieee80211_mgt_subtype_name(subtype),	\
6632176cfdSRui Paulo 				wh->i_addr2, _ssid);			\
6732176cfdSRui Paulo 		vap->iv_stats.is_rx_ssidmismatch++;			\
6832176cfdSRui Paulo 		_action;						\
6932176cfdSRui Paulo 	}								\
7032176cfdSRui Paulo } while (0)
7132176cfdSRui Paulo #else /* !IEEE80211_DEBUG */
7232176cfdSRui Paulo #define	IEEE80211_VERIFY_SSID(_ni, _ssid, _action) do {			\
7332176cfdSRui Paulo 	if ((_ssid)[1] != 0 &&						\
7432176cfdSRui Paulo 	    ((_ssid)[1] != (_ni)->ni_esslen ||				\
7532176cfdSRui Paulo 	    memcmp((_ssid) + 2, (_ni)->ni_essid, (_ssid)[1]) != 0)) {	\
7632176cfdSRui Paulo 		vap->iv_stats.is_rx_ssidmismatch++;			\
7732176cfdSRui Paulo 		_action;						\
7832176cfdSRui Paulo 	}								\
7932176cfdSRui Paulo } while (0)
8032176cfdSRui Paulo #endif /* !IEEE80211_DEBUG */
8132176cfdSRui Paulo 
824f655ef5SMatthew Dillon #include <sys/endian.h>		/* For le16toh() / le32dec() */
83*5f79922dSzrj #include <sys/types.h>
8432176cfdSRui Paulo 
8532176cfdSRui Paulo static __inline int
iswpaoui(const uint8_t * frm)8632176cfdSRui Paulo iswpaoui(const uint8_t *frm)
8732176cfdSRui Paulo {
884f655ef5SMatthew Dillon 	return frm[1] > 3 && le32dec(frm+2) == ((WPA_OUI_TYPE<<24)|WPA_OUI);
8932176cfdSRui Paulo }
9032176cfdSRui Paulo 
9132176cfdSRui Paulo static __inline int
iswmeoui(const uint8_t * frm)9232176cfdSRui Paulo iswmeoui(const uint8_t *frm)
9332176cfdSRui Paulo {
944f655ef5SMatthew Dillon 	return frm[1] > 3 && le32dec(frm+2) == ((WME_OUI_TYPE<<24)|WME_OUI);
9532176cfdSRui Paulo }
9632176cfdSRui Paulo 
9732176cfdSRui Paulo static __inline int
iswmeparam(const uint8_t * frm)9832176cfdSRui Paulo iswmeparam(const uint8_t *frm)
9932176cfdSRui Paulo {
1004f655ef5SMatthew Dillon 	return frm[1] > 5 && le32dec(frm+2) == ((WME_OUI_TYPE<<24)|WME_OUI) &&
10132176cfdSRui Paulo 		frm[6] == WME_PARAM_OUI_SUBTYPE;
10232176cfdSRui Paulo }
10332176cfdSRui Paulo 
10432176cfdSRui Paulo static __inline int
iswmeinfo(const uint8_t * frm)10532176cfdSRui Paulo iswmeinfo(const uint8_t *frm)
10632176cfdSRui Paulo {
1074f655ef5SMatthew Dillon 	return frm[1] > 5 && le32dec(frm+2) == ((WME_OUI_TYPE<<24)|WME_OUI) &&
10832176cfdSRui Paulo 		frm[6] == WME_INFO_OUI_SUBTYPE;
10932176cfdSRui Paulo }
11032176cfdSRui Paulo 
11132176cfdSRui Paulo static __inline int
isatherosoui(const uint8_t * frm)11232176cfdSRui Paulo isatherosoui(const uint8_t *frm)
11332176cfdSRui Paulo {
1144f655ef5SMatthew Dillon 	return frm[1] > 3 && le32dec(frm+2) == ((ATH_OUI_TYPE<<24)|ATH_OUI);
11532176cfdSRui Paulo }
11632176cfdSRui Paulo 
11732176cfdSRui Paulo static __inline int
istdmaoui(const uint8_t * frm)11832176cfdSRui Paulo istdmaoui(const uint8_t *frm)
11932176cfdSRui Paulo {
1204f655ef5SMatthew Dillon 	return frm[1] > 3 && le32dec(frm+2) == ((TDMA_OUI_TYPE<<24)|TDMA_OUI);
12132176cfdSRui Paulo }
12232176cfdSRui Paulo 
12332176cfdSRui Paulo static __inline int
ishtcapoui(const uint8_t * frm)12432176cfdSRui Paulo ishtcapoui(const uint8_t *frm)
12532176cfdSRui Paulo {
1264f655ef5SMatthew Dillon 	return frm[1] > 3 && le32dec(frm+2) == ((BCM_OUI_HTCAP<<24)|BCM_OUI);
12732176cfdSRui Paulo }
12832176cfdSRui Paulo 
12932176cfdSRui Paulo static __inline int
ishtinfooui(const uint8_t * frm)13032176cfdSRui Paulo ishtinfooui(const uint8_t *frm)
13132176cfdSRui Paulo {
1324f655ef5SMatthew Dillon 	return frm[1] > 3 && le32dec(frm+2) == ((BCM_OUI_HTINFO<<24)|BCM_OUI);
13332176cfdSRui Paulo }
13432176cfdSRui Paulo 
135085ff963SMatthew Dillon /*
136085ff963SMatthew Dillon  * Check the current frame sequence number against the current TID
137085ff963SMatthew Dillon  * state and return whether it's in sequence or should be dropped.
138085ff963SMatthew Dillon  *
139085ff963SMatthew Dillon  * Since out of order packet and duplicate packet eliminations should
140085ff963SMatthew Dillon  * be done by the AMPDU RX code, this routine blindly accepts all
141085ff963SMatthew Dillon  * frames from a HT station w/ a TID that is currently doing AMPDU-RX.
142085ff963SMatthew Dillon  * HT stations without WME or where the TID is not doing AMPDU-RX
143085ff963SMatthew Dillon  * are checked like non-HT stations.
144085ff963SMatthew Dillon  *
145085ff963SMatthew Dillon  * The routine only eliminates packets whose sequence/fragment
146085ff963SMatthew Dillon  * match or are less than the last seen sequence/fragment number
147085ff963SMatthew Dillon  * AND are retransmits It doesn't try to eliminate out of order packets.
148085ff963SMatthew Dillon  *
149085ff963SMatthew Dillon  * Since all frames after sequence number 4095 will be less than 4095
150085ff963SMatthew Dillon  * (as the seqnum wraps), handle that special case so packets aren't
151085ff963SMatthew Dillon  * incorrectly dropped - ie, if the next packet is sequence number 0
152085ff963SMatthew Dillon  * but a retransmit since the initial packet didn't make it.
153085ff963SMatthew Dillon  */
154085ff963SMatthew Dillon static __inline int
ieee80211_check_rxseq(struct ieee80211_node * ni,struct ieee80211_frame * wh,uint8_t * bssid)1554f655ef5SMatthew Dillon ieee80211_check_rxseq(struct ieee80211_node *ni, struct ieee80211_frame *wh,
1564f655ef5SMatthew Dillon     uint8_t *bssid)
157085ff963SMatthew Dillon {
158085ff963SMatthew Dillon #define	SEQ_LEQ(a,b)	((int)((a)-(b)) <= 0)
159085ff963SMatthew Dillon #define	SEQ_EQ(a,b)	((int)((a)-(b)) == 0)
160085ff963SMatthew Dillon #define	SEQNO(a)	((a) >> IEEE80211_SEQ_SEQ_SHIFT)
161085ff963SMatthew Dillon #define	FRAGNO(a)	((a) & IEEE80211_SEQ_FRAG_MASK)
1624f655ef5SMatthew Dillon 	struct ieee80211vap *vap = ni->ni_vap;
163085ff963SMatthew Dillon 	uint16_t rxseq;
1644f898719SImre Vadász 	uint8_t type, subtype;
165085ff963SMatthew Dillon 	uint8_t tid;
166085ff963SMatthew Dillon 	struct ieee80211_rx_ampdu *rap;
167085ff963SMatthew Dillon 
168085ff963SMatthew Dillon 	rxseq = le16toh(*(uint16_t *)wh->i_seq);
169085ff963SMatthew Dillon 	type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
1704f898719SImre Vadász 	subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK;
171085ff963SMatthew Dillon 
1724f898719SImre Vadász 	/*
1734f898719SImre Vadász 	 * Types with no sequence number (or QoS (+)Null frames)
1744f898719SImre Vadász 	 * are always treated valid.
1754f898719SImre Vadász 	 */
1764f898719SImre Vadász 	if (! IEEE80211_HAS_SEQ(type, subtype))
177085ff963SMatthew Dillon 		return 1;
178085ff963SMatthew Dillon 
179085ff963SMatthew Dillon 	tid = ieee80211_gettid(wh);
180085ff963SMatthew Dillon 
181085ff963SMatthew Dillon 	/*
182085ff963SMatthew Dillon 	 * Only do the HT AMPDU check for WME stations; non-WME HT stations
183085ff963SMatthew Dillon 	 * shouldn't exist outside of debugging. We should at least
184085ff963SMatthew Dillon 	 * handle that.
185085ff963SMatthew Dillon 	 */
186085ff963SMatthew Dillon 	if (tid < WME_NUM_TID) {
187085ff963SMatthew Dillon 		rap = &ni->ni_rx_ampdu[tid];
188085ff963SMatthew Dillon 		/* HT nodes currently doing RX AMPDU are always valid */
189085ff963SMatthew Dillon 		if ((ni->ni_flags & IEEE80211_NODE_HT) &&
190085ff963SMatthew Dillon 		    (rap->rxa_flags & IEEE80211_AGGR_RUNNING))
1914f655ef5SMatthew Dillon 			goto ok;
192085ff963SMatthew Dillon 	}
193085ff963SMatthew Dillon 
194085ff963SMatthew Dillon 	/*
195085ff963SMatthew Dillon 	 * Otherwise, retries for packets below or equal to the last
196085ff963SMatthew Dillon 	 * seen sequence number should be dropped.
197085ff963SMatthew Dillon 	 */
198085ff963SMatthew Dillon 
199085ff963SMatthew Dillon 	/*
200085ff963SMatthew Dillon 	 * Treat frame seqnum 4095 as special due to boundary
201085ff963SMatthew Dillon 	 * wrapping conditions.
202085ff963SMatthew Dillon 	 */
203085ff963SMatthew Dillon 	if (SEQNO(ni->ni_rxseqs[tid]) == 4095) {
204085ff963SMatthew Dillon 		/*
205085ff963SMatthew Dillon 		 * Drop retransmits on seqnum 4095/current fragment for itself.
206085ff963SMatthew Dillon 		 */
207085ff963SMatthew Dillon 		if (SEQ_EQ(rxseq, ni->ni_rxseqs[tid]) &&
208085ff963SMatthew Dillon 		    (wh->i_fc[1] & IEEE80211_FC1_RETRY))
2094f655ef5SMatthew Dillon 			goto fail;
210085ff963SMatthew Dillon 		/*
211085ff963SMatthew Dillon 		 * Treat any subsequent frame as fine if the last seen frame
212085ff963SMatthew Dillon 		 * is 4095 and it's not a retransmit for the same sequence
213085ff963SMatthew Dillon 		 * number. However, this doesn't capture incorrectly ordered
214085ff963SMatthew Dillon 		 * fragments w/ sequence number 4095. It shouldn't be seen
215085ff963SMatthew Dillon 		 * in practice, but see the comment above for further info.
216085ff963SMatthew Dillon 		 */
2174f655ef5SMatthew Dillon 		goto ok;
218085ff963SMatthew Dillon 	}
219085ff963SMatthew Dillon 
220085ff963SMatthew Dillon 	/*
221085ff963SMatthew Dillon 	 * At this point we assume that retransmitted seq/frag numbers below
222085ff963SMatthew Dillon 	 * the current can simply be eliminated.
223085ff963SMatthew Dillon 	 */
224085ff963SMatthew Dillon 	if ((wh->i_fc[1] & IEEE80211_FC1_RETRY) &&
225085ff963SMatthew Dillon 	    SEQ_LEQ(rxseq, ni->ni_rxseqs[tid]))
2264f655ef5SMatthew Dillon 		goto fail;
2274f655ef5SMatthew Dillon 
2284f655ef5SMatthew Dillon ok:
2294f655ef5SMatthew Dillon 	ni->ni_rxseqs[tid] = rxseq;
230085ff963SMatthew Dillon 
231085ff963SMatthew Dillon 	return 1;
2324f655ef5SMatthew Dillon 
2334f655ef5SMatthew Dillon fail:
2344f655ef5SMatthew Dillon 	/* duplicate, discard */
2354f655ef5SMatthew Dillon 	IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_INPUT, bssid, "duplicate",
2364f655ef5SMatthew Dillon 	    "seqno <%u,%u> fragno <%u,%u> tid %u",
2374f655ef5SMatthew Dillon 	     SEQNO(rxseq),  SEQNO(ni->ni_rxseqs[tid]),
2384f655ef5SMatthew Dillon 	    FRAGNO(rxseq), FRAGNO(ni->ni_rxseqs[tid]), tid);
2394f655ef5SMatthew Dillon 	vap->iv_stats.is_rx_dup++;
2404f655ef5SMatthew Dillon 	IEEE80211_NODE_STAT(ni, rx_dup);
2414f655ef5SMatthew Dillon 
2424f655ef5SMatthew Dillon 	return 0;
243085ff963SMatthew Dillon #undef	SEQ_LEQ
244085ff963SMatthew Dillon #undef	SEQ_EQ
245085ff963SMatthew Dillon #undef	SEQNO
246085ff963SMatthew Dillon #undef	FRAGNO
247085ff963SMatthew Dillon }
248085ff963SMatthew Dillon 
24932176cfdSRui Paulo void	ieee80211_deliver_data(struct ieee80211vap *,
25032176cfdSRui Paulo 		struct ieee80211_node *, struct mbuf *);
25132176cfdSRui Paulo struct mbuf *ieee80211_defrag(struct ieee80211_node *,
25232176cfdSRui Paulo 		struct mbuf *, int);
25332176cfdSRui Paulo struct mbuf *ieee80211_realign(struct ieee80211vap *, struct mbuf *, size_t);
25432176cfdSRui Paulo struct mbuf *ieee80211_decap(struct ieee80211vap *, struct mbuf *, int);
25532176cfdSRui Paulo struct mbuf *ieee80211_decap1(struct mbuf *, int *);
25632176cfdSRui Paulo int	ieee80211_setup_rates(struct ieee80211_node *ni,
25732176cfdSRui Paulo 		const uint8_t *rates, const uint8_t *xrates, int flags);
25832176cfdSRui Paulo void ieee80211_send_error(struct ieee80211_node *,
25932176cfdSRui Paulo 		const uint8_t mac[IEEE80211_ADDR_LEN], int subtype, int arg);
26032176cfdSRui Paulo int	ieee80211_alloc_challenge(struct ieee80211_node *);
26132176cfdSRui Paulo int	ieee80211_parse_beacon(struct ieee80211_node *, struct mbuf *,
2624f898719SImre Vadász 		struct ieee80211_channel *,
26332176cfdSRui Paulo 		struct ieee80211_scanparams *);
26432176cfdSRui Paulo int	ieee80211_parse_action(struct ieee80211_node *, struct mbuf *);
26532176cfdSRui Paulo #endif /* _NET80211_IEEE80211_INPUT_H_ */
266