Module Name: src
Committed By: maxv
Date: Thu Jan 18 13:24:01 UTC 2018
Modified Files:
src/sys/net80211: ieee80211_output.c
Log Message:
Several changes:
* Make the code more readable. In particular, declare variables as const
along the way.
* Explain what we're doing in ieee80211_send_mgmt(). The
IEEE80211_FC0_SUBTYPE_PROBE_RESP case has some inconsistencies, but
they are not inherently wrong so I'm not changing that.
* When sending IEEE80211_FC0_SUBTYPE_REASSOC_RESP frames, make sure to
zero out the 'association ID', otherwise two bytes are leaked.
* Fix a possible memory leak in ieee80211_send_probereq().
To generate a diff of this commit:
cvs rdiff -u -r1.59 -r1.60 src/sys/net80211/ieee80211_output.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_output.c
diff -u src/sys/net80211/ieee80211_output.c:1.59 src/sys/net80211/ieee80211_output.c:1.60
--- src/sys/net80211/ieee80211_output.c:1.59 Tue Sep 26 07:42:06 2017
+++ src/sys/net80211/ieee80211_output.c Thu Jan 18 13:24:01 2018
@@ -1,5 +1,6 @@
-/* $NetBSD: ieee80211_output.c,v 1.59 2017/09/26 07:42:06 knakahara Exp $ */
-/*-
+/* $NetBSD: ieee80211_output.c,v 1.60 2018/01/18 13:24:01 maxv Exp $ */
+
+/*
* Copyright (c) 2001 Atsushi Onoe
* Copyright (c) 2002-2005 Sam Leffler, Errno Consulting
* All rights reserved.
@@ -36,7 +37,7 @@
__FBSDID("$FreeBSD: src/sys/net80211/ieee80211_output.c,v 1.34 2005/08/10 16:22:29 sam Exp $");
#endif
#ifdef __NetBSD__
-__KERNEL_RCSID(0, "$NetBSD: ieee80211_output.c,v 1.59 2017/09/26 07:42:06 knakahara Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ieee80211_output.c,v 1.60 2018/01/18 13:24:01 maxv Exp $");
#endif
#ifdef _KERNEL_OPT
@@ -115,6 +116,7 @@ ieee80211_send_setup(struct ieee80211com
#define WH4(wh) ((struct ieee80211_frame_addr4 *)wh)
wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | type;
+
if ((type & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_DATA) {
switch (ic->ic_opmode) {
case IEEE80211_M_STA:
@@ -123,6 +125,7 @@ ieee80211_send_setup(struct ieee80211com
IEEE80211_ADDR_COPY(wh->i_addr2, sa);
IEEE80211_ADDR_COPY(wh->i_addr3, da);
break;
+
case IEEE80211_M_IBSS:
case IEEE80211_M_AHDEMO:
wh->i_fc[1] = IEEE80211_FC1_DIR_NODS;
@@ -130,12 +133,14 @@ ieee80211_send_setup(struct ieee80211com
IEEE80211_ADDR_COPY(wh->i_addr2, sa);
IEEE80211_ADDR_COPY(wh->i_addr3, bssid);
break;
+
case IEEE80211_M_HOSTAP:
wh->i_fc[1] = IEEE80211_FC1_DIR_FROMDS;
IEEE80211_ADDR_COPY(wh->i_addr1, da);
IEEE80211_ADDR_COPY(wh->i_addr2, bssid);
IEEE80211_ADDR_COPY(wh->i_addr3, sa);
break;
+
case IEEE80211_M_MONITOR: /* NB: to quiet compiler */
break;
}
@@ -145,6 +150,7 @@ ieee80211_send_setup(struct ieee80211com
IEEE80211_ADDR_COPY(wh->i_addr2, sa);
IEEE80211_ADDR_COPY(wh->i_addr3, bssid);
}
+
*(u_int16_t *)&wh->i_dur[0] = 0;
/* NB: use non-QoS tid */
*(u_int16_t *)&wh->i_seq[0] =
@@ -187,9 +193,9 @@ ieee80211_mgmt_output(struct ieee80211co
M_SETCTX(m, ni);
wh = mtod(m, struct ieee80211_frame *);
- ieee80211_send_setup(ic, ni, wh,
- IEEE80211_FC0_TYPE_MGT | type,
- ic->ic_myaddr, ni->ni_macaddr, ni->ni_bssid);
+ ieee80211_send_setup(ic, ni, wh, IEEE80211_FC0_TYPE_MGT | type,
+ ic->ic_myaddr, ni->ni_macaddr, ni->ni_bssid);
+
if ((m->m_flags & M_LINK0) != 0 && ni->ni_challenge != NULL) {
m->m_flags &= ~M_LINK0;
IEEE80211_DPRINTF(ic, IEEE80211_MSG_AUTH,
@@ -197,6 +203,7 @@ ieee80211_mgmt_output(struct ieee80211co
ether_sprintf(wh->i_addr1), __func__);
wh->i_fc[1] |= IEEE80211_FC1_WEP;
}
+
#ifdef IEEE80211_DEBUG
/* avoid printing too many frames */
if ((ieee80211_msg_debug(ic) && doprint(ic, type)) ||
@@ -209,6 +216,7 @@ ieee80211_mgmt_output(struct ieee80211co
ieee80211_chan2ieee(ic, ic->ic_curchan));
}
#endif
+
IEEE80211_NODE_STAT(ni, tx_mgmt);
IF_ENQUEUE(&ic->ic_mgtq, m);
if (timer) {
@@ -247,13 +255,17 @@ ieee80211_send_nulldata(struct ieee80211
M_SETCTX(m, ni);
wh = mtod(m, struct ieee80211_frame *);
+
ieee80211_send_setup(ic, ni, wh,
- IEEE80211_FC0_TYPE_DATA | IEEE80211_FC0_SUBTYPE_NODATA,
- ic->ic_myaddr, ni->ni_macaddr, ni->ni_bssid);
+ IEEE80211_FC0_TYPE_DATA | IEEE80211_FC0_SUBTYPE_NODATA,
+ ic->ic_myaddr, ni->ni_macaddr, ni->ni_bssid);
+
/* NB: power management bit is never sent by an AP */
if ((ni->ni_flags & IEEE80211_NODE_PWR_MGT) &&
- ic->ic_opmode != IEEE80211_M_HOSTAP)
+ ic->ic_opmode != IEEE80211_M_HOSTAP) {
wh->i_fc[1] |= IEEE80211_FC1_PWR_MGT;
+ }
+
m->m_len = m->m_pkthdr.len = sizeof(struct ieee80211_frame);
IEEE80211_NODE_STAT(ni, tx_data);
@@ -277,7 +289,8 @@ ieee80211_send_nulldata(struct ieee80211
* applied.
*/
int
-ieee80211_classify(struct ieee80211com *ic, struct mbuf *m, struct ieee80211_node *ni)
+ieee80211_classify(struct ieee80211com *ic, struct mbuf *m,
+ struct ieee80211_node *ni)
{
int v_wme_ac, d_wme_ac, ac;
#ifdef INET
@@ -405,6 +418,7 @@ ieee80211_mbuf_adjust(struct ieee80211co
needed_space += key->wk_cipher->ic_header;
/* XXX frags */
}
+
/*
* We know we are called just before stripping an Ethernet
* header and prepending an LLC header. This means we know
@@ -423,8 +437,10 @@ ieee80211_mbuf_adjust(struct ieee80211co
m_freem(m);
return NULL;
}
+
IASSERT(needed_space <= MHLEN,
("not enough room, need %u got %zu\n", needed_space, MHLEN));
+
/*
* Setup new mbuf to have leading space to prepend the
* 802.11 header and any crypto header bits that are
@@ -451,7 +467,8 @@ ieee80211_mbuf_adjust(struct ieee80211co
n->m_next = m;
m = n;
} else {
- /* We will overwrite the ethernet header in the
+ /*
+ * We will overwrite the ethernet header in the
* 802.11 encapsulation stage. Make sure that it
* is writable.
*/
@@ -539,10 +556,11 @@ ieee80211_encap(struct ieee80211com *ic,
*/
if (ic->ic_flags & IEEE80211_F_PRIVACY) {
if (ic->ic_opmode == IEEE80211_M_STA ||
- !IEEE80211_IS_MULTICAST(eh.ether_dhost))
+ !IEEE80211_IS_MULTICAST(eh.ether_dhost)) {
key = ieee80211_crypto_getucastkey(ic, ni);
- else
+ } else {
key = ieee80211_crypto_getmcastkey(ic, ni);
+ }
if (key == NULL && eh.ether_type != htons(ETHERTYPE_PAE)) {
IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO,
"[%s] no default transmit key (%s) deftxkey %u\n",
@@ -550,10 +568,13 @@ ieee80211_encap(struct ieee80211com *ic,
ic->ic_def_txkey);
ic->ic_stats.is_tx_nodefkey++;
}
- } else
+ } else {
key = NULL;
- /* XXX 4-address format */
+ }
+
/*
+ * XXX 4-address format.
+ *
* XXX Some ap's don't handle QoS-encapsulated EAPOL
* frames so suppress use. This may be an issue if other
* ap's require all data frames to be QoS-encapsulated
@@ -561,13 +582,14 @@ ieee80211_encap(struct ieee80211com *ic,
* configurable.
*/
addqos = (ni->ni_flags & IEEE80211_NODE_QOS) &&
- eh.ether_type != htons(ETHERTYPE_PAE);
+ eh.ether_type != htons(ETHERTYPE_PAE);
if (addqos)
hdrsize = sizeof(struct ieee80211_qosframe);
else
hdrsize = sizeof(struct ieee80211_frame);
if (ic->ic_flags & IEEE80211_F_DATAPAD)
hdrsize = roundup(hdrsize, sizeof(u_int32_t));
+
m = ieee80211_mbuf_adjust(ic, hdrsize, key, m);
if (m == NULL) {
/* NB: ieee80211_mbuf_adjust handles msgs+statistics */
@@ -590,9 +612,11 @@ ieee80211_encap(struct ieee80211com *ic,
ic->ic_stats.is_tx_nobuf++;
goto bad;
}
+
wh = mtod(m, struct ieee80211_frame *);
wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_DATA;
*(u_int16_t *)wh->i_dur = 0;
+
switch (ic->ic_opmode) {
case IEEE80211_M_STA:
wh->i_fc[1] = IEEE80211_FC1_DIR_TODS;
@@ -600,6 +624,7 @@ ieee80211_encap(struct ieee80211com *ic,
IEEE80211_ADDR_COPY(wh->i_addr2, eh.ether_shost);
IEEE80211_ADDR_COPY(wh->i_addr3, eh.ether_dhost);
break;
+
case IEEE80211_M_IBSS:
case IEEE80211_M_AHDEMO:
wh->i_fc[1] = IEEE80211_FC1_DIR_NODS;
@@ -611,22 +636,26 @@ ieee80211_encap(struct ieee80211com *ic,
*/
IEEE80211_ADDR_COPY(wh->i_addr3, ic->ic_bss->ni_bssid);
break;
+
case IEEE80211_M_HOSTAP:
#ifndef IEEE80211_NO_HOSTAP
wh->i_fc[1] = IEEE80211_FC1_DIR_FROMDS;
IEEE80211_ADDR_COPY(wh->i_addr1, eh.ether_dhost);
IEEE80211_ADDR_COPY(wh->i_addr2, ni->ni_bssid);
IEEE80211_ADDR_COPY(wh->i_addr3, eh.ether_shost);
-#endif /* !IEEE80211_NO_HOSTAP */
+#endif
break;
+
case IEEE80211_M_MONITOR:
goto bad;
}
+
if (m->m_flags & M_MORE_DATA)
wh->i_fc[1] |= IEEE80211_FC1_MORE_DATA;
+
if (addqos) {
struct ieee80211_qosframe *qwh =
- (struct ieee80211_qosframe *) wh;
+ (struct ieee80211_qosframe *)wh;
int ac, tid;
ac = M_WME_GETAC(m);
@@ -646,10 +675,12 @@ ieee80211_encap(struct ieee80211com *ic,
htole16(ni->ni_txseqs[0] << IEEE80211_SEQ_SEQ_SHIFT);
ni->ni_txseqs[0]++;
}
+
/* check if xmit fragmentation is required */
txfrag = (m->m_pkthdr.len > ic->ic_fragthreshold &&
!IEEE80211_IS_MULTICAST(wh->i_addr1) &&
(m->m_flags & M_FF) == 0); /* NB: don't fragment ff's */
+
if (key != NULL) {
/*
* IEEE 802.1X: send EAPOL frames always in the clear.
@@ -670,6 +701,7 @@ ieee80211_encap(struct ieee80211com *ic,
}
}
}
+
if (txfrag && !ieee80211_fragment(ic, m, hdrsize,
key != NULL ? key->wk_cipher->ic_header : 0, ic->ic_fragthreshold))
goto bad;
@@ -678,6 +710,7 @@ ieee80211_encap(struct ieee80211com *ic,
IEEE80211_NODE_STAT_ADD(ni, tx_bytes, datalen);
return m;
+
bad:
if (m != NULL)
m_freem(m);
@@ -1338,14 +1371,17 @@ ieee80211_send_probereq(struct ieee80211
m->m_pkthdr.len = m->m_len = frm - mtod(m, u_int8_t *);
M_PREPEND(m, sizeof(struct ieee80211_frame), M_DONTWAIT);
- if (m == NULL)
+ if (m == NULL) {
+ ic->ic_stats.is_tx_nobuf++;
+ ieee80211_free_node(ni);
return ENOMEM;
+ }
M_SETCTX(m, ni);
wh = mtod(m, struct ieee80211_frame *);
ieee80211_send_setup(ic, ni, wh,
- IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_PROBE_REQ,
- sa, da, bssid);
+ IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_PROBE_REQ,
+ sa, da, bssid);
/* XXX power management? */
IEEE80211_NODE_STAT(ni, tx_probereq);
@@ -1374,7 +1410,7 @@ ieee80211_send_mgmt(struct ieee80211com
struct mbuf *m;
u_int8_t *frm;
u_int16_t capinfo;
- int has_challenge, is_shared_key, ret, timer, status;
+ int ret, timer, status;
IASSERT(ni != NULL, ("null node"));
@@ -1392,7 +1428,9 @@ ieee80211_send_mgmt(struct ieee80211com
timer = 0;
switch (type) {
- case IEEE80211_FC0_SUBTYPE_PROBE_RESP:
+ case IEEE80211_FC0_SUBTYPE_PROBE_RESP: {
+ const bool has_wpa = (ic->ic_flags & IEEE80211_F_WPA) != 0;
+
/*
* probe response frame format
* [8] time stamp
@@ -1408,27 +1446,31 @@ ieee80211_send_mgmt(struct ieee80211com
* [tlv] WME (optional)
*/
m = ieee80211_getmgtframe(&frm,
- 8
- + sizeof(u_int16_t)
- + sizeof(u_int16_t)
- + 2 + IEEE80211_NWID_LEN
- + 2 + IEEE80211_RATE_SIZE
- + 7 /* max(7,3) */
- + 6
- + 3
+ 8 /* timestamp */
+ + sizeof(u_int16_t) /* interval */
+ + sizeof(u_int16_t) /* capinfo */
+ + 2 + IEEE80211_NWID_LEN /* ssid */
+ + 2 + IEEE80211_RATE_SIZE /* rates */
+ + 7 /* max(7,3) */
+ + 6 /* ibss (XXX could be 4?) */
+ + 3 /* erp */
+ 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE)
/* XXX !WPA1+WPA2 fits w/o a cluster */
- + (ic->ic_flags & IEEE80211_F_WPA ?
- 2*sizeof(struct ieee80211_ie_wpa) : 0)
+ + (has_wpa ? (2 * sizeof(struct ieee80211_ie_wpa)) : 0)
+ sizeof(struct ieee80211_wme_param)
);
if (m == NULL)
senderr(ENOMEM, is_tx_nobuf);
- memset(frm, 0, 8); /* timestamp should be filled later */
+ /* timestamp (should be filled later) */
+ memset(frm, 0, 8);
frm += 8;
+
+ /* interval */
*(u_int16_t *)frm = htole16(ic->ic_bss->ni_intval);
frm += 2;
+
+ /* capinfo */
if (ic->ic_opmode == IEEE80211_M_IBSS)
capinfo = IEEE80211_CAPINFO_IBSS;
else
@@ -1443,10 +1485,14 @@ ieee80211_send_mgmt(struct ieee80211com
*(u_int16_t *)frm = htole16(capinfo);
frm += 2;
+ /* ssid */
frm = ieee80211_add_ssid(frm, ic->ic_bss->ni_essid,
- ic->ic_bss->ni_esslen);
+ ic->ic_bss->ni_esslen);
+
+ /* rates */
frm = ieee80211_add_rates(frm, &ni->ni_rates);
+ /* variable */
if (ic->ic_phytype == IEEE80211_T_FH) {
*frm++ = IEEE80211_ELEMID_FHPARMS;
*frm++ = 5;
@@ -1463,27 +1509,39 @@ ieee80211_send_mgmt(struct ieee80211com
*frm++ = ieee80211_chan2ieee(ic, ic->ic_curchan);
}
+ /* ibss */
if (ic->ic_opmode == IEEE80211_M_IBSS) {
*frm++ = IEEE80211_ELEMID_IBSSPARMS;
*frm++ = 2;
- *frm++ = 0; *frm++ = 0; /* TODO: ATIM window */
+ *frm++ = 0; *frm++ = 0; /* TODO: ATIM window */
}
- if (ic->ic_flags & IEEE80211_F_WPA)
+
+ /* wpa */
+ if (has_wpa)
frm = ieee80211_add_wpa(frm, ic);
+
+ /* erp */
if (ic->ic_curmode == IEEE80211_MODE_11G)
frm = ieee80211_add_erp(frm, ic);
+
+ /* xrates */
frm = ieee80211_add_xrates(frm, &ni->ni_rates);
+
+ /* wme */
if (ic->ic_flags & IEEE80211_F_WME)
frm = ieee80211_add_wme_param(frm, &ic->ic_wme);
+
m->m_pkthdr.len = m->m_len = frm - mtod(m, u_int8_t *);
break;
+ }
- case IEEE80211_FC0_SUBTYPE_AUTH:
+ case IEEE80211_FC0_SUBTYPE_AUTH: {
status = arg >> 16;
arg &= 0xffff;
- has_challenge = ((arg == IEEE80211_AUTH_SHARED_CHALLENGE ||
- arg == IEEE80211_AUTH_SHARED_RESPONSE) &&
- ni->ni_challenge != NULL);
+ const bool has_challenge =
+ (arg == IEEE80211_AUTH_SHARED_CHALLENGE ||
+ arg == IEEE80211_AUTH_SHARED_RESPONSE) &&
+ ni->ni_challenge != NULL;
/*
* Deduce whether we're doing open authentication or
@@ -1492,41 +1550,44 @@ ieee80211_send_mgmt(struct ieee80211com
* handshake or if we're initiating an authentication
* request and configured to use shared key.
*/
- is_shared_key = has_challenge ||
- arg >= IEEE80211_AUTH_SHARED_RESPONSE ||
- (arg == IEEE80211_AUTH_SHARED_REQUEST &&
- ic->ic_bss->ni_authmode == IEEE80211_AUTH_SHARED);
+ const bool is_shared_key = has_challenge ||
+ (arg >= IEEE80211_AUTH_SHARED_RESPONSE) ||
+ (arg == IEEE80211_AUTH_SHARED_REQUEST &&
+ ic->ic_bss->ni_authmode == IEEE80211_AUTH_SHARED);
+
+ const bool need_challenge =
+ has_challenge && (status == IEEE80211_STATUS_SUCCESS);
+
+ const int frm_size = 3 * sizeof(u_int16_t)
+ + (need_challenge ?
+ sizeof(u_int16_t)+IEEE80211_CHALLENGE_LEN : 0);
- m = ieee80211_getmgtframe(&frm,
- 3 * sizeof(u_int16_t)
- + (has_challenge && status == IEEE80211_STATUS_SUCCESS ?
- sizeof(u_int16_t)+IEEE80211_CHALLENGE_LEN : 0)
- );
+ m = ieee80211_getmgtframe(&frm, frm_size);
if (m == NULL)
senderr(ENOMEM, is_tx_nobuf);
((u_int16_t *)frm)[0] =
- (is_shared_key) ? htole16(IEEE80211_AUTH_ALG_SHARED)
+ is_shared_key ? htole16(IEEE80211_AUTH_ALG_SHARED)
: htole16(IEEE80211_AUTH_ALG_OPEN);
((u_int16_t *)frm)[1] = htole16(arg); /* sequence number */
((u_int16_t *)frm)[2] = htole16(status);/* status */
- if (has_challenge && status == IEEE80211_STATUS_SUCCESS) {
+ if (need_challenge) {
((u_int16_t *)frm)[3] =
htole16((IEEE80211_CHALLENGE_LEN << 8) |
IEEE80211_ELEMID_CHALLENGE);
memcpy(&((u_int16_t *)frm)[4], ni->ni_challenge,
IEEE80211_CHALLENGE_LEN);
- m->m_pkthdr.len = m->m_len =
- 4 * sizeof(u_int16_t) + IEEE80211_CHALLENGE_LEN;
+
if (arg == IEEE80211_AUTH_SHARED_RESPONSE) {
IEEE80211_DPRINTF(ic, IEEE80211_MSG_AUTH,
"[%s] request encrypt frame (%s)\n",
ether_sprintf(ni->ni_macaddr), __func__);
m->m_flags |= M_LINK0; /* WEP-encrypt, please */
}
- } else
- m->m_pkthdr.len = m->m_len = 3 * sizeof(u_int16_t);
+ }
+
+ m->m_pkthdr.len = m->m_len = frm_size;
/* XXX not right for shared key */
if (status == IEEE80211_STATUS_SUCCESS)
@@ -1537,6 +1598,7 @@ ieee80211_send_mgmt(struct ieee80211com
if (ic->ic_opmode == IEEE80211_M_STA)
timer = IEEE80211_TRANS_WAIT;
break;
+ }
case IEEE80211_FC0_SUBTYPE_DEAUTH:
IEEE80211_DPRINTF(ic, IEEE80211_MSG_AUTH,
@@ -1583,7 +1645,7 @@ ieee80211_send_mgmt(struct ieee80211com
capinfo = 0;
if (ic->ic_opmode == IEEE80211_M_IBSS)
capinfo |= IEEE80211_CAPINFO_IBSS;
- else /* IEEE80211_M_STA */
+ else /* IEEE80211_M_STA */
capinfo |= IEEE80211_CAPINFO_ESS;
if (ic->ic_flags & IEEE80211_F_PRIVACY)
capinfo |= IEEE80211_CAPINFO_PRIVACY;
@@ -1661,8 +1723,10 @@ ieee80211_send_mgmt(struct ieee80211com
if (arg == IEEE80211_STATUS_SUCCESS) {
*(u_int16_t *)frm = htole16(ni->ni_associd);
IEEE80211_NODE_STAT(ni, tx_assoc);
- } else
+ } else {
+ *(u_int16_t *)frm = 0;
IEEE80211_NODE_STAT(ni, tx_assoc_fail);
+ }
frm += 2;
frm = ieee80211_add_rates(frm, &ni->ni_rates);