hostapd and wpa_supplicant include a test driver interface that allows
them to be tested on a single host without any wireless hardware for
development purposes. I have found this very valuable both for
developing new functionality and for testing existing code.
In order to provide similar mechanism for mac80211 developers and to
extend the scope of suitable test cases for hostapd/wpa_supplicant, I've
written a Linux kernel module that provides a similar test interface at
a lower layer. mac80211_hwsim simulates WLAN hardware and the air
interface between the radios by acting as a low-level radio driver for
mac80211. Neither mac80211 nor user space programs need any changes to
work with the simulated radios.
The initial version of mac80211_hwsim is available from the
mac80211_hwsim subdirectory of my hostap Git tree:
git://w1.fi/srv/git/hostap.git
http://w1.fi/gitweb/gitweb.cgi?p=hostap.git;a=tree;f=mac80211_hwsim
If there is interest in moving mac80211_hwsim module into the Linux
kernel tree, I'm open to doing that, too.
I've included some more information about the code in the README file
(see below) and there are also example configuration files for hostapd
and wpa_supplicant to show how a WPA2-Personal connection can be opened
with mac80211_hwsim.
mac80211_hwsim is still very minimal, but I have added couple of TODO
comments to the source code to indicate areas that I'm hoping to add for
more complete support of mac80211 features. I would also be interested
in feedback from other mac80211 developers on what kind of functionality
would be useful to have in this kind of simulated test setup. I'm first
looking into using this to develop IEEE 802.11w (management frame
protection) support into mac80211 and I would expect that the current
minimal design is enough for that, but there is certainly room for much
more, e.g., in the area of simulating signal strength and packet loss
for testing TX rate control, retransmission, and power save
functionality.
README:
Introduction
mac80211_hwsim is a Linux kernel module that can be used to simulate
arbitrary number of IEEE 802.11 radios for mac80211 on a single
device. It can be used to test most of the mac80211 functionality and
user space tools (e.g., hostapd and wpa_supplicant) in a way that
matches very closely with the normal case of using real WLAN
hardware. From the mac80211 view point, mac80211_hwsim is yet another
hardware driver, i.e., no changes to mac80211 are needed to use this
testing tool.
The main goal for mac80211_hwsim is to make it easier for developers
to test their code and work with new features to mac80211, hostapd,
and wpa_supplicant. The simulated radios do not have the limitations
of real hardware, so it is easy to generate an arbitrary test setup
and always reproduce the same setup for future tests. In addition,
since all radio operation is simulated, any channel can be used in
tests regardless of regulatory rules.
mac80211_hwsim kernel module has a parameter 'radios' that can be used
to select how many radios are simulates (default 2). This allows
configuration of both very simply setups (e.g., just a single access
point and a station) or large scale tests (multiple access points with
hundreds of stations).
mac80211_hwsim works by tracking the current channel of each virtual
radio and copying all transmitted frames to all other radios that are
currently enabled and on the same channel as the transmitting
radio. Software encryption in mac80211 is used so that the frames are
actually encrypted over the virtual air interface to allow more
complete testing of encryption.
Simple example
This example shows how to use mac80211_hwsim to simulate two radios:
one to act as an access point and the other as a station that
associates with the AP. hostapd and wpa_supplicant are used to take
care of WPA2-PSK authentication. In addition, hostapd is also
processing access point side of association.
Please note that the currently released Linux kernel (2.6.25) does not
enable AP mode, so a simple patch is needed to enable AP mode selection:
http://johannes.sipsolutions.net/patches/kernel/all/LATEST/006-allow-ap-vlan-modes.patch
# Build mac80211_hwsim:
make
# Load the module
insmod ./mac80211_hwsim.ko
# Run hostapd (AP) for wlan0
hostapd hostapd.conf
# Run wpa_supplicant (station) for wlan1
wpa_supplicant -Dwext -iwlan1 -c wpa_supplicant.conf
--
Jouni Malinen PGP id EFC895FA
> I'm currently running Linux 2.6.25 on my laptop and as such, this is
> indeed not based on the latest changes. I'll fix couple of issues in the
> current code with 2.6.25-based version and then look into making a
> submission against wireless-testing (or if there are large, pending
> patches that are not yet there, against something including those
> changes).
I don't think there are large pending changes, but there were large
changes in the way channels are registered, tx control works etc.
> > One thing caught my eye: you use GFP_KERNEL in the tx routine, that's
> > not good, it is running under a spinlock.
>
> Thanks, I'll fix that. I was trying to follow the documentation in
> net/mac80211.h to verify that it is correct, but clearly I missed the
> comment on tx() about the handler having to be atomic.
You should probably use the _irqsafe versions of rx and txstatus too.
> > One thing that I'd like to add is a having a "global" monitor interface
> > that is registered by the hwsim module and not mac80211 and shows all
> > frames, regardless of channel etc.
>
> Yes, I've been thinking of something similar, too. I'll add a netdev
> that gets all frames with radiotap header.
Maybe it could support injection on that too, so you can test against a
userspace agent.
The design I had come up with a long time ago allowed userspace to
control each radio by having each _radio_ have a raw netdev like this
and not doing forwarding in the kernel but relying on some userspace
tool, but I guess that much more complicated.
johannes
> The design I had come up with a long time ago allowed userspace to
> control each radio by having each _radio_ have a raw netdev like this
> and not doing forwarding in the kernel but relying on some userspace
> tool, but I guess that much more complicated.
I should mention that I have notes on that:
http://kernelnewbies.org/KernelProjects/Mac80211TestDriver
johannes
On Tue, Jun 10, 2008 at 01:16:15PM +0200, Johannes Berg wrote:
> On Tue, 2008-06-10 at 13:50 +0300, Jouni Malinen wrote:
> > hostapd and wpa_supplicant include a test driver interface that allows
> > them to be tested on a single host without any wireless hardware for
> > development purposes. I have found this very valuable both for
> > developing new functionality and for testing existing code.
> >
> > In order to provide similar mechanism for mac80211 developers and to
> > extend the scope of suitable test cases for hostapd/wpa_supplicant, I've
> > written a Linux kernel module that provides a similar test interface at
> > a lower layer. mac80211_hwsim simulates WLAN hardware and the air
> > interface between the radios by acting as a low-level radio driver for
> > mac80211. Neither mac80211 nor user space programs need any changes to
> > work with the simulated radios.
>
> Way cool!
Yes, awesome!
> > The initial version of mac80211_hwsim is available from the
> > mac80211_hwsim subdirectory of my hostap Git tree:
> > git://w1.fi/srv/git/hostap.git
> > http://w1.fi/gitweb/gitweb.cgi?p=hostap.git;a=tree;f=mac80211_hwsim
> >
> > If there is interest in moving mac80211_hwsim module into the Linux
> > kernel tree, I'm open to doing that, too.
>
> I think that would make sense, yes, especially since one look at the
> code already tells me that it needs to follow large API changes to work
> with the current mac80211.
ACK
> One thing that I'd like to add is a having a "global" monitor interface
> that is registered by the hwsim module and not mac80211 and shows all
> frames, regardless of channel etc.
That sounds like a great idea. A mechanism for injecting frames from
an external source might be useful as well...?
Jouni this looks great. Let's get this into the kernel.
John
--
John W. Linville
[email protected]
On Tue, Jun 10, 2008 at 05:11:21PM +0200, Johannes Berg wrote:
> Hmm. I suspect you called rx_irqsafe _after_ the radio was stopped (via
> mac80211's stop callback), and at stop time we also disable the tasklet,
> so something probably goes haywire if you tasklet_schedule a disabled
> tasklet.
Yes, that caused it. I added a new flag based on start/stop for
determining which interface are ready to accept new frames. I was
already doing this based on radio_enabled flag, but apparently that is
left set when setting the interface down.
--
Jouni Malinen PGP id EFC895FA
Jouni Malinen wrote:
> That sounds better. net/wireless.h was bit confusing on this part since
> it has the "filled by the core" notice only for
> IEEE80211_RATE_MANDATORY_* flags, not for IEEE80211_RATE_ERP_G. Looks
> like this should be added to the ERP flag, too.
good point.
> OK, I'll remove it. With the current bands this seems to be fine, but
> how would that work with 10 MHz and 5 MHz channels? I haven't verified,
> but I would assume they could use same center frequency with 20 MHz
> channels..
Yeah... that isn't really supported yet.
> Hmm.. Aren't the channel and rate structures being modified by
> mac80211/wireless code? Sharing the same global data area for all radios
> might not be desired if there will be different "hw" capabilities as far
> as supported channels/rates/bands are concerned. In addition, the static
> data structures were marked 'const' which would at least be somewhat
> confusing if the data ends up changing.
They're only modified all the same, so it's fine to share unless you have
different capabilities. Yeah, you should removed the const then.
johannes
On Tue, 2008-06-10 at 13:50 +0300, Jouni Malinen wrote:
> hostapd and wpa_supplicant include a test driver interface that allows
> them to be tested on a single host without any wireless hardware for
> development purposes. I have found this very valuable both for
> developing new functionality and for testing existing code.
>
> In order to provide similar mechanism for mac80211 developers and to
> extend the scope of suitable test cases for hostapd/wpa_supplicant, I've
> written a Linux kernel module that provides a similar test interface at
> a lower layer. mac80211_hwsim simulates WLAN hardware and the air
> interface between the radios by acting as a low-level radio driver for
> mac80211. Neither mac80211 nor user space programs need any changes to
> work with the simulated radios.
Way cool!
> The initial version of mac80211_hwsim is available from the
> mac80211_hwsim subdirectory of my hostap Git tree:
> git://w1.fi/srv/git/hostap.git
> http://w1.fi/gitweb/gitweb.cgi?p=hostap.git;a=tree;f=mac80211_hwsim
>
> If there is interest in moving mac80211_hwsim module into the Linux
> kernel tree, I'm open to doing that, too.
I think that would make sense, yes, especially since one look at the
code already tells me that it needs to follow large API changes to work
with the current mac80211.
One thing caught my eye: you use GFP_KERNEL in the tx routine, that's
not good, it is running under a spinlock.
One thing that I'd like to add is a having a "global" monitor interface
that is registered by the hwsim module and not mac80211 and shows all
frames, regardless of channel etc.
johannes
On Wed, Jun 11, 2008 at 3:07 PM, Johannes Berg
<[email protected]> wrote:
> Jouni Malinen wrote:
>> That sounds better. net/wireless.h was bit confusing on this part since
>> it has the "filled by the core" notice only for
>> IEEE80211_RATE_MANDATORY_* flags, not for IEEE80211_RATE_ERP_G. Looks
>> like this should be added to the ERP flag, too.
>
> good point.
>
>> OK, I'll remove it. With the current bands this seems to be fine, but
>> how would that work with 10 MHz and 5 MHz channels? I haven't verified,
>> but I would assume they could use same center frequency with 20 MHz
>> channels..
>
> Yeah... that isn't really supported yet.
>
We've added support for FAT channels 40Mhz, but that uses negative
logic i.e. whether it's not supported. This is due to fact that FAT
channel may expand to above or bellow channel.
Isn't usage of 10Mhz and 5Mz being slowly deprecated anyway?
Tomas.
On Tue, Jun 10, 2008 at 03:11:09PM +0200, Johannes Berg wrote:
> > Jouni this looks great. Let's get this into the kernel.
>
> I wonder where to stick it. net/mac80211/virtual-hw.c? Or
> drivers/net/wireless/mac80211-virt.c? Heh. Not that it matters :)
drivers/net/wireless seems appropriate to me.
--
John W. Linville
[email protected]
> Here's a completely untested (well, it compiles) patch against
> wireless-test. I'll try to do some testing tomorrow, but if someone is
> interested in taking a closer look at a version that is converted to use
> the new data structures for channel/rate configuration, here's a
> preliminary version. All comments are welcome.
>
> As far as functionality is concerned, this is supposed to match with the
> 2.6.25-based version I have in hostap.git, i.e., the only changes are to
> convert the newer version of mac80211 API. Since I'm frequently using
> the latest 2.6.x release kernel instead of wireless-test (and would
> assume I'm not the only one doing that), I'm thinking of maintaining two
> versions of the module. One would be in wireless-test and maintained
> just like any other in-tree driver. The other one is in my hostap.git
> repository and is maintained as an out-of-tree version that is based on
> the latest (or well, relatively close to the latest, i.e., whatever I
> happen to be using ;-) released kernel. Of course, once the in-tree
> version hits a released kernel, out-of-tree version can die.
Sounds good to me.
> PS.
>
> The URL in Kconfig is just a placeholder and I'll add the information in
> README and hostapd/wpa_supplicant example configuration files there
> before this gets submitted properly.
Should we add it to Documentation/networking/ instead? Don't care much,
but it might be easier to track version changes that way.
> +static const struct ieee80211_rate hwsim_rates[] = {
> + { .bitrate = 10 },
> + { .bitrate = 20, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
> + { .bitrate = 55, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
> + { .bitrate = 110, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
> + { .bitrate = 60, .flags = IEEE80211_RATE_ERP_G },
You don't need to add the ERP flag manually, it'll be added based on the
rate automatically.
> + if (is_multicast_ether_addr(hdr->addr1))
> + ack = 1;
That seems a bit weird to me. mac80211 shouldn't request an ACK for
mcast, but why fake one?
> ... beacon ...
> + if (vif->type != IEEE80211_IF_TYPE_AP)
> + return;
That could support mesh as well, in mesh-beacon-like-AP mode rather than
mesh-beacon-like-IBSS.
> + data->channel->band != data2->channel->band ||
> + data->channel->center_freq != data2->channel->center_freq)
The band check is useless since the frequency is in MHz, it's mostly to
know which band table to look up things in if necessary.
> +static void mac80211_hwsim_beacon(unsigned long arg)
> +{
> + struct ieee80211_hw *hw = (struct ieee80211_hw *) arg;
> + struct mac80211_hwsim_data *data = hw->priv;
> +
> + if (!data->started || !data->radio_enabled)
> + return;
> +
> + ieee80211_iterate_active_interfaces(hw, mac80211_hwsim_beacon_tx, hw);
Cool, another user of this API :)
> + data->rx_filter = 0;
> + if (*total_flags & FIF_PROMISC_IN_BSS)
> + data->rx_filter |= FIF_PROMISC_IN_BSS;
> + if (*total_flags & FIF_ALLMULTI)
> + data->rx_filter |= FIF_ALLMULTI;
> +
> + *total_flags = data->rx_filter;
You don't actually seem to use these flags though. Should be added at
some point, I think.
> + memcpy(data->channels, hwsim_channels, sizeof(hwsim_channels));
> + memcpy(data->rates, hwsim_rates, sizeof(hwsim_rates));
> + data->band.channels = data->channels;
> + data->band.n_channels = ARRAY_SIZE(hwsim_channels);
> + data->band.bitrates = data->rates;
> + data->band.n_bitrates = ARRAY_SIZE(hwsim_rates);
You shouldn't need to memcpy these, just point to the static
allocations.
> + hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &data->band;
You can even allocate the band struct statically.
johannes
> > One thing that I'd like to add is a having a "global" monitor interface
> > that is registered by the hwsim module and not mac80211 and shows all
> > frames, regardless of channel etc.
>
> That sounds like a great idea. A mechanism for injecting frames from
> an external source might be useful as well...?
Using the same interface maybe? We can work on it.
> Jouni this looks great. Let's get this into the kernel.
I wonder where to stick it. net/mac80211/virtual-hw.c? Or
drivers/net/wireless/mac80211-virt.c? Heh. Not that it matters :)
johannes
On Tue, Jun 10, 2008 at 01:16:15PM +0200, Johannes Berg wrote:
> On Tue, 2008-06-10 at 13:50 +0300, Jouni Malinen wrote:
> > If there is interest in moving mac80211_hwsim module into the Linux
> > kernel tree, I'm open to doing that, too.
>
> I think that would make sense, yes, especially since one look at the
> code already tells me that it needs to follow large API changes to work
> with the current mac80211.
I'm currently running Linux 2.6.25 on my laptop and as such, this is
indeed not based on the latest changes. I'll fix couple of issues in the
current code with 2.6.25-based version and then look into making a
submission against wireless-testing (or if there are large, pending
patches that are not yet there, against something including those
changes).
> One thing caught my eye: you use GFP_KERNEL in the tx routine, that's
> not good, it is running under a spinlock.
Thanks, I'll fix that. I was trying to follow the documentation in
net/mac80211.h to verify that it is correct, but clearly I missed the
comment on tx() about the handler having to be atomic.
> One thing that I'd like to add is a having a "global" monitor interface
> that is registered by the hwsim module and not mac80211 and shows all
> frames, regardless of channel etc.
Yes, I've been thinking of something similar, too. I'll add a netdev
that gets all frames with radiotap header.
--
Jouni Malinen PGP id EFC895FA
On Tue, Jun 10, 2008 at 09:00:44PM +0200, Johannes Berg wrote:
> Should we add it to Documentation/networking/ instead? Don't care much,
> but it might be easier to track version changes that way.
That's fine, too. I'll add a subdirectory there for the readme and
example configuration files.
> > +static const struct ieee80211_rate hwsim_rates[] = {
> > + { .bitrate = 60, .flags = IEEE80211_RATE_ERP_G },
>
> You don't need to add the ERP flag manually, it'll be added based on the
> rate automatically.
That sounds better. net/wireless.h was bit confusing on this part since
it has the "filled by the core" notice only for
IEEE80211_RATE_MANDATORY_* flags, not for IEEE80211_RATE_ERP_G. Looks
like this should be added to the ERP flag, too.
> > + if (is_multicast_ether_addr(hdr->addr1))
> > + ack = 1;
>
> That seems a bit weird to me. mac80211 shouldn't request an ACK for
> mcast, but why fake one?
That was leftover from the previous version that did not check whether
IEEE80211_TX_CTL_NO_ACK was used. I'll remove it.
>
> > ... beacon ...
> > + if (vif->type != IEEE80211_IF_TYPE_AP)
> > + return;
>
> That could support mesh as well, in mesh-beacon-like-AP mode rather than
> mesh-beacon-like-IBSS.
Yes. I'm not yet very familiar with the mesh implementation in mac80211
and did not want to enable things before having had chance to test them.
> > + data->channel->band != data2->channel->band ||
> > + data->channel->center_freq != data2->channel->center_freq)
>
> The band check is useless since the frequency is in MHz, it's mostly to
> know which band table to look up things in if necessary.
OK, I'll remove it. With the current bands this seems to be fine, but
how would that work with 10 MHz and 5 MHz channels? I haven't verified,
but I would assume they could use same center frequency with 20 MHz
channels..
> > + ieee80211_iterate_active_interfaces(hw, mac80211_hwsim_beacon_tx, hw);
>
> Cool, another user of this API :)
I was first assuming that I have to implement some sort of data
structure to store all vifs in the driver code to do this, but this one
came in quite handy..
> > + data->rx_filter = 0;
> > + if (*total_flags & FIF_PROMISC_IN_BSS)
> > + data->rx_filter |= FIF_PROMISC_IN_BSS;
> You don't actually seem to use these flags though. Should be added at
> some point, I think.
Yes, I left it there for future implementation of the actually
filtering logic.
> > + memcpy(data->channels, hwsim_channels, sizeof(hwsim_channels));
> You shouldn't need to memcpy these, just point to the static
> allocations.
> > + hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &data->band;
>
> You can even allocate the band struct statically.
Hmm.. Aren't the channel and rate structures being modified by
mac80211/wireless code? Sharing the same global data area for all radios
might not be desired if there will be different "hw" capabilities as far
as supported channels/rates/bands are concerned. In addition, the static
data structures were marked 'const' which would at least be somewhat
confusing if the data ends up changing.
--
Jouni Malinen PGP id EFC895FA
On Tue, Jun 10, 2008 at 11:24:18AM -0400, John W. Linville wrote:
> drivers/net/wireless seems appropriate to me.
Here's a completely untested (well, it compiles) patch against
wireless-test. I'll try to do some testing tomorrow, but if someone is
interested in taking a closer look at a version that is converted to use
the new data structures for channel/rate configuration, here's a
preliminary version. All comments are welcome.
As far as functionality is concerned, this is supposed to match with the
2.6.25-based version I have in hostap.git, i.e., the only changes are to
convert the newer version of mac80211 API. Since I'm frequently using
the latest 2.6.x release kernel instead of wireless-test (and would
assume I'm not the only one doing that), I'm thinking of maintaining two
versions of the module. One would be in wireless-test and maintained
just like any other in-tree driver. The other one is in my hostap.git
repository and is maintained as an out-of-tree version that is based on
the latest (or well, relatively close to the latest, i.e., whatever I
happen to be using ;-) released kernel. Of course, once the in-tree
version hits a released kernel, out-of-tree version can die.
PS.
The URL in Kconfig is just a placeholder and I'll add the information in
README and hostapd/wpa_supplicant example configuration files there
before this gets submitted properly.
diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig
index 86323c8..91e197d 100644
--- a/drivers/net/wireless/Kconfig
+++ b/drivers/net/wireless/Kconfig
@@ -681,6 +681,19 @@ config ADM8211
Thanks to Infineon-ADMtek for their support of this driver.
+config MAC80211_HWSIM
+ tristate "Simulated radio testing tool for mac80211"
+ depends on MAC80211 && WLAN_80211
+ ---help---
+ This driver is a developer testing tool that can be used to test
+ IEEE 802.11 networking stack (mac80211) functionality. This is not
+ needed for normal wireless LAN usage and is only for testing. See
+ http://w1.fi/mac80211_hwsim/ for more information on how to use
+ this tool.
+
+ To compile this driver as a module, choose M here: the module will be
+ called mac80211_hwsim. If unsure, say N.
+
source "drivers/net/wireless/p54/Kconfig"
source "drivers/net/wireless/ath5k/Kconfig"
source "drivers/net/wireless/iwlwifi/Kconfig"
diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile
index 5026268..72c314e 100644
--- a/drivers/net/wireless/Makefile
+++ b/drivers/net/wireless/Makefile
@@ -64,3 +64,5 @@ obj-$(CONFIG_RT2X00) += rt2x00/
obj-$(CONFIG_P54_COMMON) += p54/
obj-$(CONFIG_ATH5K) += ath5k/
+
+obj-$(CONFIG_MAC80211_HWSIM) += mac80211_hwsim.o
diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c
new file mode 100644
index 0000000..03bbc7a
--- /dev/null
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -0,0 +1,536 @@
+/*
+ * mac80211_hwsim - software simulator of 802.11 radio(s) for mac80211
+ * Copyright (c) 2008, Jouni Malinen <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+/*
+ * TODO:
+ * - IBSS mode simulation (Beacon transmission with competition for "air time")
+ * - IEEE 802.11a and 802.11n modes
+ */
+
+#include <net/mac80211.h>
+#include <net/ieee80211_radiotap.h>
+#include <linux/if_arp.h>
+#include <linux/rtnetlink.h>
+#include <linux/etherdevice.h>
+
+MODULE_AUTHOR("Jouni Malinen");
+MODULE_DESCRIPTION("Software simulator of 802.11 radio(s) for mac80211");
+MODULE_LICENSE("GPL");
+
+static int radios = 2;
+module_param(radios, int, 0444);
+MODULE_PARM_DESC(radios, "Number of simulated radios");
+
+
+static struct class *hwsim_class;
+
+static struct ieee80211_hw **hwsim_radios;
+static int hwsim_radio_count;
+static struct net_device *hwsim_mon; /* global monitor netdev */
+
+
+static const struct ieee80211_channel hwsim_channels[] = {
+ { .center_freq = 2412 },
+ { .center_freq = 2417 },
+ { .center_freq = 2422 },
+ { .center_freq = 2427 },
+ { .center_freq = 2432 },
+ { .center_freq = 2437 },
+ { .center_freq = 2442 },
+ { .center_freq = 2447 },
+ { .center_freq = 2452 },
+ { .center_freq = 2457 },
+ { .center_freq = 2462 },
+ { .center_freq = 2467 },
+ { .center_freq = 2472 },
+ { .center_freq = 2484 },
+};
+
+static const struct ieee80211_rate hwsim_rates[] = {
+ { .bitrate = 10 },
+ { .bitrate = 20, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
+ { .bitrate = 55, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
+ { .bitrate = 110, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
+ { .bitrate = 60, .flags = IEEE80211_RATE_ERP_G },
+ { .bitrate = 90, .flags = IEEE80211_RATE_ERP_G },
+ { .bitrate = 120, .flags = IEEE80211_RATE_ERP_G },
+ { .bitrate = 180, .flags = IEEE80211_RATE_ERP_G },
+ { .bitrate = 240, .flags = IEEE80211_RATE_ERP_G },
+ { .bitrate = 360, .flags = IEEE80211_RATE_ERP_G },
+ { .bitrate = 480, .flags = IEEE80211_RATE_ERP_G },
+ { .bitrate = 540, .flags = IEEE80211_RATE_ERP_G }
+};
+
+struct mac80211_hwsim_data {
+ struct device *dev;
+ struct ieee80211_supported_band band;
+ struct ieee80211_channel channels[ARRAY_SIZE(hwsim_channels)];
+ struct ieee80211_rate rates[ARRAY_SIZE(hwsim_rates)];
+
+ struct ieee80211_channel *channel;
+ int radio_enabled;
+ unsigned long beacon_int; /* in jiffies unit */
+ unsigned int rx_filter;
+ int started;
+ struct timer_list beacon_timer;
+};
+
+
+struct hwsim_radiotap_hdr {
+ struct ieee80211_radiotap_header hdr;
+ u8 rt_flags;
+ u8 rt_rate;
+ __le16 rt_channel;
+ __le16 rt_chbitmask;
+} __attribute__ ((packed));
+
+
+static int hwsim_mon_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ /* TODO: allow packet injection */
+ dev_kfree_skb(skb);
+ return 0;
+}
+
+
+static void mac80211_hwsim_monitor_rx(struct ieee80211_hw *hw,
+ struct sk_buff *tx_skb)
+{
+ struct mac80211_hwsim_data *data = hw->priv;
+ struct sk_buff *skb;
+ struct hwsim_radiotap_hdr *hdr;
+ u16 flags;
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx_skb);
+ struct ieee80211_rate *txrate = ieee80211_get_tx_rate(hw, info);
+
+ if (!netif_running(hwsim_mon))
+ return;
+
+ skb = skb_copy_expand(tx_skb, sizeof(*hdr), 0, GFP_ATOMIC);
+ if (skb == NULL)
+ return;
+
+ hdr = (struct hwsim_radiotap_hdr *) skb_push(skb, sizeof(*hdr));
+ hdr->hdr.it_version = PKTHDR_RADIOTAP_VERSION;
+ hdr->hdr.it_pad = 0;
+ hdr->hdr.it_len = cpu_to_le16(sizeof(*hdr));
+ hdr->hdr.it_present = __constant_cpu_to_le32(
+ (1 << IEEE80211_RADIOTAP_FLAGS) |
+ (1 << IEEE80211_RADIOTAP_RATE) |
+ (1 << IEEE80211_RADIOTAP_CHANNEL));
+ hdr->rt_flags = 0;
+ hdr->rt_rate = txrate->bitrate / 5;
+ hdr->rt_channel = data->channel->center_freq;
+ flags = IEEE80211_CHAN_2GHZ;
+ if (txrate->flags & IEEE80211_RATE_ERP_G)
+ flags |= IEEE80211_CHAN_OFDM;
+ else
+ flags |= IEEE80211_CHAN_CCK;
+ hdr->rt_chbitmask = cpu_to_le16(flags);
+
+ skb->dev = hwsim_mon;
+ skb_set_mac_header(skb, 0);
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ skb->pkt_type = PACKET_OTHERHOST;
+ skb->protocol = __constant_htons(ETH_P_802_2);
+ memset(skb->cb, 0, sizeof(skb->cb));
+ netif_rx(skb);
+}
+
+
+static int mac80211_hwsim_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
+{
+ struct mac80211_hwsim_data *data = hw->priv;
+ struct ieee80211_rx_status rx_status;
+ int i, ack = 0;
+ struct ieee80211_hdr *hdr;
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+ struct ieee80211_tx_info *txi;
+
+ mac80211_hwsim_monitor_rx(hw, skb);
+
+ if (skb->len < 10) {
+ /* Should not happen; just a sanity check for addr1 use */
+ dev_kfree_skb(skb);
+ return NETDEV_TX_OK;
+ }
+
+ if (!data->radio_enabled) {
+ printk(KERN_DEBUG "%s: dropped TX frame since radio "
+ "disabled\n", wiphy_name(hw->wiphy));
+ dev_kfree_skb(skb);
+ return NETDEV_TX_OK;
+ }
+
+ hdr = (struct ieee80211_hdr *) skb->data;
+ if (is_multicast_ether_addr(hdr->addr1))
+ ack = 1;
+
+ memset(&rx_status, 0, sizeof(rx_status));
+ /* TODO: set mactime */
+ rx_status.freq = data->channel->center_freq;
+ rx_status.band = data->channel->band;
+ rx_status.rate_idx = info->tx_rate_idx;
+ /* TODO: simulate signal strength (and optional packet drop) */
+
+ /* Copy skb to all enabled radios that are on the current frequency */
+ for (i = 0; i < hwsim_radio_count; i++) {
+ struct mac80211_hwsim_data *data2;
+ struct sk_buff *nskb;
+
+ if (hwsim_radios[i] == NULL || hwsim_radios[i] == hw)
+ continue;
+ data2 = hwsim_radios[i]->priv;
+ if (!data2->started || !data2->radio_enabled ||
+ data->channel->band != data2->channel->band ||
+ data->channel->center_freq != data2->channel->center_freq)
+ continue;
+
+ nskb = skb_copy(skb, GFP_ATOMIC);
+ if (nskb == NULL)
+ continue;
+
+ if (memcmp(hdr->addr1, hwsim_radios[i]->wiphy->perm_addr,
+ ETH_ALEN) == 0)
+ ack = 1;
+ ieee80211_rx_irqsafe(hwsim_radios[i], nskb, &rx_status);
+ }
+
+ txi = IEEE80211_SKB_CB(skb);
+ memset(&txi->status, 0, sizeof(txi->status));
+ if (!(txi->flags & IEEE80211_TX_CTL_NO_ACK)) {
+ if (ack)
+ txi->flags |= IEEE80211_TX_STAT_ACK;
+ else
+ txi->status.excessive_retries = 1;
+ }
+ ieee80211_tx_status_irqsafe(hw, skb);
+ return NETDEV_TX_OK;
+}
+
+
+static int mac80211_hwsim_start(struct ieee80211_hw *hw)
+{
+ struct mac80211_hwsim_data *data = hw->priv;
+ printk(KERN_DEBUG "%s:%s\n", wiphy_name(hw->wiphy), __func__);
+ data->started = 1;
+ return 0;
+}
+
+
+static void mac80211_hwsim_stop(struct ieee80211_hw *hw)
+{
+ struct mac80211_hwsim_data *data = hw->priv;
+ data->started = 0;
+ printk(KERN_DEBUG "%s:%s\n", wiphy_name(hw->wiphy), __func__);
+}
+
+
+static int mac80211_hwsim_add_interface(struct ieee80211_hw *hw,
+ struct ieee80211_if_init_conf *conf)
+{
+ DECLARE_MAC_BUF(mac);
+ printk(KERN_DEBUG "%s:%s (type=%d mac_addr=%s)\n",
+ wiphy_name(hw->wiphy), __func__, conf->type,
+ print_mac(mac, conf->mac_addr));
+ return 0;
+}
+
+
+static void mac80211_hwsim_remove_interface(
+ struct ieee80211_hw *hw, struct ieee80211_if_init_conf *conf)
+{
+ DECLARE_MAC_BUF(mac);
+ printk(KERN_DEBUG "%s:%s (type=%d mac_addr=%s)\n",
+ wiphy_name(hw->wiphy), __func__, conf->type,
+ print_mac(mac, conf->mac_addr));
+}
+
+
+static void mac80211_hwsim_beacon_tx(void *arg, u8 *mac,
+ struct ieee80211_vif *vif)
+{
+ struct ieee80211_hw *hw = arg;
+ struct mac80211_hwsim_data *data = hw->priv;
+ struct sk_buff *skb;
+ struct ieee80211_rx_status rx_status;
+ int i;
+ struct ieee80211_tx_info *info;
+
+ if (vif->type != IEEE80211_IF_TYPE_AP)
+ return;
+
+ skb = ieee80211_beacon_get(hw, vif);
+ if (skb == NULL)
+ return;
+ info = IEEE80211_SKB_CB(skb);
+
+ mac80211_hwsim_monitor_rx(hw, skb);
+
+ memset(&rx_status, 0, sizeof(rx_status));
+ /* TODO: set mactime */
+ rx_status.freq = data->channel->center_freq;
+ rx_status.band = data->channel->band;
+ rx_status.rate_idx = info->tx_rate_idx;
+ /* TODO: simulate signal strength (and optional packet drop) */
+
+ /* Copy skb to all enabled radios that are on the current frequency */
+ for (i = 0; i < hwsim_radio_count; i++) {
+ struct mac80211_hwsim_data *data2;
+ struct sk_buff *nskb;
+
+ if (hwsim_radios[i] == NULL || hwsim_radios[i] == hw)
+ continue;
+ data2 = hwsim_radios[i]->priv;
+ if (!data2->started || !data2->radio_enabled ||
+ data->channel->band != data2->channel->band ||
+ data->channel->center_freq != data2->channel->center_freq)
+ continue;
+
+ nskb = skb_copy(skb, GFP_ATOMIC);
+ if (nskb == NULL)
+ continue;
+
+ ieee80211_rx_irqsafe(hwsim_radios[i], nskb, &rx_status);
+ }
+
+ dev_kfree_skb(skb);
+}
+
+
+static void mac80211_hwsim_beacon(unsigned long arg)
+{
+ struct ieee80211_hw *hw = (struct ieee80211_hw *) arg;
+ struct mac80211_hwsim_data *data = hw->priv;
+
+ if (!data->started || !data->radio_enabled)
+ return;
+
+ ieee80211_iterate_active_interfaces(hw, mac80211_hwsim_beacon_tx, hw);
+
+ data->beacon_timer.expires = jiffies + data->beacon_int;
+ add_timer(&data->beacon_timer);
+}
+
+
+static int mac80211_hwsim_config(struct ieee80211_hw *hw,
+ struct ieee80211_conf *conf)
+{
+ struct mac80211_hwsim_data *data = hw->priv;
+
+ printk(KERN_DEBUG "%s:%s (freq=%d radio_enabled=%d beacon_int=%d)\n",
+ wiphy_name(hw->wiphy), __func__,
+ conf->channel->center_freq, conf->radio_enabled,
+ conf->beacon_int);
+
+ data->channel = conf->channel;
+ data->radio_enabled = conf->radio_enabled;
+ data->beacon_int = 1024 * conf->beacon_int / 1000 * HZ / 1000;
+ if (data->beacon_int < 1)
+ data->beacon_int = 1;
+
+ if (!data->started || !data->radio_enabled)
+ del_timer(&data->beacon_timer);
+ else
+ mod_timer(&data->beacon_timer, jiffies + data->beacon_int);
+
+ return 0;
+}
+
+
+static void mac80211_hwsim_configure_filter(struct ieee80211_hw *hw,
+ unsigned int changed_flags,
+ unsigned int *total_flags,
+ int mc_count,
+ struct dev_addr_list *mc_list)
+{
+ struct mac80211_hwsim_data *data = hw->priv;
+
+ printk(KERN_DEBUG "%s:%s\n", wiphy_name(hw->wiphy), __func__);
+
+ data->rx_filter = 0;
+ if (*total_flags & FIF_PROMISC_IN_BSS)
+ data->rx_filter |= FIF_PROMISC_IN_BSS;
+ if (*total_flags & FIF_ALLMULTI)
+ data->rx_filter |= FIF_ALLMULTI;
+
+ *total_flags = data->rx_filter;
+}
+
+
+
+static const struct ieee80211_ops mac80211_hwsim_ops =
+{
+ .tx = mac80211_hwsim_tx,
+ .start = mac80211_hwsim_start,
+ .stop = mac80211_hwsim_stop,
+ .add_interface = mac80211_hwsim_add_interface,
+ .remove_interface = mac80211_hwsim_remove_interface,
+ .config = mac80211_hwsim_config,
+ .configure_filter = mac80211_hwsim_configure_filter,
+};
+
+
+static void mac80211_hwsim_free(void)
+{
+ int i;
+
+ for (i = 0; i < hwsim_radio_count; i++) {
+ if (hwsim_radios[i]) {
+ struct mac80211_hwsim_data *data;
+ data = hwsim_radios[i]->priv;
+ ieee80211_unregister_hw(hwsim_radios[i]);
+ if (!IS_ERR(data->dev))
+ device_unregister(data->dev);
+ ieee80211_free_hw(hwsim_radios[i]);
+ }
+ }
+ kfree(hwsim_radios);
+ class_destroy(hwsim_class);
+}
+
+
+static struct device_driver mac80211_hwsim_driver = {
+ .name = "mac80211_hwsim"
+};
+
+
+static void hwsim_mon_setup(struct net_device *dev)
+{
+ dev->hard_start_xmit = hwsim_mon_xmit;
+ dev->destructor = free_netdev;
+ ether_setup(dev);
+ dev->tx_queue_len = 0;
+ dev->type = ARPHRD_IEEE80211_RADIOTAP;
+ memset(dev->dev_addr, 0, ETH_ALEN);
+ dev->dev_addr[0] = 0x12;
+}
+
+
+static int __init init_mac80211_hwsim(void)
+{
+ int i, err = 0;
+ u8 addr[ETH_ALEN];
+ struct mac80211_hwsim_data *data;
+ struct ieee80211_hw *hw;
+ DECLARE_MAC_BUF(mac);
+
+ if (radios < 1 || radios > 65535)
+ return -EINVAL;
+
+ hwsim_radio_count = radios;
+ hwsim_radios = kcalloc(hwsim_radio_count,
+ sizeof(struct ieee80211_hw *), GFP_KERNEL);
+ if (hwsim_radios == NULL)
+ return -ENOMEM;
+
+ hwsim_class = class_create(THIS_MODULE, "mac80211_hwsim");
+ if (IS_ERR(hwsim_class)) {
+ kfree(hwsim_radios);
+ return PTR_ERR(hwsim_class);
+ }
+
+ memset(addr, 0, ETH_ALEN);
+ addr[0] = 0x02;
+
+ for (i = 0; i < hwsim_radio_count; i++) {
+ printk(KERN_DEBUG "mac80211_hwsim: Initializing radio %d\n",
+ i);
+ hw = ieee80211_alloc_hw(sizeof(*data), &mac80211_hwsim_ops);
+ if (hw == NULL) {
+ printk(KERN_DEBUG "mac80211_hwsim: ieee80211_alloc_hw "
+ "failed\n");
+ err = -ENOMEM;
+ goto failed;
+ }
+ hwsim_radios[i] = hw;
+
+ data = hw->priv;
+ data->dev = device_create(hwsim_class, NULL, 0, "hwsim%d", i);
+ if (IS_ERR(data->dev)) {
+ printk(KERN_DEBUG "mac80211_hwsim: device_create "
+ "failed (%ld)\n", PTR_ERR(data->dev));
+ err = -ENOMEM;
+ goto failed;
+ }
+ data->dev->driver = &mac80211_hwsim_driver;
+ dev_set_drvdata(data->dev, hw);
+
+ SET_IEEE80211_DEV(hw, data->dev);
+ addr[3] = i >> 8;
+ addr[4] = i;
+ SET_IEEE80211_PERM_ADDR(hw, addr);
+
+ hw->channel_change_time = 1;
+ hw->queues = 1;
+
+ memcpy(data->channels, hwsim_channels, sizeof(hwsim_channels));
+ memcpy(data->rates, hwsim_rates, sizeof(hwsim_rates));
+ data->band.channels = data->channels;
+ data->band.n_channels = ARRAY_SIZE(hwsim_channels);
+ data->band.bitrates = data->rates;
+ data->band.n_bitrates = ARRAY_SIZE(hwsim_rates);
+ hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &data->band;
+
+ err = ieee80211_register_hw(hw);
+ if (err < 0) {
+ printk(KERN_DEBUG "mac80211_hwsim: "
+ "ieee80211_register_hw failed (%d)\n", err);
+ goto failed;
+ }
+
+ printk(KERN_DEBUG "%s: hwaddr %s registered\n",
+ wiphy_name(hw->wiphy),
+ print_mac(mac, hw->wiphy->perm_addr));
+
+ setup_timer(&data->beacon_timer, mac80211_hwsim_beacon,
+ (unsigned long) hw);
+ }
+
+ hwsim_mon = alloc_netdev(0, "hwsim%d", hwsim_mon_setup);
+ if (hwsim_mon == NULL)
+ goto failed;
+
+ rtnl_lock();
+
+ err = dev_alloc_name(hwsim_mon, hwsim_mon->name);
+ if (err < 0) {
+ goto failed_mon;
+ }
+
+ err = register_netdevice(hwsim_mon);
+ if (err < 0)
+ goto failed_mon;
+
+ rtnl_unlock();
+
+ return 0;
+
+failed_mon:
+ rtnl_unlock();
+ free_netdev(hwsim_mon);
+
+failed:
+ mac80211_hwsim_free();
+ return err;
+}
+
+
+static void __exit exit_mac80211_hwsim(void)
+{
+ printk(KERN_DEBUG "mac80211_hwsim: unregister %d radios\n",
+ hwsim_radio_count);
+
+ unregister_netdev(hwsim_mon);
+ mac80211_hwsim_free();
+}
+
+
+module_init(init_mac80211_hwsim);
+module_exit(exit_mac80211_hwsim);
--
Jouni Malinen PGP id EFC895FA
On Tue, 2008-06-10 at 13:50 +0300, Jouni Malinen wrote:
> hostapd and wpa_supplicant include a test driver interface that allows
> them to be tested on a single host without any wireless hardware for
> development purposes. I have found this very valuable both for
> developing new functionality and for testing existing code.
>
> In order to provide similar mechanism for mac80211 developers and to
> extend the scope of suitable test cases for hostapd/wpa_supplicant, I've
> written a Linux kernel module that provides a similar test interface at
> a lower layer. mac80211_hwsim simulates WLAN hardware and the air
> interface between the radios by acting as a low-level radio driver for
> mac80211. Neither mac80211 nor user space programs need any changes to
> work with the simulated radios.
Awesome. I was going to write a basic WEXT driver so I could get some
better tests going for NetworkManager, but you've beaten me to it :)
Thanks!
Dan
> The initial version of mac80211_hwsim is available from the
> mac80211_hwsim subdirectory of my hostap Git tree:
> git://w1.fi/srv/git/hostap.git
> http://w1.fi/gitweb/gitweb.cgi?p=hostap.git;a=tree;f=mac80211_hwsim
>
> If there is interest in moving mac80211_hwsim module into the Linux
> kernel tree, I'm open to doing that, too.
>
> I've included some more information about the code in the README file
> (see below) and there are also example configuration files for hostapd
> and wpa_supplicant to show how a WPA2-Personal connection can be opened
> with mac80211_hwsim.
>
> mac80211_hwsim is still very minimal, but I have added couple of TODO
> comments to the source code to indicate areas that I'm hoping to add for
> more complete support of mac80211 features. I would also be interested
> in feedback from other mac80211 developers on what kind of functionality
> would be useful to have in this kind of simulated test setup. I'm first
> looking into using this to develop IEEE 802.11w (management frame
> protection) support into mac80211 and I would expect that the current
> minimal design is enough for that, but there is certainly room for much
> more, e.g., in the area of simulating signal strength and packet loss
> for testing TX rate control, retransmission, and power save
> functionality.
>
>
>
> README:
>
> Introduction
>
> mac80211_hwsim is a Linux kernel module that can be used to simulate
> arbitrary number of IEEE 802.11 radios for mac80211 on a single
> device. It can be used to test most of the mac80211 functionality and
> user space tools (e.g., hostapd and wpa_supplicant) in a way that
> matches very closely with the normal case of using real WLAN
> hardware. From the mac80211 view point, mac80211_hwsim is yet another
> hardware driver, i.e., no changes to mac80211 are needed to use this
> testing tool.
>
> The main goal for mac80211_hwsim is to make it easier for developers
> to test their code and work with new features to mac80211, hostapd,
> and wpa_supplicant. The simulated radios do not have the limitations
> of real hardware, so it is easy to generate an arbitrary test setup
> and always reproduce the same setup for future tests. In addition,
> since all radio operation is simulated, any channel can be used in
> tests regardless of regulatory rules.
>
> mac80211_hwsim kernel module has a parameter 'radios' that can be used
> to select how many radios are simulates (default 2). This allows
> configuration of both very simply setups (e.g., just a single access
> point and a station) or large scale tests (multiple access points with
> hundreds of stations).
>
> mac80211_hwsim works by tracking the current channel of each virtual
> radio and copying all transmitted frames to all other radios that are
> currently enabled and on the same channel as the transmitting
> radio. Software encryption in mac80211 is used so that the frames are
> actually encrypted over the virtual air interface to allow more
> complete testing of encryption.
>
>
> Simple example
>
> This example shows how to use mac80211_hwsim to simulate two radios:
> one to act as an access point and the other as a station that
> associates with the AP. hostapd and wpa_supplicant are used to take
> care of WPA2-PSK authentication. In addition, hostapd is also
> processing access point side of association.
>
> Please note that the currently released Linux kernel (2.6.25) does not
> enable AP mode, so a simple patch is needed to enable AP mode selection:
> http://johannes.sipsolutions.net/patches/kernel/all/LATEST/006-allow-ap-vlan-modes.patch
>
>
> # Build mac80211_hwsim:
> make
>
> # Load the module
> insmod ./mac80211_hwsim.ko
>
> # Run hostapd (AP) for wlan0
> hostapd hostapd.conf
>
> # Run wpa_supplicant (station) for wlan1
> wpa_supplicant -Dwext -iwlan1 -c wpa_supplicant.conf
>
> > You should probably use the _irqsafe versions of rx and txstatus too.
>
> Hmm.. That was interesting.. Changing txstatus to use _irqsafe is was
> fine, but changing ieee80211_rx to ieee80211_rx_irqsafe triggers
> something bad.. Loadavg jumps sky high the moment I kill hostapd and
> ksoftirqd/0 and rmmod (which I ran after killing hostapd) are taking all
> CPU.. I can hardly type a command at that point. Looks like something
> goes horribly wrong with the extra queuing with ieee80211_rx_irqsafe.
> Maybe sending something to a netdev that is down ends up in a busy loop
> with a frame or something. In other words, I did not change to use
> _irqsafe yet, but will do once I have more time to figure out what on
> earth is going on here.
Hmm. I suspect you called rx_irqsafe _after_ the radio was stopped (via
mac80211's stop callback), and at stop time we also disable the tasklet,
so something probably goes haywire if you tasklet_schedule a disabled
tasklet.
> Yes, I added the global radiotap monitor to hwsim (ifname=hwsim#) and
> left the hard_xmit function empty with a TODO comment.. The netdev from
> outside mac80211 is quite useful since it can be set up before any of
> the mac80211 netdevs and it is possible to capture all frames from the
> beginning.. If needed, we could add some more flags to the radiotap
> header for indicating what was done with the frame, but that is
> something that can easily be added later.
Yeah, true, good to have the simpler code in place first anyway.
> > The design I had come up with a long time ago allowed userspace to
> > control each radio by having each _radio_ have a raw netdev like this
> > and not doing forwarding in the kernel but relying on some userspace
> > tool, but I guess that much more complicated.
>
> That might be useful for some of the tests. I was interested in adding
> some kind of interface to make it easy to design test cases from user
> space, but the current code was so simple that I did not want to make it
> any more complex in the first version. Anyway, it might make sense to
> provide option mechanism to allow more user space control since I'm also
> interested in things like testing rate control with a programmable
> signal strength/channel quality and I do not really want to see the
> controller for that simulation in the kernel..
Heh, yeah. I'd like to have it more dynamically configurable too, but we
can add that later as well. Maybe some debugfs stuff or so that allows
disconnecting a radio from the "virtual air" at which point a hwsim
per-radio netdev shows up for that one. Anyway, future, when needed.
johannes
On Tue, Jun 10, 2008 at 03:09:38PM +0200, Johannes Berg wrote:
> I don't think there are large pending changes, but there were large
> changes in the way channels are registered, tx control works etc.
OK.
> You should probably use the _irqsafe versions of rx and txstatus too.
Hmm.. That was interesting.. Changing txstatus to use _irqsafe is was
fine, but changing ieee80211_rx to ieee80211_rx_irqsafe triggers
something bad.. Loadavg jumps sky high the moment I kill hostapd and
ksoftirqd/0 and rmmod (which I ran after killing hostapd) are taking all
CPU.. I can hardly type a command at that point. Looks like something
goes horribly wrong with the extra queuing with ieee80211_rx_irqsafe.
Maybe sending something to a netdev that is down ends up in a busy loop
with a frame or something. In other words, I did not change to use
_irqsafe yet, but will do once I have more time to figure out what on
earth is going on here.
> > Yes, I've been thinking of something similar, too. I'll add a netdev
> > that gets all frames with radiotap header.
>
> Maybe it could support injection on that too, so you can test against a
> userspace agent.
Yes, I added the global radiotap monitor to hwsim (ifname=hwsim#) and
left the hard_xmit function empty with a TODO comment.. The netdev from
outside mac80211 is quite useful since it can be set up before any of
the mac80211 netdevs and it is possible to capture all frames from the
beginning.. If needed, we could add some more flags to the radiotap
header for indicating what was done with the frame, but that is
something that can easily be added later.
> The design I had come up with a long time ago allowed userspace to
> control each radio by having each _radio_ have a raw netdev like this
> and not doing forwarding in the kernel but relying on some userspace
> tool, but I guess that much more complicated.
That might be useful for some of the tests. I was interested in adding
some kind of interface to make it easy to design test cases from user
space, but the current code was so simple that I did not want to make it
any more complex in the first version. Anyway, it might make sense to
provide option mechanism to allow more user space control since I'm also
interested in things like testing rate control with a programmable
signal strength/channel quality and I do not really want to see the
controller for that simulation in the kernel..
--
Jouni Malinen PGP id EFC895FA