diff options
author | Johannes Berg <johannes.berg@intel.com> | 2012-07-27 13:48:26 -0400 |
---|---|---|
committer | Johannes Berg <johannes.berg@intel.com> | 2012-10-30 04:11:33 -0400 |
commit | e826117142d87c5fbdfd17a053f6a33ec90b20a4 (patch) | |
tree | 6e8f73db4cda6d333080a33e1ee97edb13681aa0 /drivers/net/wireless/mac80211_hwsim.c | |
parent | 6fb47de9cf1be4710fb9f364c500ff216fb47b34 (diff) |
mac80211_hwsim: allow using channel contexts
To use mac80211_hwsim for testing channel contexts it
has to support them, and for that it has to support
hw scan and hw-remain-on-channel.
Since it's pure software, the off-channel activities
are really not off-channel but listening and sending
on a second channel. Also, the multi-channel isn't
really doing TDM, it's just on both channels at the
same time.
For testing purposes, you can specify the number of
concurrent channels with a module parameter, it is
set to one by default. When set to two or more, the
userspace API for wmediumd is disabled as it has no
provisions for multi-channel yet.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'drivers/net/wireless/mac80211_hwsim.c')
-rw-r--r-- | drivers/net/wireless/mac80211_hwsim.c | 490 |
1 files changed, 390 insertions, 100 deletions
diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 429ca3215fdb..96e91dd17b34 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c | |||
@@ -44,9 +44,9 @@ static int radios = 2; | |||
44 | module_param(radios, int, 0444); | 44 | module_param(radios, int, 0444); |
45 | MODULE_PARM_DESC(radios, "Number of simulated radios"); | 45 | MODULE_PARM_DESC(radios, "Number of simulated radios"); |
46 | 46 | ||
47 | static bool fake_hw_scan; | 47 | static int channels = 1; |
48 | module_param(fake_hw_scan, bool, 0444); | 48 | module_param(channels, int, 0444); |
49 | MODULE_PARM_DESC(fake_hw_scan, "Install fake (no-op) hw-scan handler"); | 49 | MODULE_PARM_DESC(channels, "Number of concurrent channels"); |
50 | 50 | ||
51 | /** | 51 | /** |
52 | * enum hwsim_regtest - the type of regulatory tests we offer | 52 | * enum hwsim_regtest - the type of regulatory tests we offer |
@@ -166,7 +166,9 @@ struct hwsim_vif_priv { | |||
166 | static inline void hwsim_check_magic(struct ieee80211_vif *vif) | 166 | static inline void hwsim_check_magic(struct ieee80211_vif *vif) |
167 | { | 167 | { |
168 | struct hwsim_vif_priv *vp = (void *)vif->drv_priv; | 168 | struct hwsim_vif_priv *vp = (void *)vif->drv_priv; |
169 | WARN_ON(vp->magic != HWSIM_VIF_MAGIC); | 169 | WARN(vp->magic != HWSIM_VIF_MAGIC, |
170 | "Invalid VIF (%p) magic %#x, %pM, %d/%d\n", | ||
171 | vif, vp->magic, vif->addr, vif->type, vif->p2p); | ||
170 | } | 172 | } |
171 | 173 | ||
172 | static inline void hwsim_set_magic(struct ieee80211_vif *vif) | 174 | static inline void hwsim_set_magic(struct ieee80211_vif *vif) |
@@ -185,7 +187,7 @@ struct hwsim_sta_priv { | |||
185 | u32 magic; | 187 | u32 magic; |
186 | }; | 188 | }; |
187 | 189 | ||
188 | #define HWSIM_STA_MAGIC 0x6d537748 | 190 | #define HWSIM_STA_MAGIC 0x6d537749 |
189 | 191 | ||
190 | static inline void hwsim_check_sta_magic(struct ieee80211_sta *sta) | 192 | static inline void hwsim_check_sta_magic(struct ieee80211_sta *sta) |
191 | { | 193 | { |
@@ -205,6 +207,30 @@ static inline void hwsim_clear_sta_magic(struct ieee80211_sta *sta) | |||
205 | sp->magic = 0; | 207 | sp->magic = 0; |
206 | } | 208 | } |
207 | 209 | ||
210 | struct hwsim_chanctx_priv { | ||
211 | u32 magic; | ||
212 | }; | ||
213 | |||
214 | #define HWSIM_CHANCTX_MAGIC 0x6d53774a | ||
215 | |||
216 | static inline void hwsim_check_chanctx_magic(struct ieee80211_chanctx_conf *c) | ||
217 | { | ||
218 | struct hwsim_chanctx_priv *cp = (void *)c->drv_priv; | ||
219 | WARN_ON(cp->magic != HWSIM_CHANCTX_MAGIC); | ||
220 | } | ||
221 | |||
222 | static inline void hwsim_set_chanctx_magic(struct ieee80211_chanctx_conf *c) | ||
223 | { | ||
224 | struct hwsim_chanctx_priv *cp = (void *)c->drv_priv; | ||
225 | cp->magic = HWSIM_CHANCTX_MAGIC; | ||
226 | } | ||
227 | |||
228 | static inline void hwsim_clear_chanctx_magic(struct ieee80211_chanctx_conf *c) | ||
229 | { | ||
230 | struct hwsim_chanctx_priv *cp = (void *)c->drv_priv; | ||
231 | cp->magic = 0; | ||
232 | } | ||
233 | |||
208 | static struct class *hwsim_class; | 234 | static struct class *hwsim_class; |
209 | 235 | ||
210 | static struct net_device *hwsim_mon; /* global monitor netdev */ | 236 | static struct net_device *hwsim_mon; /* global monitor netdev */ |
@@ -299,6 +325,13 @@ struct mac80211_hwsim_data { | |||
299 | 325 | ||
300 | struct mac_address addresses[2]; | 326 | struct mac_address addresses[2]; |
301 | 327 | ||
328 | struct ieee80211_channel *tmp_chan; | ||
329 | struct delayed_work roc_done; | ||
330 | struct delayed_work hw_scan; | ||
331 | struct cfg80211_scan_request *hw_scan_request; | ||
332 | struct ieee80211_vif *hw_scan_vif; | ||
333 | int scan_chan_idx; | ||
334 | |||
302 | struct ieee80211_channel *channel; | 335 | struct ieee80211_channel *channel; |
303 | unsigned long beacon_int; /* in jiffies unit */ | 336 | unsigned long beacon_int; /* in jiffies unit */ |
304 | unsigned int rx_filter; | 337 | unsigned int rx_filter; |
@@ -396,7 +429,8 @@ static void mac80211_hwsim_set_tsf(struct ieee80211_hw *hw, | |||
396 | } | 429 | } |
397 | 430 | ||
398 | static void mac80211_hwsim_monitor_rx(struct ieee80211_hw *hw, | 431 | static void mac80211_hwsim_monitor_rx(struct ieee80211_hw *hw, |
399 | struct sk_buff *tx_skb) | 432 | struct sk_buff *tx_skb, |
433 | struct ieee80211_channel *chan) | ||
400 | { | 434 | { |
401 | struct mac80211_hwsim_data *data = hw->priv; | 435 | struct mac80211_hwsim_data *data = hw->priv; |
402 | struct sk_buff *skb; | 436 | struct sk_buff *skb; |
@@ -423,7 +457,7 @@ static void mac80211_hwsim_monitor_rx(struct ieee80211_hw *hw, | |||
423 | hdr->rt_tsft = __mac80211_hwsim_get_tsf(data); | 457 | hdr->rt_tsft = __mac80211_hwsim_get_tsf(data); |
424 | hdr->rt_flags = 0; | 458 | hdr->rt_flags = 0; |
425 | hdr->rt_rate = txrate->bitrate / 5; | 459 | hdr->rt_rate = txrate->bitrate / 5; |
426 | hdr->rt_channel = cpu_to_le16(data->channel->center_freq); | 460 | hdr->rt_channel = cpu_to_le16(chan->center_freq); |
427 | flags = IEEE80211_CHAN_2GHZ; | 461 | flags = IEEE80211_CHAN_2GHZ; |
428 | if (txrate->flags & IEEE80211_RATE_ERP_G) | 462 | if (txrate->flags & IEEE80211_RATE_ERP_G) |
429 | flags |= IEEE80211_CHAN_OFDM; | 463 | flags |= IEEE80211_CHAN_OFDM; |
@@ -441,9 +475,9 @@ static void mac80211_hwsim_monitor_rx(struct ieee80211_hw *hw, | |||
441 | } | 475 | } |
442 | 476 | ||
443 | 477 | ||
444 | static void mac80211_hwsim_monitor_ack(struct ieee80211_hw *hw, const u8 *addr) | 478 | static void mac80211_hwsim_monitor_ack(struct ieee80211_channel *chan, |
479 | const u8 *addr) | ||
445 | { | 480 | { |
446 | struct mac80211_hwsim_data *data = hw->priv; | ||
447 | struct sk_buff *skb; | 481 | struct sk_buff *skb; |
448 | struct hwsim_radiotap_hdr *hdr; | 482 | struct hwsim_radiotap_hdr *hdr; |
449 | u16 flags; | 483 | u16 flags; |
@@ -464,7 +498,7 @@ static void mac80211_hwsim_monitor_ack(struct ieee80211_hw *hw, const u8 *addr) | |||
464 | (1 << IEEE80211_RADIOTAP_CHANNEL)); | 498 | (1 << IEEE80211_RADIOTAP_CHANNEL)); |
465 | hdr->rt_flags = 0; | 499 | hdr->rt_flags = 0; |
466 | hdr->rt_rate = 0; | 500 | hdr->rt_rate = 0; |
467 | hdr->rt_channel = cpu_to_le16(data->channel->center_freq); | 501 | hdr->rt_channel = cpu_to_le16(chan->center_freq); |
468 | flags = IEEE80211_CHAN_2GHZ; | 502 | flags = IEEE80211_CHAN_2GHZ; |
469 | hdr->rt_chbitmask = cpu_to_le16(flags); | 503 | hdr->rt_chbitmask = cpu_to_le16(flags); |
470 | 504 | ||
@@ -556,12 +590,6 @@ static void mac80211_hwsim_tx_frame_nl(struct ieee80211_hw *hw, | |||
556 | int i; | 590 | int i; |
557 | struct hwsim_tx_rate tx_attempts[IEEE80211_TX_MAX_RATES]; | 591 | struct hwsim_tx_rate tx_attempts[IEEE80211_TX_MAX_RATES]; |
558 | 592 | ||
559 | if (data->idle) { | ||
560 | wiphy_debug(hw->wiphy, "Trying to TX when idle - reject\n"); | ||
561 | dev_kfree_skb(my_skb); | ||
562 | return; | ||
563 | } | ||
564 | |||
565 | if (data->ps != PS_DISABLED) | 593 | if (data->ps != PS_DISABLED) |
566 | hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM); | 594 | hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM); |
567 | /* If the queue contains MAX_QUEUE skb's drop some */ | 595 | /* If the queue contains MAX_QUEUE skb's drop some */ |
@@ -629,8 +657,38 @@ nla_put_failure: | |||
629 | printk(KERN_DEBUG "mac80211_hwsim: error occurred in %s\n", __func__); | 657 | printk(KERN_DEBUG "mac80211_hwsim: error occurred in %s\n", __func__); |
630 | } | 658 | } |
631 | 659 | ||
660 | static bool hwsim_chans_compat(struct ieee80211_channel *c1, | ||
661 | struct ieee80211_channel *c2) | ||
662 | { | ||
663 | if (!c1 || !c2) | ||
664 | return false; | ||
665 | |||
666 | return c1->center_freq == c2->center_freq; | ||
667 | } | ||
668 | |||
669 | struct tx_iter_data { | ||
670 | struct ieee80211_channel *channel; | ||
671 | bool receive; | ||
672 | }; | ||
673 | |||
674 | static void mac80211_hwsim_tx_iter(void *_data, u8 *addr, | ||
675 | struct ieee80211_vif *vif) | ||
676 | { | ||
677 | struct tx_iter_data *data = _data; | ||
678 | |||
679 | if (!vif->chanctx_conf) | ||
680 | return; | ||
681 | |||
682 | if (!hwsim_chans_compat(data->channel, | ||
683 | rcu_dereference(vif->chanctx_conf)->channel)) | ||
684 | return; | ||
685 | |||
686 | data->receive = true; | ||
687 | } | ||
688 | |||
632 | static bool mac80211_hwsim_tx_frame_no_nl(struct ieee80211_hw *hw, | 689 | static bool mac80211_hwsim_tx_frame_no_nl(struct ieee80211_hw *hw, |
633 | struct sk_buff *skb) | 690 | struct sk_buff *skb, |
691 | struct ieee80211_channel *chan) | ||
634 | { | 692 | { |
635 | struct mac80211_hwsim_data *data = hw->priv, *data2; | 693 | struct mac80211_hwsim_data *data = hw->priv, *data2; |
636 | bool ack = false; | 694 | bool ack = false; |
@@ -639,15 +697,10 @@ static bool mac80211_hwsim_tx_frame_no_nl(struct ieee80211_hw *hw, | |||
639 | struct ieee80211_rx_status rx_status; | 697 | struct ieee80211_rx_status rx_status; |
640 | struct ieee80211_rate *txrate = ieee80211_get_tx_rate(hw, info); | 698 | struct ieee80211_rate *txrate = ieee80211_get_tx_rate(hw, info); |
641 | 699 | ||
642 | if (data->idle) { | ||
643 | wiphy_debug(hw->wiphy, "Trying to TX when idle - reject\n"); | ||
644 | return false; | ||
645 | } | ||
646 | |||
647 | memset(&rx_status, 0, sizeof(rx_status)); | 700 | memset(&rx_status, 0, sizeof(rx_status)); |
648 | rx_status.flag |= RX_FLAG_MACTIME_MPDU; | 701 | rx_status.flag |= RX_FLAG_MACTIME_MPDU; |
649 | rx_status.freq = data->channel->center_freq; | 702 | rx_status.freq = chan->center_freq; |
650 | rx_status.band = data->channel->band; | 703 | rx_status.band = chan->band; |
651 | rx_status.rate_idx = info->control.rates[0].idx; | 704 | rx_status.rate_idx = info->control.rates[0].idx; |
652 | if (info->control.rates[0].flags & IEEE80211_TX_RC_MCS) | 705 | if (info->control.rates[0].flags & IEEE80211_TX_RC_MCS) |
653 | rx_status.flag |= RX_FLAG_HT; | 706 | rx_status.flag |= RX_FLAG_HT; |
@@ -673,16 +726,30 @@ static bool mac80211_hwsim_tx_frame_no_nl(struct ieee80211_hw *hw, | |||
673 | list_for_each_entry(data2, &hwsim_radios, list) { | 726 | list_for_each_entry(data2, &hwsim_radios, list) { |
674 | struct sk_buff *nskb; | 727 | struct sk_buff *nskb; |
675 | struct ieee80211_mgmt *mgmt; | 728 | struct ieee80211_mgmt *mgmt; |
729 | struct tx_iter_data tx_iter_data = { | ||
730 | .receive = false, | ||
731 | .channel = chan, | ||
732 | }; | ||
676 | 733 | ||
677 | if (data == data2) | 734 | if (data == data2) |
678 | continue; | 735 | continue; |
679 | 736 | ||
680 | if (data2->idle || !data2->started || | 737 | if (!data2->started || (data2->idle && !data2->tmp_chan) || |
681 | !hwsim_ps_rx_ok(data2, skb) || !data2->channel || | 738 | !hwsim_ps_rx_ok(data2, skb)) |
682 | data->channel->center_freq != data2->channel->center_freq || | ||
683 | !(data->group & data2->group)) | ||
684 | continue; | 739 | continue; |
685 | 740 | ||
741 | if (!(data->group & data2->group)) | ||
742 | continue; | ||
743 | |||
744 | if (!hwsim_chans_compat(chan, data2->tmp_chan) && | ||
745 | !hwsim_chans_compat(chan, data2->channel)) { | ||
746 | ieee80211_iterate_active_interfaces_atomic( | ||
747 | data2->hw, mac80211_hwsim_tx_iter, | ||
748 | &tx_iter_data); | ||
749 | if (!tx_iter_data.receive) | ||
750 | continue; | ||
751 | } | ||
752 | |||
686 | nskb = skb_copy(skb, GFP_ATOMIC); | 753 | nskb = skb_copy(skb, GFP_ATOMIC); |
687 | if (nskb == NULL) | 754 | if (nskb == NULL) |
688 | continue; | 755 | continue; |
@@ -713,18 +780,51 @@ static void mac80211_hwsim_tx(struct ieee80211_hw *hw, | |||
713 | struct ieee80211_tx_control *control, | 780 | struct ieee80211_tx_control *control, |
714 | struct sk_buff *skb) | 781 | struct sk_buff *skb) |
715 | { | 782 | { |
783 | struct mac80211_hwsim_data *data = hw->priv; | ||
784 | struct ieee80211_tx_info *txi = IEEE80211_SKB_CB(skb); | ||
785 | struct ieee80211_chanctx_conf *chanctx_conf; | ||
786 | struct ieee80211_channel *channel; | ||
716 | bool ack; | 787 | bool ack; |
717 | struct ieee80211_tx_info *txi; | ||
718 | u32 _portid; | 788 | u32 _portid; |
719 | 789 | ||
720 | mac80211_hwsim_monitor_rx(hw, skb); | 790 | if (WARN_ON(skb->len < 10)) { |
721 | |||
722 | if (skb->len < 10) { | ||
723 | /* Should not happen; just a sanity check for addr1 use */ | 791 | /* Should not happen; just a sanity check for addr1 use */ |
724 | dev_kfree_skb(skb); | 792 | dev_kfree_skb(skb); |
725 | return; | 793 | return; |
726 | } | 794 | } |
727 | 795 | ||
796 | if (channels == 1) { | ||
797 | channel = data->channel; | ||
798 | } else if (txi->hw_queue == 4) { | ||
799 | channel = data->tmp_chan; | ||
800 | } else { | ||
801 | chanctx_conf = rcu_dereference(txi->control.vif->chanctx_conf); | ||
802 | if (chanctx_conf) | ||
803 | channel = chanctx_conf->channel; | ||
804 | else | ||
805 | channel = NULL; | ||
806 | } | ||
807 | |||
808 | if (WARN(!channel, "TX w/o channel - queue = %d\n", txi->hw_queue)) { | ||
809 | dev_kfree_skb(skb); | ||
810 | return; | ||
811 | } | ||
812 | |||
813 | if (data->idle && !data->tmp_chan) { | ||
814 | wiphy_debug(hw->wiphy, "Trying to TX when idle - reject\n"); | ||
815 | dev_kfree_skb(skb); | ||
816 | return; | ||
817 | } | ||
818 | |||
819 | if (txi->control.vif) | ||
820 | hwsim_check_magic(txi->control.vif); | ||
821 | if (control->sta) | ||
822 | hwsim_check_sta_magic(control->sta); | ||
823 | |||
824 | txi->rate_driver_data[0] = channel; | ||
825 | |||
826 | mac80211_hwsim_monitor_rx(hw, skb, channel); | ||
827 | |||
728 | /* wmediumd mode check */ | 828 | /* wmediumd mode check */ |
729 | _portid = ACCESS_ONCE(wmediumd_portid); | 829 | _portid = ACCESS_ONCE(wmediumd_portid); |
730 | 830 | ||
@@ -732,15 +832,13 @@ static void mac80211_hwsim_tx(struct ieee80211_hw *hw, | |||
732 | return mac80211_hwsim_tx_frame_nl(hw, skb, _portid); | 832 | return mac80211_hwsim_tx_frame_nl(hw, skb, _portid); |
733 | 833 | ||
734 | /* NO wmediumd detected, perfect medium simulation */ | 834 | /* NO wmediumd detected, perfect medium simulation */ |
735 | ack = mac80211_hwsim_tx_frame_no_nl(hw, skb); | 835 | ack = mac80211_hwsim_tx_frame_no_nl(hw, skb, channel); |
736 | 836 | ||
737 | if (ack && skb->len >= 16) { | 837 | if (ack && skb->len >= 16) { |
738 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; | 838 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; |
739 | mac80211_hwsim_monitor_ack(hw, hdr->addr2); | 839 | mac80211_hwsim_monitor_ack(channel, hdr->addr2); |
740 | } | 840 | } |
741 | 841 | ||
742 | txi = IEEE80211_SKB_CB(skb); | ||
743 | |||
744 | ieee80211_tx_info_clear_status(txi); | 842 | ieee80211_tx_info_clear_status(txi); |
745 | 843 | ||
746 | /* frame was transmitted at most favorable rate at first attempt */ | 844 | /* frame was transmitted at most favorable rate at first attempt */ |
@@ -778,6 +876,13 @@ static int mac80211_hwsim_add_interface(struct ieee80211_hw *hw, | |||
778 | __func__, ieee80211_vif_type_p2p(vif), | 876 | __func__, ieee80211_vif_type_p2p(vif), |
779 | vif->addr); | 877 | vif->addr); |
780 | hwsim_set_magic(vif); | 878 | hwsim_set_magic(vif); |
879 | |||
880 | vif->cab_queue = 0; | ||
881 | vif->hw_queue[IEEE80211_AC_VO] = 0; | ||
882 | vif->hw_queue[IEEE80211_AC_VI] = 1; | ||
883 | vif->hw_queue[IEEE80211_AC_BE] = 2; | ||
884 | vif->hw_queue[IEEE80211_AC_BK] = 3; | ||
885 | |||
781 | return 0; | 886 | return 0; |
782 | } | 887 | } |
783 | 888 | ||
@@ -807,14 +912,26 @@ static void mac80211_hwsim_remove_interface( | |||
807 | hwsim_clear_magic(vif); | 912 | hwsim_clear_magic(vif); |
808 | } | 913 | } |
809 | 914 | ||
915 | static void mac80211_hwsim_tx_frame(struct ieee80211_hw *hw, | ||
916 | struct sk_buff *skb, | ||
917 | struct ieee80211_channel *chan) | ||
918 | { | ||
919 | u32 _pid = ACCESS_ONCE(wmediumd_portid); | ||
920 | |||
921 | mac80211_hwsim_monitor_rx(hw, skb, chan); | ||
922 | |||
923 | if (_pid) | ||
924 | return mac80211_hwsim_tx_frame_nl(hw, skb, _pid); | ||
925 | |||
926 | mac80211_hwsim_tx_frame_no_nl(hw, skb, chan); | ||
927 | dev_kfree_skb(skb); | ||
928 | } | ||
810 | 929 | ||
811 | static void mac80211_hwsim_beacon_tx(void *arg, u8 *mac, | 930 | static void mac80211_hwsim_beacon_tx(void *arg, u8 *mac, |
812 | struct ieee80211_vif *vif) | 931 | struct ieee80211_vif *vif) |
813 | { | 932 | { |
814 | struct ieee80211_hw *hw = arg; | 933 | struct ieee80211_hw *hw = arg; |
815 | struct sk_buff *skb; | 934 | struct sk_buff *skb; |
816 | struct ieee80211_tx_info *info; | ||
817 | u32 _portid; | ||
818 | 935 | ||
819 | hwsim_check_magic(vif); | 936 | hwsim_check_magic(vif); |
820 | 937 | ||
@@ -826,18 +943,9 @@ static void mac80211_hwsim_beacon_tx(void *arg, u8 *mac, | |||
826 | skb = ieee80211_beacon_get(hw, vif); | 943 | skb = ieee80211_beacon_get(hw, vif); |
827 | if (skb == NULL) | 944 | if (skb == NULL) |
828 | return; | 945 | return; |
829 | info = IEEE80211_SKB_CB(skb); | ||
830 | |||
831 | mac80211_hwsim_monitor_rx(hw, skb); | ||
832 | |||
833 | /* wmediumd mode check */ | ||
834 | _portid = ACCESS_ONCE(wmediumd_portid); | ||
835 | |||
836 | if (_portid) | ||
837 | return mac80211_hwsim_tx_frame_nl(hw, skb, _portid); | ||
838 | 946 | ||
839 | mac80211_hwsim_tx_frame_no_nl(hw, skb); | 947 | mac80211_hwsim_tx_frame(hw, skb, |
840 | dev_kfree_skb(skb); | 948 | rcu_dereference(vif->chanctx_conf)->channel); |
841 | } | 949 | } |
842 | 950 | ||
843 | 951 | ||
@@ -877,7 +985,7 @@ static int mac80211_hwsim_config(struct ieee80211_hw *hw, u32 changed) | |||
877 | wiphy_debug(hw->wiphy, | 985 | wiphy_debug(hw->wiphy, |
878 | "%s (freq=%d/%s idle=%d ps=%d smps=%s)\n", | 986 | "%s (freq=%d/%s idle=%d ps=%d smps=%s)\n", |
879 | __func__, | 987 | __func__, |
880 | conf->channel->center_freq, | 988 | conf->channel ? conf->channel->center_freq : 0, |
881 | hwsim_chantypes[conf->channel_type], | 989 | hwsim_chantypes[conf->channel_type], |
882 | !!(conf->flags & IEEE80211_CONF_IDLE), | 990 | !!(conf->flags & IEEE80211_CONF_IDLE), |
883 | !!(conf->flags & IEEE80211_CONF_PS), | 991 | !!(conf->flags & IEEE80211_CONF_PS), |
@@ -886,6 +994,9 @@ static int mac80211_hwsim_config(struct ieee80211_hw *hw, u32 changed) | |||
886 | data->idle = !!(conf->flags & IEEE80211_CONF_IDLE); | 994 | data->idle = !!(conf->flags & IEEE80211_CONF_IDLE); |
887 | 995 | ||
888 | data->channel = conf->channel; | 996 | data->channel = conf->channel; |
997 | |||
998 | WARN_ON(data->channel && channels > 1); | ||
999 | |||
889 | data->power_level = conf->power_level; | 1000 | data->power_level = conf->power_level; |
890 | if (!data->started || !data->beacon_int) | 1001 | if (!data->started || !data->beacon_int) |
891 | del_timer(&data->beacon_timer); | 1002 | del_timer(&data->beacon_timer); |
@@ -1166,45 +1277,102 @@ static void mac80211_hwsim_flush(struct ieee80211_hw *hw, bool drop) | |||
1166 | /* Not implemented, queues only on kernel side */ | 1277 | /* Not implemented, queues only on kernel side */ |
1167 | } | 1278 | } |
1168 | 1279 | ||
1169 | struct hw_scan_done { | 1280 | static void hw_scan_work(struct work_struct *work) |
1170 | struct delayed_work w; | ||
1171 | struct ieee80211_hw *hw; | ||
1172 | }; | ||
1173 | |||
1174 | static void hw_scan_done(struct work_struct *work) | ||
1175 | { | 1281 | { |
1176 | struct hw_scan_done *hsd = | 1282 | struct mac80211_hwsim_data *hwsim = |
1177 | container_of(work, struct hw_scan_done, w.work); | 1283 | container_of(work, struct mac80211_hwsim_data, hw_scan.work); |
1284 | struct cfg80211_scan_request *req = hwsim->hw_scan_request; | ||
1285 | int dwell, i; | ||
1178 | 1286 | ||
1179 | ieee80211_scan_completed(hsd->hw, false); | 1287 | mutex_lock(&hwsim->mutex); |
1180 | kfree(hsd); | 1288 | if (hwsim->scan_chan_idx >= req->n_channels) { |
1289 | wiphy_debug(hwsim->hw->wiphy, "hw scan complete\n"); | ||
1290 | ieee80211_scan_completed(hwsim->hw, false); | ||
1291 | hwsim->hw_scan_request = NULL; | ||
1292 | hwsim->hw_scan_vif = NULL; | ||
1293 | hwsim->tmp_chan = NULL; | ||
1294 | mutex_unlock(&hwsim->mutex); | ||
1295 | return; | ||
1296 | } | ||
1297 | |||
1298 | wiphy_debug(hwsim->hw->wiphy, "hw scan %d MHz\n", | ||
1299 | req->channels[hwsim->scan_chan_idx]->center_freq); | ||
1300 | |||
1301 | hwsim->tmp_chan = req->channels[hwsim->scan_chan_idx]; | ||
1302 | if (hwsim->tmp_chan->flags & IEEE80211_CHAN_PASSIVE_SCAN || | ||
1303 | !req->n_ssids) { | ||
1304 | dwell = 120; | ||
1305 | } else { | ||
1306 | dwell = 30; | ||
1307 | /* send probes */ | ||
1308 | for (i = 0; i < req->n_ssids; i++) { | ||
1309 | struct sk_buff *probe; | ||
1310 | |||
1311 | probe = ieee80211_probereq_get(hwsim->hw, | ||
1312 | hwsim->hw_scan_vif, | ||
1313 | req->ssids[i].ssid, | ||
1314 | req->ssids[i].ssid_len, | ||
1315 | req->ie, req->ie_len); | ||
1316 | if (!probe) | ||
1317 | continue; | ||
1318 | local_bh_disable(); | ||
1319 | mac80211_hwsim_tx_frame(hwsim->hw, probe, | ||
1320 | hwsim->tmp_chan); | ||
1321 | local_bh_enable(); | ||
1322 | } | ||
1323 | } | ||
1324 | ieee80211_queue_delayed_work(hwsim->hw, &hwsim->hw_scan, | ||
1325 | msecs_to_jiffies(dwell)); | ||
1326 | hwsim->scan_chan_idx++; | ||
1327 | mutex_unlock(&hwsim->mutex); | ||
1181 | } | 1328 | } |
1182 | 1329 | ||
1183 | static int mac80211_hwsim_hw_scan(struct ieee80211_hw *hw, | 1330 | static int mac80211_hwsim_hw_scan(struct ieee80211_hw *hw, |
1184 | struct ieee80211_vif *vif, | 1331 | struct ieee80211_vif *vif, |
1185 | struct cfg80211_scan_request *req) | 1332 | struct cfg80211_scan_request *req) |
1186 | { | 1333 | { |
1187 | struct hw_scan_done *hsd = kzalloc(sizeof(*hsd), GFP_KERNEL); | 1334 | struct mac80211_hwsim_data *hwsim = hw->priv; |
1188 | int i; | 1335 | int i; |
1189 | 1336 | ||
1190 | if (!hsd) | 1337 | mutex_lock(&hwsim->mutex); |
1191 | return -ENOMEM; | 1338 | if (WARN_ON(hwsim->tmp_chan || hwsim->hw_scan_request)) { |
1192 | 1339 | mutex_unlock(&hwsim->mutex); | |
1193 | hsd->hw = hw; | 1340 | return -EBUSY; |
1194 | INIT_DELAYED_WORK(&hsd->w, hw_scan_done); | 1341 | } |
1342 | hwsim->hw_scan_request = req; | ||
1343 | hwsim->hw_scan_vif = vif; | ||
1344 | hwsim->scan_chan_idx = 0; | ||
1345 | mutex_unlock(&hwsim->mutex); | ||
1195 | 1346 | ||
1196 | printk(KERN_DEBUG "hwsim hw_scan request\n"); | 1347 | wiphy_debug(hw->wiphy, "hwsim hw_scan request\n"); |
1197 | for (i = 0; i < req->n_channels; i++) | 1348 | for (i = 0; i < req->n_channels; i++) |
1198 | printk(KERN_DEBUG "hwsim hw_scan freq %d\n", | 1349 | printk(KERN_DEBUG "hwsim hw_scan freq %d\n", |
1199 | req->channels[i]->center_freq); | 1350 | req->channels[i]->center_freq); |
1200 | print_hex_dump(KERN_DEBUG, "scan IEs: ", DUMP_PREFIX_OFFSET, | 1351 | print_hex_dump(KERN_DEBUG, "scan IEs: ", DUMP_PREFIX_OFFSET, |
1201 | 16, 1, req->ie, req->ie_len, 1); | 1352 | 16, 1, req->ie, req->ie_len, 1); |
1202 | 1353 | ||
1203 | ieee80211_queue_delayed_work(hw, &hsd->w, 2 * HZ); | 1354 | ieee80211_queue_delayed_work(hwsim->hw, &hwsim->hw_scan, 0); |
1204 | 1355 | ||
1205 | return 0; | 1356 | return 0; |
1206 | } | 1357 | } |
1207 | 1358 | ||
1359 | static void mac80211_hwsim_cancel_hw_scan(struct ieee80211_hw *hw, | ||
1360 | struct ieee80211_vif *vif) | ||
1361 | { | ||
1362 | struct mac80211_hwsim_data *hwsim = hw->priv; | ||
1363 | |||
1364 | wiphy_debug(hw->wiphy, "hwsim cancel_hw_scan\n"); | ||
1365 | |||
1366 | cancel_delayed_work_sync(&hwsim->hw_scan); | ||
1367 | |||
1368 | mutex_lock(&hwsim->mutex); | ||
1369 | ieee80211_scan_completed(hwsim->hw, true); | ||
1370 | hwsim->tmp_chan = NULL; | ||
1371 | hwsim->hw_scan_request = NULL; | ||
1372 | hwsim->hw_scan_vif = NULL; | ||
1373 | mutex_unlock(&hwsim->mutex); | ||
1374 | } | ||
1375 | |||
1208 | static void mac80211_hwsim_sw_scan(struct ieee80211_hw *hw) | 1376 | static void mac80211_hwsim_sw_scan(struct ieee80211_hw *hw) |
1209 | { | 1377 | { |
1210 | struct mac80211_hwsim_data *hwsim = hw->priv; | 1378 | struct mac80211_hwsim_data *hwsim = hw->priv; |
@@ -1235,6 +1403,105 @@ static void mac80211_hwsim_sw_scan_complete(struct ieee80211_hw *hw) | |||
1235 | mutex_unlock(&hwsim->mutex); | 1403 | mutex_unlock(&hwsim->mutex); |
1236 | } | 1404 | } |
1237 | 1405 | ||
1406 | static void hw_roc_done(struct work_struct *work) | ||
1407 | { | ||
1408 | struct mac80211_hwsim_data *hwsim = | ||
1409 | container_of(work, struct mac80211_hwsim_data, roc_done.work); | ||
1410 | |||
1411 | mutex_lock(&hwsim->mutex); | ||
1412 | ieee80211_remain_on_channel_expired(hwsim->hw); | ||
1413 | hwsim->tmp_chan = NULL; | ||
1414 | mutex_unlock(&hwsim->mutex); | ||
1415 | |||
1416 | wiphy_debug(hwsim->hw->wiphy, "hwsim ROC expired\n"); | ||
1417 | } | ||
1418 | |||
1419 | static int mac80211_hwsim_roc(struct ieee80211_hw *hw, | ||
1420 | struct ieee80211_channel *chan, | ||
1421 | enum nl80211_channel_type channel_type, | ||
1422 | int duration) | ||
1423 | { | ||
1424 | struct mac80211_hwsim_data *hwsim = hw->priv; | ||
1425 | |||
1426 | mutex_lock(&hwsim->mutex); | ||
1427 | if (WARN_ON(hwsim->tmp_chan || hwsim->hw_scan_request)) { | ||
1428 | mutex_unlock(&hwsim->mutex); | ||
1429 | return -EBUSY; | ||
1430 | } | ||
1431 | |||
1432 | hwsim->tmp_chan = chan; | ||
1433 | mutex_unlock(&hwsim->mutex); | ||
1434 | |||
1435 | wiphy_debug(hw->wiphy, "hwsim ROC (%d MHz, %d ms)\n", | ||
1436 | chan->center_freq, duration); | ||
1437 | |||
1438 | ieee80211_ready_on_channel(hw); | ||
1439 | |||
1440 | ieee80211_queue_delayed_work(hw, &hwsim->roc_done, | ||
1441 | msecs_to_jiffies(duration)); | ||
1442 | return 0; | ||
1443 | } | ||
1444 | |||
1445 | static int mac80211_hwsim_croc(struct ieee80211_hw *hw) | ||
1446 | { | ||
1447 | struct mac80211_hwsim_data *hwsim = hw->priv; | ||
1448 | |||
1449 | cancel_delayed_work_sync(&hwsim->roc_done); | ||
1450 | |||
1451 | mutex_lock(&hwsim->mutex); | ||
1452 | hwsim->tmp_chan = NULL; | ||
1453 | mutex_unlock(&hwsim->mutex); | ||
1454 | |||
1455 | wiphy_debug(hw->wiphy, "hwsim ROC canceled\n"); | ||
1456 | |||
1457 | return 0; | ||
1458 | } | ||
1459 | |||
1460 | static int mac80211_hwsim_add_chanctx(struct ieee80211_hw *hw, | ||
1461 | struct ieee80211_chanctx_conf *ctx) | ||
1462 | { | ||
1463 | hwsim_set_chanctx_magic(ctx); | ||
1464 | wiphy_debug(hw->wiphy, "add channel context %d MHz/%d\n", | ||
1465 | ctx->channel->center_freq, ctx->channel_type); | ||
1466 | return 0; | ||
1467 | } | ||
1468 | |||
1469 | static void mac80211_hwsim_remove_chanctx(struct ieee80211_hw *hw, | ||
1470 | struct ieee80211_chanctx_conf *ctx) | ||
1471 | { | ||
1472 | wiphy_debug(hw->wiphy, "remove channel context %d MHz/%d\n", | ||
1473 | ctx->channel->center_freq, ctx->channel_type); | ||
1474 | hwsim_check_chanctx_magic(ctx); | ||
1475 | hwsim_clear_chanctx_magic(ctx); | ||
1476 | } | ||
1477 | |||
1478 | static void mac80211_hwsim_change_chanctx(struct ieee80211_hw *hw, | ||
1479 | struct ieee80211_chanctx_conf *ctx, | ||
1480 | u32 changed) | ||
1481 | { | ||
1482 | hwsim_check_chanctx_magic(ctx); | ||
1483 | wiphy_debug(hw->wiphy, "change channel context %#x (%d MHz/%d)\n", | ||
1484 | changed, ctx->channel->center_freq, ctx->channel_type); | ||
1485 | } | ||
1486 | |||
1487 | static int mac80211_hwsim_assign_vif_chanctx(struct ieee80211_hw *hw, | ||
1488 | struct ieee80211_vif *vif, | ||
1489 | struct ieee80211_chanctx_conf *ctx) | ||
1490 | { | ||
1491 | hwsim_check_magic(vif); | ||
1492 | hwsim_check_chanctx_magic(ctx); | ||
1493 | |||
1494 | return 0; | ||
1495 | } | ||
1496 | |||
1497 | static void mac80211_hwsim_unassign_vif_chanctx(struct ieee80211_hw *hw, | ||
1498 | struct ieee80211_vif *vif, | ||
1499 | struct ieee80211_chanctx_conf *ctx) | ||
1500 | { | ||
1501 | hwsim_check_magic(vif); | ||
1502 | hwsim_check_chanctx_magic(ctx); | ||
1503 | } | ||
1504 | |||
1238 | static struct ieee80211_ops mac80211_hwsim_ops = | 1505 | static struct ieee80211_ops mac80211_hwsim_ops = |
1239 | { | 1506 | { |
1240 | .tx = mac80211_hwsim_tx, | 1507 | .tx = mac80211_hwsim_tx, |
@@ -1315,7 +1582,6 @@ static void hwsim_send_ps_poll(void *dat, u8 *mac, struct ieee80211_vif *vif) | |||
1315 | struct hwsim_vif_priv *vp = (void *)vif->drv_priv; | 1582 | struct hwsim_vif_priv *vp = (void *)vif->drv_priv; |
1316 | struct sk_buff *skb; | 1583 | struct sk_buff *skb; |
1317 | struct ieee80211_pspoll *pspoll; | 1584 | struct ieee80211_pspoll *pspoll; |
1318 | u32 _portid; | ||
1319 | 1585 | ||
1320 | if (!vp->assoc) | 1586 | if (!vp->assoc) |
1321 | return; | 1587 | return; |
@@ -1335,25 +1601,18 @@ static void hwsim_send_ps_poll(void *dat, u8 *mac, struct ieee80211_vif *vif) | |||
1335 | memcpy(pspoll->bssid, vp->bssid, ETH_ALEN); | 1601 | memcpy(pspoll->bssid, vp->bssid, ETH_ALEN); |
1336 | memcpy(pspoll->ta, mac, ETH_ALEN); | 1602 | memcpy(pspoll->ta, mac, ETH_ALEN); |
1337 | 1603 | ||
1338 | /* wmediumd mode check */ | 1604 | rcu_read_lock(); |
1339 | _portid = ACCESS_ONCE(wmediumd_portid); | 1605 | mac80211_hwsim_tx_frame(data->hw, skb, |
1340 | 1606 | rcu_dereference(vif->chanctx_conf)->channel); | |
1341 | if (_portid) | 1607 | rcu_read_unlock(); |
1342 | return mac80211_hwsim_tx_frame_nl(data->hw, skb, _portid); | ||
1343 | |||
1344 | if (!mac80211_hwsim_tx_frame_no_nl(data->hw, skb)) | ||
1345 | printk(KERN_DEBUG "%s: PS-poll frame not ack'ed\n", __func__); | ||
1346 | dev_kfree_skb(skb); | ||
1347 | } | 1608 | } |
1348 | 1609 | ||
1349 | |||
1350 | static void hwsim_send_nullfunc(struct mac80211_hwsim_data *data, u8 *mac, | 1610 | static void hwsim_send_nullfunc(struct mac80211_hwsim_data *data, u8 *mac, |
1351 | struct ieee80211_vif *vif, int ps) | 1611 | struct ieee80211_vif *vif, int ps) |
1352 | { | 1612 | { |
1353 | struct hwsim_vif_priv *vp = (void *)vif->drv_priv; | 1613 | struct hwsim_vif_priv *vp = (void *)vif->drv_priv; |
1354 | struct sk_buff *skb; | 1614 | struct sk_buff *skb; |
1355 | struct ieee80211_hdr *hdr; | 1615 | struct ieee80211_hdr *hdr; |
1356 | u32 _portid; | ||
1357 | 1616 | ||
1358 | if (!vp->assoc) | 1617 | if (!vp->assoc) |
1359 | return; | 1618 | return; |
@@ -1374,15 +1633,10 @@ static void hwsim_send_nullfunc(struct mac80211_hwsim_data *data, u8 *mac, | |||
1374 | memcpy(hdr->addr2, mac, ETH_ALEN); | 1633 | memcpy(hdr->addr2, mac, ETH_ALEN); |
1375 | memcpy(hdr->addr3, vp->bssid, ETH_ALEN); | 1634 | memcpy(hdr->addr3, vp->bssid, ETH_ALEN); |
1376 | 1635 | ||
1377 | /* wmediumd mode check */ | 1636 | rcu_read_lock(); |
1378 | _portid = ACCESS_ONCE(wmediumd_portid); | 1637 | mac80211_hwsim_tx_frame(data->hw, skb, |
1379 | 1638 | rcu_dereference(vif->chanctx_conf)->channel); | |
1380 | if (_portid) | 1639 | rcu_read_unlock(); |
1381 | return mac80211_hwsim_tx_frame_nl(data->hw, skb, _portid); | ||
1382 | |||
1383 | if (!mac80211_hwsim_tx_frame_no_nl(data->hw, skb)) | ||
1384 | printk(KERN_DEBUG "%s: nullfunc frame not ack'ed\n", __func__); | ||
1385 | dev_kfree_skb(skb); | ||
1386 | } | 1640 | } |
1387 | 1641 | ||
1388 | 1642 | ||
@@ -1551,7 +1805,8 @@ static int hwsim_tx_info_frame_received_nl(struct sk_buff *skb_2, | |||
1551 | (hwsim_flags & HWSIM_TX_STAT_ACK)) { | 1805 | (hwsim_flags & HWSIM_TX_STAT_ACK)) { |
1552 | if (skb->len >= 16) { | 1806 | if (skb->len >= 16) { |
1553 | hdr = (struct ieee80211_hdr *) skb->data; | 1807 | hdr = (struct ieee80211_hdr *) skb->data; |
1554 | mac80211_hwsim_monitor_ack(data2->hw, hdr->addr2); | 1808 | mac80211_hwsim_monitor_ack(txi->rate_driver_data[0], |
1809 | hdr->addr2); | ||
1555 | } | 1810 | } |
1556 | txi->flags |= IEEE80211_TX_STAT_ACK; | 1811 | txi->flags |= IEEE80211_TX_STAT_ACK; |
1557 | } | 1812 | } |
@@ -1566,7 +1821,7 @@ static int hwsim_cloned_frame_received_nl(struct sk_buff *skb_2, | |||
1566 | struct genl_info *info) | 1821 | struct genl_info *info) |
1567 | { | 1822 | { |
1568 | 1823 | ||
1569 | struct mac80211_hwsim_data *data2; | 1824 | struct mac80211_hwsim_data *data2; |
1570 | struct ieee80211_rx_status rx_status; | 1825 | struct ieee80211_rx_status rx_status; |
1571 | struct mac_address *dst; | 1826 | struct mac_address *dst; |
1572 | int frame_data_len; | 1827 | int frame_data_len; |
@@ -1574,9 +1829,9 @@ static int hwsim_cloned_frame_received_nl(struct sk_buff *skb_2, | |||
1574 | struct sk_buff *skb = NULL; | 1829 | struct sk_buff *skb = NULL; |
1575 | 1830 | ||
1576 | if (!info->attrs[HWSIM_ATTR_ADDR_RECEIVER] || | 1831 | if (!info->attrs[HWSIM_ATTR_ADDR_RECEIVER] || |
1577 | !info->attrs[HWSIM_ATTR_FRAME] || | 1832 | !info->attrs[HWSIM_ATTR_FRAME] || |
1578 | !info->attrs[HWSIM_ATTR_RX_RATE] || | 1833 | !info->attrs[HWSIM_ATTR_RX_RATE] || |
1579 | !info->attrs[HWSIM_ATTR_SIGNAL]) | 1834 | !info->attrs[HWSIM_ATTR_SIGNAL]) |
1580 | goto out; | 1835 | goto out; |
1581 | 1836 | ||
1582 | dst = (struct mac_address *)nla_data( | 1837 | dst = (struct mac_address *)nla_data( |
@@ -1604,7 +1859,7 @@ static int hwsim_cloned_frame_received_nl(struct sk_buff *skb_2, | |||
1604 | 1859 | ||
1605 | /* check if radio is configured properly */ | 1860 | /* check if radio is configured properly */ |
1606 | 1861 | ||
1607 | if (data2->idle || !data2->started || !data2->channel) | 1862 | if (data2->idle || !data2->started) |
1608 | goto out; | 1863 | goto out; |
1609 | 1864 | ||
1610 | /*A frame is received from user space*/ | 1865 | /*A frame is received from user space*/ |
@@ -1688,6 +1943,11 @@ static struct notifier_block hwsim_netlink_notifier = { | |||
1688 | static int hwsim_init_netlink(void) | 1943 | static int hwsim_init_netlink(void) |
1689 | { | 1944 | { |
1690 | int rc; | 1945 | int rc; |
1946 | |||
1947 | /* userspace test API hasn't been adjusted for multi-channel */ | ||
1948 | if (channels > 1) | ||
1949 | return 0; | ||
1950 | |||
1691 | printk(KERN_INFO "mac80211_hwsim: initializing netlink\n"); | 1951 | printk(KERN_INFO "mac80211_hwsim: initializing netlink\n"); |
1692 | 1952 | ||
1693 | rc = genl_register_family_with_ops(&hwsim_genl_family, | 1953 | rc = genl_register_family_with_ops(&hwsim_genl_family, |
@@ -1710,6 +1970,10 @@ static void hwsim_exit_netlink(void) | |||
1710 | { | 1970 | { |
1711 | int ret; | 1971 | int ret; |
1712 | 1972 | ||
1973 | /* userspace test API hasn't been adjusted for multi-channel */ | ||
1974 | if (channels > 1) | ||
1975 | return; | ||
1976 | |||
1713 | printk(KERN_INFO "mac80211_hwsim: closing netlink\n"); | 1977 | printk(KERN_INFO "mac80211_hwsim: closing netlink\n"); |
1714 | /* unregister the notifier */ | 1978 | /* unregister the notifier */ |
1715 | netlink_unregister_notifier(&hwsim_netlink_notifier); | 1979 | netlink_unregister_notifier(&hwsim_netlink_notifier); |
@@ -1732,7 +1996,7 @@ static const struct ieee80211_iface_limit hwsim_if_limits[] = { | |||
1732 | { .max = 1, .types = BIT(NL80211_IFTYPE_P2P_DEVICE) }, | 1996 | { .max = 1, .types = BIT(NL80211_IFTYPE_P2P_DEVICE) }, |
1733 | }; | 1997 | }; |
1734 | 1998 | ||
1735 | static const struct ieee80211_iface_combination hwsim_if_comb = { | 1999 | static struct ieee80211_iface_combination hwsim_if_comb = { |
1736 | .limits = hwsim_if_limits, | 2000 | .limits = hwsim_if_limits, |
1737 | .n_limits = ARRAY_SIZE(hwsim_if_limits), | 2001 | .n_limits = ARRAY_SIZE(hwsim_if_limits), |
1738 | .max_interfaces = 2048, | 2002 | .max_interfaces = 2048, |
@@ -1750,10 +2014,30 @@ static int __init init_mac80211_hwsim(void) | |||
1750 | if (radios < 1 || radios > 100) | 2014 | if (radios < 1 || radios > 100) |
1751 | return -EINVAL; | 2015 | return -EINVAL; |
1752 | 2016 | ||
1753 | if (fake_hw_scan) { | 2017 | if (channels < 1) |
2018 | return -EINVAL; | ||
2019 | |||
2020 | if (channels > 1) { | ||
2021 | hwsim_if_comb.num_different_channels = channels; | ||
1754 | mac80211_hwsim_ops.hw_scan = mac80211_hwsim_hw_scan; | 2022 | mac80211_hwsim_ops.hw_scan = mac80211_hwsim_hw_scan; |
2023 | mac80211_hwsim_ops.cancel_hw_scan = | ||
2024 | mac80211_hwsim_cancel_hw_scan; | ||
1755 | mac80211_hwsim_ops.sw_scan_start = NULL; | 2025 | mac80211_hwsim_ops.sw_scan_start = NULL; |
1756 | mac80211_hwsim_ops.sw_scan_complete = NULL; | 2026 | mac80211_hwsim_ops.sw_scan_complete = NULL; |
2027 | mac80211_hwsim_ops.remain_on_channel = | ||
2028 | mac80211_hwsim_roc; | ||
2029 | mac80211_hwsim_ops.cancel_remain_on_channel = | ||
2030 | mac80211_hwsim_croc; | ||
2031 | mac80211_hwsim_ops.add_chanctx = | ||
2032 | mac80211_hwsim_add_chanctx; | ||
2033 | mac80211_hwsim_ops.remove_chanctx = | ||
2034 | mac80211_hwsim_remove_chanctx; | ||
2035 | mac80211_hwsim_ops.change_chanctx = | ||
2036 | mac80211_hwsim_change_chanctx; | ||
2037 | mac80211_hwsim_ops.assign_vif_chanctx = | ||
2038 | mac80211_hwsim_assign_vif_chanctx; | ||
2039 | mac80211_hwsim_ops.unassign_vif_chanctx = | ||
2040 | mac80211_hwsim_unassign_vif_chanctx; | ||
1757 | } | 2041 | } |
1758 | 2042 | ||
1759 | spin_lock_init(&hwsim_radio_lock); | 2043 | spin_lock_init(&hwsim_radio_lock); |
@@ -1803,13 +2087,18 @@ static int __init init_mac80211_hwsim(void) | |||
1803 | hw->wiphy->iface_combinations = &hwsim_if_comb; | 2087 | hw->wiphy->iface_combinations = &hwsim_if_comb; |
1804 | hw->wiphy->n_iface_combinations = 1; | 2088 | hw->wiphy->n_iface_combinations = 1; |
1805 | 2089 | ||
1806 | if (fake_hw_scan) { | 2090 | if (channels > 1) { |
1807 | hw->wiphy->max_scan_ssids = 255; | 2091 | hw->wiphy->max_scan_ssids = 255; |
1808 | hw->wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN; | 2092 | hw->wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN; |
2093 | hw->wiphy->max_remain_on_channel_duration = 1000; | ||
1809 | } | 2094 | } |
1810 | 2095 | ||
2096 | INIT_DELAYED_WORK(&data->roc_done, hw_roc_done); | ||
2097 | INIT_DELAYED_WORK(&data->hw_scan, hw_scan_work); | ||
2098 | |||
1811 | hw->channel_change_time = 1; | 2099 | hw->channel_change_time = 1; |
1812 | hw->queues = 4; | 2100 | hw->queues = 5; |
2101 | hw->offchannel_tx_hw_queue = 4; | ||
1813 | hw->wiphy->interface_modes = | 2102 | hw->wiphy->interface_modes = |
1814 | BIT(NL80211_IFTYPE_STATION) | | 2103 | BIT(NL80211_IFTYPE_STATION) | |
1815 | BIT(NL80211_IFTYPE_AP) | | 2104 | BIT(NL80211_IFTYPE_AP) | |
@@ -1824,7 +2113,8 @@ static int __init init_mac80211_hwsim(void) | |||
1824 | IEEE80211_HW_SUPPORTS_STATIC_SMPS | | 2113 | IEEE80211_HW_SUPPORTS_STATIC_SMPS | |
1825 | IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS | | 2114 | IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS | |
1826 | IEEE80211_HW_AMPDU_AGGREGATION | | 2115 | IEEE80211_HW_AMPDU_AGGREGATION | |
1827 | IEEE80211_HW_WANT_MONITOR_VIF; | 2116 | IEEE80211_HW_WANT_MONITOR_VIF | |
2117 | IEEE80211_HW_QUEUE_CONTROL; | ||
1828 | 2118 | ||
1829 | hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS | | 2119 | hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS | |
1830 | WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; | 2120 | WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; |