| 1 | /*- |
| 2 | * SPDX-License-Identifier: BSD-2-Clause |
| 3 | * |
| 4 | * Copyright (c) 2007-2009 Sam Leffler, Errno Consulting |
| 5 | * All rights reserved. |
| 6 | * |
| 7 | * Redistribution and use in source and binary forms, with or without |
| 8 | * modification, are permitted provided that the following conditions |
| 9 | * are met: |
| 10 | * 1. Redistributions of source code must retain the above copyright |
| 11 | * notice, this list of conditions and the following disclaimer. |
| 12 | * 2. Redistributions in binary form must reproduce the above copyright |
| 13 | * notice, this list of conditions and the following disclaimer in the |
| 14 | * documentation and/or other materials provided with the distribution. |
| 15 | * |
| 16 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
| 17 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
| 18 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
| 19 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
| 20 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
| 21 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 22 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 23 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
| 25 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 26 | */ |
| 27 | #ifndef _NET80211_IEEE80211_INPUT_H_ |
| 28 | #define _NET80211_IEEE80211_INPUT_H_ |
| 29 | |
| 30 | /* Verify the existence and length of __elem or get out. */ |
| 31 | #define IEEE80211_VERIFY_ELEMENT(__elem, __maxlen, _action) do {	\ |
| 32 | 	if ((__elem) == NULL) {						\ |
| 33 | 		IEEE80211_DISCARD(vap, IEEE80211_MSG_ELEMID,		\ |
| 34 | 		 wh, NULL, "%s", "no " #__elem );			\ |
| 35 | 		vap->iv_stats.is_rx_elem_missing++;			\ |
| 36 | 		_action;						\ |
| 37 | 	} else if ((__elem)[1] > (__maxlen)) {				\ |
| 38 | 		IEEE80211_DISCARD(vap, IEEE80211_MSG_ELEMID,		\ |
| 39 | 		 wh, NULL, "bad " #__elem " len %d", (__elem)[1]);	\ |
| 40 | 		vap->iv_stats.is_rx_elem_toobig++;			\ |
| 41 | 		_action;						\ |
| 42 | 	}								\ |
| 43 | } while (0) |
| 44 | |
| 45 | #define	IEEE80211_VERIFY_LENGTH(_len, _minlen, _action) do {		\ |
| 46 | 	if ((_len) < (_minlen)) {					\ |
| 47 | 		IEEE80211_DISCARD(vap, IEEE80211_MSG_ELEMID,		\ |
| 48 | 		 wh, NULL, "ie too short, got %d, expected %d",	\ |
| 49 | 		 (_len), (_minlen));					\ |
| 50 | 		vap->iv_stats.is_rx_elem_toosmall++;			\ |
| 51 | 		_action;						\ |
| 52 | 	}								\ |
| 53 | } while (0) |
| 54 | |
| 55 | #ifdef IEEE80211_DEBUG |
| 56 | void	ieee80211_ssid_mismatch(struct ieee80211vap *, const char *tag, |
| 57 | 	uint8_t mac[IEEE80211_ADDR_LEN], uint8_t *ssid); |
| 58 | |
| 59 | #define	IEEE80211_VERIFY_SSID(_ni, _ssid, _action) do {			\ |
| 60 | 	if ((_ssid)[1] != 0 &&						\ |
| 61 | 	 ((_ssid)[1] != (_ni)->ni_esslen ||				\ |
| 62 | 	 memcmp((_ssid) + 2, (_ni)->ni_essid, (_ssid)[1]) != 0)) {	\ |
| 63 | 		if (ieee80211_msg_input(vap))				\ |
| 64 | 			ieee80211_ssid_mismatch(vap, 			\ |
| 65 | 			 ieee80211_mgt_subtype_name(subtype),	\ |
| 66 | 				wh->i_addr2, _ssid);			\ |
| 67 | 		vap->iv_stats.is_rx_ssidmismatch++;			\ |
| 68 | 		_action;						\ |
| 69 | 	}								\ |
| 70 | } while (0) |
| 71 | #else /* !IEEE80211_DEBUG */ |
| 72 | #define	IEEE80211_VERIFY_SSID(_ni, _ssid, _action) do {			\ |
| 73 | 	if ((_ssid)[1] != 0 &&						\ |
| 74 | 	 ((_ssid)[1] != (_ni)->ni_esslen ||				\ |
| 75 | 	 memcmp((_ssid) + 2, (_ni)->ni_essid, (_ssid)[1]) != 0)) {	\ |
| 76 | 		vap->iv_stats.is_rx_ssidmismatch++;			\ |
| 77 | 		_action;						\ |
| 78 | 	}								\ |
| 79 | } while (0) |
| 80 | #endif /* !IEEE80211_DEBUG */ |
| 81 | |
| 82 | #include <sys/endian.h>		/* For le16toh() / le32dec() */ |
| 83 | |
| 84 | static __inline int |
| 85 | iswpaoui(const uint8_t *frm) |
| 86 | { |
| 87 | 	return frm[1] > 3 && le32dec(frm+2) == ((WPA_OUI_TYPE<<24)|WPA_OUI); |
| 88 | } |
| 89 | |
| 90 | static __inline int |
| 91 | iswmeoui(const uint8_t *frm) |
| 92 | { |
| 93 | 	return frm[1] > 3 && le32dec(frm+2) == ((WME_OUI_TYPE<<24)|WME_OUI); |
| 94 | } |
| 95 | |
| 96 | static __inline int |
| 97 | iswmeparam(const uint8_t *frm) |
| 98 | { |
| 99 | 	return frm[1] > 5 && le32dec(frm+2) == ((WME_OUI_TYPE<<24)|WME_OUI) && |
| 100 | 		frm[6] == WME_PARAM_OUI_SUBTYPE; |
| 101 | } |
| 102 | |
| 103 | static __inline int |
| 104 | iswmeinfo(const uint8_t *frm) |
| 105 | { |
| 106 | 	return frm[1] > 5 && le32dec(frm+2) == ((WME_OUI_TYPE<<24)|WME_OUI) && |
| 107 | 		frm[6] == WME_INFO_OUI_SUBTYPE; |
| 108 | } |
| 109 | |
| 110 | static __inline int |
| 111 | isatherosoui(const uint8_t *frm) |
| 112 | { |
| 113 | 	return frm[1] > 3 && le32dec(frm+2) == ((ATH_OUI_TYPE<<24)|ATH_OUI); |
| 114 | } |
| 115 | |
| 116 | static __inline int |
| 117 | istdmaoui(const uint8_t *frm) |
| 118 | { |
| 119 | 	return frm[1] > 3 && le32dec(frm+2) == ((TDMA_OUI_TYPE<<24)|TDMA_OUI); |
| 120 | } |
| 121 | |
| 122 | static __inline int |
| 123 | ishtcapoui(const uint8_t *frm) |
| 124 | { |
| 125 | 	return frm[1] > 3 && le32dec(frm+2) == ((BCM_OUI_HTCAP<<24)|BCM_OUI); |
| 126 | } |
| 127 | |
| 128 | static __inline int |
| 129 | ishtinfooui(const uint8_t *frm) |
| 130 | { |
| 131 | 	return frm[1] > 3 && le32dec(frm+2) == ((BCM_OUI_HTINFO<<24)|BCM_OUI); |
| 132 | } |
| 133 | |
| 134 | static __inline int |
| 135 | ieee80211_check_rxseq_amsdu(const struct ieee80211_rx_stats *rxs) |
| 136 | { |
| 137 | 	if (rxs == NULL) |
| 138 | 		return 0; |
| 139 | 	return (!! (rxs->c_pktflags & IEEE80211_RX_F_AMSDU)); |
| 140 | } |
| 141 | |
| 142 | /* |
| 143 | * Return 1 if the rxseq check should increment the sequence |
| 144 | * number. Return 0 if it's part of an AMSDU batch and it isn't |
| 145 | * the final frame in the decap'ed burst. |
| 146 | */ |
| 147 | static __inline int |
| 148 | ieee80211_check_rxseq_amsdu_more(const struct ieee80211_rx_stats *rxs) |
| 149 | { |
| 150 | 	/* No state? ok */ |
| 151 | 	if (rxs == NULL) |
| 152 | 		return (1); |
| 153 | |
| 154 | 	/* State but no AMSDU set? ok */ |
| 155 | 	if ((rxs->c_pktflags & IEEE80211_RX_F_AMSDU) == 0) |
| 156 | 		return (1); |
| 157 | |
| 158 | 	/* State, AMSDU set, then _MORE means "don't inc yet" */ |
| 159 | 	if (rxs->c_pktflags & IEEE80211_RX_F_AMSDU_MORE) { |
| 160 | 		return (0); |
| 161 | 	} |
| 162 | |
| 163 | 	/* Both are set, so return ok */ |
| 164 | 	return (1); |
| 165 | } |
| 166 | |
| 167 | /* |
| 168 | * Check the current frame sequence number against the current TID |
| 169 | * state and return whether it's in sequence or should be dropped. |
| 170 | * |
| 171 | * Since out of order packet and duplicate packet eliminations should |
| 172 | * be done by the AMPDU RX code, this routine blindly accepts all |
| 173 | * frames from a HT station w/ a TID that is currently doing AMPDU-RX. |
| 174 | * HT stations without WME or where the TID is not doing AMPDU-RX |
| 175 | * are checked like non-HT stations. |
| 176 | * |
| 177 | * The routine only eliminates packets whose sequence/fragment |
| 178 | * match or are less than the last seen sequence/fragment number |
| 179 | * AND are retransmits. It doesn't try to eliminate out of order packets. |
| 180 | * |
| 181 | * Since all frames after sequence number 4095 will be less than 4095 |
| 182 | * (as the seqnum wraps), handle that special case so packets aren't |
| 183 | * incorrectly dropped - ie, if the next packet is sequence number 0 |
| 184 | * but a retransmit since the initial packet didn't make it. |
| 185 | * |
| 186 | * XXX TODO: handle sequence number space wrapping with dropped frames; |
| 187 | * especially in high interference conditions under high traffic load |
| 188 | * The RX AMPDU reorder code also needs it. |
| 189 | * |
| 190 | * XXX TODO: update for 802.11-2012 9.3.2.10 Duplicate Detection and Recovery. |
| 191 | */ |
| 192 | static __inline int |
| 193 | ieee80211_check_rxseq(struct ieee80211_node *ni, struct ieee80211_frame *wh, |
| 194 | uint8_t *bssid, const struct ieee80211_rx_stats *rxs) |
| 195 | { |
| 196 | #define	SEQ_LEQ(a,b)	((int)((a)-(b)) <= 0) |
| 197 | #define	SEQ_EQ(a,b)	((int)((a)-(b)) == 0) |
| 198 | #define	SEQNO(a)	((a) >> IEEE80211_SEQ_SEQ_SHIFT) |
| 199 | #define	FRAGNO(a)	((a) & IEEE80211_SEQ_FRAG_MASK) |
| 200 | 	struct ieee80211vap *vap = ni->ni_vap; |
| 201 | 	uint16_t rxseq; |
| 202 | 	uint8_t type, subtype; |
| 203 | 	uint8_t tid; |
| 204 | 	struct ieee80211_rx_ampdu *rap; |
| 205 | |
| 206 | 	rxseq = le16toh(*(uint16_t *)wh->i_seq); |
| 207 | 	type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; |
| 208 | 	subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK; |
| 209 | |
| 210 | 	/* |
| 211 | 	 * Types with no sequence number (or QoS (+)Null frames) |
| 212 | 	 * are always treated valid. |
| 213 | 	 */ |
| 214 | 	if (! IEEE80211_HAS_SEQ(type, subtype)) |
| 215 | 		return 1; |
| 216 | |
| 217 | 	/* |
| 218 | 	 * Always allow multicast frames for now - QoS (any TID) |
| 219 | 	 * or not. |
| 220 | 	 */ |
| 221 | 	if (IEEE80211_IS_MULTICAST(wh->i_addr1)) |
| 222 | 		return 1; |
| 223 | |
| 224 | 	tid = ieee80211_gettid(wh); |
| 225 | |
| 226 | 	/* |
| 227 | 	 * Only do the HT AMPDU check for WME stations; non-WME HT stations |
| 228 | 	 * shouldn't exist outside of debugging. We should at least |
| 229 | 	 * handle that. |
| 230 | 	 */ |
| 231 | 	if (tid < WME_NUM_TID) { |
| 232 | 		rap = &ni->ni_rx_ampdu[tid]; |
| 233 | 		/* HT nodes currently doing RX AMPDU are always valid */ |
| 234 | 		if ((ni->ni_flags & IEEE80211_NODE_HT) && |
| 235 | 		 (rap->rxa_flags & IEEE80211_AGGR_RUNNING)) |
| 236 | 			goto ok; |
| 237 | 	} |
| 238 | |
| 239 | 	/*	 |
| 240 | 	 * Otherwise, retries for packets below or equal to the last |
| 241 | 	 * seen sequence number should be dropped. |
| 242 | 	 */ |
| 243 | |
| 244 | 	/* |
| 245 | 	 * Treat frame seqnum 4095 as special due to boundary |
| 246 | 	 * wrapping conditions. |
| 247 | 	 */ |
| 248 | 	if (SEQNO(ni->ni_rxseqs[tid]) == 4095) { |
| 249 | 		/* |
| 250 | 		 * Drop retransmits on seqnum 4095/current fragment for itself. |
| 251 | 		 */ |
| 252 | 		if (SEQ_EQ(rxseq, ni->ni_rxseqs[tid]) && |
| 253 | 		 (wh->i_fc[1] & IEEE80211_FC1_RETRY)) |
| 254 | 			goto fail; |
| 255 | 		/* |
| 256 | 		 * Treat any subsequent frame as fine if the last seen frame |
| 257 | 		 * is 4095 and it's not a retransmit for the same sequence |
| 258 | 		 * number. However, this doesn't capture incorrectly ordered |
| 259 | 	 	 * fragments w/ sequence number 4095. It shouldn't be seen |
| 260 | 		 * in practice, but see the comment above for further info. |
| 261 | 		 */ |
| 262 | 		goto ok; |
| 263 | 	} |
| 264 | |
| 265 | 	/* |
| 266 | 	 * At this point we assume that retransmitted seq/frag numbers below |
| 267 | 	 * the current can simply be eliminated. |
| 268 | 	 */ |
| 269 | 	if ((wh->i_fc[1] & IEEE80211_FC1_RETRY) && |
| 270 | 	 SEQ_LEQ(rxseq, ni->ni_rxseqs[tid])) |
| 271 | 		goto fail; |
| 272 | |
| 273 | ok: |
| 274 | 	/* |
| 275 | 	 * Only bump the sequence number if it's the last frame |
| 276 | 	 * in a batch. That way frames in the rest of the batch |
| 277 | 	 * get included, and the last frame in the batch kicks |
| 278 | 	 * it next. |
| 279 | 	 */ |
| 280 | 	if (ieee80211_check_rxseq_amsdu_more(rxs)) { |
| 281 | 		ni->ni_rxseqs[tid] = rxseq; |
| 282 | 		if ((rxs != NULL) && ieee80211_check_rxseq_amsdu(rxs)) |
| 283 | 			IEEE80211_NODE_STAT(ni, rx_amsdu_more_end); |
| 284 | 	} else { |
| 285 | 		/* .. still waiting */ |
| 286 | 		IEEE80211_NODE_STAT(ni, rx_amsdu_more); |
| 287 | 	} |
| 288 | |
| 289 | 	return 1; |
| 290 | |
| 291 | fail: |
| 292 | 	/* duplicate, discard */ |
| 293 | 	IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_INPUT, bssid, "duplicate", |
| 294 | 	 "seqno <%u,%u> fragno <%u,%u> tid %u", |
| 295 | 	 SEQNO(rxseq), SEQNO(ni->ni_rxseqs[tid]), |
| 296 | 	 FRAGNO(rxseq), FRAGNO(ni->ni_rxseqs[tid]), tid); |
| 297 | 	vap->iv_stats.is_rx_dup++; |
| 298 | 	IEEE80211_NODE_STAT(ni, rx_dup); |
| 299 | |
| 300 | 	return 0; |
| 301 | #undef	SEQ_LEQ |
| 302 | #undef	SEQ_EQ |
| 303 | #undef	SEQNO |
| 304 | #undef	FRAGNO |
| 305 | } |
| 306 | |
| 307 | void	ieee80211_deliver_data(struct ieee80211vap *, |
| 308 | 		struct ieee80211_node *, struct mbuf *); |
| 309 | struct mbuf *ieee80211_defrag(struct ieee80211_node *, |
| 310 | 		struct mbuf *, int, int); |
| 311 | struct mbuf *ieee80211_realign(struct ieee80211vap *, struct mbuf *, size_t); |
| 312 | struct mbuf *ieee80211_decap(struct ieee80211vap *, struct mbuf *, int, |
| 313 | 		uint8_t); |
| 314 | struct mbuf *ieee80211_decap1(struct mbuf *, int *); |
| 315 | int	ieee80211_setup_rates(struct ieee80211_node *ni, |
| 316 | 		const uint8_t *rates, const uint8_t *xrates, int flags); |
| 317 | void ieee80211_send_error(struct ieee80211_node *, |
| 318 | 		const uint8_t mac[IEEE80211_ADDR_LEN], int subtype, int arg); |
| 319 | int	ieee80211_alloc_challenge(struct ieee80211_node *); |
| 320 | int	ieee80211_parse_beacon(struct ieee80211_node *, struct mbuf *, |
| 321 | 		struct ieee80211_channel *, |
| 322 | 		struct ieee80211_scanparams *); |
| 323 | int	ieee80211_parse_action(struct ieee80211_node *, struct mbuf *); |
| 324 | #endif /* _NET80211_IEEE80211_INPUT_H_ */ |