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