aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJouni Malinen <j@w1.fi>2008-06-11 03:42:31 -0400
committerJohn W. Linville <linville@tuxdriver.com>2008-06-14 12:18:11 -0400
commitacc1e7a3007ec1940374206a84465c1e0cfcda09 (patch)
treeaf6f8a36da6979d0e4504615aa57a6b4bd87c561
parent14a08a7fcf72a8d69cdee225cc76c50b229faa20 (diff)
mac80211_hwsim: 802.11 radio simulator for mac80211
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. Signed-off-by: Jouni Malinen <j@w1.fi> Acked-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r--Documentation/networking/mac80211_hwsim/README68
-rw-r--r--Documentation/networking/mac80211_hwsim/hostapd.conf11
-rw-r--r--Documentation/networking/mac80211_hwsim/wpa_supplicant.conf10
-rw-r--r--drivers/net/wireless/Kconfig13
-rw-r--r--drivers/net/wireless/Makefile2
-rw-r--r--drivers/net/wireless/mac80211_hwsim.c533
6 files changed, 637 insertions, 0 deletions
diff --git a/Documentation/networking/mac80211_hwsim/README b/Documentation/networking/mac80211_hwsim/README
new file mode 100644
index 000000000000..2f6e90fcb5a7
--- /dev/null
+++ b/Documentation/networking/mac80211_hwsim/README
@@ -0,0 +1,68 @@
1mac80211_hwsim - software simulator of 802.11 radio(s) for mac80211
2Copyright (c) 2008, Jouni Malinen <j@w1.fi>
3
4This program is free software; you can redistribute it and/or modify
5it under the terms of the GNU General Public License version 2 as
6published by the Free Software Foundation.
7
8
9Introduction
10
11mac80211_hwsim is a Linux kernel module that can be used to simulate
12arbitrary number of IEEE 802.11 radios for mac80211 on a single
13device. It can be used to test most of the mac80211 functionality and
14user space tools (e.g., hostapd and wpa_supplicant) in a way that
15matches very closely with the normal case of using real WLAN
16hardware. From the mac80211 view point, mac80211_hwsim is yet another
17hardware driver, i.e., no changes to mac80211 are needed to use this
18testing tool.
19
20The main goal for mac80211_hwsim is to make it easier for developers
21to test their code and work with new features to mac80211, hostapd,
22and wpa_supplicant. The simulated radios do not have the limitations
23of real hardware, so it is easy to generate an arbitrary test setup
24and always reproduce the same setup for future tests. In addition,
25since all radio operation is simulated, any channel can be used in
26tests regardless of regulatory rules.
27
28mac80211_hwsim kernel module has a parameter 'radios' that can be used
29to select how many radios are simulates (default 2). This allows
30configuration of both very simply setups (e.g., just a single access
31point and a station) or large scale tests (multiple access points with
32hundreds of stations).
33
34mac80211_hwsim works by tracking the current channel of each virtual
35radio and copying all transmitted frames to all other radios that are
36currently enabled and on the same channel as the transmitting
37radio. Software encryption in mac80211 is used so that the frames are
38actually encrypted over the virtual air interface to allow more
39complete testing of encryption.
40
41A global monitoring netdev, hwsim#, is created independent of
42mac80211. This interface can be used to monitor all transmitted frames
43regardless of channel.
44
45
46Simple example
47
48This example shows how to use mac80211_hwsim to simulate two radios:
49one to act as an access point and the other as a station that
50associates with the AP. hostapd and wpa_supplicant are used to take
51care of WPA2-PSK authentication. In addition, hostapd is also
52processing access point side of association.
53
54Please note that the current Linux kernel does not enable AP mode, so a
55simple patch is needed to enable AP mode selection:
56http://johannes.sipsolutions.net/patches/kernel/all/LATEST/006-allow-ap-vlan-modes.patch
57
58
59# Build mac80211_hwsim as part of kernel configuration
60
61# Load the module
62modprobe mac80211_hwsim
63
64# Run hostapd (AP) for wlan0
65hostapd hostapd.conf
66
67# Run wpa_supplicant (station) for wlan1
68wpa_supplicant -Dwext -iwlan1 -c wpa_supplicant.conf
diff --git a/Documentation/networking/mac80211_hwsim/hostapd.conf b/Documentation/networking/mac80211_hwsim/hostapd.conf
new file mode 100644
index 000000000000..08cde7e35f2e
--- /dev/null
+++ b/Documentation/networking/mac80211_hwsim/hostapd.conf
@@ -0,0 +1,11 @@
1interface=wlan0
2driver=nl80211
3
4hw_mode=g
5channel=1
6ssid=mac80211 test
7
8wpa=2
9wpa_key_mgmt=WPA-PSK
10wpa_pairwise=CCMP
11wpa_passphrase=12345678
diff --git a/Documentation/networking/mac80211_hwsim/wpa_supplicant.conf b/Documentation/networking/mac80211_hwsim/wpa_supplicant.conf
new file mode 100644
index 000000000000..299128cff035
--- /dev/null
+++ b/Documentation/networking/mac80211_hwsim/wpa_supplicant.conf
@@ -0,0 +1,10 @@
1ctrl_interface=/var/run/wpa_supplicant
2
3network={
4 ssid="mac80211 test"
5 psk="12345678"
6 key_mgmt=WPA-PSK
7 proto=WPA2
8 pairwise=CCMP
9 group=CCMP
10}
diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig
index fdf5aa8b8429..22e1e9a1fb73 100644
--- a/drivers/net/wireless/Kconfig
+++ b/drivers/net/wireless/Kconfig
@@ -673,6 +673,19 @@ config ADM8211
673 673
674 Thanks to Infineon-ADMtek for their support of this driver. 674 Thanks to Infineon-ADMtek for their support of this driver.
675 675
676config MAC80211_HWSIM
677 tristate "Simulated radio testing tool for mac80211"
678 depends on MAC80211 && WLAN_80211
679 ---help---
680 This driver is a developer testing tool that can be used to test
681 IEEE 802.11 networking stack (mac80211) functionality. This is not
682 needed for normal wireless LAN usage and is only for testing. See
683 Documentation/networking/mac80211_hwsim for more information on how
684 to use this tool.
685
686 To compile this driver as a module, choose M here: the module will be
687 called mac80211_hwsim. If unsure, say N.
688
676source "drivers/net/wireless/p54/Kconfig" 689source "drivers/net/wireless/p54/Kconfig"
677source "drivers/net/wireless/ath5k/Kconfig" 690source "drivers/net/wireless/ath5k/Kconfig"
678source "drivers/net/wireless/iwlwifi/Kconfig" 691source "drivers/net/wireless/iwlwifi/Kconfig"
diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile
index 2c343aae38d4..54a4f6f1db67 100644
--- a/drivers/net/wireless/Makefile
+++ b/drivers/net/wireless/Makefile
@@ -62,3 +62,5 @@ obj-$(CONFIG_RT2X00) += rt2x00/
62obj-$(CONFIG_P54_COMMON) += p54/ 62obj-$(CONFIG_P54_COMMON) += p54/
63 63
64obj-$(CONFIG_ATH5K) += ath5k/ 64obj-$(CONFIG_ATH5K) += ath5k/
65
66obj-$(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 000000000000..3e33b29a4fc9
--- /dev/null
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -0,0 +1,533 @@
1/*
2 * mac80211_hwsim - software simulator of 802.11 radio(s) for mac80211
3 * Copyright (c) 2008, Jouni Malinen <j@w1.fi>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
8 */
9
10/*
11 * TODO:
12 * - IBSS mode simulation (Beacon transmission with competition for "air time")
13 * - IEEE 802.11a and 802.11n modes
14 * - RX filtering based on filter configuration (data->rx_filter)
15 */
16
17#include <net/mac80211.h>
18#include <net/ieee80211_radiotap.h>
19#include <linux/if_arp.h>
20#include <linux/rtnetlink.h>
21#include <linux/etherdevice.h>
22
23MODULE_AUTHOR("Jouni Malinen");
24MODULE_DESCRIPTION("Software simulator of 802.11 radio(s) for mac80211");
25MODULE_LICENSE("GPL");
26
27static int radios = 2;
28module_param(radios, int, 0444);
29MODULE_PARM_DESC(radios, "Number of simulated radios");
30
31
32static struct class *hwsim_class;
33
34static struct ieee80211_hw **hwsim_radios;
35static int hwsim_radio_count;
36static struct net_device *hwsim_mon; /* global monitor netdev */
37
38
39static const struct ieee80211_channel hwsim_channels[] = {
40 { .center_freq = 2412 },
41 { .center_freq = 2417 },
42 { .center_freq = 2422 },
43 { .center_freq = 2427 },
44 { .center_freq = 2432 },
45 { .center_freq = 2437 },
46 { .center_freq = 2442 },
47 { .center_freq = 2447 },
48 { .center_freq = 2452 },
49 { .center_freq = 2457 },
50 { .center_freq = 2462 },
51 { .center_freq = 2467 },
52 { .center_freq = 2472 },
53 { .center_freq = 2484 },
54};
55
56static const struct ieee80211_rate hwsim_rates[] = {
57 { .bitrate = 10 },
58 { .bitrate = 20, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
59 { .bitrate = 55, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
60 { .bitrate = 110, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
61 { .bitrate = 60 },
62 { .bitrate = 90 },
63 { .bitrate = 120 },
64 { .bitrate = 180 },
65 { .bitrate = 240 },
66 { .bitrate = 360 },
67 { .bitrate = 480 },
68 { .bitrate = 540 }
69};
70
71struct mac80211_hwsim_data {
72 struct device *dev;
73 struct ieee80211_supported_band band;
74 struct ieee80211_channel channels[ARRAY_SIZE(hwsim_channels)];
75 struct ieee80211_rate rates[ARRAY_SIZE(hwsim_rates)];
76
77 struct ieee80211_channel *channel;
78 int radio_enabled;
79 unsigned long beacon_int; /* in jiffies unit */
80 unsigned int rx_filter;
81 int started;
82 struct timer_list beacon_timer;
83};
84
85
86struct hwsim_radiotap_hdr {
87 struct ieee80211_radiotap_header hdr;
88 u8 rt_flags;
89 u8 rt_rate;
90 __le16 rt_channel;
91 __le16 rt_chbitmask;
92} __attribute__ ((packed));
93
94
95static int hwsim_mon_xmit(struct sk_buff *skb, struct net_device *dev)
96{
97 /* TODO: allow packet injection */
98 dev_kfree_skb(skb);
99 return 0;
100}
101
102
103static void mac80211_hwsim_monitor_rx(struct ieee80211_hw *hw,
104 struct sk_buff *tx_skb)
105{
106 struct mac80211_hwsim_data *data = hw->priv;
107 struct sk_buff *skb;
108 struct hwsim_radiotap_hdr *hdr;
109 u16 flags;
110 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx_skb);
111 struct ieee80211_rate *txrate = ieee80211_get_tx_rate(hw, info);
112
113 if (!netif_running(hwsim_mon))
114 return;
115
116 skb = skb_copy_expand(tx_skb, sizeof(*hdr), 0, GFP_ATOMIC);
117 if (skb == NULL)
118 return;
119
120 hdr = (struct hwsim_radiotap_hdr *) skb_push(skb, sizeof(*hdr));
121 hdr->hdr.it_version = PKTHDR_RADIOTAP_VERSION;
122 hdr->hdr.it_pad = 0;
123 hdr->hdr.it_len = cpu_to_le16(sizeof(*hdr));
124 hdr->hdr.it_present = __constant_cpu_to_le32(
125 (1 << IEEE80211_RADIOTAP_FLAGS) |
126 (1 << IEEE80211_RADIOTAP_RATE) |
127 (1 << IEEE80211_RADIOTAP_CHANNEL));
128 hdr->rt_flags = 0;
129 hdr->rt_rate = txrate->bitrate / 5;
130 hdr->rt_channel = data->channel->center_freq;
131 flags = IEEE80211_CHAN_2GHZ;
132 if (txrate->flags & IEEE80211_RATE_ERP_G)
133 flags |= IEEE80211_CHAN_OFDM;
134 else
135 flags |= IEEE80211_CHAN_CCK;
136 hdr->rt_chbitmask = cpu_to_le16(flags);
137
138 skb->dev = hwsim_mon;
139 skb_set_mac_header(skb, 0);
140 skb->ip_summed = CHECKSUM_UNNECESSARY;
141 skb->pkt_type = PACKET_OTHERHOST;
142 skb->protocol = __constant_htons(ETH_P_802_2);
143 memset(skb->cb, 0, sizeof(skb->cb));
144 netif_rx(skb);
145}
146
147
148static int mac80211_hwsim_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
149{
150 struct mac80211_hwsim_data *data = hw->priv;
151 struct ieee80211_rx_status rx_status;
152 int i, ack = 0;
153 struct ieee80211_hdr *hdr;
154 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
155 struct ieee80211_tx_info *txi;
156
157 mac80211_hwsim_monitor_rx(hw, skb);
158
159 if (skb->len < 10) {
160 /* Should not happen; just a sanity check for addr1 use */
161 dev_kfree_skb(skb);
162 return NETDEV_TX_OK;
163 }
164
165 if (!data->radio_enabled) {
166 printk(KERN_DEBUG "%s: dropped TX frame since radio "
167 "disabled\n", wiphy_name(hw->wiphy));
168 dev_kfree_skb(skb);
169 return NETDEV_TX_OK;
170 }
171
172 hdr = (struct ieee80211_hdr *) skb->data;
173
174 memset(&rx_status, 0, sizeof(rx_status));
175 /* TODO: set mactime */
176 rx_status.freq = data->channel->center_freq;
177 rx_status.band = data->channel->band;
178 rx_status.rate_idx = info->tx_rate_idx;
179 /* TODO: simulate signal strength (and optional packet drop) */
180
181 /* Copy skb to all enabled radios that are on the current frequency */
182 for (i = 0; i < hwsim_radio_count; i++) {
183 struct mac80211_hwsim_data *data2;
184 struct sk_buff *nskb;
185
186 if (hwsim_radios[i] == NULL || hwsim_radios[i] == hw)
187 continue;
188 data2 = hwsim_radios[i]->priv;
189 if (!data2->started || !data2->radio_enabled ||
190 data->channel->center_freq != data2->channel->center_freq)
191 continue;
192
193 nskb = skb_copy(skb, GFP_ATOMIC);
194 if (nskb == NULL)
195 continue;
196
197 if (memcmp(hdr->addr1, hwsim_radios[i]->wiphy->perm_addr,
198 ETH_ALEN) == 0)
199 ack = 1;
200 ieee80211_rx_irqsafe(hwsim_radios[i], nskb, &rx_status);
201 }
202
203 txi = IEEE80211_SKB_CB(skb);
204 memset(&txi->status, 0, sizeof(txi->status));
205 if (!(txi->flags & IEEE80211_TX_CTL_NO_ACK)) {
206 if (ack)
207 txi->flags |= IEEE80211_TX_STAT_ACK;
208 else
209 txi->status.excessive_retries = 1;
210 }
211 ieee80211_tx_status_irqsafe(hw, skb);
212 return NETDEV_TX_OK;
213}
214
215
216static int mac80211_hwsim_start(struct ieee80211_hw *hw)
217{
218 struct mac80211_hwsim_data *data = hw->priv;
219 printk(KERN_DEBUG "%s:%s\n", wiphy_name(hw->wiphy), __func__);
220 data->started = 1;
221 return 0;
222}
223
224
225static void mac80211_hwsim_stop(struct ieee80211_hw *hw)
226{
227 struct mac80211_hwsim_data *data = hw->priv;
228 data->started = 0;
229 printk(KERN_DEBUG "%s:%s\n", wiphy_name(hw->wiphy), __func__);
230}
231
232
233static int mac80211_hwsim_add_interface(struct ieee80211_hw *hw,
234 struct ieee80211_if_init_conf *conf)
235{
236 DECLARE_MAC_BUF(mac);
237 printk(KERN_DEBUG "%s:%s (type=%d mac_addr=%s)\n",
238 wiphy_name(hw->wiphy), __func__, conf->type,
239 print_mac(mac, conf->mac_addr));
240 return 0;
241}
242
243
244static void mac80211_hwsim_remove_interface(
245 struct ieee80211_hw *hw, struct ieee80211_if_init_conf *conf)
246{
247 DECLARE_MAC_BUF(mac);
248 printk(KERN_DEBUG "%s:%s (type=%d mac_addr=%s)\n",
249 wiphy_name(hw->wiphy), __func__, conf->type,
250 print_mac(mac, conf->mac_addr));
251}
252
253
254static void mac80211_hwsim_beacon_tx(void *arg, u8 *mac,
255 struct ieee80211_vif *vif)
256{
257 struct ieee80211_hw *hw = arg;
258 struct mac80211_hwsim_data *data = hw->priv;
259 struct sk_buff *skb;
260 struct ieee80211_rx_status rx_status;
261 int i;
262 struct ieee80211_tx_info *info;
263
264 if (vif->type != IEEE80211_IF_TYPE_AP)
265 return;
266
267 skb = ieee80211_beacon_get(hw, vif);
268 if (skb == NULL)
269 return;
270 info = IEEE80211_SKB_CB(skb);
271
272 mac80211_hwsim_monitor_rx(hw, skb);
273
274 memset(&rx_status, 0, sizeof(rx_status));
275 /* TODO: set mactime */
276 rx_status.freq = data->channel->center_freq;
277 rx_status.band = data->channel->band;
278 rx_status.rate_idx = info->tx_rate_idx;
279 /* TODO: simulate signal strength (and optional packet drop) */
280
281 /* Copy skb to all enabled radios that are on the current frequency */
282 for (i = 0; i < hwsim_radio_count; i++) {
283 struct mac80211_hwsim_data *data2;
284 struct sk_buff *nskb;
285
286 if (hwsim_radios[i] == NULL || hwsim_radios[i] == hw)
287 continue;
288 data2 = hwsim_radios[i]->priv;
289 if (!data2->started || !data2->radio_enabled ||
290 data->channel->center_freq != data2->channel->center_freq)
291 continue;
292
293 nskb = skb_copy(skb, GFP_ATOMIC);
294 if (nskb == NULL)
295 continue;
296
297 ieee80211_rx_irqsafe(hwsim_radios[i], nskb, &rx_status);
298 }
299
300 dev_kfree_skb(skb);
301}
302
303
304static void mac80211_hwsim_beacon(unsigned long arg)
305{
306 struct ieee80211_hw *hw = (struct ieee80211_hw *) arg;
307 struct mac80211_hwsim_data *data = hw->priv;
308
309 if (!data->started || !data->radio_enabled)
310 return;
311
312 ieee80211_iterate_active_interfaces(hw, mac80211_hwsim_beacon_tx, hw);
313
314 data->beacon_timer.expires = jiffies + data->beacon_int;
315 add_timer(&data->beacon_timer);
316}
317
318
319static int mac80211_hwsim_config(struct ieee80211_hw *hw,
320 struct ieee80211_conf *conf)
321{
322 struct mac80211_hwsim_data *data = hw->priv;
323
324 printk(KERN_DEBUG "%s:%s (freq=%d radio_enabled=%d beacon_int=%d)\n",
325 wiphy_name(hw->wiphy), __func__,
326 conf->channel->center_freq, conf->radio_enabled,
327 conf->beacon_int);
328
329 data->channel = conf->channel;
330 data->radio_enabled = conf->radio_enabled;
331 data->beacon_int = 1024 * conf->beacon_int / 1000 * HZ / 1000;
332 if (data->beacon_int < 1)
333 data->beacon_int = 1;
334
335 if (!data->started || !data->radio_enabled)
336 del_timer(&data->beacon_timer);
337 else
338 mod_timer(&data->beacon_timer, jiffies + data->beacon_int);
339
340 return 0;
341}
342
343
344static void mac80211_hwsim_configure_filter(struct ieee80211_hw *hw,
345 unsigned int changed_flags,
346 unsigned int *total_flags,
347 int mc_count,
348 struct dev_addr_list *mc_list)
349{
350 struct mac80211_hwsim_data *data = hw->priv;
351
352 printk(KERN_DEBUG "%s:%s\n", wiphy_name(hw->wiphy), __func__);
353
354 data->rx_filter = 0;
355 if (*total_flags & FIF_PROMISC_IN_BSS)
356 data->rx_filter |= FIF_PROMISC_IN_BSS;
357 if (*total_flags & FIF_ALLMULTI)
358 data->rx_filter |= FIF_ALLMULTI;
359
360 *total_flags = data->rx_filter;
361}
362
363
364
365static const struct ieee80211_ops mac80211_hwsim_ops =
366{
367 .tx = mac80211_hwsim_tx,
368 .start = mac80211_hwsim_start,
369 .stop = mac80211_hwsim_stop,
370 .add_interface = mac80211_hwsim_add_interface,
371 .remove_interface = mac80211_hwsim_remove_interface,
372 .config = mac80211_hwsim_config,
373 .configure_filter = mac80211_hwsim_configure_filter,
374};
375
376
377static void mac80211_hwsim_free(void)
378{
379 int i;
380
381 for (i = 0; i < hwsim_radio_count; i++) {
382 if (hwsim_radios[i]) {
383 struct mac80211_hwsim_data *data;
384 data = hwsim_radios[i]->priv;
385 ieee80211_unregister_hw(hwsim_radios[i]);
386 if (!IS_ERR(data->dev))
387 device_unregister(data->dev);
388 ieee80211_free_hw(hwsim_radios[i]);
389 }
390 }
391 kfree(hwsim_radios);
392 class_destroy(hwsim_class);
393}
394
395
396static struct device_driver mac80211_hwsim_driver = {
397 .name = "mac80211_hwsim"
398};
399
400
401static void hwsim_mon_setup(struct net_device *dev)
402{
403 dev->hard_start_xmit = hwsim_mon_xmit;
404 dev->destructor = free_netdev;
405 ether_setup(dev);
406 dev->tx_queue_len = 0;
407 dev->type = ARPHRD_IEEE80211_RADIOTAP;
408 memset(dev->dev_addr, 0, ETH_ALEN);
409 dev->dev_addr[0] = 0x12;
410}
411
412
413static int __init init_mac80211_hwsim(void)
414{
415 int i, err = 0;
416 u8 addr[ETH_ALEN];
417 struct mac80211_hwsim_data *data;
418 struct ieee80211_hw *hw;
419 DECLARE_MAC_BUF(mac);
420
421 if (radios < 1 || radios > 65535)
422 return -EINVAL;
423
424 hwsim_radio_count = radios;
425 hwsim_radios = kcalloc(hwsim_radio_count,
426 sizeof(struct ieee80211_hw *), GFP_KERNEL);
427 if (hwsim_radios == NULL)
428 return -ENOMEM;
429
430 hwsim_class = class_create(THIS_MODULE, "mac80211_hwsim");
431 if (IS_ERR(hwsim_class)) {
432 kfree(hwsim_radios);
433 return PTR_ERR(hwsim_class);
434 }
435
436 memset(addr, 0, ETH_ALEN);
437 addr[0] = 0x02;
438
439 for (i = 0; i < hwsim_radio_count; i++) {
440 printk(KERN_DEBUG "mac80211_hwsim: Initializing radio %d\n",
441 i);
442 hw = ieee80211_alloc_hw(sizeof(*data), &mac80211_hwsim_ops);
443 if (hw == NULL) {
444 printk(KERN_DEBUG "mac80211_hwsim: ieee80211_alloc_hw "
445 "failed\n");
446 err = -ENOMEM;
447 goto failed;
448 }
449 hwsim_radios[i] = hw;
450
451 data = hw->priv;
452 data->dev = device_create(hwsim_class, NULL, 0, "hwsim%d", i);
453 if (IS_ERR(data->dev)) {
454 printk(KERN_DEBUG "mac80211_hwsim: device_create "
455 "failed (%ld)\n", PTR_ERR(data->dev));
456 err = -ENOMEM;
457 goto failed;
458 }
459 data->dev->driver = &mac80211_hwsim_driver;
460 dev_set_drvdata(data->dev, hw);
461
462 SET_IEEE80211_DEV(hw, data->dev);
463 addr[3] = i >> 8;
464 addr[4] = i;
465 SET_IEEE80211_PERM_ADDR(hw, addr);
466
467 hw->channel_change_time = 1;
468 hw->queues = 1;
469
470 memcpy(data->channels, hwsim_channels, sizeof(hwsim_channels));
471 memcpy(data->rates, hwsim_rates, sizeof(hwsim_rates));
472 data->band.channels = data->channels;
473 data->band.n_channels = ARRAY_SIZE(hwsim_channels);
474 data->band.bitrates = data->rates;
475 data->band.n_bitrates = ARRAY_SIZE(hwsim_rates);
476 hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &data->band;
477
478 err = ieee80211_register_hw(hw);
479 if (err < 0) {
480 printk(KERN_DEBUG "mac80211_hwsim: "
481 "ieee80211_register_hw failed (%d)\n", err);
482 goto failed;
483 }
484
485 printk(KERN_DEBUG "%s: hwaddr %s registered\n",
486 wiphy_name(hw->wiphy),
487 print_mac(mac, hw->wiphy->perm_addr));
488
489 setup_timer(&data->beacon_timer, mac80211_hwsim_beacon,
490 (unsigned long) hw);
491 }
492
493 hwsim_mon = alloc_netdev(0, "hwsim%d", hwsim_mon_setup);
494 if (hwsim_mon == NULL)
495 goto failed;
496
497 rtnl_lock();
498
499 err = dev_alloc_name(hwsim_mon, hwsim_mon->name);
500 if (err < 0) {
501 goto failed_mon;
502 }
503
504 err = register_netdevice(hwsim_mon);
505 if (err < 0)
506 goto failed_mon;
507
508 rtnl_unlock();
509
510 return 0;
511
512failed_mon:
513 rtnl_unlock();
514 free_netdev(hwsim_mon);
515
516failed:
517 mac80211_hwsim_free();
518 return err;
519}
520
521
522static void __exit exit_mac80211_hwsim(void)
523{
524 printk(KERN_DEBUG "mac80211_hwsim: unregister %d radios\n",
525 hwsim_radio_count);
526
527 unregister_netdev(hwsim_mon);
528 mac80211_hwsim_free();
529}
530
531
532module_init(init_mac80211_hwsim);
533module_exit(exit_mac80211_hwsim);