git: d9945d7821b9 - main - LinuxKPI: 802.11: improve hw_scan
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Fri, 15 Apr 2022 15:56:55 UTC
The branch main has been updated by bz: URL: https://cgit.FreeBSD.org/src/commit/?id=d9945d7821b9baf724a704d37d33b9adcad70030 commit d9945d7821b9baf724a704d37d33b9adcad70030 Author: Bjoern A. Zeeb <bz@FreeBSD.org> AuthorDate: 2022-04-15 14:55:40 +0000 Commit: Bjoern A. Zeeb <bz@FreeBSD.org> CommitDate: 2022-04-15 15:54:03 +0000 LinuxKPI: 802.11: improve hw_scan Initially we were using the IEs from ieee80211_probereq_ie() of net80211 and put them into the common_ies field. Start by manually building the per-band and common IE parts as drivers put them back together. This also involves allocating the req.ie as one buffer for all IEs over all bands and setting req.ie_len correctly based on how many bytes we put in. Manually building per-band scan IEs we still use the net80211 routines to add IEs to the buffer (mostly). This is needed by Realtek drivers but will equally used by others. Realtek would simply panic due to skbs being allocated with the wrong length. Longer-term this will help us, e.g., when not supporting VHT on 2Ghz and we would have to do this anyway. Sponsored by: The FreeBSD Foundation MFC after: 3 days --- sys/compat/linuxkpi/common/src/linux_80211.c | 174 ++++++++++++++++++++++----- sys/compat/linuxkpi/common/src/linux_80211.h | 5 + 2 files changed, 149 insertions(+), 30 deletions(-) diff --git a/sys/compat/linuxkpi/common/src/linux_80211.c b/sys/compat/linuxkpi/common/src/linux_80211.c index 286c40d7de4f..b80d8b62087b 100644 --- a/sys/compat/linuxkpi/common/src/linux_80211.c +++ b/sys/compat/linuxkpi/common/src/linux_80211.c @@ -2424,15 +2424,72 @@ linuxkpi_ieee80211_ie_advance(size_t *xp, const u8 *ies, size_t ies_len) return (true); } -static int -lkpi_ieee80211_probereq_ie_alloc(struct ieee80211vap *vap, - struct ieee80211com *ic, struct ieee80211_scan_ies *scan_ies, - const uint8_t *ssid, size_t ssidlen) +static uint8_t * +lkpi_scan_ies_add(uint8_t *p, struct ieee80211_scan_ies *scan_ies, + uint32_t band_mask, struct ieee80211vap *vap, struct ieee80211_hw *hw) { + struct ieee80211_supported_band *supband; + struct linuxkpi_ieee80211_channel *channels; + const struct ieee80211_channel *chan; + const struct ieee80211_rateset *rs; + uint8_t *pb; + int band, i; + + for (band = 0; band < NUM_NL80211_BANDS; band++) { + if ((band_mask & (1 << band)) == 0) + continue; + + supband = hw->wiphy->bands[band]; + /* + * This should not happen; + * band_mask is a bitmask of valid bands to scan on. + */ + if (supband == NULL || supband->n_channels == 0) + continue; + + /* Find a first channel to get the mode and rates from. */ + channels = supband->channels; + chan = NULL; + for (i = 0; i < supband->n_channels; i++) { + + if (channels[i].flags & IEEE80211_CHAN_DISABLED) + continue; + + chan = ieee80211_find_channel(vap->iv_ic, + channels[i].center_freq, 0); + if (chan != NULL) + break; + } + + /* This really should not happen. */ + if (chan == NULL) + continue; + + pb = p; + rs = ieee80211_get_suprates(vap->iv_ic, chan); /* calls chan2mode */ + p = ieee80211_add_rates(p, rs); + p = ieee80211_add_xrates(p, rs); + + scan_ies->ies[band] = pb; + scan_ies->len[band] = p - pb; + } + + /* Add common_ies */ + pb = p; + if ((vap->iv_flags & IEEE80211_F_WPA1) != 0 && + vap->iv_wpa_ie != NULL) { + memcpy(p, vap->iv_wpa_ie, 2 + vap->iv_wpa_ie[1]); + p += 2 + vap->iv_wpa_ie[1]; + } + if (vap->iv_appie_probereq != NULL) { + memcpy(p, vap->iv_appie_probereq->ie_data, + vap->iv_appie_probereq->ie_len); + p += vap->iv_appie_probereq->ie_len; + } + scan_ies->common_ies = pb; + scan_ies->common_ie_len = p - pb; - return (ieee80211_probereq_ie(vap, ic, - &scan_ies->common_ies, &scan_ies->common_ie_len, - ssid, ssidlen, true)); + return (p); } static void @@ -2482,26 +2539,50 @@ sw_scan: struct cfg80211_ssid *ssids; struct cfg80211_scan_6ghz_params *s6gp; size_t chan_len, nchan, ssids_len, s6ghzlen; - int i; + int band, i, ssid_count, common_ie_len; + uint32_t band_mask; + uint8_t *ie, *ieend; + + if (!ieee80211_hw_check(hw, SINGLE_SCAN_ON_ALL_BANDS)) { + IMPROVE("individual band scans not yet supported"); + /* In theory net80211 would have to drive this. */ + return; + } - ssids_len = ss->ss_nssid * sizeof(*ssids);; + ssid_count = min(ss->ss_nssid, hw->wiphy->max_scan_ssids); + ssids_len = ssid_count * sizeof(*ssids); s6ghzlen = 0 * (sizeof(*s6gp)); /* XXX-BZ */ + band_mask = 0; nchan = 0; - for (i = ss->ss_next; i < ss->ss_last; i++) + for (i = ss->ss_next; i < ss->ss_last; i++) { nchan++; + band = lkpi_net80211_chan_to_nl80211_band( + ss->ss_chans[ss->ss_next + i]); + band_mask |= (1 << band); + } chan_len = nchan * (sizeof(lc) + sizeof(*lc)); + common_ie_len = 0; + if ((vap->iv_flags & IEEE80211_F_WPA1) != 0 && + vap->iv_wpa_ie != NULL) + common_ie_len += vap->iv_wpa_ie[1]; + if (vap->iv_appie_probereq != NULL) + common_ie_len += vap->iv_appie_probereq->ie_len; + + /* We would love to check this at an earlier stage... */ + if (common_ie_len > hw->wiphy->max_scan_ie_len) { + ic_printf(ic, "WARNING: %s: common_ie_len %d > " + "wiphy->max_scan_ie_len %d\n", __func__, + common_ie_len, hw->wiphy->max_scan_ie_len); + } + KASSERT(lhw->hw_req == NULL, ("%s: ic %p lhw %p hw_req %p " "!= NULL\n", __func__, ic, lhw, lhw->hw_req)); - lhw->hw_req = hw_req = malloc(sizeof(*hw_req) + ssids_len + - s6ghzlen + chan_len, M_LKPI80211, M_WAITOK | M_ZERO); - error = lkpi_ieee80211_probereq_ie_alloc(vap, ic, - &hw_req->ies, NULL, -1); - if (error != 0) - ic_printf(ic, "ERROR: %s: probereq_ie returned %d\n", - __func__, error); + lhw->hw_req = hw_req = malloc(sizeof(*hw_req) + ssids_len + + s6ghzlen + chan_len + lhw->supbands * lhw->scan_ie_len + + common_ie_len, M_LKPI80211, M_WAITOK | M_ZERO); hw_req->req.flags = 0; /* XXX ??? */ /* hw_req->req.wdev */ @@ -2517,14 +2598,6 @@ sw_scan: memcpy(hw_req->req.mac_addr, xxx, IEEE80211_ADDR_LEN); memset(hw_req->req.mac_addr_mask, 0xxx, IEEE80211_ADDR_LEN); #endif -#if 0 - hw_req->req.ie_len = ; - hw_req->req.ie = ; -#endif -#if 0 - hw->wiphy->max_scan_ie_len - hw->wiphy->max_scan_ssids -#endif hw_req->req.n_channels = nchan; cpp = (struct linuxkpi_ieee80211_channel **)(hw_req + 1); @@ -2545,11 +2618,11 @@ sw_scan: lc++; } - hw_req->req.n_ssids = ss->ss_nssid; + hw_req->req.n_ssids = ssid_count; if (hw_req->req.n_ssids > 0) { ssids = (struct cfg80211_ssid *)lc; hw_req->req.ssids = ssids; - for (i = 0; i < ss->ss_nssid; i++) { + for (i = 0; i < ssid_count; i++) { ssids->ssid_len = ss->ss_ssid[i].len; memcpy(ssids->ssid, ss->ss_ssid[i].ssid, ss->ss_ssid[i].len); @@ -2566,15 +2639,21 @@ sw_scan: hw_req->req.scan_6ghz = false; /* Weird boolean; not what you think. */ /* s6gp->... */ + ie = ieend = (uint8_t *)s6gp; + /* Copy per-band IEs, copy common IEs */ + ieend = lkpi_scan_ies_add(ie, &hw_req->ies, band_mask, vap, hw); + hw_req->req.ie = ie; + hw_req->req.ie_len = ieend - ie; + lvif = VAP_TO_LVIF(vap); vif = LVIF_TO_VIF(lvif); error = lkpi_80211_mo_hw_scan(hw, vif, hw_req); if (error != 0) { - free(hw_req->ies.common_ies, M_80211_VAP); + ieee80211_cancel_scan(vap); + free(hw_req, M_LKPI80211); lhw->hw_req = NULL; - ieee80211_cancel_scan(vap); /* * XXX-SIGH magic number. * rtw88 has a magic "return 1" if offloading scan is @@ -3434,7 +3513,10 @@ linuxkpi_ieee80211_ifattach(struct ieee80211_hw *hw) /* * Assign the first possible channel for now; seems Realtek drivers * expect one. + * Also remember the amount of bands we support and the most rates + * in any band so we can scale [(ext) sup rates] IE(s) accordingly. */ + lhw->supbands = lhw->max_rates = 0; for (band = 0; band < NUM_NL80211_BANDS && hw->conf.chandef.chan == NULL; band++) { struct ieee80211_supported_band *supband; @@ -3444,6 +3526,9 @@ linuxkpi_ieee80211_ifattach(struct ieee80211_hw *hw) if (supband == NULL || supband->n_channels == 0) continue; + lhw->supbands++; + lhw->max_rates = max(lhw->max_rates, supband->n_bitrates); + channels = supband->channels; for (i = 0; i < supband->n_channels; i++) { @@ -3456,6 +3541,36 @@ linuxkpi_ieee80211_ifattach(struct ieee80211_hw *hw) } } + IMPROVE("see net80211::ieee80211_chan_init vs. wiphy->bands[].bitrates possibly in lkpi_ic_getradiocaps?"); + + /* Make sure we do not support more than net80211 is willing to take. */ + if (lhw->max_rates > IEEE80211_RATE_MAXSIZE) { + ic_printf(ic, "%s: limiting max_rates %d to %d!\n", __func__, + lhw->max_rates, IEEE80211_RATE_MAXSIZE); + lhw->max_rates = IEEE80211_RATE_MAXSIZE; + } + + /* + * The maximum supported bitrates on any band + size for + * DSSS Parameter Set give our per-band IE size. + * XXX-BZ FIXME add HT VHT ... later + * SSID is the responsibility of the driver and goes on the side. + * The user specified bits coming from the vap go into the + * "common ies" fields. + */ + lhw->scan_ie_len = 2 + IEEE80211_RATE_SIZE; + if (lhw->max_rates > IEEE80211_RATE_SIZE) + lhw->scan_ie_len += 2 + (lhw->max_rates - IEEE80211_RATE_SIZE); + /* + * net80211 does not seem to support the DSSS Parameter Set but some of + * the drivers insert it so calculate the extra fixed space in. + */ + lhw->scan_ie_len += 2 + 1; + + /* Reduce the max_scan_ie_len "left" by the amount we consume already. */ + if (hw->wiphy->max_scan_ie_len > 0) + hw->wiphy->max_scan_ie_len -= lhw->scan_ie_len; + if (bootverbose) ieee80211_announce(ic); @@ -3623,7 +3738,6 @@ linuxkpi_ieee80211_scan_completed(struct ieee80211_hw *hw, ieee80211_scan_done(ss->ss_vap); LKPI_80211_LHW_LOCK(lhw); - free(lhw->hw_req->ies.common_ies, M_80211_VAP); free(lhw->hw_req, M_LKPI80211); lhw->hw_req = NULL; lhw->scan_flags &= ~LKPI_SCAN_RUNNING; diff --git a/sys/compat/linuxkpi/common/src/linux_80211.h b/sys/compat/linuxkpi/common/src/linux_80211.h index bdcdb3fbf455..f7ade2d5e2f9 100644 --- a/sys/compat/linuxkpi/common/src/linux_80211.h +++ b/sys/compat/linuxkpi/common/src/linux_80211.h @@ -155,6 +155,11 @@ struct lkpi_hw { /* name it mac80211_sc? */ uint32_t sc_flags; #define LKPI_SCAN_RUNNING 0x00000001 uint32_t scan_flags; + + int supbands; /* Number of supported bands. */ + int max_rates; /* Maximum number of bitrates supported in any channel. */ + int scan_ie_len; /* Length of common per-band scan IEs. */ + bool update_mc; /* Must be last! */