diff options
Diffstat (limited to 'drivers')
-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(); |