Module Name:    src
Committed By:   maxv
Date:           Wed Jan 17 16:03:16 UTC 2018

Modified Files:
        src/sys/net80211: ieee80211_input.c

Log Message:
Several changes:

 * Style in several places, to make the code more readable or easier to
   understand.

 * Instead of checking m->m_pkthdr.len, check m->m_len. m_pkthdr.len is
   the total size of the packet, not the size of the current mbuf (which
   may be smaller).

 * Add a missing length check when handling QoS frames.

 * Cast the lengths passed in IEEE80211_VERIFY_LENGTH to size_t.

 * Remove the length check on scan.sp_xrates, that I added yesterday.
   xrates gets silently truncated in ieee80211_setup_rates().

 * Fix several buffer overflows in the parsers of the MANAGEMENT frames.


To generate a diff of this commit:
cvs rdiff -u -r1.108 -r1.109 src/sys/net80211/ieee80211_input.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/net80211/ieee80211_input.c
diff -u src/sys/net80211/ieee80211_input.c:1.108 src/sys/net80211/ieee80211_input.c:1.109
--- src/sys/net80211/ieee80211_input.c:1.108	Tue Jan 16 18:53:32 2018
+++ src/sys/net80211/ieee80211_input.c	Wed Jan 17 16:03:16 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: ieee80211_input.c,v 1.108 2018/01/16 18:53:32 maxv Exp $	*/
+/*	$NetBSD: ieee80211_input.c,v 1.109 2018/01/17 16:03:16 maxv Exp $	*/
 
 /*
  * Copyright (c) 2001 Atsushi Onoe
@@ -37,7 +37,7 @@
 __FBSDID("$FreeBSD: src/sys/net80211/ieee80211_input.c,v 1.81 2005/08/10 16:22:29 sam Exp $");
 #endif
 #ifdef __NetBSD__
-__KERNEL_RCSID(0, "$NetBSD: ieee80211_input.c,v 1.108 2018/01/16 18:53:32 maxv Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ieee80211_input.c,v 1.109 2018/01/17 16:03:16 maxv Exp $");
 #endif
 
 #ifdef _KERNEL_OPT
@@ -354,8 +354,7 @@ ieee80211_input_data(struct ieee80211com
 		 * any non-PAE frames received without encryption.
 		 */
 		if ((ic->ic_flags & IEEE80211_F_DROPUNENC) &&
-		    key == NULL &&
-		    eh->ether_type != htons(ETHERTYPE_PAE)) {
+		    key == NULL && eh->ether_type != htons(ETHERTYPE_PAE)) {
 			/*
 			 * Drop unencrypted frames.
 			 */
@@ -407,10 +406,9 @@ ieee80211_input_management(struct ieee80
 		ic->ic_stats.is_rx_wrongdir++;
 		goto err;
 	}
-	if (m->m_pkthdr.len < sizeof(struct ieee80211_frame)) {
-		IEEE80211_DISCARD_MAC(ic, IEEE80211_MSG_ANY,
-		    ni->ni_macaddr, "mgt", "too short: len %u",
-		    m->m_pkthdr.len);
+	if (m->m_len < sizeof(struct ieee80211_frame)) {
+		IEEE80211_DISCARD_MAC(ic, IEEE80211_MSG_ANY, ni->ni_macaddr,
+		    "mgt", "too short: len %u", m->m_len);
 		ic->ic_stats.is_rx_tooshort++;
 		goto out;
 	}
@@ -542,10 +540,10 @@ ieee80211_input(struct ieee80211com *ic,
 	if (ic->ic_opmode == IEEE80211_M_MONITOR)
 		goto out;
 
-	if (m->m_pkthdr.len < sizeof(struct ieee80211_frame_min)) {
+	if (m->m_len < sizeof(struct ieee80211_frame_min)) {
 		IEEE80211_DISCARD_MAC(ic, IEEE80211_MSG_ANY,
 		    ni->ni_macaddr, NULL,
-		    "too short (1): len %u", m->m_pkthdr.len);
+		    "too short (1): len %u", m->m_len);
 		ic->ic_stats.is_rx_tooshort++;
 		goto out;
 	}
@@ -607,11 +605,11 @@ ieee80211_input(struct ieee80211com *ic,
 			else if (type == IEEE80211_FC0_TYPE_CTL)
 				bssid = wh->i_addr1;
 			else {
-				if (m->m_pkthdr.len < sizeof(struct ieee80211_frame)) {
+				if (m->m_len < sizeof(struct ieee80211_frame)) {
 					IEEE80211_DISCARD_MAC(ic,
 					    IEEE80211_MSG_ANY, ni->ni_macaddr,
 					    NULL, "too short (2): len %u",
-					    m->m_pkthdr.len);
+					    m->m_len);
 					ic->ic_stats.is_rx_tooshort++;
 					goto out;
 				}
@@ -674,7 +672,14 @@ ieee80211_input(struct ieee80211com *ic,
 			if (ieee80211_has_qos(wh)) {
 				struct ieee80211_qosframe *qosf;
 
-				/* XXX mbuf length check */
+				if (m->m_len < sizeof(struct ieee80211_qosframe)) {
+					IEEE80211_DISCARD_MAC(ic,
+					    IEEE80211_MSG_ANY,
+					    ni->ni_macaddr, NULL,
+					    "too short (1): len %u", m->m_len);
+					ic->ic_stats.is_rx_tooshort++;
+					goto out;
+				}
 				qosf = mtod(m, struct ieee80211_qosframe *);
 
 				tid = qosf->i_qos[0] & IEEE80211_QOS_TID;
@@ -1089,6 +1094,7 @@ ieee80211_auth_open(struct ieee80211com 
 		    ni->ni_macaddr, "open auth",
 		    "bad sta auth mode %u", ni->ni_authmode);
 		ic->ic_stats.is_rx_bad_auth++;	/* XXX */
+
 		if (ic->ic_opmode == IEEE80211_M_HOSTAP) {
 			/* XXX hack to workaround calling convention */
 			ieee80211_send_error(ic, ni, wh->i_addr2,
@@ -1097,6 +1103,7 @@ ieee80211_auth_open(struct ieee80211com 
 		}
 		return;
 	}
+
 	switch (ic->ic_opmode) {
 	case IEEE80211_M_IBSS:
 	case IEEE80211_M_AHDEMO:
@@ -1114,13 +1121,16 @@ ieee80211_auth_open(struct ieee80211com 
 			ic->ic_stats.is_rx_bad_auth++;
 			return;
 		}
+
 		/* always accept open authentication requests */
 		if (ni == ic->ic_bss) {
 			ni = ieee80211_dup_bss(&ic->ic_sta, wh->i_addr2);
 			if (ni == NULL)
 				return;
-		} else if ((ni->ni_flags & IEEE80211_NODE_AREF) == 0)
-			(void) ieee80211_ref_node(ni);
+		} else if ((ni->ni_flags & IEEE80211_NODE_AREF) == 0) {
+			(void)ieee80211_ref_node(ni);
+		}
+
 		/*
 		 * Mark the node as referenced to reflect that its
 		 * reference count has been bumped to insure it remains
@@ -1128,11 +1138,12 @@ ieee80211_auth_open(struct ieee80211com 
 		 */
 		ni->ni_flags |= IEEE80211_NODE_AREF;
 
-		IEEE80211_SEND_MGMT(ic, ni,
-			IEEE80211_FC0_SUBTYPE_AUTH, seq + 1);
+		IEEE80211_SEND_MGMT(ic, ni, IEEE80211_FC0_SUBTYPE_AUTH,
+		    seq + 1);
 		IEEE80211_DPRINTF(ic, IEEE80211_MSG_DEBUG | IEEE80211_MSG_AUTH,
 		    "[%s] station authenticated (open)\n",
 		    ether_snprintf(ebuf, sizeof(ebuf), ni->ni_macaddr));
+
 		/*
 		 * When 802.1x is not in use mark the port
 		 * authorized at this point so traffic can flow.
@@ -1149,20 +1160,22 @@ ieee80211_auth_open(struct ieee80211com 
 			return;
 		}
 		if (status != 0) {
-
 			IEEE80211_DPRINTF(ic,
 			    IEEE80211_MSG_DEBUG | IEEE80211_MSG_AUTH,
 			    "[%s] open auth failed (reason %d)\n",
 			    ether_snprintf(ebuf, sizeof(ebuf), ni->ni_macaddr),
 			    status);
+
 			/* XXX can this happen? */
 			if (ni != ic->ic_bss)
 				ni->ni_fails++;
+
 			ic->ic_stats.is_rx_auth_fail++;
 			ieee80211_new_state(ic, IEEE80211_S_SCAN, 0);
-		} else
+		} else {
 			ieee80211_new_state(ic, IEEE80211_S_ASSOC,
 			    wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK);
+		}
 		break;
 	}
 }
@@ -1176,9 +1189,9 @@ ieee80211_auth_open(struct ieee80211com 
  */
 static void
 ieee80211_send_error(struct ieee80211com *ic, struct ieee80211_node *ni,
-	const u_int8_t *mac, int subtype, int arg)
+    const u_int8_t *mac, int subtype, int arg)
 {
-	int istmp;
+	bool istmp;
 
 	if (ni == ic->ic_bss) {
 		ni = ieee80211_tmp_node(ic, mac);
@@ -1186,9 +1199,11 @@ ieee80211_send_error(struct ieee80211com
 			/* XXX msg */
 			return;
 		}
-		istmp = 1;
-	} else
-		istmp = 0;
+		istmp = true;
+	} else {
+		istmp = false;
+	}
+
 	IEEE80211_SEND_MGMT(ic, ni, subtype, arg);
 	if (istmp)
 		ieee80211_free_node(ni);
@@ -1197,11 +1212,12 @@ ieee80211_send_error(struct ieee80211com
 static int
 alloc_challenge(struct ieee80211com *ic, struct ieee80211_node *ni)
 {
-	if (ni->ni_challenge == NULL)
+	if (ni->ni_challenge == NULL) {
 		ni->ni_challenge = malloc(IEEE80211_CHALLENGE_LEN,
 		    M_DEVBUF, M_NOWAIT);
+	}
 	if (ni->ni_challenge == NULL) {
-		 IEEE80211_DEBUGVAR(char ebuf[3 * ETHER_ADDR_LEN]);
+		IEEE80211_DEBUGVAR(char ebuf[3 * ETHER_ADDR_LEN]);
 
 		IEEE80211_DPRINTF(ic, IEEE80211_MSG_DEBUG | IEEE80211_MSG_AUTH,
 		    "[%s] shared key challenge alloc failed\n",
@@ -1236,6 +1252,7 @@ ieee80211_auth_shared(struct ieee80211co
 		estatus = IEEE80211_STATUS_ALG;
 		goto bad;
 	}
+
 	/*
 	 * Pre-shared key authentication is evil; accept
 	 * it only if explicitly configured (it is supported
@@ -1266,6 +1283,7 @@ ieee80211_auth_shared(struct ieee80211co
 			challenge = frm;
 		frm += frm[1] + 2;
 	}
+
 	switch (seq) {
 	case IEEE80211_AUTH_SHARED_CHALLENGE:
 	case IEEE80211_AUTH_SHARED_RESPONSE:
@@ -1288,6 +1306,7 @@ ieee80211_auth_shared(struct ieee80211co
 	default:
 		break;
 	}
+
 	switch (ic->ic_opmode) {
 	case IEEE80211_M_MONITOR:
 	case IEEE80211_M_AHDEMO:
@@ -1296,6 +1315,7 @@ ieee80211_auth_shared(struct ieee80211co
 		    ni->ni_macaddr, "shared key auth",
 		    "bad operating mode %u", ic->ic_opmode);
 		return;
+
 	case IEEE80211_M_HOSTAP:
 #ifndef IEEE80211_NO_HOSTAP
 	{
@@ -1318,10 +1338,11 @@ ieee80211_auth_shared(struct ieee80211co
 				allocbs = 1;
 			} else {
 				if ((ni->ni_flags & IEEE80211_NODE_AREF) == 0)
-					(void) ieee80211_ref_node(ni);
+					(void)ieee80211_ref_node(ni);
 				allocbs = 0;
 			}
 			__USE(allocbs);
+
 			/*
 			 * Mark the node as referenced to reflect that its
 			 * reference count has been bumped to insure it remains
@@ -1334,8 +1355,10 @@ ieee80211_auth_shared(struct ieee80211co
 				/* NB: don't return error so they rexmit */
 				return;
 			}
+
 			get_random_bytes(ni->ni_challenge,
 				IEEE80211_CHALLENGE_LEN);
+
 			IEEE80211_DPRINTF(ic,
 				IEEE80211_MSG_DEBUG | IEEE80211_MSG_AUTH,
 				"[%s] shared key %sauth request\n",
@@ -1343,6 +1366,7 @@ ieee80211_auth_shared(struct ieee80211co
 				ni->ni_macaddr),
 				allocbs ? "" : "re");
 			break;
+
 		case IEEE80211_AUTH_SHARED_RESPONSE:
 			if (ni == ic->ic_bss) {
 				IEEE80211_DISCARD_MAC(ic, IEEE80211_MSG_AUTH,
@@ -1351,6 +1375,7 @@ ieee80211_auth_shared(struct ieee80211co
 				/* NB: don't send a response */
 				return;
 			}
+
 			if (ni->ni_challenge == NULL) {
 				IEEE80211_DISCARD_MAC(ic, IEEE80211_MSG_AUTH,
 				    ni->ni_macaddr, "shared key response",
@@ -1359,8 +1384,9 @@ ieee80211_auth_shared(struct ieee80211co
 				estatus = IEEE80211_STATUS_CHALLENGE;
 				goto bad;
 			}
+
 			if (memcmp(ni->ni_challenge, &challenge[2],
-			           challenge[1]) != 0) {
+			    challenge[1]) != 0) {
 				IEEE80211_DISCARD_MAC(ic, IEEE80211_MSG_AUTH,
 				    ni->ni_macaddr, "shared key response",
 				    "%s", "challenge mismatch");
@@ -1368,12 +1394,15 @@ ieee80211_auth_shared(struct ieee80211co
 				estatus = IEEE80211_STATUS_CHALLENGE;
 				goto bad;
 			}
+
 			IEEE80211_DPRINTF(ic,
 			    IEEE80211_MSG_DEBUG | IEEE80211_MSG_AUTH,
 			    "[%s] station authenticated (shared key)\n",
 			    ether_snprintf(ebuf, sizeof(ebuf), ni->ni_macaddr));
+
 			ieee80211_node_authorize(ni);
 			break;
+
 		default:
 			IEEE80211_DISCARD_MAC(ic, IEEE80211_MSG_AUTH,
 			    ni->ni_macaddr, "shared key auth",
@@ -1382,8 +1411,9 @@ ieee80211_auth_shared(struct ieee80211co
 			estatus = IEEE80211_STATUS_SEQUENCE;
 			goto bad;
 		}
-		IEEE80211_SEND_MGMT(ic, ni,
-			IEEE80211_FC0_SUBTYPE_AUTH, seq + 1);
+
+		IEEE80211_SEND_MGMT(ic, ni, IEEE80211_FC0_SUBTYPE_AUTH,
+		    seq + 1);
 	}
 #endif /* !IEEE80211_NO_HOSTAP */
 		break;
@@ -1404,23 +1434,29 @@ ieee80211_auth_shared(struct ieee80211co
 				    ether_snprintf(ebuf, sizeof(ebuf),
 				    ieee80211_getbssid(ic, wh)),
 				    status);
+
 				/* XXX can this happen? */
 				if (ni != ic->ic_bss)
 					ni->ni_fails++;
+
 				ic->ic_stats.is_rx_auth_fail++;
 				return;
 			}
+
 			ieee80211_new_state(ic, IEEE80211_S_ASSOC,
 			    wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK);
 			break;
+
 		case IEEE80211_AUTH_SHARED_CHALLENGE:
 			if (!alloc_challenge(ic, ni))
 				return;
 			/* XXX could optimize by passing recvd challenge */
 			memcpy(ni->ni_challenge, &challenge[2], challenge[1]);
-			IEEE80211_SEND_MGMT(ic, ni,
-				IEEE80211_FC0_SUBTYPE_AUTH, seq + 1);
+
+			IEEE80211_SEND_MGMT(ic, ni, IEEE80211_FC0_SUBTYPE_AUTH,
+			    seq + 1);
 			break;
+
 		default:
 			IEEE80211_DISCARD(ic, IEEE80211_MSG_AUTH,
 			    wh, "shared key auth", "bad seq %d", seq);
@@ -1430,6 +1466,7 @@ ieee80211_auth_shared(struct ieee80211co
 		break;
 	}
 	return;
+
 bad:
 #ifndef IEEE80211_NO_HOSTAP
 	/*
@@ -1589,30 +1626,34 @@ wpa_keymgmt(u_int8_t *sel)
  */
 static int
 ieee80211_parse_wpa(struct ieee80211com *ic, u_int8_t *frm,
-	struct ieee80211_rsnparms *rsn, const struct ieee80211_frame *wh)
+    struct ieee80211_rsnparms *rsn, const struct ieee80211_frame *wh)
 {
 	u_int8_t len = frm[1];
 	u_int32_t w;
 	int n;
 
-	/*
-	 * Check the length once for fixed parts: OUI, type,
-	 * version, mcast cipher, and 2 selector counts.
-	 * Other, variable-length data, must be checked separately.
-	 */
 	if ((ic->ic_flags & IEEE80211_F_WPA1) == 0) {
 		IEEE80211_DISCARD_IE(ic,
 		    IEEE80211_MSG_ELEMID | IEEE80211_MSG_WPA,
 		    wh, "WPA", "not WPA, flags 0x%x", ic->ic_flags);
 		return IEEE80211_REASON_IE_INVALID;
 	}
+
+	/*
+	 * Check the length once for fixed parts: OUI, type,
+	 * version, mcast cipher, and 2 selector counts.
+	 * Other, variable-length data, must be checked separately.
+	 */
 	if (len < 14) {
 		IEEE80211_DISCARD_IE(ic,
 		    IEEE80211_MSG_ELEMID | IEEE80211_MSG_WPA,
 		    wh, "WPA", "too short, len %u", len);
 		return IEEE80211_REASON_IE_INVALID;
 	}
-	frm += 6, len -= 4;		/* NB: len is payload only */
+
+	frm += 2; /* beginning of payload */
+	frm += 4, len -= 4;
+
 	/* NB: iswapoui already validated the OUI and type */
 	w = LE_READ_2(frm);
 	if (w != WPA_VERSION) {
@@ -1646,7 +1687,7 @@ ieee80211_parse_wpa(struct ieee80211com 
 	}
 	w = 0;
 	for (; n > 0; n--) {
-		w |= 1<<wpa_cipher(frm, &rsn->rsn_ucastkeylen);
+		w |= 1 << wpa_cipher(frm, &rsn->rsn_ucastkeylen);
 		frm += 4, len -= 4;
 	}
 	w &= rsn->rsn_ucastcipherset;
@@ -1656,7 +1697,7 @@ ieee80211_parse_wpa(struct ieee80211com 
 		    wh, "WPA", "%s", "ucast cipher set empty");
 		return IEEE80211_REASON_IE_INVALID;
 	}
-	if (w & (1<<IEEE80211_CIPHER_TKIP))
+	if (w & (1 << IEEE80211_CIPHER_TKIP))
 		rsn->rsn_ucastcipher = IEEE80211_CIPHER_TKIP;
 	else
 		rsn->rsn_ucastcipher = IEEE80211_CIPHER_AES_CCM;
@@ -1756,30 +1797,32 @@ rsn_keymgmt(u_int8_t *sel)
  */
 static int
 ieee80211_parse_rsn(struct ieee80211com *ic, u_int8_t *frm,
-	struct ieee80211_rsnparms *rsn, const struct ieee80211_frame *wh)
+    struct ieee80211_rsnparms *rsn, const struct ieee80211_frame *wh)
 {
 	u_int8_t len = frm[1];
 	u_int32_t w;
 	int n;
 
-	/*
-	 * Check the length once for fixed parts:
-	 * version, mcast cipher, and 2 selector counts.
-	 * Other, variable-length data, must be checked separately.
-	 */
 	if ((ic->ic_flags & IEEE80211_F_WPA2) == 0) {
 		IEEE80211_DISCARD_IE(ic,
 		    IEEE80211_MSG_ELEMID | IEEE80211_MSG_WPA,
 		    wh, "WPA", "not RSN, flags 0x%x", ic->ic_flags);
 		return IEEE80211_REASON_IE_INVALID;
 	}
+
+	/*
+	 * Check the length once for fixed parts:
+	 * version, mcast cipher, and 2 selector counts.
+	 * Other, variable-length data, must be checked separately.
+	 */
 	if (len < 10) {
 		IEEE80211_DISCARD_IE(ic,
 		    IEEE80211_MSG_ELEMID | IEEE80211_MSG_WPA,
 		    wh, "RSN", "too short, len %u", len);
 		return IEEE80211_REASON_IE_INVALID;
 	}
-	frm += 2;
+
+	frm += 2; /* beginning of payload */
 	w = LE_READ_2(frm);
 	if (w != RSN_VERSION) {
 		IEEE80211_DISCARD_IE(ic,
@@ -1812,7 +1855,7 @@ ieee80211_parse_rsn(struct ieee80211com 
 	}
 	w = 0;
 	for (; n > 0; n--) {
-		w |= 1<<rsn_cipher(frm, &rsn->rsn_ucastkeylen);
+		w |= 1 << rsn_cipher(frm, &rsn->rsn_ucastkeylen);
 		frm += 4, len -= 4;
 	}
 	w &= rsn->rsn_ucastcipherset;
@@ -1822,7 +1865,7 @@ ieee80211_parse_rsn(struct ieee80211com 
 		    wh, "RSN", "%s", "ucast cipher set empty");
 		return IEEE80211_REASON_IE_INVALID;
 	}
-	if (w & (1<<IEEE80211_CIPHER_TKIP))
+	if (w & (1 << IEEE80211_CIPHER_TKIP))
 		rsn->rsn_ucastcipher = IEEE80211_CIPHER_TKIP;
 	else
 		rsn->rsn_ucastcipher = IEEE80211_CIPHER_AES_CCM;
@@ -1864,7 +1907,7 @@ ieee80211_parse_rsn(struct ieee80211com 
 
 static int
 ieee80211_parse_wmeparams(struct ieee80211com *ic, u_int8_t *frm,
-	const struct ieee80211_frame *wh)
+    const struct ieee80211_frame *wh)
 {
 #define	MS(_v, _f)	(((_v) & _f) >> _f##_S)
 	struct ieee80211_wme_state *wme = &ic->ic_wme;
@@ -1907,9 +1950,8 @@ void
 ieee80211_saveie(u_int8_t **iep, const u_int8_t *ie)
 {
 	u_int ielen = ie[1]+2;
-	/*
-	 * Record information element for later use.
-	 */
+
+	/* Record information element for later use. */
 	if (*iep == NULL || (*iep)[1] != ie[1]) {
 		if (*iep != NULL)
 			free(*iep, M_DEVBUF);
@@ -2004,7 +2046,7 @@ ieee80211_update_adhoc_node(struct ieee8
 } while (0)
 
 #define	IEEE80211_VERIFY_LENGTH(_len, _minlen) do {			\
-	if ((_len) < (_minlen)) {					\
+	if ((size_t)(_len) < (size_t)(_minlen)) {			\
 		IEEE80211_DISCARD(ic, IEEE80211_MSG_ELEMID,		\
 		    wh, ieee80211_mgt_subtype_name[subtype >>		\
 			IEEE80211_FC0_SUBTYPE_SHIFT],			\
@@ -2106,12 +2148,6 @@ ieee80211_recv_mgmt_beacon(struct ieee80
 		case IEEE80211_ELEMID_IBSSPARMS:
 			break;
 		case IEEE80211_ELEMID_XRATES:
-			if (frm[1] > IEEE80211_RATE_MAXSIZE) {
-				IEEE80211_DISCARD_IE(ic, IEEE80211_MSG_ELEMID,
-				    wh, "XRATE", "bad len %u", frm[1]);
-				ic->ic_stats.is_rx_elem_toobig++;
-				break;
-			}
 			scan.sp_xrates = frm;
 			break;
 		case IEEE80211_ELEMID_ERP:
@@ -2225,11 +2261,13 @@ ieee80211_recv_mgmt_beacon(struct ieee80
 			    "[%s] erp change: was 0x%x, now 0x%x\n",
 			    ether_snprintf(ebuf, sizeof(ebuf),
 			    wh->i_addr2), ni->ni_erp, scan.sp_erp);
+
 			if (ic->ic_curmode == IEEE80211_MODE_11G &&
-			    (ni->ni_erp & IEEE80211_ERP_USE_PROTECTION))
+			    (ni->ni_erp & IEEE80211_ERP_USE_PROTECTION)) {
 				ic->ic_flags |= IEEE80211_F_USEPROT;
-			else
+			} else {
 				ic->ic_flags &= ~IEEE80211_F_USEPROT;
+			}
 			ni->ni_erp = scan.sp_erp;
 		}
 
@@ -2304,7 +2342,7 @@ ieee80211_recv_mgmt_probe_req(struct iee
 	struct ieee80211_frame *wh;
 	u_int8_t *frm, *efrm;
 	u_int8_t *ssid, *rates, *xrates;
-	int allocbs;
+	bool need_free = false;
 	u_int8_t rate;
 	IEEE80211_DEBUGVAR(char ebuf[3 * ETHER_ADDR_LEN]);
 
@@ -2319,7 +2357,7 @@ ieee80211_recv_mgmt_probe_req(struct iee
 	}
 	if (IEEE80211_IS_MULTICAST(wh->i_addr2)) {
 		/* frame must be directed */
-		ic->ic_stats.is_rx_mgtdiscard++;	/* XXX stat */
+		ic->ic_stats.is_rx_mgtdiscard++;
 		return;
 	}
 
@@ -2330,7 +2368,9 @@ ieee80211_recv_mgmt_probe_req(struct iee
 	 *	[tlv] extended supported rates
 	 */
 	ssid = rates = xrates = NULL;
-	while (frm < efrm) {
+	while (frm + 1 < efrm) {
+		IEEE80211_VERIFY_LENGTH(efrm - frm, frm[1] + 2);
+
 		switch (*frm) {
 		case IEEE80211_ELEMID_SSID:
 			ssid = frm;
@@ -2342,6 +2382,7 @@ ieee80211_recv_mgmt_probe_req(struct iee
 			xrates = frm;
 			break;
 		}
+
 		frm += frm[1] + 2;
 	}
 
@@ -2361,6 +2402,7 @@ ieee80211_recv_mgmt_probe_req(struct iee
 	if (ni == ic->ic_bss) {
 		if (ic->ic_opmode != IEEE80211_M_IBSS) {
 			ni = ieee80211_tmp_node(ic, wh->i_addr2);
+			need_free = true;
 		} else if (IEEE80211_ADDR_EQ(wh->i_addr2, ni->ni_macaddr)) {
 			;
 		} else {
@@ -2375,9 +2417,6 @@ ieee80211_recv_mgmt_probe_req(struct iee
 		}
 		if (ni == NULL)
 			return;
-		allocbs = 1;
-	} else {
-		allocbs = 0;
 	}
 
 	IEEE80211_DPRINTF(ic, IEEE80211_MSG_ASSOC, "[%s] recv probe req\n",
@@ -2386,8 +2425,8 @@ ieee80211_recv_mgmt_probe_req(struct iee
 	ni->ni_rssi = rssi;
 	ni->ni_rstamp = rstamp;
 	rate = ieee80211_setup_rates(ni, rates, xrates,
-		  IEEE80211_R_DOSORT | IEEE80211_R_DOFRATE
-		| IEEE80211_R_DONEGO | IEEE80211_R_DODEL);
+	    IEEE80211_R_DOSORT | IEEE80211_R_DOFRATE |
+	    IEEE80211_R_DONEGO | IEEE80211_R_DODEL);
 
 	if (rate & IEEE80211_RATE_BASIC) {
 		IEEE80211_DISCARD(ic, IEEE80211_MSG_XRATE,
@@ -2399,7 +2438,7 @@ ieee80211_recv_mgmt_probe_req(struct iee
 		    IEEE80211_FC0_SUBTYPE_PROBE_RESP, 0);
 	}
 
-	if (allocbs && ic->ic_opmode != IEEE80211_M_IBSS) {
+	if (need_free) {
 		/* reclaim immediately */
 		ieee80211_free_node(ni);
 	}
@@ -2464,13 +2503,12 @@ ieee80211_recv_mgmt_auth(struct ieee8021
 		return;
 	}
 
-	if (algo == IEEE80211_AUTH_ALG_SHARED)
+	if (algo == IEEE80211_AUTH_ALG_SHARED) {
 		ieee80211_auth_shared(ic, wh, frm + 6, efrm, ni, rssi,
 		    rstamp, seq, status);
-	else if (algo == IEEE80211_AUTH_ALG_OPEN)
-		ieee80211_auth_open(ic, wh, ni, rssi, rstamp, seq,
-		    status);
-	else {
+	} else if (algo == IEEE80211_AUTH_ALG_OPEN) {
+		ieee80211_auth_open(ic, wh, ni, rssi, rstamp, seq, status);
+	} else {
 		IEEE80211_DISCARD(ic, IEEE80211_MSG_ANY,
 		    wh, "auth", "unsupported alg %d", algo);
 		ic->ic_stats.is_rx_auth_unsupported++;
@@ -2482,7 +2520,6 @@ ieee80211_recv_mgmt_auth(struct ieee8021
 				(seq+1) | (IEEE80211_STATUS_ALG<<16));
 		}
 #endif
-		return;
 	}
 }
 
@@ -2529,6 +2566,7 @@ ieee80211_recv_mgmt_assoc_req(struct iee
 	 *	[tlv] WPA or RSN
 	 */
 	IEEE80211_VERIFY_LENGTH(efrm - frm, (reassoc ? 10 : 4));
+
 	if (!IEEE80211_ADDR_EQ(wh->i_addr3, ic->ic_bss->ni_bssid)) {
 		IEEE80211_DISCARD(ic, IEEE80211_MSG_ANY,
 		    wh, ieee80211_mgt_subtype_name[subtype >>
@@ -2544,7 +2582,9 @@ ieee80211_recv_mgmt_assoc_req(struct iee
 		frm += 6;	/* ignore current AP info */
 
 	ssid = rates = xrates = wpa = wme = NULL;
-	while (frm < efrm) {
+	while (frm + 1 < efrm) {
+		IEEE80211_VERIFY_LENGTH(efrm - frm, frm[1] + 2);
+
 		switch (*frm) {
 		case IEEE80211_ELEMID_SSID:
 			ssid = frm;
@@ -2567,6 +2607,7 @@ ieee80211_recv_mgmt_assoc_req(struct iee
 			/* XXX Atheros OUI support */
 			break;
 		}
+
 		frm += frm[1] + 2;
 	}
 
@@ -2586,16 +2627,18 @@ ieee80211_recv_mgmt_assoc_req(struct iee
 		return;
 	}
 
-	/* assert right associstion security credentials */
+	/* assert right association security credentials */
 	if (wpa == NULL && (ic->ic_flags & IEEE80211_F_WPA)) {
 		IEEE80211_DPRINTF(ic,
 		    IEEE80211_MSG_ASSOC | IEEE80211_MSG_WPA,
 		    "[%s] no WPA/RSN IE in association request\n",
 		    ether_snprintf(ebuf, sizeof(ebuf), wh->i_addr2));
+
 		IEEE80211_SEND_MGMT(ic, ni,
 		    IEEE80211_FC0_SUBTYPE_DEAUTH,
 		    IEEE80211_REASON_RSN_REQUIRED);
 		ieee80211_node_leave(ic, ni);
+
 		/* XXX distinguish WPA/RSN? */
 		ic->ic_stats.is_rx_assoc_badwpaie++;
 		return;
@@ -2614,14 +2657,17 @@ ieee80211_recv_mgmt_assoc_req(struct iee
 			reason = ieee80211_parse_wpa(ic, wpa, &rsn, wh);
 		else
 			reason = ieee80211_parse_rsn(ic, wpa, &rsn, wh);
+
 		if (reason != 0) {
 			IEEE80211_SEND_MGMT(ic, ni,
 			    IEEE80211_FC0_SUBTYPE_DEAUTH, reason);
 			ieee80211_node_leave(ic, ni);
+
 			/* XXX distinguish WPA/RSN? */
 			ic->ic_stats.is_rx_assoc_badwpaie++;
 			return;
 		}
+
 		IEEE80211_DPRINTF(ic,
 		    IEEE80211_MSG_ASSOC | IEEE80211_MSG_WPA,
 		    "[%s] %s ie: mc %u/%u uc %u/%u key %u caps 0x%x\n",
@@ -2726,7 +2772,7 @@ ieee80211_recv_mgmt_assoc_resp(struct ie
 {
 	struct ieee80211_frame *wh;
 	u_int8_t *frm, *efrm;
-	u_int8_t *rates, *xrates, *wpa, *wme;
+	u_int8_t *rates, *xrates, *wme;
 	u_int8_t rate;
 	IEEE80211_DEBUGVAR(char ebuf[3 * ETHER_ADDR_LEN]);
 	u_int16_t capinfo, associd;
@@ -2770,8 +2816,10 @@ ieee80211_recv_mgmt_assoc_resp(struct ie
 	associd = le16toh(*(u_int16_t *)frm);
 	frm += 2;
 
-	rates = xrates = wpa = wme = NULL;
-	while (frm < efrm) {
+	rates = xrates = wme = NULL;
+	while (frm + 1 < efrm) {
+		IEEE80211_VERIFY_LENGTH(efrm - frm, frm[1] + 2);
+
 		switch (*frm) {
 		case IEEE80211_ELEMID_RATES:
 			rates = frm;
@@ -2785,13 +2833,16 @@ ieee80211_recv_mgmt_assoc_resp(struct ie
 			/* XXX Atheros OUI support */
 			break;
 		}
+
 		frm += frm[1] + 2;
 	}
 
 	IEEE80211_VERIFY_ELEMENT(rates, IEEE80211_RATE_MAXSIZE);
+
 	rate = ieee80211_setup_rates(ni, rates, xrates,
-			IEEE80211_R_DOSORT | IEEE80211_R_DOFRATE |
-			IEEE80211_R_DONEGO | IEEE80211_R_DODEL);
+	    IEEE80211_R_DOSORT | IEEE80211_R_DOFRATE |
+	    IEEE80211_R_DONEGO | IEEE80211_R_DODEL);
+
 	if (rate & IEEE80211_RATE_BASIC) {
 		IEEE80211_DPRINTF(ic, IEEE80211_MSG_ASSOC,
 		    "[%s] %sassoc failed (rate set mismatch)\n",
@@ -2806,8 +2857,7 @@ ieee80211_recv_mgmt_assoc_resp(struct ie
 
 	ni->ni_capinfo = capinfo;
 	ni->ni_associd = associd;
-	if (wme != NULL &&
-	    ieee80211_parse_wmeparams(ic, wme, wh) >= 0) {
+	if (wme != NULL && ieee80211_parse_wmeparams(ic, wme, wh) >= 0) {
 		ni->ni_flags |= IEEE80211_NODE_QOS;
 		ieee80211_wme_updateparams(ic);
 	} else {
@@ -2838,10 +2888,11 @@ ieee80211_recv_mgmt_assoc_resp(struct ie
 	 * XXX check ic_curmode anyway?
 	 */
 	if (ic->ic_curmode == IEEE80211_MODE_11G &&
-	    (ni->ni_erp & IEEE80211_ERP_USE_PROTECTION))
+	    (ni->ni_erp & IEEE80211_ERP_USE_PROTECTION)) {
 		ic->ic_flags |= IEEE80211_F_USEPROT;
-	else
+	} else {
 		ic->ic_flags &= ~IEEE80211_F_USEPROT;
+	}
 
 	IEEE80211_DPRINTF(ic, IEEE80211_MSG_ASSOC,
 	    "[%s] %sassoc success: %s preamble, %s slot time%s%s\n",
@@ -3060,16 +3111,19 @@ ieee80211_node_pwrsave(struct ieee80211_
 			ic->ic_set_tim(ni, 0);		/* just in case */
 		return;
 	}
+
 	IEEE80211_DPRINTF(ic, IEEE80211_MSG_POWER,
 	    "[%s] flush ps queue, %u packets queued\n",
 	    ether_snprintf(ebuf, sizeof(ebuf), ni->ni_macaddr),
 	    IEEE80211_NODE_SAVEQ_QLEN(ni));
+
 	for (;;) {
 		int qlen;
 
 		IEEE80211_NODE_SAVEQ_DEQUEUE(ni, m, qlen);
 		if (m == NULL)
 			break;
+
 		/*
 		 * If this is the last packet, turn off the TIM bit.
 		 * If there are more packets, set the more packets bit
@@ -3078,10 +3132,12 @@ ieee80211_node_pwrsave(struct ieee80211_
 		 */
 		if (qlen != 0)
 			m->m_flags |= M_MORE_DATA;
+
 		/* XXX need different driver interface */
 		/* XXX bypasses q max */
 		IF_ENQUEUE(&ic->ic_ifp->if_snd, m);
 	}
+
 	if (ic->ic_set_tim != NULL)
 		ic->ic_set_tim(ni, 0);
 }
@@ -3090,8 +3146,8 @@ ieee80211_node_pwrsave(struct ieee80211_
  * Process a received ps-poll frame.
  */
 static void
-ieee80211_recv_pspoll(struct ieee80211com *ic,
-	struct ieee80211_node *ni, struct mbuf *m0)
+ieee80211_recv_pspoll(struct ieee80211com *ic, struct ieee80211_node *ni,
+    struct mbuf *m0)
 {
 	struct ieee80211_frame_min *wh;
 	struct mbuf *m;
@@ -3102,7 +3158,7 @@ ieee80211_recv_pspoll(struct ieee80211co
 	wh = mtod(m0, struct ieee80211_frame_min *);
 	if (ni->ni_associd == 0) {
 		IEEE80211_DISCARD(ic, IEEE80211_MSG_POWER | IEEE80211_MSG_DEBUG,
-		    (struct ieee80211_frame *) wh, "ps-poll",
+		    (struct ieee80211_frame *)wh, "ps-poll",
 		    "%s", "unassociated station");
 		ic->ic_stats.is_ps_unassoc++;
 		IEEE80211_SEND_MGMT(ic, ni, IEEE80211_FC0_SUBTYPE_DEAUTH,
@@ -3113,7 +3169,7 @@ ieee80211_recv_pspoll(struct ieee80211co
 	aid = le16toh(*(u_int16_t *)wh->i_dur);
 	if (aid != ni->ni_associd) {
 		IEEE80211_DISCARD(ic, IEEE80211_MSG_POWER | IEEE80211_MSG_DEBUG,
-		    (struct ieee80211_frame *) wh, "ps-poll",
+		    (struct ieee80211_frame *)wh, "ps-poll",
 		    "aid mismatch: sta aid 0x%x poll aid 0x%x",
 		    ni->ni_associd, aid);
 		ic->ic_stats.is_ps_badaid++;
@@ -3134,6 +3190,7 @@ ieee80211_recv_pspoll(struct ieee80211co
 			ic->ic_set_tim(ni, 0);	/* just in case */
 		return;
 	}
+
 	/*
 	 * If there are more packets, set the more packets bit
 	 * in the packet dispatched to the station; otherwise
@@ -3151,6 +3208,7 @@ ieee80211_recv_pspoll(struct ieee80211co
 		if (ic->ic_set_tim != NULL)
 			ic->ic_set_tim(ni, 0);
 	}
+
 	m->m_flags |= M_PWR_SAV;		/* bypass PS handling */
 	IF_ENQUEUE(&ic->ic_ifp->if_snd, m);
 }

Reply via email to