On Wed, 15 Mar 2006 16:36:16 -0800, Jouni Malinen wrote:
> In theory, the low-level driver can determine the needed mask itself.
> However, it would need to be somehow notified of allowed BSSID values.
> By removing this entry, this information would need to fetched from
> somewhere else before interfaces are added.
> 
> Most hardware implementations have storage for a single MAC address in
> EEPROM (or something similar) and in some cases, no addresses are stored
> with the card and some external store is needed for this. We have been
> using this mechanism of passing the information from user space to avoid
> problems in figuring out board specific mechanisms for storing extra
> data. Do you have any ideas on what would be the best of getting this
> information configured after this change?

See the patch below. Is it viable?

> This and similar change for ieee80211_get_buffered_bc() add more
> requirements for the low-level driver. It used to be enough to just know
> that the low-level code should ask for up to N beacon frames. However,
> with this change, the low-level driver would need to maintain a list of
> ifindexes for the virtual interfaces. This is somewhat against the
> original design of hiding all the virtual interfaces from low-level
> code.

I like the approach, but I'm afraid it's not generic enough. The new
code should cover all possibilities (even such hypothetical case as a
card capable of multiple APs in its firmware with host-buffering of
frames for STAs in PS mode).

In a typical case of only-one-AP capable card the code will be nearly
the same. In your case it indeed means one extra list.

> I think the ifindex values could be made available from add/remove
> interface calls that you added. Was that what you had in mind or is
> there another mechanism for getting the needed ifindexes down?

Yes, I wanted to add ifindex into ieee80211_if_conf but apparently
forgot to. See patch below.

---->8----

This patch fixes some problems in interface configuration.

- Pass interface ID to add_interface and remove_interface callbacks. This ID
  is used by a driver when calling ieee80211_beacon_get and
  ieee80211_get_buffered_bc functions.
- New configuration callback, config_interface, is introduced.
- Allow BSSID to be set per-interface.

Signed-off-by: Jiri Benc <[EMAIL PROTECTED]>

Index: dscape/include/net/d80211.h
===================================================================
--- dscape.orig/include/net/d80211.h    2006-03-06 16:23:57.000000000 +0100
+++ dscape/include/net/d80211.h 2006-03-16 16:10:08.000000000 +0100
@@ -286,8 +286,6 @@ struct ieee80211_conf {
 
        int atheros_xr;
 
-       u8 client_bssid[ETH_ALEN];
-
        /* Following five fields are used for IEEE 802.11H */
        unsigned int radar_detect;
        unsigned int spect_mgmt;
@@ -310,11 +308,18 @@ struct ieee80211_conf {
 #define IEEE80211_SUB_IF_TYPE_WDS  0x5A580211
 #define IEEE80211_SUB_IF_TYPE_VLAN 0x00080211
 
-struct ieee80211_if_conf {
+struct ieee80211_if_init_conf {
+       int if_id;              /* not valid for monitor interface */
        int type;
        void *mac_addr;
 };
 
+struct ieee80211_if_conf {
+       int type;               /* just for convenience; doesn't change during
+                                * the live of the interface */
+       u8 *bssid;
+};
+
 typedef enum { ALG_NONE, ALG_WEP, ALG_TKIP, ALG_CCMP, ALG_NULL }
 ieee80211_key_alg;
 
@@ -476,17 +481,22 @@ struct ieee80211_hw {
         * of open() and add_interface() handler has to be non-NULL. If
         * add_interface() is NULL, one STA interface is permitted only. */
        int (*add_interface)(struct net_device *dev,
-                            struct ieee80211_if_conf *conf);
+                            struct ieee80211_if_init_conf *conf);
 
        /* Notify a driver that interface is going down. The stop() handler
         * is called prior to this if this is a last interface. */
        void (*remove_interface)(struct net_device *dev,
-                                struct ieee80211_if_conf *conf);
+                                struct ieee80211_if_init_conf *conf);
 
        /* Handler for configuration requests. IEEE 802.11 code calls this
         * function to change hardware configuration, e.g., channel. */
        int (*config)(struct net_device *dev, struct ieee80211_conf *conf);
 
+       /* Handler for configuration requests related to interfaces (e.g.
+        * BSSID). */
+       int (*config_interface)(struct net_device *dev, int if_id,
+                               struct ieee80211_if_conf *conf);
+
        /* ieee80211 drivers should use this and not the function in
         * net_device. dev->flags, dev->mc_count and dev->mc_list must not
         * be used; use passed parameters and ieee80211_get_mc_list_item
@@ -674,7 +684,7 @@ void ieee80211_tx_status_irqsafe(struct 
  * low-level is responsible for calling this function before beacon data is
  * needed (e.g., based on hardware interrupt). Returned skb is used only once
  * and low-level driver is responsible of freeing it. */
-struct sk_buff * ieee80211_beacon_get(struct net_device *dev, int bss_idx,
+struct sk_buff * ieee80211_beacon_get(struct net_device *dev, int if_id,
                                      struct ieee80211_tx_control *control);
 
 /* Function for accessing buffered broadcast and multicast frames. If
@@ -692,7 +702,7 @@ struct sk_buff * ieee80211_beacon_get(st
  * does not need to check for DTIM beacons separately and should be able to
  * use common code for all beacons. */
 struct sk_buff *
-ieee80211_get_buffered_bc(struct net_device *dev, int bss_idx,
+ieee80211_get_buffered_bc(struct net_device *dev, int if_id,
                          struct ieee80211_tx_control *control);
 
 /* Low level drivers that have their own MLME and MAC indicate
Index: dscape/net/d80211/ieee80211.c
===================================================================
--- dscape.orig/net/d80211/ieee80211.c  2006-03-15 19:09:06.000000000 +0100
+++ dscape/net/d80211/ieee80211.c       2006-03-16 16:10:38.000000000 +0100
@@ -1556,7 +1556,7 @@ static void ieee80211_beacon_add_tim(str
 }
 
 
-struct sk_buff * ieee80211_beacon_get(struct net_device *dev, int bss_idx,
+struct sk_buff * ieee80211_beacon_get(struct net_device *dev, int if_id,
                                      struct ieee80211_tx_control *control)
 {
        struct ieee80211_local *local = dev->priv;
@@ -1569,18 +1569,19 @@ struct sk_buff * ieee80211_beacon_get(st
        u8 *b_head, *b_tail;
        int bh_len, bt_len;
 
-       bdev = dev_get_by_index(bss_idx);
+       bdev = dev_get_by_index(if_id);
        if (bdev) {
                sdata = IEEE80211_DEV_TO_SUB_IF(bdev);
                ap = &sdata->u.ap;
                dev_put(bdev);
        }
 
-       if (ap == NULL || ap->beacon_head == NULL) {
+       if (ap == NULL || sdata->type != IEEE80211_SUB_IF_TYPE_AP ||
+           ap->beacon_head == NULL) {
 #ifdef CONFIG_D80211_VERBOSE_DEBUG
                if (net_ratelimit())
                        printk(KERN_DEBUG "no beacon data avail for idx=%d "
-                              "(%s)\n", bss_idx, bdev ? bdev->name : "N/A");
+                              "(%s)\n", if_id, bdev ? bdev->name : "N/A");
 #endif /* CONFIG_D80211_VERBOSE_DEBUG */
                return NULL;
        }
@@ -1632,7 +1633,7 @@ struct sk_buff * ieee80211_beacon_get(st
 
 
 struct sk_buff *
-ieee80211_get_buffered_bc(struct net_device *dev, int bss_idx,
+ieee80211_get_buffered_bc(struct net_device *dev, int if_id,
                          struct ieee80211_tx_control *control)
 {
        struct ieee80211_local *local = dev->priv;
@@ -1645,13 +1646,14 @@ ieee80211_get_buffered_bc(struct net_dev
        struct ieee80211_sub_if_data *sdata;
        struct ieee80211_if_ap *bss = NULL;
 
-       bdev = dev_get_by_index(bss_idx);
+       bdev = dev_get_by_index(if_id);
        if (bdev) {
                sdata = IEEE80211_DEV_TO_SUB_IF(bdev);
                bss = &sdata->u.ap;
                dev_put(bdev);
        }
-       if (bss == NULL || bss->beacon_head == NULL)
+       if (bss == NULL || sdata->type != IEEE80211_SUB_IF_TYPE_AP ||
+           bss->beacon_head == NULL)
                return NULL;
 
        if (bss->dtim_count != 0)
@@ -1694,6 +1696,23 @@ ieee80211_get_buffered_bc(struct net_dev
        return skb;
 }
 
+int ieee80211_if_config(struct net_device *dev)
+{
+       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+       struct ieee80211_local *local = dev->priv;
+       struct ieee80211_if_conf conf;
+
+       if (!local->hw->config_interface)
+               return 0;
+
+       memset(&conf, 0, sizeof(conf));
+       conf.type = sdata->type;
+       if (sdata->type == IEEE80211_SUB_IF_TYPE_STA ||
+           sdata->type == IEEE80211_SUB_IF_TYPE_IBSS) {
+               conf.bssid = sdata->u.sta.bssid;
+       }
+       return local->hw->config_interface(local->mdev, dev->ifindex, &conf);
+}
 
 int ieee80211_hw_config(struct net_device *dev)
 {
@@ -1914,10 +1933,11 @@ static int ieee80211_master_stop(struct 
  * and switch them if necessary. */
 static inline void ieee80211_start_soft_monitor(struct ieee80211_local *local)
 {
-       struct ieee80211_if_conf conf;
+       struct ieee80211_if_init_conf conf;
 
        if (local->open_count && local->open_count == local->monitors &&
            !local->hw->monitor_during_oper && local->hw->remove_interface) {
+               conf.if_id = -1;
                conf.type = IEEE80211_SUB_IF_TYPE_MNTR;
                conf.mac_addr = NULL;
                local->hw->remove_interface(local->mdev, &conf);
@@ -1928,10 +1948,11 @@ static inline void ieee80211_start_soft_
  * and switch them if necessary. */
 static void ieee80211_start_hard_monitor(struct ieee80211_local *local)
 {
-       struct ieee80211_if_conf conf;
+       struct ieee80211_if_init_conf conf;
 
        if (local->open_count && local->open_count == local->monitors &&
            !local->hw->monitor_during_oper && local->hw->add_interface) {
+               conf.if_id = -1;
                conf.type = IEEE80211_SUB_IF_TYPE_MNTR;
                conf.mac_addr = NULL;
                local->hw->add_interface(local->mdev, &conf);
@@ -1942,7 +1963,7 @@ static int ieee80211_open(struct net_dev
 {
        struct ieee80211_sub_if_data *sdata, *nsdata;
        struct ieee80211_local *local = dev->priv;
-       struct ieee80211_if_conf conf;
+       struct ieee80211_if_init_conf conf;
        int res;
 
        sdata = IEEE80211_DEV_TO_SUB_IF(dev);
@@ -1971,6 +1992,7 @@ static int ieee80211_open(struct net_dev
        ieee80211_start_soft_monitor(local);
 
        if (local->hw->add_interface) {
+               conf.if_id = dev->ifindex;
                conf.type = sdata->type;
                conf.mac_addr = dev->dev_addr;
                res = local->hw->add_interface(sdata->master, &conf);
@@ -2034,8 +2056,9 @@ static int ieee80211_stop(struct net_dev
                        local->hw->stop(sdata->master);
         }
        if (local->hw->remove_interface) {
-               struct ieee80211_if_conf conf;
+               struct ieee80211_if_init_conf conf;
 
+               conf.if_id = dev->ifindex;
                conf.type = sdata->type;
                conf.mac_addr = dev->dev_addr;
                local->hw->remove_interface(sdata->master, &conf);
Index: dscape/net/d80211/ieee80211_i.h
===================================================================
--- dscape.orig/net/d80211/ieee80211_i.h        2006-03-15 19:09:06.000000000 
+0100
+++ dscape/net/d80211/ieee80211_i.h     2006-03-16 15:54:06.000000000 +0100
@@ -493,6 +493,7 @@ struct ieee80211_local {
 
 /* ieee80211.c */
 int ieee80211_hw_config(struct net_device *dev);
+int ieee80211_if_config(struct net_device *dev);
 struct ieee80211_key_conf *
 ieee80211_key_data2conf(struct ieee80211_local *local,
                        struct ieee80211_key *data);
Index: dscape/net/d80211/ieee80211_ioctl.c
===================================================================
--- dscape.orig/net/d80211/ieee80211_ioctl.c    2006-03-15 19:09:06.000000000 
+0100
+++ dscape/net/d80211/ieee80211_ioctl.c 2006-03-16 16:03:46.000000000 +0100
@@ -1791,22 +1791,11 @@ static int ieee80211_ioctl_siwap(struct 
                                 struct iw_request_info *info,
                                 struct sockaddr *ap_addr, char *extra)
 {
-       struct ieee80211_local *local = dev->priv;
        struct ieee80211_sub_if_data *sdata;
 
        sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        if (sdata->type == IEEE80211_SUB_IF_TYPE_STA ||
            sdata->type == IEEE80211_SUB_IF_TYPE_IBSS) {
-               int changed_bssid = 0;
-               if (memcmp(local->conf.client_bssid, (u8 *) &ap_addr->sa_data,
-                          ETH_ALEN) != 0)
-                       changed_bssid = 1;
-               memcpy(local->conf.client_bssid, (u8 *) &ap_addr->sa_data,
-                      ETH_ALEN);
-               if (changed_bssid && ieee80211_hw_config(dev)) {
-                       printk(KERN_DEBUG "%s: Failed to config new BSSID to "
-                              "the low-level driver\n", dev->name);
-               }
                return ieee80211_sta_set_bssid(dev, (u8 *) &ap_addr->sa_data);
        } else if (sdata->type == IEEE80211_SUB_IF_TYPE_WDS) {
                if (memcmp(sdata->u.wds.remote_addr, (u8 *) &ap_addr->sa_data,
Index: dscape/net/d80211/ieee80211_sta.c
===================================================================
--- dscape.orig/net/d80211/ieee80211_sta.c      2006-03-06 16:23:56.000000000 
+0100
+++ dscape/net/d80211/ieee80211_sta.c   2006-03-16 16:07:45.000000000 +0100
@@ -1990,7 +1990,9 @@ static int ieee80211_sta_join_ibss(struc
                local->hw->reset_tsf(local->mdev);
        }
        memcpy(ifsta->bssid, bss->bssid, ETH_ALEN);
-       memcpy(local->conf.client_bssid, bss->bssid, ETH_ALEN);
+       res = ieee80211_if_config(dev);
+       if (res)
+               return res;
 
        local->conf.beacon_int = bss->beacon_int >= 10 ? bss->beacon_int : 10;
 
@@ -2345,11 +2347,20 @@ int ieee80211_sta_set_bssid(struct net_d
 {
        struct ieee80211_sub_if_data *sdata;
        struct ieee80211_if_sta *ifsta;
+       int res;
 
        sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        ifsta = &sdata->u.sta;
 
-       memcpy(ifsta->bssid, bssid, ETH_ALEN);
+       if (memcmp(ifsta->bssid, bssid, ETH_ALEN) != 0) {
+               memcpy(ifsta->bssid, bssid, ETH_ALEN);
+               res = ieee80211_if_config(dev);
+               if (res) {
+                       printk(KERN_DEBUG "%s: Failed to config new BSSID to "
+                              "the low-level driver\n", dev->name);
+                       return res;
+               }
+       }
 
        if (memcmp(bssid, "\x00\x00\x00\x00\x00\x00", ETH_ALEN) == 0)
                ifsta->bssid_set = 0;


-- 
Jiri Benc
SUSE Labs
-
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to