On Fri, 19 May 2006 15:15:54 -0400, John W. Linville wrote: > Jiri Benc: > d80211: switching management interface on/off
This patch is wrong, it uses incorrect ioctl number (collides with userspace MLME). As I discovered some bugs and I'm still working on some of them, I haven't sent pull request yet. Bad idea, unfortunately. > d80211: use alloc_netdev > d80211: fix is_ieee80211_device Would it be possible to drop these patches and pull from 'up' branch of my tree? If not, I will try to rebase my tree (I have another patches before them) and send corrections to already applied patches as new patches. --- git://git.kernel.org/pub/scm/linux/kernel/git/jbenc/dscape.git up Jiri Benc: d80211: don't config uninitialized interface d80211: fix recursive locking d80211: switching management interface on/off d80211: use alloc_netdev d80211: fix is_ieee80211_device Jouni Malinen: d80211: Add support for user space client MLME Michael Wu: d80211: Don't discriminate against 802.11b drivers net/d80211/hostapd_ioctl.h | 2 net/d80211/ieee80211.c | 169 ++++++++++++++++++++----------------------- net/d80211/ieee80211_i.h | 16 ++-- net/d80211/ieee80211_iface.c | 94 ++++++++++++++++++----- net/d80211/ieee80211_ioctl.c | 66 ++++++++++++++-- net/d80211/ieee80211_sta.c | 10 +- 6 files changed, 224 insertions(+), 133 deletions(-) diff --git a/net/d80211/hostapd_ioctl.h b/net/d80211/hostapd_ioctl.h index a462688..7c7305c 100644 --- a/net/d80211/hostapd_ioctl.h +++ b/net/d80211/hostapd_ioctl.h @@ -91,6 +91,8 @@ enum { PRISM2_PARAM_KEY_MGMT = 1040, PRISM2_PARAM_RADAR_DETECT = 1043, PRISM2_PARAM_SPECTRUM_MGMT = 1044, + PRISM2_PARAM_USER_SPACE_MLME = 1045, + PRISM2_PARAM_MGMT_IF = 1046, /* NOTE: Please try to coordinate with other active development * branches before allocating new param numbers so that each new param * will be unique within all branches and the allocated number will not diff --git a/net/d80211/ieee80211.c b/net/d80211/ieee80211.c index ffb7985..b850fb7 100644 --- a/net/d80211/ieee80211.c +++ b/net/d80211/ieee80211.c @@ -59,6 +59,8 @@ static int rate_control_initialize(struc static u8 * ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len); +static int ieee80211_mgmt_start_xmit(struct sk_buff *skb, + struct net_device *dev); struct ieee80211_key_conf * ieee80211_key_data2conf(struct ieee80211_local *local, @@ -1097,7 +1099,8 @@ __ieee80211_tx_prepare(struct ieee80211_ static int inline is_ieee80211_device(struct net_device *dev) { return (dev->wireless_handlers == - (struct iw_handler_def *) &ieee80211_iw_handler_def); + (struct iw_handler_def *) &ieee80211_iw_handler_def) || + (dev->hard_start_xmit == ieee80211_mgmt_start_xmit); } /* Device in tx->dev has a reference added; use dev_put(tx->dev) when @@ -1754,7 +1757,7 @@ int ieee80211_if_config(struct net_devic struct ieee80211_local *local = dev->priv; struct ieee80211_if_conf conf; - if (!local->hw->config_interface) + if (!local->hw->config_interface || !netif_running(dev)) return 0; memset(&conf, 0, sizeof(conf)); @@ -1954,8 +1957,6 @@ static inline int identical_mac_addr_all { return (type1 == IEEE80211_IF_TYPE_MNTR || type2 == IEEE80211_IF_TYPE_MNTR || - type1 == IEEE80211_IF_TYPE_MGMT || - type2 == IEEE80211_IF_TYPE_MGMT || (type1 == IEEE80211_IF_TYPE_AP && type2 == IEEE80211_IF_TYPE_WDS) || (type1 == IEEE80211_IF_TYPE_WDS && @@ -1990,6 +1991,20 @@ static int ieee80211_master_stop(struct return 0; } +static int ieee80211_mgmt_open(struct net_device *dev) +{ + struct ieee80211_local *local = dev->priv; + + if (!netif_running(local->mdev)) + return -EOPNOTSUPP; + return 0; +} + +static int ieee80211_mgmt_stop(struct net_device *dev) +{ + return 0; +} + /* Check if running monitor interfaces should go to a "soft monitor" mode * and switch them if necessary. */ static inline void ieee80211_start_soft_monitor(struct ieee80211_local *local) @@ -2032,7 +2047,6 @@ static int ieee80211_open(struct net_dev struct net_device *ndev = nsdata->dev; if (ndev != dev && ndev != local->mdev && - ndev != local->apdev && netif_running(ndev) && memcmp(dev->dev_addr, ndev->dev_addr, ETH_ALEN) == 0 && !identical_mac_addr_allowed(sdata->type, nsdata->type)) { @@ -2075,8 +2089,11 @@ static int ieee80211_open(struct net_dev res = local->hw->open(sdata->master); if (res == 0) { res = dev_open(sdata->master); - if (res && local->hw->stop) - local->hw->stop(sdata->master); + if (res) { + if (local->hw->stop) + local->hw->stop(sdata->master); + } else if (local->apdev) + dev_open(local->apdev); } if (res) { if (local->hw->remove_interface) @@ -2089,6 +2106,8 @@ static int ieee80211_open(struct net_dev if (sdata->type == IEEE80211_IF_TYPE_MNTR) local->monitors++; + else + ieee80211_if_config(dev); netif_start_queue(dev); return 0; @@ -2119,6 +2138,8 @@ static int ieee80211_stop(struct net_dev if (local->open_count == 0) { ieee80211_stop_scan(sdata->master); dev_close(sdata->master); + if (local->apdev) + dev_close(local->apdev); if (local->hw->stop) local->hw->stop(sdata->master); } @@ -2367,6 +2388,10 @@ ieee80211_rx_mgmt(struct net_device *dev if (msg_type != ieee80211_msg_monitor) dev = local->apdev; + if (!dev) { + dev_kfree_skb(skb); + return; + } skb->dev = dev; sdata = IEEE80211_DEV_TO_SUB_IF(dev); @@ -3116,8 +3141,9 @@ ieee80211_rx_h_mgmt(struct ieee80211_txr { struct ieee80211_sub_if_data *sdata; sdata = IEEE80211_DEV_TO_SUB_IF(rx->dev); - if (sdata->type == IEEE80211_IF_TYPE_STA || - sdata->type == IEEE80211_IF_TYPE_IBSS) { + if ((sdata->type == IEEE80211_IF_TYPE_STA || + sdata->type == IEEE80211_IF_TYPE_IBSS) && + !rx->local->user_space_mlme) { ieee80211_sta_rx_mgmt(rx->dev, rx->skb, rx->u.rx.status); } else { /* Management frames are sent to hostapd for processing */ @@ -3998,15 +4024,31 @@ void ieee80211_if_setup(struct net_devic dev->destructor = ieee80211_if_free; } +void ieee80211_if_mgmt_setup(struct net_device *dev) +{ + ether_setup(dev); + dev->hard_start_xmit = ieee80211_mgmt_start_xmit; + dev->change_mtu = ieee80211_change_mtu_apdev; + dev->get_stats = ieee80211_get_stats; + dev->open = ieee80211_mgmt_open; + dev->stop = ieee80211_mgmt_stop; + dev->type = ARPHRD_IEEE80211_PRISM; + dev->hard_header_parse = header_parse_80211; + dev->tx_queue_len = 0; + dev->destructor = ieee80211_if_free; +} -static void ieee80211_precalc_rates(struct ieee80211_hw *hw) +static void ieee80211_precalc_modes(struct ieee80211_hw *hw, + struct ieee80211_local *local) { struct ieee80211_hw_modes *mode; struct ieee80211_rate *rate; int m, r; + local->hw_modes = 0; for (m = 0; m < hw->num_modes; m++) { mode = &hw->modes[m]; + local->hw_modes |= 1 << mode->mode; for (r = 0; r < mode->num_rates; r++) { rate = &mode->rates[r]; rate->rate_inv = CHAN_UTIL_RATE_LCM / rate->rate; @@ -4018,57 +4060,43 @@ static void ieee80211_precalc_rates(stru struct net_device *ieee80211_alloc_hw(size_t priv_data_len, void (*setup)(struct net_device *)) { - struct net_device *apdev, *mdev; + struct net_device *mdev; struct ieee80211_local *local; struct ieee80211_sub_if_data *sdata; - int alloc_size; + int priv_size; - /* Ensure 32-bit alignment of our private data and hw private data. - * Each net_device is followed by a sub_if_data which which is used - * for wds/vlan information; it is aligned as well. + /* Ensure 32-byte alignment of our private data and hw private data. + * Each net_device is followed by a sub_if_data which is used for + * interface specific information. * * Sample memory map looks something like: * * 0000 ***************** * * net_dev * - * 015c ***************** + * 0160 ***************** * * sub_if * - * 017c ***************** + * 0180 ***************** * * local * - * 0b84 ***************** + * 0b80 ***************** * * hw_priv * * 1664 ***************** - * * ap net_dev * - * 17c0 ***************** - * * sub_if * - * ***************** */ - alloc_size = sizeof(struct net_device) + - sizeof(struct ieee80211_sub_if_data) + 3 + - sizeof(struct ieee80211_local) + 3 + - priv_data_len + 3 + - sizeof(struct net_device) + 3 + - sizeof(struct ieee80211_sub_if_data) + 3 + - 4096; - mdev = (struct net_device *) kzalloc(alloc_size, GFP_KERNEL); + priv_size = ((sizeof(struct ieee80211_sub_if_data) + + NETDEV_ALIGN_CONST) & ~NETDEV_ALIGN_CONST) + + ((sizeof(struct ieee80211_local) + + NETDEV_ALIGN_CONST) & ~NETDEV_ALIGN_CONST) + + priv_data_len; + mdev = alloc_netdev(priv_size, "wmaster%d", ether_setup); if (mdev == NULL) return NULL; - mdev->priv = (struct net_device *) - ((char *) mdev + - ((sizeof(struct net_device) + 3) & ~3) + - ((sizeof(struct ieee80211_sub_if_data) + 3) & ~3)); + mdev->priv = (char *)netdev_priv(mdev) + + ((sizeof(struct ieee80211_sub_if_data) + + NETDEV_ALIGN_CONST) & ~NETDEV_ALIGN_CONST); local = mdev->priv; - local->hw_priv = (void *) - ((char *) local + ((sizeof(struct ieee80211_local) + 3) & ~3)); - apdev = (struct net_device *) - ((char *) local->hw_priv + ((priv_data_len + 3) & ~3)); - - ether_setup(mdev); - memcpy(mdev->name, "wmaster%d", 10); - - if (strlen(mdev->name) + 2 >= sizeof(mdev->name)) - goto fail; + local->hw_priv = (char *)local + + ((sizeof(struct ieee80211_local) + + NETDEV_ALIGN_CONST) & ~NETDEV_ALIGN_CONST); local->dev_index = -1; local->mdev = mdev; @@ -4087,7 +4115,7 @@ struct net_device *ieee80211_alloc_hw(si local->rate_ctrl_num_down = RATE_CONTROL_NUM_DOWN; local->scan.in_scan = 0; - local->hw_modes = (unsigned int) -1; + local->enabled_modes = (unsigned int) -1; init_timer(&local->scan.timer); /* clear it out */ @@ -4104,28 +4132,6 @@ struct net_device *ieee80211_alloc_hw(si ieee80211_if_init(mdev); - apdev = (struct net_device *) - ((char *) local->hw_priv + ((priv_data_len + 3) & ~3)); - local->apdev = apdev; - ether_setup(apdev); - apdev->priv = local; - apdev->hard_start_xmit = ieee80211_mgmt_start_xmit; - apdev->change_mtu = ieee80211_change_mtu_apdev; - apdev->get_stats = ieee80211_get_stats; - apdev->open = ieee80211_open; - apdev->stop = ieee80211_stop; - apdev->type = ARPHRD_IEEE80211_PRISM; - apdev->hard_header_parse = header_parse_80211; - apdev->tx_queue_len = 0; - sprintf(apdev->name, "%sap", mdev->name); - - sdata = IEEE80211_DEV_TO_SUB_IF(apdev); - sdata->type = IEEE80211_IF_TYPE_MGMT; - sdata->dev = apdev; - sdata->master = mdev; - sdata->local = local; - list_add_tail(&sdata->list, &local->sub_if_list); - mdev->hard_start_xmit = ieee80211_master_start_xmit; mdev->wireless_handlers = (struct iw_handler_def *) &ieee80211_iw_handler_def; @@ -4155,10 +4161,6 @@ struct net_device *ieee80211_alloc_hw(si setup(mdev); return mdev; - - fail: - ieee80211_free_hw(mdev); - return NULL; } @@ -4193,15 +4195,11 @@ int ieee80211_register_hw(struct net_dev sta_info_start(local); - result = register_netdev(local->apdev); - if (result < 0) - goto fail_1st_dev; - if (hw->fraglist) dev->features |= NETIF_F_FRAGLIST; result = register_netdev(dev); if (result < 0) - goto fail_2nd_dev; + goto fail_dev; if (rate_control_initialize(local) < 0) { printk(KERN_DEBUG "%s: Failed to initialize rate control " @@ -4226,9 +4224,7 @@ int ieee80211_register_hw(struct net_dev fail_rate: unregister_netdev(dev); -fail_2nd_dev: - unregister_netdev(local->apdev); -fail_1st_dev: +fail_dev: sta_info_stop(local); ieee80211_unregister_sysfs(local); fail_sysfs: @@ -4247,17 +4243,11 @@ int ieee80211_update_hw(struct net_devic if (hw->queues == 0) hw->queues = 1; - memcpy(local->apdev->dev_addr, dev->dev_addr, ETH_ALEN); - local->apdev->base_addr = dev->base_addr; - local->apdev->irq = dev->irq; - local->apdev->mem_start = dev->mem_start; - local->apdev->mem_end = dev->mem_end; - if (!hw->modes || !hw->modes->channels || !hw->modes->rates || !hw->modes->num_channels || !hw->modes->num_rates) return -1; - ieee80211_precalc_rates(hw); + ieee80211_precalc_modes(hw, local); local->conf.phymode = hw->modes[0].mode; local->curr_rates = hw->modes[0].rates; local->num_curr_rates = hw->modes[0].num_rates; @@ -4291,6 +4281,9 @@ void ieee80211_unregister_hw(struct net_ del_timer_sync(&local->scan_timer); ieee80211_rx_bss_list_deinit(dev); + if (local->apdev) + ieee80211_if_del(local->apdev); + list_for_each_safe(ptr, n, &local->sub_if_list) { struct ieee80211_sub_if_data *sdata = list_entry(ptr, struct ieee80211_sub_if_data, list); @@ -4323,7 +4316,7 @@ void ieee80211_unregister_hw(struct net_ void ieee80211_free_hw(struct net_device *dev) { - kfree(dev); + free_netdev(dev); } diff --git a/net/d80211/ieee80211_i.h b/net/d80211/ieee80211_i.h index ee0b399..94e151d 100644 --- a/net/d80211/ieee80211_i.h +++ b/net/d80211/ieee80211_i.h @@ -307,11 +307,7 @@ #define NUM_DEFAULT_KEYS 4 int channel_use_raw; }; -#define IEEE80211_DEV_TO_SUB_IF(dev) ((struct ieee80211_sub_if_data *) \ - ((char *)(dev) + ((sizeof(struct net_device) + 3) & ~3))) -#define IEEE80211_SUB_IF_TO_DEV(sub_if) ((struct net_device *) \ - ((char *)(sub_if) - ((sizeof(struct net_device) + 3) & ~3))) - +#define IEEE80211_DEV_TO_SUB_IF(dev) netdev_priv(dev) struct ieee80211_local { struct ieee80211_hw *hw; @@ -409,7 +405,6 @@ #define IEEE80211_IRQSAFE_QUEUE_LIMIT 12 int scan_oper_antenna_max; u8 scan_ssid[IEEE80211_MAX_SSID_LEN]; size_t scan_ssid_len; - int scan_skip_11b; struct list_head sta_bss_list; struct ieee80211_sta_bss *sta_bss_hash[STA_HASH_SIZE]; spinlock_t sta_bss_lock; @@ -500,8 +495,12 @@ #endif /* CONFIG_D80211_DEBUG_COUNTERS * int wifi_wme_noack_test; unsigned int wmm_acm; /* bit field of ACM bits (BIT(802.1D tag)) */ - unsigned int hw_modes; /* bitfield of allowed hardware modes; + unsigned int enabled_modes; /* bitfield of allowed modes; + * (1 << MODE_*) */ + unsigned int hw_modes; /* bitfield of supported hardware modes; * (1 << MODE_*) */ + + int user_space_mlme; }; @@ -518,6 +517,7 @@ void ieee80211_prepare_rates(struct net_ void ieee80211_tx_set_iswep(struct ieee80211_txrx_data *tx); int ieee80211_if_update_wds(struct net_device *dev, u8 *remote_addr); void ieee80211_if_setup(struct net_device *dev); +void ieee80211_if_mgmt_setup(struct net_device *dev); /* ieee80211_ioctl.c */ int ieee80211_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); @@ -595,6 +595,8 @@ int ieee80211_if_remove(struct net_devic void ieee80211_if_free(struct net_device *dev); void ieee80211_if_flush(struct net_device *dev); void ieee80211_if_sdata_init(struct ieee80211_sub_if_data *sdata); +int ieee80211_if_add_mgmt(struct net_device *dev); +void ieee80211_if_del_mgmt(struct net_device *dev); /* ieee80211_sysfs.c */ int ieee80211_register_sysfs(struct ieee80211_local *local); diff --git a/net/d80211/ieee80211_iface.c b/net/d80211/ieee80211_iface.c index f3ce45f..6631738 100644 --- a/net/d80211/ieee80211_iface.c +++ b/net/d80211/ieee80211_iface.c @@ -31,16 +31,12 @@ int ieee80211_if_add(struct net_device * struct net_device *ndev, *tmp_dev; struct ieee80211_local *local = dev->priv; struct ieee80211_sub_if_data *sdata = NULL, *sdata_parent; - int alloc_size; int ret; int i; ASSERT_RTNL(); - /* ensure 32-bit alignment of our private data and hw private data */ - alloc_size = sizeof(struct net_device) + 3 + - sizeof(struct ieee80211_sub_if_data) + 3; - - ndev = *new_dev = (struct net_device *) kzalloc(alloc_size, GFP_KERNEL); + ndev = *new_dev = alloc_netdev(sizeof(struct ieee80211_sub_if_data), + "", ieee80211_if_setup); if (ndev == NULL) return -ENOMEM; @@ -68,7 +64,6 @@ int ieee80211_if_add(struct net_device * ndev->mem_start = dev->mem_start; ndev->mem_end = dev->mem_end; ndev->flags = dev->flags & IFF_MULTICAST; - ieee80211_if_setup(ndev); sdata = IEEE80211_DEV_TO_SUB_IF(ndev); sdata->type = IEEE80211_IF_TYPE_AP; @@ -88,11 +83,66 @@ int ieee80211_if_add(struct net_device * return 0; fail: - kfree(ndev); + free_netdev(ndev); *new_dev = NULL; return ret; } +int ieee80211_if_add_mgmt(struct net_device *dev) +{ + struct net_device *ndev; + struct ieee80211_local *local = dev->priv; + struct ieee80211_sub_if_data *sdata, *nsdata; + int ret; + + sdata = IEEE80211_DEV_TO_SUB_IF(dev); + ASSERT_RTNL(); + + ndev = alloc_netdev(sizeof(struct ieee80211_sub_if_data), "", + ieee80211_if_mgmt_setup); + if (ndev == NULL) + return -ENOMEM; + ret = dev_alloc_name(ndev, "wmgmt%d"); + if (ret) + goto fail; + + ndev->priv = local; + memcpy(ndev->dev_addr, dev->dev_addr, ETH_ALEN); + ndev->base_addr = dev->base_addr; + ndev->irq = dev->irq; + ndev->mem_start = dev->mem_start; + ndev->mem_end = dev->mem_end; + + nsdata = IEEE80211_DEV_TO_SUB_IF(ndev); + nsdata->type = IEEE80211_IF_TYPE_MGMT; + nsdata->master = local->mdev; + nsdata->dev = ndev; + nsdata->local = local; + ieee80211_if_sdata_init(nsdata); + + ret = register_netdevice(ndev); + if (ret) + goto fail; + if (local->open_count > 0) + dev_open(ndev); + local->apdev = ndev; + return 0; +fail: + free_netdev(ndev); + return ret; +} + +void ieee80211_if_del_mgmt(struct net_device *dev) +{ + struct ieee80211_local *local = dev->priv; + struct net_device *apdev; + + ASSERT_RTNL(); + apdev = local->apdev; + local->apdev = NULL; + unregister_netdevice(apdev); +} + void ieee80211_if_set_type(struct net_device *dev, int type) { struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); @@ -244,9 +294,8 @@ void __ieee80211_if_del(struct ieee80211 list_del(&sdata->list); ieee80211_proc_deinit_virtual(dev); unregister_netdevice(dev); - /* Default data device and management device are allocated with the - * master device. All other devices are separately allocated and will - * be freed by net_device->destructor (i. e. ieee80211_if_free). */ + /* Except master interface, the net_device will be freed by + * net_device->destructor (i. e. ieee80211_if_free). */ } /* Must be called with rtnl lock held. */ @@ -263,8 +312,7 @@ int ieee80211_if_remove(struct net_devic list_for_each_entry_safe(sdata, n, &local->sub_if_list, list) { if ((sdata->type == id || id == -1) && strcmp(name, sdata->dev->name) == 0 && - sdata->dev != local->mdev && - sdata->dev != local->apdev) { + sdata->dev != local->mdev) { __ieee80211_if_del(local, sdata); return 0; } @@ -277,7 +325,7 @@ void ieee80211_if_free(struct net_device struct ieee80211_local *local = dev->priv; BUG_ON(dev == local->mdev || dev == local->apdev); - kfree(dev); + free_netdev(dev); } /* Must be called with rtnl lock held. */ @@ -298,6 +346,9 @@ void ieee80211_if_del(struct net_device struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); rtnl_lock(); - __ieee80211_if_del(local, sdata); + if (sdata->type == IEEE80211_IF_TYPE_MGMT) + ieee80211_if_del_mgmt(local->mdev); + else + __ieee80211_if_del(local, sdata); rtnl_unlock(); } diff --git a/net/d80211/ieee80211_ioctl.c b/net/d80211/ieee80211_ioctl.c index 5d31a8f..30dfc76 100644 --- a/net/d80211/ieee80211_ioctl.c +++ b/net/d80211/ieee80211_ioctl.c @@ -937,7 +937,8 @@ static int ieee80211_ioctl_add_if(struct ieee80211_if_set_type(new_dev, IEEE80211_IF_TYPE_WDS); res = ieee80211_if_update_wds(new_dev, wds->remote_addr); if (res) - ieee80211_if_del(new_dev); + __ieee80211_if_del(dev->priv, + IEEE80211_DEV_TO_SUB_IF(new_dev)); return res; } else if (param->u.if_info.type == HOSTAP_IF_VLAN) { if (left < sizeof(struct hostapd_if_vlan)) @@ -950,7 +951,8 @@ static int ieee80211_ioctl_add_if(struct #if 0 res = ieee80211_if_update_vlan(new_dev, vlan->id); if (res) - ieee80211_if_del(new_dev); + __ieee80211_if_del(dev->priv, + IEEE80211_DEV_TO_SUB_IF(new_dev)); #endif return res; } else if (param->u.if_info.type == HOSTAP_IF_BSS) { @@ -1048,10 +1050,14 @@ static int ieee80211_ioctl_scan_req(stru struct prism2_hostapd_param *param, int param_len) { + struct ieee80211_local *local = dev->priv; u8 *pos = param->u.scan_req.ssid; int left = param_len - ((u8 *) pos - (u8 *) param); int len = param->u.scan_req.ssid_len; + if (local->user_space_mlme) + return -EOPNOTSUPP; + if (left < len || len > IEEE80211_MAX_SSID_LEN) return -EINVAL; @@ -1076,8 +1082,12 @@ static int ieee80211_ioctl_sta_get_state static int ieee80211_ioctl_mlme(struct net_device *dev, struct prism2_hostapd_param *param) { + struct ieee80211_local *local = dev->priv; struct ieee80211_sub_if_data *sdata; + if (local->user_space_mlme) + return -EOPNOTSUPP; + sdata = IEEE80211_DEV_TO_SUB_IF(dev); if (sdata->type != IEEE80211_IF_TYPE_STA && sdata->type != IEEE80211_IF_TYPE_IBSS) @@ -1136,6 +1146,10 @@ #endif static int ieee80211_set_gen_ie(struct net_device *dev, u8 *ie, size_t len) { struct ieee80211_sub_if_data *sdata; + struct ieee80211_local *local = dev->priv; + + if (local->user_space_mlme) + return -EOPNOTSUPP; sdata = IEEE80211_DEV_TO_SUB_IF(dev); if (sdata->type == IEEE80211_IF_TYPE_STA || @@ -1699,7 +1713,7 @@ int ieee80211_ioctl_siwfreq(struct net_d if (chan->flag & IEEE80211_CHAN_W_SCAN && ((freq->e == 0 && chan->chan == freq->m) || (freq->e > 0 && nfreq == chan->freq)) && - (local->hw_modes & (1 << mode->mode))) { + (local->enabled_modes & (1 << mode->mode))) { /* Use next_mode as the mode preference to * resolve non-unique channel numbers. */ if (set && mode->mode != local->next_mode) @@ -1745,6 +1759,7 @@ static int ieee80211_ioctl_siwessid(stru struct iw_request_info *info, struct iw_point *data, char *ssid) { + struct ieee80211_local *local = dev->priv; struct ieee80211_sub_if_data *sdata; size_t len = data->length; @@ -1754,8 +1769,16 @@ static int ieee80211_ioctl_siwessid(stru sdata = IEEE80211_DEV_TO_SUB_IF(dev); if (sdata->type == IEEE80211_IF_TYPE_STA || - sdata->type == IEEE80211_IF_TYPE_IBSS) + sdata->type == IEEE80211_IF_TYPE_IBSS) { + if (local->user_space_mlme) { + if (len > IEEE80211_MAX_SSID_LEN) + return -EINVAL; + memcpy(sdata->u.sta.ssid, ssid, len); + sdata->u.sta.ssid_len = len; + return 0; + } return ieee80211_sta_set_ssid(dev, ssid, len); + } if (sdata->type == IEEE80211_IF_TYPE_AP) { memcpy(sdata->u.ap.ssid, ssid, len); @@ -1804,11 +1827,17 @@ 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) { + if (local->user_space_mlme) { + memcpy(sdata->u.sta.bssid, (u8 *) &ap_addr->sa_data, + ETH_ALEN); + return 0; + } 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, @@ -2447,7 +2476,7 @@ static int ieee80211_ioctl_prism2_param( break; case PRISM2_PARAM_HW_MODES: - local->hw_modes = value; + local->enabled_modes = value; break; case PRISM2_PARAM_CREATE_IBSS: @@ -2469,6 +2498,19 @@ static int ieee80211_ioctl_prism2_param( case PRISM2_PARAM_SPECTRUM_MGMT: local->conf.spect_mgmt = value; break; + case PRISM2_PARAM_MGMT_IF: + if (value == 1) { + if (local->apdev == NULL) + ret = ieee80211_if_add_mgmt(local->mdev); + } else if (value == 0) { + if (local->apdev) + ieee80211_if_del_mgmt(local->mdev); + } else + ret = -EINVAL; + break; + case PRISM2_PARAM_USER_SPACE_MLME: + local->user_space_mlme = value; + break; default: ret = -EOPNOTSUPP; break; @@ -2620,7 +2662,7 @@ static int ieee80211_ioctl_get_prism2_pa break; case PRISM2_PARAM_HW_MODES: - *param = local->hw_modes; + *param = local->enabled_modes; break; case PRISM2_PARAM_CREATE_IBSS: @@ -2651,6 +2693,15 @@ static int ieee80211_ioctl_get_prism2_pa else *param = !!sdata->u.sta.wmm_enabled; break; + case PRISM2_PARAM_MGMT_IF: + if (local->apdev) + *param = local->apdev->ifindex; + else + ret = -ENOENT; + break; + case PRISM2_PARAM_USER_SPACE_MLME: + *param = local->user_space_mlme; + break; default: ret = -EOPNOTSUPP; diff --git a/net/d80211/ieee80211_sta.c b/net/d80211/ieee80211_sta.c index 2720f1d..af58013 100644 --- a/net/d80211/ieee80211_sta.c +++ b/net/d80211/ieee80211_sta.c @@ -2462,13 +2462,13 @@ static void ieee80211_sta_scan_timer(uns } return; } - skip = !(local->hw_modes & (1 << mode->mode)); + skip = !(local->enabled_modes & (1 << mode->mode)); chan = &mode->channels[local->scan_channel_idx]; if (!(chan->flag & IEEE80211_CHAN_W_SCAN) || (sdata->type == IEEE80211_IF_TYPE_IBSS && !(chan->flag & IEEE80211_CHAN_W_IBSS)) || - (local->hw_modes & (1 << MODE_IEEE80211G) && - mode->mode == MODE_IEEE80211B && local->scan_skip_11b)) + (local->hw_modes & local->enabled_modes & + (1 << MODE_IEEE80211G) && mode->mode == MODE_IEEE80211B)) skip = 1; if (!skip) { @@ -2566,7 +2566,6 @@ int ieee80211_sta_req_scan(struct net_de memcpy(local->scan_ssid, ssid, ssid_len); } else local->scan_ssid_len = 0; - local->scan_skip_11b = 1; /* FIX: clear this is 11g is not supported */ local->scan_state = SCAN_SET_CHANNEL; local->scan_hw_mode_idx = 0; local->scan_channel_idx = 0; @@ -2592,7 +2591,7 @@ ieee80211_sta_scan_result(struct net_dev bss->last_update + IEEE80211_SCAN_RESULT_EXPIRE)) return current_ev; - if (!(local->hw_modes & (1 << bss->hw_mode))) + if (!(local->enabled_modes & (1 << bss->hw_mode))) return current_ev; if (local->scan_flags & IEEE80211_SCAN_WPA_ONLY && -- 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