Since we have a TODO item to make all station
management dependent on virtual interfaces, I
figured I'd start with pushing such a change
to drivers before more drivers use this kind
of functionality...
The iwlwifi bits are easy, but I don't know
what to do about the ath9k bits. Any ideas?
---
drivers/net/wireless/ath/ath9k/recv.c | 2 +-
drivers/net/wireless/ath/ath9k/xmit.c | 2 +-
drivers/net/wireless/iwlwifi/iwl-3945-rs.c | 3 ++-
drivers/net/wireless/iwlwifi/iwl-core.c | 2 +-
drivers/net/wireless/iwlwifi/iwl-sta.c | 2 +-
include/net/mac80211.h | 4 ++--
net/mac80211/sta_info.c | 7 +++++--
7 files changed, 13 insertions(+), 9 deletions(-)
--- wireless-testing.orig/drivers/net/wireless/iwlwifi/iwl-3945-rs.c 2009-10-30 10:54:30.000000000 +0100
+++ wireless-testing/drivers/net/wireless/iwlwifi/iwl-3945-rs.c 2009-10-30 10:54:46.000000000 +0100
@@ -960,7 +960,8 @@ void iwl3945_rate_scale_init(struct ieee
rcu_read_lock();
- sta = ieee80211_find_sta(hw, priv->stations[sta_id].sta.sta.addr);
+ sta = ieee80211_find_sta(priv->vif,
+ priv->stations[sta_id].sta.sta.addr);
if (!sta) {
rcu_read_unlock();
return;
--- wireless-testing.orig/drivers/net/wireless/iwlwifi/iwl-core.c 2009-10-30 10:54:50.000000000 +0100
+++ wireless-testing/drivers/net/wireless/iwlwifi/iwl-core.c 2009-10-30 10:54:56.000000000 +0100
@@ -2338,7 +2338,7 @@ static void iwl_ht_conf(struct iwl_priv
switch (priv->iw_mode) {
case NL80211_IFTYPE_STATION:
rcu_read_lock();
- sta = ieee80211_find_sta(priv->hw, priv->bssid);
+ sta = ieee80211_find_sta(priv->vif, priv->bssid);
if (sta) {
struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap;
int maxstreams;
--- wireless-testing.orig/drivers/net/wireless/iwlwifi/iwl-sta.c 2009-10-30 10:55:00.000000000 +0100
+++ wireless-testing/drivers/net/wireless/iwlwifi/iwl-sta.c 2009-10-30 10:55:03.000000000 +0100
@@ -1012,7 +1012,7 @@ int iwl_rxon_add_station(struct iwl_priv
*/
if (priv->current_ht_config.is_ht) {
rcu_read_lock();
- sta = ieee80211_find_sta(priv->hw, addr);
+ sta = ieee80211_find_sta(priv->vif, addr);
if (sta) {
memcpy(&ht_config, &sta->ht_cap, sizeof(ht_config));
cur_ht_config = &ht_config;
--- wireless-testing.orig/include/net/mac80211.h 2009-10-30 10:51:36.000000000 +0100
+++ wireless-testing/include/net/mac80211.h 2009-10-30 10:51:58.000000000 +0100
@@ -2106,13 +2106,13 @@ void ieee80211_stop_tx_ba_cb_irqsafe(str
/**
* ieee80211_find_sta - find a station
*
- * @hw: pointer as obtained from ieee80211_alloc_hw()
+ * @vif: virtual interface to look for station on
* @addr: station's address
*
* This function must be called under RCU lock and the
* resulting pointer is only valid under RCU lock as well.
*/
-struct ieee80211_sta *ieee80211_find_sta(struct ieee80211_hw *hw,
+struct ieee80211_sta *ieee80211_find_sta(struct ieee80211_vif *vif,
const u8 *addr);
/**
--- wireless-testing.orig/net/mac80211/sta_info.c 2009-10-30 10:52:13.000000000 +0100
+++ wireless-testing/net/mac80211/sta_info.c 2009-10-30 10:53:07.000000000 +0100
@@ -801,10 +801,13 @@ void ieee80211_sta_expire(struct ieee802
sta_info_destroy(sta);
}
-struct ieee80211_sta *ieee80211_find_sta(struct ieee80211_hw *hw,
+struct ieee80211_sta *ieee80211_find_sta(struct ieee80211_vif *vif,
const u8 *addr)
{
- struct sta_info *sta = sta_info_get(hw_to_local(hw), addr);
+ struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
+ struct sta_info *sta;
+
+ sta = sta_info_get(sdata->local, addr);
if (!sta)
return NULL;
--- wireless-testing.orig/drivers/net/wireless/ath/ath9k/recv.c 2009-10-30 10:53:27.000000000 +0100
+++ wireless-testing/drivers/net/wireless/ath/ath9k/recv.c 2009-10-30 10:55:38.000000000 +0100
@@ -202,7 +202,7 @@ static int ath_rx_prepare(struct sk_buff
}
rcu_read_lock();
- sta = ieee80211_find_sta(sc->hw, hdr->addr2);
+ sta = ieee80211_find_sta(/*?????*/, hdr->addr2);
if (sta) {
an = (struct ath_node *) sta->drv_priv;
if (ds->ds_rxstat.rs_rssi != ATH9K_RSSI_BAD &&
--- wireless-testing.orig/drivers/net/wireless/ath/ath9k/xmit.c 2009-10-30 10:54:10.000000000 +0100
+++ wireless-testing/drivers/net/wireless/ath/ath9k/xmit.c 2009-10-30 10:55:48.000000000 +0100
@@ -282,7 +282,7 @@ static void ath_tx_complete_aggr(struct
rcu_read_lock();
- sta = ieee80211_find_sta(sc->hw, hdr->addr1);
+ sta = ieee80211_find_sta(/*??????*/, hdr->addr1);
if (!sta) {
rcu_read_unlock();
return;
On Fri, Oct 30, 2009 at 2:58 AM, Johannes Berg
<[email protected]> wrote:
> Since we have a TODO item to make all station
> management dependent on virtual interfaces, I
> figured I'd start with pushing such a change
> to drivers before more drivers use this kind
> of functionality...
>
> The iwlwifi bits are easy, but I don't know
> what to do about the ath9k bits. Any ideas?
> --- wireless-testing.orig/drivers/net/wireless/ath/ath9k/xmit.c 2009-10-30 10:54:10.000000000 +0100
> +++ wireless-testing/drivers/net/wireless/ath/ath9k/xmit.c 2009-10-30 10:55:48.000000000 +0100
> @@ -282,7 +282,7 @@ static void ath_tx_complete_aggr(struct
>
> rcu_read_lock();
>
> - sta = ieee80211_find_sta(sc->hw, hdr->addr1);
> + sta = ieee80211_find_sta(/*??????*/, hdr->addr1);
Not sure but I just wanted to point out the that the sc->hw above here
was wrong anyway for virtual wiphy support, this should instead
probably look for the aphy with ath_get_virt_hw() as is done with
ath_rx_prepare().
Luis
On Fri, Oct 30, 2009 at 08:02:26AM -0700, Luis R. Rodriguez wrote:
> On Fri, Oct 30, 2009 at 2:58 AM, Johannes Berg
> <[email protected]> wrote:
> > Since we have a TODO item to make all station
> > management dependent on virtual interfaces, I
> > figured I'd start with pushing such a change
> > to drivers before more drivers use this kind
> > of functionality...
> >
> > The iwlwifi bits are easy, but I don't know
> > what to do about the ath9k bits. Any ideas?
>
> > --- wireless-testing.orig/drivers/net/wireless/ath/ath9k/xmit.c 2009-10-30 10:54:10.000000000 +0100
> > +++ wireless-testing/drivers/net/wireless/ath/ath9k/xmit.c ? ? ?2009-10-30 10:55:48.000000000 +0100
> > @@ -282,7 +282,7 @@ static void ath_tx_complete_aggr(struct
> >
> > ? ? ? ?rcu_read_lock();
> >
> > - ? ? ? sta = ieee80211_find_sta(sc->hw, hdr->addr1);
> > + ? ? ? sta = ieee80211_find_sta(/*??????*/, hdr->addr1);
>
> Not sure but I just wanted to point out the that the sc->hw above here
> was wrong anyway for virtual wiphy support, this should instead
> probably look for the aphy with ath_get_virt_hw() as is done with
> ath_rx_prepare().
And upon further investigation one way to do this is something as below. I did this
as a test as I needed to answer the question of "who does this skb belong to" for
virtual wiphy purposes. The question of who it belongs to is not that important but
the more important thing is to determine the appropriate ieee80211_hw and the mode
of operation the hw should use to behave for the skb. ath9k uses the sc->sc_ah->opmode
in many places and it was to be determined how we'd update this for virtual wiphys.
To answer that you need to determine either the minimum hw configuration your device
needs to operate under to allow all current virtual wiphys to operate properly
or just determine the vif we are to use. Either way it turns out these questions
are not easy to answer from the driver.
A simple question like: "do we have monitor vif?" is not an easy question to answer
for mac80211 drivers as such, as this patch should illustrate, we should perhaps
consider moving more of the virtual wiphy implementation to mac80211/cfg80211 or
as you have put it -- just bring the vif capability to be on its own channel.
diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c
index 330cd3b..9c41071 100644
--- a/drivers/net/wireless/ath/ath9k/recv.c
+++ b/drivers/net/wireless/ath/ath9k/recv.c
@@ -17,23 +17,29 @@
#include "ath9k.h"
static struct ieee80211_hw * ath_get_virt_hw(struct ath_softc *sc,
- struct ieee80211_hdr *hdr)
+ struct ieee80211_hdr *hdr,
+ struct ieee80211_vif **vif)
{
struct ieee80211_hw *hw = sc->pri_wiphy->hw;
int i;
+ *vif = ieee80211_get_vif_by_mac_atomic(hw, hdr->addr1);
+ if (*vif)
+ return hw;
+
spin_lock_bh(&sc->wiphy_lock);
for (i = 0; i < sc->num_sec_wiphy; i++) {
struct ath_wiphy *aphy = sc->sec_wiphy[i];
- if (aphy == NULL)
+ if (!aphy)
continue;
- if (compare_ether_addr(hdr->addr1, aphy->hw->wiphy->perm_addr)
- == 0) {
+ *vif = ieee80211_get_vif_by_mac_atomic(aphy->hw, hdr->addr1);
+ if (*vif) {
hw = aphy->hw;
break;
}
}
spin_unlock_bh(&sc->wiphy_lock);
+
return hw;
}
@@ -662,6 +668,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush)
struct ieee80211_rx_status rx_status;
struct ath_hw *ah = sc->sc_ah;
struct ath_common *common = ath9k_hw_common(ah);
+ struct ieee80211_vif *vif;
/*
* The hw can techncically differ from common->hw when using ath9k
* virtual wiphy so to account for that we iterate over the active
@@ -748,7 +755,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush)
DMA_FROM_DEVICE);
hdr = (struct ieee80211_hdr *) skb->data;
- hw = ath_get_virt_hw(sc, hdr);
+ hw = ath_get_virt_hw(sc, hdr, &vif);
/*
* If we're asked to flush receive queue, directly
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index e12293e..1d2bb0a 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -1999,6 +1999,12 @@ void ieee80211_iterate_active_interfaces_atomic(struct ieee80211_hw *hw,
struct ieee80211_vif *vif),
void *data);
+struct ieee80211_vif *ieee80211_get_vif_by_mac(struct ieee80211_hw *hw,
+ u8 *mac);
+
+struct ieee80211_vif *ieee80211_get_vif_by_mac_atomic(struct ieee80211_hw *hw,
+ u8 *mac);
+
/**
* ieee80211_queue_work - add work onto the mac80211 workqueue
*
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index aedbaaa..f3f5a8b 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -511,6 +511,107 @@ void ieee80211_iterate_active_interfaces_atomic(
}
EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces_atomic);
+static struct ieee80211_vif *ieee80211_get_first_mon_vif(struct ieee80211_hw *hw)
+{
+ struct ieee80211_local *local = hw_to_local(hw);
+ struct ieee80211_sub_if_data *sdata;
+ struct ieee80211_vif *vif = NULL;
+
+ if (likely(!local->monitors && local->cooked_mntrs++))
+ return NULL;
+
+ list_for_each_entry(sdata, &local->interfaces, list) {
+ if (sdata->vif.type == NL80211_IFTYPE_MONITOR) {
+ vif = &sdata->vif;
+ break;
+ }
+ }
+
+ return vif;
+}
+
+struct ieee80211_vif *ieee80211_get_vif_by_mac(struct ieee80211_hw *hw,
+ u8 *mac)
+{
+ struct ieee80211_local *local = hw_to_local(hw);
+ struct ieee80211_sub_if_data *sdata;
+ struct ieee80211_vif *vif = NULL;
+
+ mutex_lock(&local->iflist_mtx);
+
+ list_for_each_entry(sdata, &local->interfaces, list) {
+ switch (sdata->vif.type) {
+ case __NL80211_IFTYPE_AFTER_LAST:
+ case NL80211_IFTYPE_UNSPECIFIED:
+ case NL80211_IFTYPE_MONITOR:
+ case NL80211_IFTYPE_AP_VLAN:
+ continue;
+ case NL80211_IFTYPE_AP:
+ case NL80211_IFTYPE_STATION:
+ case NL80211_IFTYPE_ADHOC:
+ case NL80211_IFTYPE_WDS:
+ case NL80211_IFTYPE_MESH_POINT:
+ break;
+ }
+
+ if (compare_ether_addr(mac, sdata->dev->dev_addr) == 0) {
+ vif = &sdata->vif;
+ break;
+ }
+ }
+
+ if (!vif) {
+ vif = ieee80211_get_first_mon_vif(hw);
+ WARN_ON(!vif);
+ }
+
+ mutex_unlock(&local->iflist_mtx);
+
+ return vif;
+}
+EXPORT_SYMBOL_GPL(ieee80211_get_vif_by_mac);
+
+struct ieee80211_vif *ieee80211_get_vif_by_mac_atomic(struct ieee80211_hw *hw,
+ u8 *mac)
+{
+ struct ieee80211_local *local = hw_to_local(hw);
+ struct ieee80211_sub_if_data *sdata;
+ struct ieee80211_vif *vif = NULL;
+
+ rcu_read_lock();
+
+ list_for_each_entry(sdata, &local->interfaces, list) {
+ switch (sdata->vif.type) {
+ case __NL80211_IFTYPE_AFTER_LAST:
+ case NL80211_IFTYPE_UNSPECIFIED:
+ case NL80211_IFTYPE_MONITOR:
+ case NL80211_IFTYPE_AP_VLAN:
+ continue;
+ case NL80211_IFTYPE_AP:
+ case NL80211_IFTYPE_STATION:
+ case NL80211_IFTYPE_ADHOC:
+ case NL80211_IFTYPE_WDS:
+ case NL80211_IFTYPE_MESH_POINT:
+ break;
+ }
+
+ if (compare_ether_addr(mac, sdata->dev->dev_addr) == 0) {
+ vif = &sdata->vif;
+ break;
+ }
+ }
+
+ if (!vif) {
+ vif = ieee80211_get_first_mon_vif(hw);
+ WARN_ON(!vif);
+ }
+
+ rcu_read_unlock();
+
+ return vif;
+}
+EXPORT_SYMBOL_GPL(ieee80211_get_vif_by_mac_atomic);
+
/*
* Nothing should have been stuffed into the workqueue during
* the suspend->resume cycle. If this WARN is seen then there