diff options
author | Johannes Berg <johannes@sipsolutions.net> | 2008-09-11 18:39:22 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2008-09-15 16:48:25 -0400 |
commit | 0e057d73eacd952d321d46c7eb972969ec245026 (patch) | |
tree | ca20bd3d12e605c63bd5dea9536a73b92b2f06e8 /drivers/net | |
parent | 25d834e16294c8dfd923dae6bdb8a055391a99a5 (diff) |
mac80211 hwsim: make radio list dynamic
This paves the way for dynamic radio additions while the module
is loaded. Also restrict the number of radios to 100 because
creating that many already takes forever.
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/wireless/mac80211_hwsim.c | 86 |
1 files changed, 45 insertions, 41 deletions
diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 631d65b73edf..c9e4a435b2fc 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c | |||
@@ -14,6 +14,8 @@ | |||
14 | * - RX filtering based on filter configuration (data->rx_filter) | 14 | * - RX filtering based on filter configuration (data->rx_filter) |
15 | */ | 15 | */ |
16 | 16 | ||
17 | #include <linux/list.h> | ||
18 | #include <linux/spinlock.h> | ||
17 | #include <net/mac80211.h> | 19 | #include <net/mac80211.h> |
18 | #include <net/ieee80211_radiotap.h> | 20 | #include <net/ieee80211_radiotap.h> |
19 | #include <linux/if_arp.h> | 21 | #include <linux/if_arp.h> |
@@ -78,8 +80,6 @@ static inline void hwsim_clear_sta_magic(struct ieee80211_sta *sta) | |||
78 | 80 | ||
79 | static struct class *hwsim_class; | 81 | static struct class *hwsim_class; |
80 | 82 | ||
81 | static struct ieee80211_hw **hwsim_radios; | ||
82 | static int hwsim_radio_count; | ||
83 | static struct net_device *hwsim_mon; /* global monitor netdev */ | 83 | static struct net_device *hwsim_mon; /* global monitor netdev */ |
84 | 84 | ||
85 | 85 | ||
@@ -115,7 +115,12 @@ static const struct ieee80211_rate hwsim_rates[] = { | |||
115 | { .bitrate = 540 } | 115 | { .bitrate = 540 } |
116 | }; | 116 | }; |
117 | 117 | ||
118 | static spinlock_t hwsim_radio_lock; | ||
119 | static struct list_head hwsim_radios; | ||
120 | |||
118 | struct mac80211_hwsim_data { | 121 | struct mac80211_hwsim_data { |
122 | struct list_head list; | ||
123 | struct ieee80211_hw *hw; | ||
119 | struct device *dev; | 124 | struct device *dev; |
120 | struct ieee80211_supported_band band; | 125 | struct ieee80211_supported_band band; |
121 | struct ieee80211_channel channels[ARRAY_SIZE(hwsim_channels)]; | 126 | struct ieee80211_channel channels[ARRAY_SIZE(hwsim_channels)]; |
@@ -191,11 +196,11 @@ static void mac80211_hwsim_monitor_rx(struct ieee80211_hw *hw, | |||
191 | } | 196 | } |
192 | 197 | ||
193 | 198 | ||
194 | static int mac80211_hwsim_tx_frame(struct ieee80211_hw *hw, | 199 | static bool mac80211_hwsim_tx_frame(struct ieee80211_hw *hw, |
195 | struct sk_buff *skb) | 200 | struct sk_buff *skb) |
196 | { | 201 | { |
197 | struct mac80211_hwsim_data *data = hw->priv; | 202 | struct mac80211_hwsim_data *data = hw->priv, *data2; |
198 | int i, ack = 0; | 203 | bool ack = false; |
199 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; | 204 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; |
200 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | 205 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
201 | struct ieee80211_rx_status rx_status; | 206 | struct ieee80211_rx_status rx_status; |
@@ -208,13 +213,13 @@ static int mac80211_hwsim_tx_frame(struct ieee80211_hw *hw, | |||
208 | /* TODO: simulate signal strength (and optional packet drop) */ | 213 | /* TODO: simulate signal strength (and optional packet drop) */ |
209 | 214 | ||
210 | /* Copy skb to all enabled radios that are on the current frequency */ | 215 | /* Copy skb to all enabled radios that are on the current frequency */ |
211 | for (i = 0; i < hwsim_radio_count; i++) { | 216 | spin_lock(&hwsim_radio_lock); |
212 | struct mac80211_hwsim_data *data2; | 217 | list_for_each_entry(data2, &hwsim_radios, list) { |
213 | struct sk_buff *nskb; | 218 | struct sk_buff *nskb; |
214 | 219 | ||
215 | if (hwsim_radios[i] == NULL || hwsim_radios[i] == hw) | 220 | if (data == data2) |
216 | continue; | 221 | continue; |
217 | data2 = hwsim_radios[i]->priv; | 222 | |
218 | if (!data2->started || !data2->radio_enabled || | 223 | if (!data2->started || !data2->radio_enabled || |
219 | data->channel->center_freq != data2->channel->center_freq) | 224 | data->channel->center_freq != data2->channel->center_freq) |
220 | continue; | 225 | continue; |
@@ -223,11 +228,12 @@ static int mac80211_hwsim_tx_frame(struct ieee80211_hw *hw, | |||
223 | if (nskb == NULL) | 228 | if (nskb == NULL) |
224 | continue; | 229 | continue; |
225 | 230 | ||
226 | if (memcmp(hdr->addr1, hwsim_radios[i]->wiphy->perm_addr, | 231 | if (memcmp(hdr->addr1, data2->hw->wiphy->perm_addr, |
227 | ETH_ALEN) == 0) | 232 | ETH_ALEN) == 0) |
228 | ack = 1; | 233 | ack = true; |
229 | ieee80211_rx_irqsafe(hwsim_radios[i], nskb, &rx_status); | 234 | ieee80211_rx_irqsafe(data2->hw, nskb, &rx_status); |
230 | } | 235 | } |
236 | spin_unlock(&hwsim_radio_lock); | ||
231 | 237 | ||
232 | return ack; | 238 | return ack; |
233 | } | 239 | } |
@@ -236,7 +242,7 @@ static int mac80211_hwsim_tx_frame(struct ieee80211_hw *hw, | |||
236 | static int mac80211_hwsim_tx(struct ieee80211_hw *hw, struct sk_buff *skb) | 242 | static int mac80211_hwsim_tx(struct ieee80211_hw *hw, struct sk_buff *skb) |
237 | { | 243 | { |
238 | struct mac80211_hwsim_data *data = hw->priv; | 244 | struct mac80211_hwsim_data *data = hw->priv; |
239 | int ack; | 245 | bool ack; |
240 | struct ieee80211_tx_info *txi; | 246 | struct ieee80211_tx_info *txi; |
241 | 247 | ||
242 | mac80211_hwsim_monitor_rx(hw, skb); | 248 | mac80211_hwsim_monitor_rx(hw, skb); |
@@ -457,18 +463,21 @@ static const struct ieee80211_ops mac80211_hwsim_ops = | |||
457 | 463 | ||
458 | static void mac80211_hwsim_free(void) | 464 | static void mac80211_hwsim_free(void) |
459 | { | 465 | { |
460 | int i; | 466 | struct list_head tmplist, *i, *tmp; |
461 | 467 | struct mac80211_hwsim_data *data; | |
462 | for (i = 0; i < hwsim_radio_count; i++) { | 468 | |
463 | if (hwsim_radios[i]) { | 469 | INIT_LIST_HEAD(&tmplist); |
464 | struct mac80211_hwsim_data *data; | 470 | |
465 | data = hwsim_radios[i]->priv; | 471 | spin_lock_bh(&hwsim_radio_lock); |
466 | ieee80211_unregister_hw(hwsim_radios[i]); | 472 | list_for_each_safe(i, tmp, &hwsim_radios) |
467 | device_unregister(data->dev); | 473 | list_move(i, &tmplist); |
468 | ieee80211_free_hw(hwsim_radios[i]); | 474 | spin_unlock_bh(&hwsim_radio_lock); |
469 | } | 475 | |
476 | list_for_each_entry(data, &tmplist, list) { | ||
477 | ieee80211_unregister_hw(data->hw); | ||
478 | device_unregister(data->dev); | ||
479 | ieee80211_free_hw(data->hw); | ||
470 | } | 480 | } |
471 | kfree(hwsim_radios); | ||
472 | class_destroy(hwsim_class); | 481 | class_destroy(hwsim_class); |
473 | } | 482 | } |
474 | 483 | ||
@@ -498,37 +507,32 @@ static int __init init_mac80211_hwsim(void) | |||
498 | struct ieee80211_hw *hw; | 507 | struct ieee80211_hw *hw; |
499 | DECLARE_MAC_BUF(mac); | 508 | DECLARE_MAC_BUF(mac); |
500 | 509 | ||
501 | if (radios < 1 || radios > 65535) | 510 | if (radios < 1 || radios > 100) |
502 | return -EINVAL; | 511 | return -EINVAL; |
503 | 512 | ||
504 | hwsim_radio_count = radios; | 513 | spin_lock_init(&hwsim_radio_lock); |
505 | hwsim_radios = kcalloc(hwsim_radio_count, | 514 | INIT_LIST_HEAD(&hwsim_radios); |
506 | sizeof(struct ieee80211_hw *), GFP_KERNEL); | ||
507 | if (hwsim_radios == NULL) | ||
508 | return -ENOMEM; | ||
509 | 515 | ||
510 | hwsim_class = class_create(THIS_MODULE, "mac80211_hwsim"); | 516 | hwsim_class = class_create(THIS_MODULE, "mac80211_hwsim"); |
511 | if (IS_ERR(hwsim_class)) { | 517 | if (IS_ERR(hwsim_class)) |
512 | kfree(hwsim_radios); | ||
513 | return PTR_ERR(hwsim_class); | 518 | return PTR_ERR(hwsim_class); |
514 | } | ||
515 | 519 | ||
516 | memset(addr, 0, ETH_ALEN); | 520 | memset(addr, 0, ETH_ALEN); |
517 | addr[0] = 0x02; | 521 | addr[0] = 0x02; |
518 | 522 | ||
519 | for (i = 0; i < hwsim_radio_count; i++) { | 523 | for (i = 0; i < radios; i++) { |
520 | printk(KERN_DEBUG "mac80211_hwsim: Initializing radio %d\n", | 524 | printk(KERN_DEBUG "mac80211_hwsim: Initializing radio %d\n", |
521 | i); | 525 | i); |
522 | hw = ieee80211_alloc_hw(sizeof(*data), &mac80211_hwsim_ops); | 526 | hw = ieee80211_alloc_hw(sizeof(*data), &mac80211_hwsim_ops); |
523 | if (hw == NULL) { | 527 | if (!hw) { |
524 | printk(KERN_DEBUG "mac80211_hwsim: ieee80211_alloc_hw " | 528 | printk(KERN_DEBUG "mac80211_hwsim: ieee80211_alloc_hw " |
525 | "failed\n"); | 529 | "failed\n"); |
526 | err = -ENOMEM; | 530 | err = -ENOMEM; |
527 | goto failed; | 531 | goto failed; |
528 | } | 532 | } |
529 | hwsim_radios[i] = hw; | ||
530 | |||
531 | data = hw->priv; | 533 | data = hw->priv; |
534 | data->hw = hw; | ||
535 | |||
532 | data->dev = device_create_drvdata(hwsim_class, NULL, 0, hw, | 536 | data->dev = device_create_drvdata(hwsim_class, NULL, 0, hw, |
533 | "hwsim%d", i); | 537 | "hwsim%d", i); |
534 | if (IS_ERR(data->dev)) { | 538 | if (IS_ERR(data->dev)) { |
@@ -590,6 +594,8 @@ static int __init init_mac80211_hwsim(void) | |||
590 | 594 | ||
591 | setup_timer(&data->beacon_timer, mac80211_hwsim_beacon, | 595 | setup_timer(&data->beacon_timer, mac80211_hwsim_beacon, |
592 | (unsigned long) hw); | 596 | (unsigned long) hw); |
597 | |||
598 | list_add_tail(&data->list, &hwsim_radios); | ||
593 | } | 599 | } |
594 | 600 | ||
595 | hwsim_mon = alloc_netdev(0, "hwsim%d", hwsim_mon_setup); | 601 | hwsim_mon = alloc_netdev(0, "hwsim%d", hwsim_mon_setup); |
@@ -621,7 +627,6 @@ failed_hw: | |||
621 | device_unregister(data->dev); | 627 | device_unregister(data->dev); |
622 | failed_drvdata: | 628 | failed_drvdata: |
623 | ieee80211_free_hw(hw); | 629 | ieee80211_free_hw(hw); |
624 | hwsim_radios[i] = NULL; | ||
625 | failed: | 630 | failed: |
626 | mac80211_hwsim_free(); | 631 | mac80211_hwsim_free(); |
627 | return err; | 632 | return err; |
@@ -630,8 +635,7 @@ failed: | |||
630 | 635 | ||
631 | static void __exit exit_mac80211_hwsim(void) | 636 | static void __exit exit_mac80211_hwsim(void) |
632 | { | 637 | { |
633 | printk(KERN_DEBUG "mac80211_hwsim: unregister %d radios\n", | 638 | printk(KERN_DEBUG "mac80211_hwsim: unregister radios\n"); |
634 | hwsim_radio_count); | ||
635 | 639 | ||
636 | unregister_netdev(hwsim_mon); | 640 | unregister_netdev(hwsim_mon); |
637 | mac80211_hwsim_free(); | 641 | mac80211_hwsim_free(); |