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