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
MFC after:	10 days
This commit is contained in:
Bjoern A. Zeeb 2022-12-31 01:18:16 +00:00
parent b6b352e4c7
commit 5edde07c2a
2 changed files with 199 additions and 46 deletions

View File

@ -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)
{

View File

@ -544,31 +544,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,
@ -4586,6 +4561,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);