aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBjoern A. Zeeb <bz@FreeBSD.org>2022-12-31 01:18:16 +0000
committerBjoern A. Zeeb <bz@FreeBSD.org>2023-01-18 13:25:52 +0000
commitca6485cbf42038c3575e2acaf17fb7f7b048e477 (patch)
treeea0b334a07770896dcc73d189a5ba545bb4c3f39
parent44b254d9d32939ef223cb0e3df1ea085a3a5efd2 (diff)
downloadsrc-ca6485cbf42038c3575e2acaf17fb7f7b048e477.tar.gz
src-ca6485cbf42038c3575e2acaf17fb7f7b048e477.zip
LinuxKPI: 802.11: implement cfg80211_{get,put}_bss
Implement cfg80211_{get,put}_bss currently doing malloc/free bits, so hopefully the drivers get the calls right. cfg80211_get_bss() sets up a lookup structure which may also take a result (first hit wins) and calls ieee80211_scan_iterate() comparing the various values in the iterator funcion. Some of the checks are partially pointless (as it seems the drivers are not interested in these parts [ANY] but we keep them for documentation purposes should futher values arise in the future). We currently only iterate over the first VAP which will do for now. Sponsored by: The FreeBSD Foundation (cherry picked from commit 5edde07c2aba02d0f7d30bbb0f203ec3e920e273)
-rw-r--r--sys/compat/linuxkpi/common/include/net/cfg80211.h51
-rw-r--r--sys/compat/linuxkpi/common/src/linux_80211.c194
2 files changed, 199 insertions, 46 deletions
diff --git a/sys/compat/linuxkpi/common/include/net/cfg80211.h b/sys/compat/linuxkpi/common/include/net/cfg80211.h
index ee6697bb4d4a..8d69ff0891d9 100644
--- a/sys/compat/linuxkpi/common/include/net/cfg80211.h
+++ b/sys/compat/linuxkpi/common/include/net/cfg80211.h
@@ -1118,6 +1118,10 @@ uint32_t linuxkpi_ieee80211_channel_to_frequency(uint32_t, enum nl80211_band);
uint32_t linuxkpi_ieee80211_frequency_to_channel(uint32_t, uint32_t);
struct linuxkpi_ieee80211_channel *
linuxkpi_ieee80211_get_channel(struct wiphy *, uint32_t);
+struct cfg80211_bss *linuxkpi_cfg80211_get_bss(struct wiphy *,
+ struct linuxkpi_ieee80211_channel *, const uint8_t *,
+ const uint8_t *, size_t, enum ieee80211_bss_type, enum ieee80211_privacy);
+void linuxkpi_cfg80211_put_bss(struct wiphy *, struct cfg80211_bss *);
void linuxkpi_cfg80211_bss_flush(struct wiphy *);
/* -------------------------------------------------------------------------- */
@@ -1189,6 +1193,32 @@ wiphy_rfkill_set_hw_state_reason(struct wiphy *wiphy, bool blocked,
/* -------------------------------------------------------------------------- */
+static inline struct cfg80211_bss *
+cfg80211_get_bss(struct wiphy *wiphy, struct linuxkpi_ieee80211_channel *chan,
+ const uint8_t *bssid, const uint8_t *ssid, size_t ssid_len,
+ enum ieee80211_bss_type bss_type, enum ieee80211_privacy privacy)
+{
+
+ return (linuxkpi_cfg80211_get_bss(wiphy, chan, bssid, ssid, ssid_len,
+ bss_type, privacy));
+}
+
+static inline void
+cfg80211_put_bss(struct wiphy *wiphy, struct cfg80211_bss *bss)
+{
+
+ linuxkpi_cfg80211_put_bss(wiphy, bss);
+}
+
+static inline void
+cfg80211_bss_flush(struct wiphy *wiphy)
+{
+
+ linuxkpi_cfg80211_bss_flush(wiphy);
+}
+
+/* -------------------------------------------------------------------------- */
+
static __inline bool
rfkill_blocked(int rfkill) /* argument type? */
{
@@ -1383,20 +1413,6 @@ freq_reg_info(struct wiphy *wiphy, uint32_t center_freq)
return (NULL);
}
-static __inline struct cfg80211_bss *
-cfg80211_get_bss(struct wiphy *wiphy, struct linuxkpi_ieee80211_channel *chan,
- const uint8_t *bssid, void *p, int x, uint32_t f1, uint32_t f2)
-{
- TODO();
- return (NULL);
-}
-
-static __inline void
-cfg80211_put_bss(struct wiphy *wiphy, struct cfg80211_bss *bss)
-{
- TODO();
-}
-
static __inline void
wiphy_apply_custom_regulatory(struct wiphy *wiphy,
const struct linuxkpi_ieee80211_regdomain *regd)
@@ -1658,13 +1674,6 @@ ieee80211_get_hdrlen_from_skb(struct sk_buff *skb)
return (-1);
}
-static __inline void
-cfg80211_bss_flush(struct wiphy *wiphy)
-{
-
- linuxkpi_cfg80211_bss_flush(wiphy);
-}
-
static __inline bool
cfg80211_channel_is_psc(struct linuxkpi_ieee80211_channel *channel)
{
diff --git a/sys/compat/linuxkpi/common/src/linux_80211.c b/sys/compat/linuxkpi/common/src/linux_80211.c
index 01263a642abd..947878449db4 100644
--- a/sys/compat/linuxkpi/common/src/linux_80211.c
+++ b/sys/compat/linuxkpi/common/src/linux_80211.c
@@ -524,31 +524,6 @@ linuxkpi_ieee80211_get_channel(struct wiphy *wiphy, uint32_t freq)
return (NULL);
}
-void
-linuxkpi_cfg80211_bss_flush(struct wiphy *wiphy)
-{
- struct lkpi_hw *lhw;
- struct ieee80211com *ic;
- struct ieee80211vap *vap;
-
- lhw = wiphy_priv(wiphy);
- ic = lhw->ic;
-
- /*
- * If we haven't called ieee80211_ifattach() yet
- * or there is no VAP, there are no scans to flush.
- */
- if (ic == NULL ||
- (lhw->sc_flags & LKPI_MAC80211_DRV_STARTED) == 0)
- return;
-
- /* Should only happen on the current one? Not seen it late enough. */
- IEEE80211_LOCK(ic);
- TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next)
- ieee80211_scan_flush(vap);
- IEEE80211_UNLOCK(ic);
-}
-
#ifdef LKPI_80211_HW_CRYPTO
static int
_lkpi_iv_key_set_delete(struct ieee80211vap *vap, const struct ieee80211_key *k,
@@ -4566,6 +4541,175 @@ linuxkpi_ieee80211_beacon_loss(struct ieee80211_vif *vif)
ieee80211_beacon_miss(vap->iv_ic);
}
+/* -------------------------------------------------------------------------- */
+
+struct lkpi_cfg80211_bss {
+ u_int refcnt;
+ struct cfg80211_bss bss;
+};
+
+struct lkpi_cfg80211_get_bss_iter_lookup {
+ struct wiphy *wiphy;
+ struct linuxkpi_ieee80211_channel *chan;
+ const uint8_t *bssid;
+ const uint8_t *ssid;
+ size_t ssid_len;
+ enum ieee80211_bss_type bss_type;
+ enum ieee80211_privacy privacy;
+
+ /*
+ * Something to store a copy of the result as the net80211 scan cache
+ * is not refoucnted so a scan entry might go away any time.
+ */
+ bool match;
+ struct cfg80211_bss *bss;
+};
+
+static void
+lkpi_cfg80211_get_bss_iterf(void *arg, const struct ieee80211_scan_entry *se)
+{
+ struct lkpi_cfg80211_get_bss_iter_lookup *lookup;
+ size_t ielen;
+
+ lookup = arg;
+
+ /* Do not try to find another match. */
+ if (lookup->match)
+ return;
+
+ /* Nothing to store result. */
+ if (lookup->bss == NULL)
+ return;
+
+ if (lookup->privacy != IEEE80211_PRIVACY_ANY) {
+ /* if (se->se_capinfo & IEEE80211_CAPINFO_PRIVACY) */
+ /* We have no idea what to compare to as the drivers only request ANY */
+ return;
+ }
+
+ if (lookup->bss_type != IEEE80211_BSS_TYPE_ANY) {
+ /* if (se->se_capinfo & (IEEE80211_CAPINFO_IBSS|IEEE80211_CAPINFO_ESS)) */
+ /* We have no idea what to compare to as the drivers only request ANY */
+ return;
+ }
+
+ if (lookup->chan != NULL) {
+ struct linuxkpi_ieee80211_channel *chan;
+
+ chan = linuxkpi_ieee80211_get_channel(lookup->wiphy,
+ se->se_chan->ic_freq);
+ if (chan == NULL || chan != lookup->chan)
+ return;
+ }
+
+ if (lookup->bssid && !IEEE80211_ADDR_EQ(lookup->bssid, se->se_bssid))
+ return;
+
+ if (lookup->ssid) {
+ if (lookup->ssid_len != se->se_ssid[1] ||
+ se->se_ssid[1] == 0)
+ return;
+ if (memcmp(lookup->ssid, se->se_ssid+2, lookup->ssid_len) != 0)
+ return;
+ }
+
+ ielen = se->se_ies.len;
+
+ lookup->bss->ies = malloc(sizeof(*lookup->bss->ies) + ielen,
+ M_LKPI80211, M_NOWAIT | M_ZERO);
+ if (lookup->bss->ies == NULL)
+ return;
+
+ lookup->bss->ies->data = (uint8_t *)lookup->bss->ies + sizeof(*lookup->bss->ies);
+ lookup->bss->ies->len = ielen;
+ if (ielen)
+ memcpy(lookup->bss->ies->data, se->se_ies.data, ielen);
+
+ lookup->match = true;
+}
+
+struct cfg80211_bss *
+linuxkpi_cfg80211_get_bss(struct wiphy *wiphy, struct linuxkpi_ieee80211_channel *chan,
+ const uint8_t *bssid, const uint8_t *ssid, size_t ssid_len,
+ enum ieee80211_bss_type bss_type, enum ieee80211_privacy privacy)
+{
+ struct lkpi_cfg80211_bss *lbss;
+ struct lkpi_cfg80211_get_bss_iter_lookup lookup;
+ struct lkpi_hw *lhw;
+ struct ieee80211vap *vap;
+
+ lhw = wiphy_priv(wiphy);
+
+ /* Let's hope we can alloc. */
+ lbss = malloc(sizeof(*lbss), M_LKPI80211, M_NOWAIT | M_ZERO);
+ if (lbss == NULL) {
+ ic_printf(lhw->ic, "%s: alloc failed.\n", __func__);
+ return (NULL);
+ }
+
+ lookup.wiphy = wiphy;
+ lookup.chan = chan;
+ lookup.bssid = bssid;
+ lookup.ssid = ssid;
+ lookup.ssid_len = ssid_len;
+ lookup.bss_type = bss_type;
+ lookup.privacy = privacy;
+ lookup.match = false;
+ lookup.bss = &lbss->bss;
+
+ IMPROVE("Iterate over all VAPs comparing perm_addr and addresses?");
+ vap = TAILQ_FIRST(&lhw->ic->ic_vaps);
+ ieee80211_scan_iterate(vap, lkpi_cfg80211_get_bss_iterf, &lookup);
+ if (!lookup.match) {
+ free(lbss, M_LKPI80211);
+ return (NULL);
+ }
+
+ refcount_init(&lbss->refcnt, 1);
+ return (&lbss->bss);
+}
+
+void
+linuxkpi_cfg80211_put_bss(struct wiphy *wiphy, struct cfg80211_bss *bss)
+{
+ struct lkpi_cfg80211_bss *lbss;
+
+ lbss = container_of(bss, struct lkpi_cfg80211_bss, bss);
+
+ /* Free everything again on refcount ... */
+ if (refcount_release(&lbss->refcnt)) {
+ free(lbss->bss.ies, M_LKPI80211);
+ free(lbss, M_LKPI80211);
+ }
+}
+
+void
+linuxkpi_cfg80211_bss_flush(struct wiphy *wiphy)
+{
+ struct lkpi_hw *lhw;
+ struct ieee80211com *ic;
+ struct ieee80211vap *vap;
+
+ lhw = wiphy_priv(wiphy);
+ ic = lhw->ic;
+
+ /*
+ * If we haven't called ieee80211_ifattach() yet
+ * or there is no VAP, there are no scans to flush.
+ */
+ if (ic == NULL ||
+ (lhw->sc_flags & LKPI_MAC80211_DRV_STARTED) == 0)
+ return;
+
+ /* Should only happen on the current one? Not seen it late enough. */
+ IEEE80211_LOCK(ic);
+ TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next)
+ ieee80211_scan_flush(vap);
+ IEEE80211_UNLOCK(ic);
+}
+
+/* -------------------------------------------------------------------------- */
+
MODULE_VERSION(linuxkpi_wlan, 1);
MODULE_DEPEND(linuxkpi_wlan, linuxkpi, 1, 1, 1);
MODULE_DEPEND(linuxkpi_wlan, wlan, 1, 1, 1);