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]> --- include/net/d80211.h | 63 ++++++++++++++++++++++++++++++++++-------- net/d80211/ieee80211.c | 35 +++++++++++++++++++---- net/d80211/ieee80211_i.h | 1 + net/d80211/ieee80211_ioctl.c | 11 ------- net/d80211/ieee80211_sta.c | 15 +++++++++- 5 files changed, 93 insertions(+), 32 deletions(-) 9b4d05977dda50bec721e696ec3cf98afd7d1ca9 diff --git a/include/net/d80211.h b/include/net/d80211.h index 5dff49a..84abd7c 100644 --- a/include/net/d80211.h +++ b/include/net/d80211.h @@ -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; @@ -325,6 +323,9 @@ enum ieee80211_if_types { /** * struct ieee80211_if_init_conf - initial configuration of an interface + * @if_id: internal interface ID. This number has no particular meaning to + * drivers and the only allowed usage is to pass it to + * ieee80211_beacon_get() and ieee80211_get_buffered_bc() functions. * @type: one of &enum ieee80211_if_types constants. Determines the type of * added/removed interface. * @mac_addr: pointer to MAC address of the interface. This pointer is valid @@ -335,10 +336,27 @@ enum ieee80211_if_types { * callbacks of &struct ieee80211_hw. */ struct ieee80211_if_init_conf { + int if_id; int type; void *mac_addr; }; +/** + * struct ieee80211_if_conf - configuration of an interface + * @type: type of the interface. This is always the same as was specified in + * &struct ieee80211_if_init_conf. The type of interface never change + * during the live of the interface; this field is present only for + * convenience. + * @bssid: BSSID of the network we are associated to/creating. + * + * This structure is passed to config_interface() callback of + * &struct ieee80211_hw. + */ +struct ieee80211_if_conf { + int type; + u8 *bssid; +}; + typedef enum { ALG_NONE, ALG_WEP, ALG_TKIP, ALG_CCMP, ALG_NULL } ieee80211_key_alg; @@ -505,6 +523,11 @@ struct ieee80211_hw { * 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); + /* Set TIM bit handler. If the hardware/firmware takes care of beacon * generation, IEEE 802.11 code uses this function to tell the * low-level to set (or clear if set==0) TIM bit for the given aid. If @@ -682,16 +705,31 @@ void ieee80211_tx_status(struct net_devi void ieee80211_tx_status_irqsafe(struct net_device *dev, struct sk_buff *skb, struct ieee80211_tx_status *status); -/* Beacon generation function. If the beacon frames are generated by the host - * system (i.e., not in hardware/firmware), the low-level driver uses this - * function to receive the next beacon frame from the 802.11 code. The - * 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, +/** + * ieee80211_beacon_get - beacon generation function + * @dev: pointer to &struct net_device as obtained from + * ieee80211_alloc_hw(). + * @if_id: interface ID from &struct ieee80211_if_init_conf. + * @control: will be filled with information needed to send this beacon. + * + * If the beacon frames are generated by the host system (i.e., not in + * hardware/firmware), the low-level driver uses this function to receive + * the next beacon frame from the 802.11 code. The 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 if_id, struct ieee80211_tx_control *control); -/* Function for accessing buffered broadcast and multicast frames. If +/** + * ieee80211_beacon_get - accessing buffered broadcast and multicast frames + * @dev: pointer to &struct net_device as obtained from + * ieee80211_alloc_hw(). + * @if_id: interface ID from &struct ieee80211_if_init_conf. + * @control: will be filled with information needed to send returned frame. + * + * Function for accessing buffered broadcast and multicast frames. If * hardware/firmware does not implement buffering of broadcast/multicast * frames when power saving is used, 802.11 code buffers them in the host * memory. The low-level driver uses this function to fetch next buffered @@ -704,9 +742,10 @@ struct sk_buff * ieee80211_beacon_get(st * call ieee80211_beacon_get() first. ieee80211_get_buffered_bc() returns * NULL if the previous generated beacon was not DTIM, so the low-level driver * does not need to check for DTIM beacons separately and should be able to - * use common code for all beacons. */ + * 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 diff --git a/net/d80211/ieee80211.c b/net/d80211/ieee80211.c index e3e155e..e6d4342 100644 --- a/net/d80211/ieee80211.c +++ b/net/d80211/ieee80211.c @@ -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_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 @@ #endif /* CONFIG_D80211_VERBOSE_DEBUG */ 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_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_IF_TYPE_STA || + sdata->type == IEEE80211_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) { @@ -1824,6 +1843,7 @@ static int ieee80211_open(struct net_dev if (local->hw->add_interface) { struct ieee80211_if_init_conf conf; + conf.if_id = dev->ifindex; conf.type = sdata->type; conf.mac_addr = dev->dev_addr; res = local->hw->add_interface(sdata->master, &conf); @@ -1868,6 +1888,7 @@ static int ieee80211_stop(struct net_dev if (local->hw->remove_interface) { 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); diff --git a/net/d80211/ieee80211_i.h b/net/d80211/ieee80211_i.h index 3766232..8fd0ac4 100644 --- a/net/d80211/ieee80211_i.h +++ b/net/d80211/ieee80211_i.h @@ -484,6 +484,7 @@ #endif /* CONFIG_D80211_DEBUG_COUNTERS * /* 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); diff --git a/net/d80211/ieee80211_ioctl.c b/net/d80211/ieee80211_ioctl.c index 461e2d9..00efe47 100644 --- a/net/d80211/ieee80211_ioctl.c +++ b/net/d80211/ieee80211_ioctl.c @@ -1782,22 +1782,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_IF_TYPE_STA || sdata->type == IEEE80211_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_IF_TYPE_WDS) { if (memcmp(sdata->u.wds.remote_addr, (u8 *) &ap_addr->sa_data, diff --git a/net/d80211/ieee80211_sta.c b/net/d80211/ieee80211_sta.c index 49c1b62..d9c3d67 100644 --- a/net/d80211/ieee80211_sta.c +++ b/net/d80211/ieee80211_sta.c @@ -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; -- 1.3.0 - 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