git: a42584a066c9 - stable/13 - net80211: split up ieee80211_probereq()

Bjoern A. Zeeb bz at FreeBSD.org
Sun Jul 18 00:35:46 UTC 2021


The branch stable/13 has been updated by bz:

URL: https://cgit.FreeBSD.org/src/commit/?id=a42584a066c91bd22e92c57ce4f2ee01218c264c

commit a42584a066c91bd22e92c57ce4f2ee01218c264c
Author:     Bjoern A. Zeeb <bz at FreeBSD.org>
AuthorDate: 2021-07-18 00:32:19 +0000
Commit:     Bjoern A. Zeeb <bz at FreeBSD.org>
CommitDate: 2021-07-18 00:34:57 +0000

    net80211: split up ieee80211_probereq()
    
    Factor out ieee80211_probereq_ie() and ieee80211_probereq_ie_len()
    and make the length dynamic rather than static max.  The latter is
    needed as our current fixed length was longer than some "hw scan",
    e.g. that of ath10k, will take.  This way we can pass what we have.
    Should this not be sufficient in the future we might have to deal
    with filtering and much more error handling.
    
    This also removes a duplicate calculation for ieee80211_ie_wpa [1].
    
    c338cf2c6d5eacdee813191d5976aa531d450ee7 split up ieee80211_probereq_ie().
    For HW scans we usually do not want to add a SSID to the IEs.
    During that split we allocate memory based on the length which will
    always include the length of the SSID and only later we reduced the
    length but never updated the value passed back to the caller.
    Split the SSID handling up and reduce the length before malloc().
    This not only makes us not over-allocate in these situatoins but also
    fixes the length returned to the caller and with that usually directly
    passed to firmware.
    
    Repoprted by:   Martin Husemann <martin NetBSD.org> [1]
    Sponsored by:   Rubicon Communications, LLC ("Netgate")
    Sponsored by:   The FreeBSD Foundation (update for alloc)
    Reviewed by:    adrian, martin NetBSD.org (earlier version)
    Reviewed by:    philip
    Differential Revision: https://reviews.freebsd.org/D26545
    Differential Revision: https://reviews.freebsd.org/D30813
    
    (cherry picked from commit c338cf2c6d5eacdee813191d5976aa531d450ee7)
    (cherry picked from commit 243b95978debac3db06df6d26ca9f8d84f6cbd83)
---
 sys/net80211/ieee80211_output.c | 172 +++++++++++++++++++++++++++-------------
 sys/net80211/ieee80211_proto.h  |   2 +
 2 files changed, 118 insertions(+), 56 deletions(-)

diff --git a/sys/net80211/ieee80211_output.c b/sys/net80211/ieee80211_output.c
index b67302b8d66f..ab3e3142ad2c 100644
--- a/sys/net80211/ieee80211_output.c
+++ b/sys/net80211/ieee80211_output.c
@@ -2414,80 +2414,77 @@ ieee80211_add_qos(uint8_t *frm, const struct ieee80211_node *ni)
 }
 
 /*
- * Send a probe request frame with the specified ssid
- * and any optional information element data.
+ * ieee80211_send_probereq(): send a probe request frame with the specified ssid
+ * and any optional information element data;  some helper functions as FW based
+ * HW scans need some of that information passed too.
  */
-int
-ieee80211_send_probereq(struct ieee80211_node *ni,
-	const uint8_t sa[IEEE80211_ADDR_LEN],
-	const uint8_t da[IEEE80211_ADDR_LEN],
-	const uint8_t bssid[IEEE80211_ADDR_LEN],
-	const uint8_t *ssid, size_t ssidlen)
+static uint32_t
+ieee80211_probereq_ie_len(struct ieee80211vap *vap, struct ieee80211com *ic)
 {
-	struct ieee80211vap *vap = ni->ni_vap;
-	struct ieee80211com *ic = ni->ni_ic;
-	struct ieee80211_node *bss;
-	const struct ieee80211_txparam *tp;
-	struct ieee80211_bpf_params params;
 	const struct ieee80211_rateset *rs;
-	struct mbuf *m;
-	uint8_t *frm;
-	int ret;
-
-	bss = ieee80211_ref_node(vap->iv_bss);
 
-	if (vap->iv_state == IEEE80211_S_CAC) {
-		IEEE80211_NOTE(vap, IEEE80211_MSG_OUTPUT, ni,
-		    "block %s frame in CAC state", "probe request");
-		vap->iv_stats.is_tx_badstate++;
-		ieee80211_free_node(bss);
-		return EIO;		/* XXX */
-	}
-
-	/*
-	 * Hold a reference on the node so it doesn't go away until after
-	 * the xmit is complete all the way in the driver.  On error we
-	 * will remove our reference.
-	 */
-	IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE,
-		"ieee80211_ref_node (%s:%u) %p<%s> refcnt %d\n",
-		__func__, __LINE__,
-		ni, ether_sprintf(ni->ni_macaddr),
-		ieee80211_node_refcnt(ni)+1);
-	ieee80211_ref_node(ni);
+	rs = ieee80211_get_suprates(ic, ic->ic_curchan);
 
 	/*
 	 * prreq frame format
 	 *	[tlv] ssid
 	 *	[tlv] supported rates
 	 *	[tlv] RSN (optional)
-	 *	[tlv] extended supported rates
+	 *	[tlv] extended supported rates (if needed)
 	 *	[tlv] HT cap (optional)
 	 *	[tlv] VHT cap (optional)
 	 *	[tlv] WPA (optional)
 	 *	[tlv] user-specified ie's
 	 */
-	m = ieee80211_getmgtframe(&frm,
-		 ic->ic_headroom + sizeof(struct ieee80211_frame),
-	       	 2 + IEEE80211_NWID_LEN
+	return ( 2 + IEEE80211_NWID_LEN
 	       + 2 + IEEE80211_RATE_SIZE
-	       + sizeof(struct ieee80211_ie_htcap)
-	       + sizeof(struct ieee80211_ie_vhtcap)
+	       + ((vap->iv_flags & IEEE80211_F_WPA2 && vap->iv_rsn_ie != NULL) ?
+	           vap->iv_rsn_ie[1] : 0)
+	       + ((rs->rs_nrates > IEEE80211_RATE_SIZE) ?
+	           2 + (rs->rs_nrates - IEEE80211_RATE_SIZE) : 0)
+	       + (((vap->iv_opmode == IEEE80211_M_IBSS) &&
+		    (vap->iv_flags_ht & IEEE80211_FHT_HT)) ?
+	                sizeof(struct ieee80211_ie_htcap) : 0)
+#ifdef notyet
 	       + sizeof(struct ieee80211_ie_htinfo)	/* XXX not needed? */
-	       + sizeof(struct ieee80211_ie_wpa)
-	       + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE)
-	       + sizeof(struct ieee80211_ie_wpa)
+	       + sizeof(struct ieee80211_ie_vhtcap)
+#endif
+	       + ((vap->iv_flags & IEEE80211_F_WPA1 && vap->iv_wpa_ie != NULL) ?
+	           vap->iv_wpa_ie[1] : 0)
 	       + (vap->iv_appie_probereq != NULL ?
 		   vap->iv_appie_probereq->ie_len : 0)
 	);
-	if (m == NULL) {
-		vap->iv_stats.is_tx_nobuf++;
-		ieee80211_free_node(ni);
-		ieee80211_free_node(bss);
-		return ENOMEM;
-	}
+}
+
+int
+ieee80211_probereq_ie(struct ieee80211vap *vap, struct ieee80211com *ic,
+    uint8_t **frmp, uint32_t *frmlen, const uint8_t *ssid, size_t ssidlen,
+    bool alloc)
+{
+	const struct ieee80211_rateset *rs;
+	uint8_t	*frm;
+	uint32_t len;
+
+	if (!alloc && (frmp == NULL || frmlen == NULL))
+		return (EINVAL);
 
-	frm = ieee80211_add_ssid(frm, ssid, ssidlen);
+	len = ieee80211_probereq_ie_len(vap, ic);
+	if (!alloc && len > *frmlen)
+		return (ENOBUFS);
+
+	/* For HW scans we usually do not pass in the SSID as IE. */
+	if (ssidlen == -1)
+		len -= (2 + IEEE80211_NWID_LEN);
+
+	if (alloc) {
+		frm = malloc(len, M_80211_VAP, M_WAITOK | M_ZERO);
+		*frmp = frm;
+		*frmlen = len;
+	} else
+		frm = *frmp;
+
+	if (ssidlen != -1)
+		frm = ieee80211_add_ssid(frm, ssid, ssidlen);
 	rs = ieee80211_get_suprates(ic, ic->ic_curchan);
 	frm = ieee80211_add_rates(frm, rs);
 	frm = ieee80211_add_rsn(frm, vap);
@@ -2517,8 +2514,8 @@ ieee80211_send_probereq(struct ieee80211_node *ni,
 	 * XXX TODO: need to figure out what/how to update the
 	 * VHT channel.
 	 */
-#if 0
-	(vap->iv_flags_vht & IEEE80211_FVHT_VHT) {
+#ifdef notyet
+	if (vap->iv_flags_vht & IEEE80211_FVHT_VHT) {
 		struct ieee80211_channel *c;
 
 		c = ieee80211_ht_adjust_channel(ic, ic->ic_curchan,
@@ -2531,8 +2528,71 @@ ieee80211_send_probereq(struct ieee80211_node *ni,
 	frm = ieee80211_add_wpa(frm, vap);
 	if (vap->iv_appie_probereq != NULL)
 		frm = add_appie(frm, vap->iv_appie_probereq);
-	m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *);
 
+	if (!alloc) {
+		*frmp = frm;
+		*frmlen = len;
+	}
+
+	return (0);
+}
+
+int
+ieee80211_send_probereq(struct ieee80211_node *ni,
+	const uint8_t sa[IEEE80211_ADDR_LEN],
+	const uint8_t da[IEEE80211_ADDR_LEN],
+	const uint8_t bssid[IEEE80211_ADDR_LEN],
+	const uint8_t *ssid, size_t ssidlen)
+{
+	struct ieee80211vap *vap = ni->ni_vap;
+	struct ieee80211com *ic = ni->ni_ic;
+	struct ieee80211_node *bss;
+	const struct ieee80211_txparam *tp;
+	struct ieee80211_bpf_params params;
+	struct mbuf *m;
+	uint8_t *frm;
+	uint32_t frmlen;
+	int ret;
+
+	bss = ieee80211_ref_node(vap->iv_bss);
+
+	if (vap->iv_state == IEEE80211_S_CAC) {
+		IEEE80211_NOTE(vap, IEEE80211_MSG_OUTPUT, ni,
+		    "block %s frame in CAC state", "probe request");
+		vap->iv_stats.is_tx_badstate++;
+		ieee80211_free_node(bss);
+		return EIO;		/* XXX */
+	}
+
+	/*
+	 * Hold a reference on the node so it doesn't go away until after
+	 * the xmit is complete all the way in the driver.  On error we
+	 * will remove our reference.
+	 */
+	IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE,
+		"ieee80211_ref_node (%s:%u) %p<%s> refcnt %d\n",
+		__func__, __LINE__,
+		ni, ether_sprintf(ni->ni_macaddr),
+		ieee80211_node_refcnt(ni)+1);
+	ieee80211_ref_node(ni);
+
+	/* See comments above for entire frame format. */
+	frmlen = ieee80211_probereq_ie_len(vap, ic);
+	m = ieee80211_getmgtframe(&frm,
+	    ic->ic_headroom + sizeof(struct ieee80211_frame), frmlen);
+	if (m == NULL) {
+		vap->iv_stats.is_tx_nobuf++;
+		ieee80211_free_node(ni);
+		ieee80211_free_node(bss);
+		return ENOMEM;
+	}
+
+	ret = ieee80211_probereq_ie(vap, ic, &frm, &frmlen, ssid, ssidlen,
+	    false);
+	KASSERT(ret == 0,
+	    ("%s: ieee80211_probereq_ie railed: %d\n", __func__, ret));
+
+	m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *);
 	KASSERT(M_LEADINGSPACE(m) >= sizeof(struct ieee80211_frame),
 	    ("leading space %zd", M_LEADINGSPACE(m)));
 	M_PREPEND(m, sizeof(struct ieee80211_frame), M_NOWAIT);
diff --git a/sys/net80211/ieee80211_proto.h b/sys/net80211/ieee80211_proto.h
index fafedf46cab5..4b324caa694b 100644
--- a/sys/net80211/ieee80211_proto.h
+++ b/sys/net80211/ieee80211_proto.h
@@ -114,6 +114,8 @@ struct mbuf *ieee80211_encap(struct ieee80211vap *, struct ieee80211_node *,
 void	ieee80211_free_mbuf(struct mbuf *);
 int	ieee80211_send_mgmt(struct ieee80211_node *, int, int);
 struct ieee80211_appie;
+int	ieee80211_probereq_ie(struct ieee80211vap *, struct ieee80211com *,
+		uint8_t **, uint32_t *, const uint8_t *, size_t, bool);
 int	ieee80211_send_probereq(struct ieee80211_node *ni,
 		const uint8_t sa[IEEE80211_ADDR_LEN],
 		const uint8_t da[IEEE80211_ADDR_LEN],


More information about the dev-commits-src-all mailing list