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