diff options
author | Andrea Bastoni <bastoni@cs.unc.edu> | 2010-05-30 19:16:45 -0400 |
---|---|---|
committer | Andrea Bastoni <bastoni@cs.unc.edu> | 2010-05-30 19:16:45 -0400 |
commit | ada47b5fe13d89735805b566185f4885f5a3f750 (patch) | |
tree | 644b88f8a71896307d71438e9b3af49126ffb22b /drivers/net/wireless/mac80211_hwsim.c | |
parent | 43e98717ad40a4ae64545b5ba047c7b86aa44f4f (diff) | |
parent | 3280f21d43ee541f97f8cda5792150d2dbec20d5 (diff) |
Merge branch 'wip-2.6.34' into old-private-masterarchived-private-master
Diffstat (limited to 'drivers/net/wireless/mac80211_hwsim.c')
-rw-r--r-- | drivers/net/wireless/mac80211_hwsim.c | 284 |
1 files changed, 247 insertions, 37 deletions
diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 38cfd79e0590..7cd5f56662fc 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c | |||
@@ -14,6 +14,7 @@ | |||
14 | */ | 14 | */ |
15 | 15 | ||
16 | #include <linux/list.h> | 16 | #include <linux/list.h> |
17 | #include <linux/slab.h> | ||
17 | #include <linux/spinlock.h> | 18 | #include <linux/spinlock.h> |
18 | #include <net/dst.h> | 19 | #include <net/dst.h> |
19 | #include <net/xfrm.h> | 20 | #include <net/xfrm.h> |
@@ -32,6 +33,10 @@ static int radios = 2; | |||
32 | module_param(radios, int, 0444); | 33 | module_param(radios, int, 0444); |
33 | MODULE_PARM_DESC(radios, "Number of simulated radios"); | 34 | MODULE_PARM_DESC(radios, "Number of simulated radios"); |
34 | 35 | ||
36 | static bool fake_hw_scan; | ||
37 | module_param(fake_hw_scan, bool, 0444); | ||
38 | MODULE_PARM_DESC(fake_hw_scan, "Install fake (no-op) hw-scan handler"); | ||
39 | |||
35 | /** | 40 | /** |
36 | * enum hwsim_regtest - the type of regulatory tests we offer | 41 | * enum hwsim_regtest - the type of regulatory tests we offer |
37 | * | 42 | * |
@@ -281,10 +286,12 @@ struct mac80211_hwsim_data { | |||
281 | struct ieee80211_channel channels_5ghz[ARRAY_SIZE(hwsim_channels_5ghz)]; | 286 | struct ieee80211_channel channels_5ghz[ARRAY_SIZE(hwsim_channels_5ghz)]; |
282 | struct ieee80211_rate rates[ARRAY_SIZE(hwsim_rates)]; | 287 | struct ieee80211_rate rates[ARRAY_SIZE(hwsim_rates)]; |
283 | 288 | ||
289 | struct mac_address addresses[2]; | ||
290 | |||
284 | struct ieee80211_channel *channel; | 291 | struct ieee80211_channel *channel; |
285 | unsigned long beacon_int; /* in jiffies unit */ | 292 | unsigned long beacon_int; /* in jiffies unit */ |
286 | unsigned int rx_filter; | 293 | unsigned int rx_filter; |
287 | int started; | 294 | bool started, idle; |
288 | struct timer_list beacon_timer; | 295 | struct timer_list beacon_timer; |
289 | enum ps_mode { | 296 | enum ps_mode { |
290 | PS_DISABLED, PS_ENABLED, PS_AUTO_POLL, PS_MANUAL_POLL | 297 | PS_DISABLED, PS_ENABLED, PS_AUTO_POLL, PS_MANUAL_POLL |
@@ -365,6 +372,49 @@ static void mac80211_hwsim_monitor_rx(struct ieee80211_hw *hw, | |||
365 | } | 372 | } |
366 | 373 | ||
367 | 374 | ||
375 | static void mac80211_hwsim_monitor_ack(struct ieee80211_hw *hw, const u8 *addr) | ||
376 | { | ||
377 | struct mac80211_hwsim_data *data = hw->priv; | ||
378 | struct sk_buff *skb; | ||
379 | struct hwsim_radiotap_hdr *hdr; | ||
380 | u16 flags; | ||
381 | struct ieee80211_hdr *hdr11; | ||
382 | |||
383 | if (!netif_running(hwsim_mon)) | ||
384 | return; | ||
385 | |||
386 | skb = dev_alloc_skb(100); | ||
387 | if (skb == NULL) | ||
388 | return; | ||
389 | |||
390 | hdr = (struct hwsim_radiotap_hdr *) skb_put(skb, sizeof(*hdr)); | ||
391 | hdr->hdr.it_version = PKTHDR_RADIOTAP_VERSION; | ||
392 | hdr->hdr.it_pad = 0; | ||
393 | hdr->hdr.it_len = cpu_to_le16(sizeof(*hdr)); | ||
394 | hdr->hdr.it_present = cpu_to_le32((1 << IEEE80211_RADIOTAP_FLAGS) | | ||
395 | (1 << IEEE80211_RADIOTAP_CHANNEL)); | ||
396 | hdr->rt_flags = 0; | ||
397 | hdr->rt_rate = 0; | ||
398 | hdr->rt_channel = cpu_to_le16(data->channel->center_freq); | ||
399 | flags = IEEE80211_CHAN_2GHZ; | ||
400 | hdr->rt_chbitmask = cpu_to_le16(flags); | ||
401 | |||
402 | hdr11 = (struct ieee80211_hdr *) skb_put(skb, 10); | ||
403 | hdr11->frame_control = cpu_to_le16(IEEE80211_FTYPE_CTL | | ||
404 | IEEE80211_STYPE_ACK); | ||
405 | hdr11->duration_id = cpu_to_le16(0); | ||
406 | memcpy(hdr11->addr1, addr, ETH_ALEN); | ||
407 | |||
408 | skb->dev = hwsim_mon; | ||
409 | skb_set_mac_header(skb, 0); | ||
410 | skb->ip_summed = CHECKSUM_UNNECESSARY; | ||
411 | skb->pkt_type = PACKET_OTHERHOST; | ||
412 | skb->protocol = htons(ETH_P_802_2); | ||
413 | memset(skb->cb, 0, sizeof(skb->cb)); | ||
414 | netif_rx(skb); | ||
415 | } | ||
416 | |||
417 | |||
368 | static bool hwsim_ps_rx_ok(struct mac80211_hwsim_data *data, | 418 | static bool hwsim_ps_rx_ok(struct mac80211_hwsim_data *data, |
369 | struct sk_buff *skb) | 419 | struct sk_buff *skb) |
370 | { | 420 | { |
@@ -393,6 +443,38 @@ static bool hwsim_ps_rx_ok(struct mac80211_hwsim_data *data, | |||
393 | } | 443 | } |
394 | 444 | ||
395 | 445 | ||
446 | struct mac80211_hwsim_addr_match_data { | ||
447 | bool ret; | ||
448 | const u8 *addr; | ||
449 | }; | ||
450 | |||
451 | static void mac80211_hwsim_addr_iter(void *data, u8 *mac, | ||
452 | struct ieee80211_vif *vif) | ||
453 | { | ||
454 | struct mac80211_hwsim_addr_match_data *md = data; | ||
455 | if (memcmp(mac, md->addr, ETH_ALEN) == 0) | ||
456 | md->ret = true; | ||
457 | } | ||
458 | |||
459 | |||
460 | static bool mac80211_hwsim_addr_match(struct mac80211_hwsim_data *data, | ||
461 | const u8 *addr) | ||
462 | { | ||
463 | struct mac80211_hwsim_addr_match_data md; | ||
464 | |||
465 | if (memcmp(addr, data->hw->wiphy->perm_addr, ETH_ALEN) == 0) | ||
466 | return true; | ||
467 | |||
468 | md.ret = false; | ||
469 | md.addr = addr; | ||
470 | ieee80211_iterate_active_interfaces_atomic(data->hw, | ||
471 | mac80211_hwsim_addr_iter, | ||
472 | &md); | ||
473 | |||
474 | return md.ret; | ||
475 | } | ||
476 | |||
477 | |||
396 | static bool mac80211_hwsim_tx_frame(struct ieee80211_hw *hw, | 478 | static bool mac80211_hwsim_tx_frame(struct ieee80211_hw *hw, |
397 | struct sk_buff *skb) | 479 | struct sk_buff *skb) |
398 | { | 480 | { |
@@ -402,6 +484,12 @@ static bool mac80211_hwsim_tx_frame(struct ieee80211_hw *hw, | |||
402 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | 484 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
403 | struct ieee80211_rx_status rx_status; | 485 | struct ieee80211_rx_status rx_status; |
404 | 486 | ||
487 | if (data->idle) { | ||
488 | printk(KERN_DEBUG "%s: Trying to TX when idle - reject\n", | ||
489 | wiphy_name(hw->wiphy)); | ||
490 | return false; | ||
491 | } | ||
492 | |||
405 | memset(&rx_status, 0, sizeof(rx_status)); | 493 | memset(&rx_status, 0, sizeof(rx_status)); |
406 | /* TODO: set mactime */ | 494 | /* TODO: set mactime */ |
407 | rx_status.freq = data->channel->center_freq; | 495 | rx_status.freq = data->channel->center_freq; |
@@ -428,7 +516,8 @@ static bool mac80211_hwsim_tx_frame(struct ieee80211_hw *hw, | |||
428 | if (data == data2) | 516 | if (data == data2) |
429 | continue; | 517 | continue; |
430 | 518 | ||
431 | if (!data2->started || !hwsim_ps_rx_ok(data2, skb) || | 519 | if (data2->idle || !data2->started || |
520 | !hwsim_ps_rx_ok(data2, skb) || | ||
432 | !data->channel || !data2->channel || | 521 | !data->channel || !data2->channel || |
433 | data->channel->center_freq != data2->channel->center_freq || | 522 | data->channel->center_freq != data2->channel->center_freq || |
434 | !(data->group & data2->group)) | 523 | !(data->group & data2->group)) |
@@ -438,8 +527,7 @@ static bool mac80211_hwsim_tx_frame(struct ieee80211_hw *hw, | |||
438 | if (nskb == NULL) | 527 | if (nskb == NULL) |
439 | continue; | 528 | continue; |
440 | 529 | ||
441 | if (memcmp(hdr->addr1, data2->hw->wiphy->perm_addr, | 530 | if (mac80211_hwsim_addr_match(data2, hdr->addr1)) |
442 | ETH_ALEN) == 0) | ||
443 | ack = true; | 531 | ack = true; |
444 | memcpy(IEEE80211_SKB_RXCB(nskb), &rx_status, sizeof(rx_status)); | 532 | memcpy(IEEE80211_SKB_RXCB(nskb), &rx_status, sizeof(rx_status)); |
445 | ieee80211_rx_irqsafe(data2->hw, nskb); | 533 | ieee80211_rx_irqsafe(data2->hw, nskb); |
@@ -464,6 +552,10 @@ static int mac80211_hwsim_tx(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
464 | } | 552 | } |
465 | 553 | ||
466 | ack = mac80211_hwsim_tx_frame(hw, skb); | 554 | ack = mac80211_hwsim_tx_frame(hw, skb); |
555 | if (ack && skb->len >= 16) { | ||
556 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; | ||
557 | mac80211_hwsim_monitor_ack(hw, hdr->addr2); | ||
558 | } | ||
467 | 559 | ||
468 | txi = IEEE80211_SKB_CB(skb); | 560 | txi = IEEE80211_SKB_CB(skb); |
469 | 561 | ||
@@ -499,24 +591,24 @@ static void mac80211_hwsim_stop(struct ieee80211_hw *hw) | |||
499 | 591 | ||
500 | 592 | ||
501 | static int mac80211_hwsim_add_interface(struct ieee80211_hw *hw, | 593 | static int mac80211_hwsim_add_interface(struct ieee80211_hw *hw, |
502 | struct ieee80211_if_init_conf *conf) | 594 | struct ieee80211_vif *vif) |
503 | { | 595 | { |
504 | printk(KERN_DEBUG "%s:%s (type=%d mac_addr=%pM)\n", | 596 | printk(KERN_DEBUG "%s:%s (type=%d mac_addr=%pM)\n", |
505 | wiphy_name(hw->wiphy), __func__, conf->type, | 597 | wiphy_name(hw->wiphy), __func__, vif->type, |
506 | conf->mac_addr); | 598 | vif->addr); |
507 | hwsim_set_magic(conf->vif); | 599 | hwsim_set_magic(vif); |
508 | return 0; | 600 | return 0; |
509 | } | 601 | } |
510 | 602 | ||
511 | 603 | ||
512 | static void mac80211_hwsim_remove_interface( | 604 | static void mac80211_hwsim_remove_interface( |
513 | struct ieee80211_hw *hw, struct ieee80211_if_init_conf *conf) | 605 | struct ieee80211_hw *hw, struct ieee80211_vif *vif) |
514 | { | 606 | { |
515 | printk(KERN_DEBUG "%s:%s (type=%d mac_addr=%pM)\n", | 607 | printk(KERN_DEBUG "%s:%s (type=%d mac_addr=%pM)\n", |
516 | wiphy_name(hw->wiphy), __func__, conf->type, | 608 | wiphy_name(hw->wiphy), __func__, vif->type, |
517 | conf->mac_addr); | 609 | vif->addr); |
518 | hwsim_check_magic(conf->vif); | 610 | hwsim_check_magic(vif); |
519 | hwsim_clear_magic(conf->vif); | 611 | hwsim_clear_magic(vif); |
520 | } | 612 | } |
521 | 613 | ||
522 | 614 | ||
@@ -564,12 +656,28 @@ static int mac80211_hwsim_config(struct ieee80211_hw *hw, u32 changed) | |||
564 | { | 656 | { |
565 | struct mac80211_hwsim_data *data = hw->priv; | 657 | struct mac80211_hwsim_data *data = hw->priv; |
566 | struct ieee80211_conf *conf = &hw->conf; | 658 | struct ieee80211_conf *conf = &hw->conf; |
567 | 659 | static const char *chantypes[4] = { | |
568 | printk(KERN_DEBUG "%s:%s (freq=%d idle=%d ps=%d)\n", | 660 | [NL80211_CHAN_NO_HT] = "noht", |
661 | [NL80211_CHAN_HT20] = "ht20", | ||
662 | [NL80211_CHAN_HT40MINUS] = "ht40-", | ||
663 | [NL80211_CHAN_HT40PLUS] = "ht40+", | ||
664 | }; | ||
665 | static const char *smps_modes[IEEE80211_SMPS_NUM_MODES] = { | ||
666 | [IEEE80211_SMPS_AUTOMATIC] = "auto", | ||
667 | [IEEE80211_SMPS_OFF] = "off", | ||
668 | [IEEE80211_SMPS_STATIC] = "static", | ||
669 | [IEEE80211_SMPS_DYNAMIC] = "dynamic", | ||
670 | }; | ||
671 | |||
672 | printk(KERN_DEBUG "%s:%s (freq=%d/%s idle=%d ps=%d smps=%s)\n", | ||
569 | wiphy_name(hw->wiphy), __func__, | 673 | wiphy_name(hw->wiphy), __func__, |
570 | conf->channel->center_freq, | 674 | conf->channel->center_freq, |
675 | chantypes[conf->channel_type], | ||
571 | !!(conf->flags & IEEE80211_CONF_IDLE), | 676 | !!(conf->flags & IEEE80211_CONF_IDLE), |
572 | !!(conf->flags & IEEE80211_CONF_PS)); | 677 | !!(conf->flags & IEEE80211_CONF_PS), |
678 | smps_modes[conf->smps_mode]); | ||
679 | |||
680 | data->idle = !!(conf->flags & IEEE80211_CONF_IDLE); | ||
573 | 681 | ||
574 | data->channel = conf->channel; | 682 | data->channel = conf->channel; |
575 | if (!data->started || !data->beacon_int) | 683 | if (!data->started || !data->beacon_int) |
@@ -664,23 +772,41 @@ static void mac80211_hwsim_bss_info_changed(struct ieee80211_hw *hw, | |||
664 | } | 772 | } |
665 | } | 773 | } |
666 | 774 | ||
775 | static int mac80211_hwsim_sta_add(struct ieee80211_hw *hw, | ||
776 | struct ieee80211_vif *vif, | ||
777 | struct ieee80211_sta *sta) | ||
778 | { | ||
779 | hwsim_check_magic(vif); | ||
780 | hwsim_set_sta_magic(sta); | ||
781 | |||
782 | return 0; | ||
783 | } | ||
784 | |||
785 | static int mac80211_hwsim_sta_remove(struct ieee80211_hw *hw, | ||
786 | struct ieee80211_vif *vif, | ||
787 | struct ieee80211_sta *sta) | ||
788 | { | ||
789 | hwsim_check_magic(vif); | ||
790 | hwsim_clear_sta_magic(sta); | ||
791 | |||
792 | return 0; | ||
793 | } | ||
794 | |||
667 | static void mac80211_hwsim_sta_notify(struct ieee80211_hw *hw, | 795 | static void mac80211_hwsim_sta_notify(struct ieee80211_hw *hw, |
668 | struct ieee80211_vif *vif, | 796 | struct ieee80211_vif *vif, |
669 | enum sta_notify_cmd cmd, | 797 | enum sta_notify_cmd cmd, |
670 | struct ieee80211_sta *sta) | 798 | struct ieee80211_sta *sta) |
671 | { | 799 | { |
672 | hwsim_check_magic(vif); | 800 | hwsim_check_magic(vif); |
801 | |||
673 | switch (cmd) { | 802 | switch (cmd) { |
674 | case STA_NOTIFY_ADD: | ||
675 | hwsim_set_sta_magic(sta); | ||
676 | break; | ||
677 | case STA_NOTIFY_REMOVE: | ||
678 | hwsim_clear_sta_magic(sta); | ||
679 | break; | ||
680 | case STA_NOTIFY_SLEEP: | 803 | case STA_NOTIFY_SLEEP: |
681 | case STA_NOTIFY_AWAKE: | 804 | case STA_NOTIFY_AWAKE: |
682 | /* TODO: make good use of these flags */ | 805 | /* TODO: make good use of these flags */ |
683 | break; | 806 | break; |
807 | default: | ||
808 | WARN(1, "Invalid sta notify: %d\n", cmd); | ||
809 | break; | ||
684 | } | 810 | } |
685 | } | 811 | } |
686 | 812 | ||
@@ -771,7 +897,77 @@ static int mac80211_hwsim_testmode_cmd(struct ieee80211_hw *hw, | |||
771 | } | 897 | } |
772 | #endif | 898 | #endif |
773 | 899 | ||
774 | static const struct ieee80211_ops mac80211_hwsim_ops = | 900 | static int mac80211_hwsim_ampdu_action(struct ieee80211_hw *hw, |
901 | struct ieee80211_vif *vif, | ||
902 | enum ieee80211_ampdu_mlme_action action, | ||
903 | struct ieee80211_sta *sta, u16 tid, u16 *ssn) | ||
904 | { | ||
905 | switch (action) { | ||
906 | case IEEE80211_AMPDU_TX_START: | ||
907 | ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid); | ||
908 | break; | ||
909 | case IEEE80211_AMPDU_TX_STOP: | ||
910 | ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); | ||
911 | break; | ||
912 | case IEEE80211_AMPDU_TX_OPERATIONAL: | ||
913 | break; | ||
914 | case IEEE80211_AMPDU_RX_START: | ||
915 | case IEEE80211_AMPDU_RX_STOP: | ||
916 | break; | ||
917 | default: | ||
918 | return -EOPNOTSUPP; | ||
919 | } | ||
920 | |||
921 | return 0; | ||
922 | } | ||
923 | |||
924 | static void mac80211_hwsim_flush(struct ieee80211_hw *hw, bool drop) | ||
925 | { | ||
926 | /* | ||
927 | * In this special case, there's nothing we need to | ||
928 | * do because hwsim does transmission synchronously. | ||
929 | * In the future, when it does transmissions via | ||
930 | * userspace, we may need to do something. | ||
931 | */ | ||
932 | } | ||
933 | |||
934 | struct hw_scan_done { | ||
935 | struct delayed_work w; | ||
936 | struct ieee80211_hw *hw; | ||
937 | }; | ||
938 | |||
939 | static void hw_scan_done(struct work_struct *work) | ||
940 | { | ||
941 | struct hw_scan_done *hsd = | ||
942 | container_of(work, struct hw_scan_done, w.work); | ||
943 | |||
944 | ieee80211_scan_completed(hsd->hw, false); | ||
945 | kfree(hsd); | ||
946 | } | ||
947 | |||
948 | static int mac80211_hwsim_hw_scan(struct ieee80211_hw *hw, | ||
949 | struct cfg80211_scan_request *req) | ||
950 | { | ||
951 | struct hw_scan_done *hsd = kzalloc(sizeof(*hsd), GFP_KERNEL); | ||
952 | int i; | ||
953 | |||
954 | if (!hsd) | ||
955 | return -ENOMEM; | ||
956 | |||
957 | hsd->hw = hw; | ||
958 | INIT_DELAYED_WORK(&hsd->w, hw_scan_done); | ||
959 | |||
960 | printk(KERN_DEBUG "hwsim scan request\n"); | ||
961 | for (i = 0; i < req->n_channels; i++) | ||
962 | printk(KERN_DEBUG "hwsim scan freq %d\n", | ||
963 | req->channels[i]->center_freq); | ||
964 | |||
965 | ieee80211_queue_delayed_work(hw, &hsd->w, 2 * HZ); | ||
966 | |||
967 | return 0; | ||
968 | } | ||
969 | |||
970 | static struct ieee80211_ops mac80211_hwsim_ops = | ||
775 | { | 971 | { |
776 | .tx = mac80211_hwsim_tx, | 972 | .tx = mac80211_hwsim_tx, |
777 | .start = mac80211_hwsim_start, | 973 | .start = mac80211_hwsim_start, |
@@ -781,10 +977,14 @@ static const struct ieee80211_ops mac80211_hwsim_ops = | |||
781 | .config = mac80211_hwsim_config, | 977 | .config = mac80211_hwsim_config, |
782 | .configure_filter = mac80211_hwsim_configure_filter, | 978 | .configure_filter = mac80211_hwsim_configure_filter, |
783 | .bss_info_changed = mac80211_hwsim_bss_info_changed, | 979 | .bss_info_changed = mac80211_hwsim_bss_info_changed, |
980 | .sta_add = mac80211_hwsim_sta_add, | ||
981 | .sta_remove = mac80211_hwsim_sta_remove, | ||
784 | .sta_notify = mac80211_hwsim_sta_notify, | 982 | .sta_notify = mac80211_hwsim_sta_notify, |
785 | .set_tim = mac80211_hwsim_set_tim, | 983 | .set_tim = mac80211_hwsim_set_tim, |
786 | .conf_tx = mac80211_hwsim_conf_tx, | 984 | .conf_tx = mac80211_hwsim_conf_tx, |
787 | CFG80211_TESTMODE_CMD(mac80211_hwsim_testmode_cmd) | 985 | CFG80211_TESTMODE_CMD(mac80211_hwsim_testmode_cmd) |
986 | .ampdu_action = mac80211_hwsim_ampdu_action, | ||
987 | .flush = mac80211_hwsim_flush, | ||
788 | }; | 988 | }; |
789 | 989 | ||
790 | 990 | ||
@@ -979,6 +1179,9 @@ static int __init init_mac80211_hwsim(void) | |||
979 | if (radios < 1 || radios > 100) | 1179 | if (radios < 1 || radios > 100) |
980 | return -EINVAL; | 1180 | return -EINVAL; |
981 | 1181 | ||
1182 | if (fake_hw_scan) | ||
1183 | mac80211_hwsim_ops.hw_scan = mac80211_hwsim_hw_scan; | ||
1184 | |||
982 | spin_lock_init(&hwsim_radio_lock); | 1185 | spin_lock_init(&hwsim_radio_lock); |
983 | INIT_LIST_HEAD(&hwsim_radios); | 1186 | INIT_LIST_HEAD(&hwsim_radios); |
984 | 1187 | ||
@@ -1016,7 +1219,11 @@ static int __init init_mac80211_hwsim(void) | |||
1016 | SET_IEEE80211_DEV(hw, data->dev); | 1219 | SET_IEEE80211_DEV(hw, data->dev); |
1017 | addr[3] = i >> 8; | 1220 | addr[3] = i >> 8; |
1018 | addr[4] = i; | 1221 | addr[4] = i; |
1019 | SET_IEEE80211_PERM_ADDR(hw, addr); | 1222 | memcpy(data->addresses[0].addr, addr, ETH_ALEN); |
1223 | memcpy(data->addresses[1].addr, addr, ETH_ALEN); | ||
1224 | data->addresses[1].addr[0] |= 0x40; | ||
1225 | hw->wiphy->n_addresses = 2; | ||
1226 | hw->wiphy->addresses = data->addresses; | ||
1020 | 1227 | ||
1021 | hw->channel_change_time = 1; | 1228 | hw->channel_change_time = 1; |
1022 | hw->queues = 4; | 1229 | hw->queues = 4; |
@@ -1026,7 +1233,9 @@ static int __init init_mac80211_hwsim(void) | |||
1026 | BIT(NL80211_IFTYPE_MESH_POINT); | 1233 | BIT(NL80211_IFTYPE_MESH_POINT); |
1027 | 1234 | ||
1028 | hw->flags = IEEE80211_HW_MFP_CAPABLE | | 1235 | hw->flags = IEEE80211_HW_MFP_CAPABLE | |
1029 | IEEE80211_HW_SIGNAL_DBM; | 1236 | IEEE80211_HW_SIGNAL_DBM | |
1237 | IEEE80211_HW_SUPPORTS_STATIC_SMPS | | ||
1238 | IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS; | ||
1030 | 1239 | ||
1031 | /* ask mac80211 to reserve space for magic */ | 1240 | /* ask mac80211 to reserve space for magic */ |
1032 | hw->vif_data_size = sizeof(struct hwsim_vif_priv); | 1241 | hw->vif_data_size = sizeof(struct hwsim_vif_priv); |
@@ -1045,19 +1254,20 @@ static int __init init_mac80211_hwsim(void) | |||
1045 | sband->channels = data->channels_2ghz; | 1254 | sband->channels = data->channels_2ghz; |
1046 | sband->n_channels = | 1255 | sband->n_channels = |
1047 | ARRAY_SIZE(hwsim_channels_2ghz); | 1256 | ARRAY_SIZE(hwsim_channels_2ghz); |
1257 | sband->bitrates = data->rates; | ||
1258 | sband->n_bitrates = ARRAY_SIZE(hwsim_rates); | ||
1048 | break; | 1259 | break; |
1049 | case IEEE80211_BAND_5GHZ: | 1260 | case IEEE80211_BAND_5GHZ: |
1050 | sband->channels = data->channels_5ghz; | 1261 | sband->channels = data->channels_5ghz; |
1051 | sband->n_channels = | 1262 | sband->n_channels = |
1052 | ARRAY_SIZE(hwsim_channels_5ghz); | 1263 | ARRAY_SIZE(hwsim_channels_5ghz); |
1264 | sband->bitrates = data->rates + 4; | ||
1265 | sband->n_bitrates = ARRAY_SIZE(hwsim_rates) - 4; | ||
1053 | break; | 1266 | break; |
1054 | default: | 1267 | default: |
1055 | break; | 1268 | break; |
1056 | } | 1269 | } |
1057 | 1270 | ||
1058 | sband->bitrates = data->rates; | ||
1059 | sband->n_bitrates = ARRAY_SIZE(hwsim_rates); | ||
1060 | |||
1061 | sband->ht_cap.ht_supported = true; | 1271 | sband->ht_cap.ht_supported = true; |
1062 | sband->ht_cap.cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 | | 1272 | sband->ht_cap.cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 | |
1063 | IEEE80211_HT_CAP_GRN_FLD | | 1273 | IEEE80211_HT_CAP_GRN_FLD | |
@@ -1089,46 +1299,46 @@ static int __init init_mac80211_hwsim(void) | |||
1089 | break; | 1299 | break; |
1090 | case HWSIM_REGTEST_WORLD_ROAM: | 1300 | case HWSIM_REGTEST_WORLD_ROAM: |
1091 | if (i == 0) { | 1301 | if (i == 0) { |
1092 | hw->wiphy->custom_regulatory = true; | 1302 | hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY; |
1093 | wiphy_apply_custom_regulatory(hw->wiphy, | 1303 | wiphy_apply_custom_regulatory(hw->wiphy, |
1094 | &hwsim_world_regdom_custom_01); | 1304 | &hwsim_world_regdom_custom_01); |
1095 | } | 1305 | } |
1096 | break; | 1306 | break; |
1097 | case HWSIM_REGTEST_CUSTOM_WORLD: | 1307 | case HWSIM_REGTEST_CUSTOM_WORLD: |
1098 | hw->wiphy->custom_regulatory = true; | 1308 | hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY; |
1099 | wiphy_apply_custom_regulatory(hw->wiphy, | 1309 | wiphy_apply_custom_regulatory(hw->wiphy, |
1100 | &hwsim_world_regdom_custom_01); | 1310 | &hwsim_world_regdom_custom_01); |
1101 | break; | 1311 | break; |
1102 | case HWSIM_REGTEST_CUSTOM_WORLD_2: | 1312 | case HWSIM_REGTEST_CUSTOM_WORLD_2: |
1103 | if (i == 0) { | 1313 | if (i == 0) { |
1104 | hw->wiphy->custom_regulatory = true; | 1314 | hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY; |
1105 | wiphy_apply_custom_regulatory(hw->wiphy, | 1315 | wiphy_apply_custom_regulatory(hw->wiphy, |
1106 | &hwsim_world_regdom_custom_01); | 1316 | &hwsim_world_regdom_custom_01); |
1107 | } else if (i == 1) { | 1317 | } else if (i == 1) { |
1108 | hw->wiphy->custom_regulatory = true; | 1318 | hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY; |
1109 | wiphy_apply_custom_regulatory(hw->wiphy, | 1319 | wiphy_apply_custom_regulatory(hw->wiphy, |
1110 | &hwsim_world_regdom_custom_02); | 1320 | &hwsim_world_regdom_custom_02); |
1111 | } | 1321 | } |
1112 | break; | 1322 | break; |
1113 | case HWSIM_REGTEST_STRICT_ALL: | 1323 | case HWSIM_REGTEST_STRICT_ALL: |
1114 | hw->wiphy->strict_regulatory = true; | 1324 | hw->wiphy->flags |= WIPHY_FLAG_STRICT_REGULATORY; |
1115 | break; | 1325 | break; |
1116 | case HWSIM_REGTEST_STRICT_FOLLOW: | 1326 | case HWSIM_REGTEST_STRICT_FOLLOW: |
1117 | case HWSIM_REGTEST_STRICT_AND_DRIVER_REG: | 1327 | case HWSIM_REGTEST_STRICT_AND_DRIVER_REG: |
1118 | if (i == 0) | 1328 | if (i == 0) |
1119 | hw->wiphy->strict_regulatory = true; | 1329 | hw->wiphy->flags |= WIPHY_FLAG_STRICT_REGULATORY; |
1120 | break; | 1330 | break; |
1121 | case HWSIM_REGTEST_ALL: | 1331 | case HWSIM_REGTEST_ALL: |
1122 | if (i == 0) { | 1332 | if (i == 0) { |
1123 | hw->wiphy->custom_regulatory = true; | 1333 | hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY; |
1124 | wiphy_apply_custom_regulatory(hw->wiphy, | 1334 | wiphy_apply_custom_regulatory(hw->wiphy, |
1125 | &hwsim_world_regdom_custom_01); | 1335 | &hwsim_world_regdom_custom_01); |
1126 | } else if (i == 1) { | 1336 | } else if (i == 1) { |
1127 | hw->wiphy->custom_regulatory = true; | 1337 | hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY; |
1128 | wiphy_apply_custom_regulatory(hw->wiphy, | 1338 | wiphy_apply_custom_regulatory(hw->wiphy, |
1129 | &hwsim_world_regdom_custom_02); | 1339 | &hwsim_world_regdom_custom_02); |
1130 | } else if (i == 4) | 1340 | } else if (i == 4) |
1131 | hw->wiphy->strict_regulatory = true; | 1341 | hw->wiphy->flags |= WIPHY_FLAG_STRICT_REGULATORY; |
1132 | break; | 1342 | break; |
1133 | default: | 1343 | default: |
1134 | break; | 1344 | break; |