diff options
Diffstat (limited to 'drivers/net/wireless/mac80211_hwsim.c')
-rw-r--r-- | drivers/net/wireless/mac80211_hwsim.c | 288 |
1 files changed, 257 insertions, 31 deletions
diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 1a019e98dac3..b9230da925ee 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c | |||
@@ -21,6 +21,7 @@ | |||
21 | #include <linux/if_arp.h> | 21 | #include <linux/if_arp.h> |
22 | #include <linux/rtnetlink.h> | 22 | #include <linux/rtnetlink.h> |
23 | #include <linux/etherdevice.h> | 23 | #include <linux/etherdevice.h> |
24 | #include <linux/debugfs.h> | ||
24 | 25 | ||
25 | MODULE_AUTHOR("Jouni Malinen"); | 26 | MODULE_AUTHOR("Jouni Malinen"); |
26 | MODULE_DESCRIPTION("Software simulator of 802.11 radio(s) for mac80211"); | 27 | MODULE_DESCRIPTION("Software simulator of 802.11 radio(s) for mac80211"); |
@@ -32,6 +33,9 @@ MODULE_PARM_DESC(radios, "Number of simulated radios"); | |||
32 | 33 | ||
33 | struct hwsim_vif_priv { | 34 | struct hwsim_vif_priv { |
34 | u32 magic; | 35 | u32 magic; |
36 | u8 bssid[ETH_ALEN]; | ||
37 | bool assoc; | ||
38 | u16 aid; | ||
35 | }; | 39 | }; |
36 | 40 | ||
37 | #define HWSIM_VIF_MAGIC 0x69537748 | 41 | #define HWSIM_VIF_MAGIC 0x69537748 |
@@ -63,13 +67,13 @@ struct hwsim_sta_priv { | |||
63 | static inline void hwsim_check_sta_magic(struct ieee80211_sta *sta) | 67 | static inline void hwsim_check_sta_magic(struct ieee80211_sta *sta) |
64 | { | 68 | { |
65 | struct hwsim_sta_priv *sp = (void *)sta->drv_priv; | 69 | struct hwsim_sta_priv *sp = (void *)sta->drv_priv; |
66 | WARN_ON(sp->magic != HWSIM_VIF_MAGIC); | 70 | WARN_ON(sp->magic != HWSIM_STA_MAGIC); |
67 | } | 71 | } |
68 | 72 | ||
69 | static inline void hwsim_set_sta_magic(struct ieee80211_sta *sta) | 73 | static inline void hwsim_set_sta_magic(struct ieee80211_sta *sta) |
70 | { | 74 | { |
71 | struct hwsim_sta_priv *sp = (void *)sta->drv_priv; | 75 | struct hwsim_sta_priv *sp = (void *)sta->drv_priv; |
72 | sp->magic = HWSIM_VIF_MAGIC; | 76 | sp->magic = HWSIM_STA_MAGIC; |
73 | } | 77 | } |
74 | 78 | ||
75 | static inline void hwsim_clear_sta_magic(struct ieee80211_sta *sta) | 79 | static inline void hwsim_clear_sta_magic(struct ieee80211_sta *sta) |
@@ -132,6 +136,12 @@ struct mac80211_hwsim_data { | |||
132 | unsigned int rx_filter; | 136 | unsigned int rx_filter; |
133 | int started; | 137 | int started; |
134 | struct timer_list beacon_timer; | 138 | struct timer_list beacon_timer; |
139 | enum ps_mode { | ||
140 | PS_DISABLED, PS_ENABLED, PS_AUTO_POLL, PS_MANUAL_POLL | ||
141 | } ps; | ||
142 | bool ps_poll_pending; | ||
143 | struct dentry *debugfs; | ||
144 | struct dentry *debugfs_ps; | ||
135 | }; | 145 | }; |
136 | 146 | ||
137 | 147 | ||
@@ -196,6 +206,34 @@ static void mac80211_hwsim_monitor_rx(struct ieee80211_hw *hw, | |||
196 | } | 206 | } |
197 | 207 | ||
198 | 208 | ||
209 | static bool hwsim_ps_rx_ok(struct mac80211_hwsim_data *data, | ||
210 | struct sk_buff *skb) | ||
211 | { | ||
212 | switch (data->ps) { | ||
213 | case PS_DISABLED: | ||
214 | return true; | ||
215 | case PS_ENABLED: | ||
216 | return false; | ||
217 | case PS_AUTO_POLL: | ||
218 | /* TODO: accept (some) Beacons by default and other frames only | ||
219 | * if pending PS-Poll has been sent */ | ||
220 | return true; | ||
221 | case PS_MANUAL_POLL: | ||
222 | /* Allow unicast frames to own address if there is a pending | ||
223 | * PS-Poll */ | ||
224 | if (data->ps_poll_pending && | ||
225 | memcmp(data->hw->wiphy->perm_addr, skb->data + 4, | ||
226 | ETH_ALEN) == 0) { | ||
227 | data->ps_poll_pending = false; | ||
228 | return true; | ||
229 | } | ||
230 | return false; | ||
231 | } | ||
232 | |||
233 | return true; | ||
234 | } | ||
235 | |||
236 | |||
199 | static bool mac80211_hwsim_tx_frame(struct ieee80211_hw *hw, | 237 | static bool mac80211_hwsim_tx_frame(struct ieee80211_hw *hw, |
200 | struct sk_buff *skb) | 238 | struct sk_buff *skb) |
201 | { | 239 | { |
@@ -209,9 +247,12 @@ static bool mac80211_hwsim_tx_frame(struct ieee80211_hw *hw, | |||
209 | /* TODO: set mactime */ | 247 | /* TODO: set mactime */ |
210 | rx_status.freq = data->channel->center_freq; | 248 | rx_status.freq = data->channel->center_freq; |
211 | rx_status.band = data->channel->band; | 249 | rx_status.band = data->channel->band; |
212 | rx_status.rate_idx = info->tx_rate_idx; | 250 | rx_status.rate_idx = info->control.rates[0].idx; |
213 | /* TODO: simulate signal strength (and optional packet drop) */ | 251 | /* TODO: simulate signal strength (and optional packet drop) */ |
214 | 252 | ||
253 | if (data->ps != PS_DISABLED) | ||
254 | hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM); | ||
255 | |||
215 | /* Copy skb to all enabled radios that are on the current frequency */ | 256 | /* Copy skb to all enabled radios that are on the current frequency */ |
216 | spin_lock(&hwsim_radio_lock); | 257 | spin_lock(&hwsim_radio_lock); |
217 | list_for_each_entry(data2, &hwsim_radios, list) { | 258 | list_for_each_entry(data2, &hwsim_radios, list) { |
@@ -221,6 +262,7 @@ static bool mac80211_hwsim_tx_frame(struct ieee80211_hw *hw, | |||
221 | continue; | 262 | continue; |
222 | 263 | ||
223 | if (!data2->started || !data2->radio_enabled || | 264 | if (!data2->started || !data2->radio_enabled || |
265 | !hwsim_ps_rx_ok(data2, skb) || | ||
224 | data->channel->center_freq != data2->channel->center_freq) | 266 | data->channel->center_freq != data2->channel->center_freq) |
225 | continue; | 267 | continue; |
226 | 268 | ||
@@ -269,13 +311,9 @@ static int mac80211_hwsim_tx(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
269 | if (txi->control.sta) | 311 | if (txi->control.sta) |
270 | hwsim_check_sta_magic(txi->control.sta); | 312 | hwsim_check_sta_magic(txi->control.sta); |
271 | 313 | ||
272 | memset(&txi->status, 0, sizeof(txi->status)); | 314 | ieee80211_tx_info_clear_status(txi); |
273 | if (!(txi->flags & IEEE80211_TX_CTL_NO_ACK)) { | 315 | if (!(txi->flags & IEEE80211_TX_CTL_NO_ACK) && ack) |
274 | if (ack) | 316 | txi->flags |= IEEE80211_TX_STAT_ACK; |
275 | txi->flags |= IEEE80211_TX_STAT_ACK; | ||
276 | else | ||
277 | txi->status.excessive_retries = 1; | ||
278 | } | ||
279 | ieee80211_tx_status_irqsafe(hw, skb); | 317 | ieee80211_tx_status_irqsafe(hw, skb); |
280 | return NETDEV_TX_OK; | 318 | return NETDEV_TX_OK; |
281 | } | 319 | } |
@@ -294,6 +332,7 @@ static void mac80211_hwsim_stop(struct ieee80211_hw *hw) | |||
294 | { | 332 | { |
295 | struct mac80211_hwsim_data *data = hw->priv; | 333 | struct mac80211_hwsim_data *data = hw->priv; |
296 | data->started = 0; | 334 | data->started = 0; |
335 | del_timer(&data->beacon_timer); | ||
297 | printk(KERN_DEBUG "%s:%s\n", wiphy_name(hw->wiphy), __func__); | 336 | printk(KERN_DEBUG "%s:%s\n", wiphy_name(hw->wiphy), __func__); |
298 | } | 337 | } |
299 | 338 | ||
@@ -301,10 +340,9 @@ static void mac80211_hwsim_stop(struct ieee80211_hw *hw) | |||
301 | static int mac80211_hwsim_add_interface(struct ieee80211_hw *hw, | 340 | static int mac80211_hwsim_add_interface(struct ieee80211_hw *hw, |
302 | struct ieee80211_if_init_conf *conf) | 341 | struct ieee80211_if_init_conf *conf) |
303 | { | 342 | { |
304 | DECLARE_MAC_BUF(mac); | 343 | printk(KERN_DEBUG "%s:%s (type=%d mac_addr=%pM)\n", |
305 | printk(KERN_DEBUG "%s:%s (type=%d mac_addr=%s)\n", | ||
306 | wiphy_name(hw->wiphy), __func__, conf->type, | 344 | wiphy_name(hw->wiphy), __func__, conf->type, |
307 | print_mac(mac, conf->mac_addr)); | 345 | conf->mac_addr); |
308 | hwsim_set_magic(conf->vif); | 346 | hwsim_set_magic(conf->vif); |
309 | return 0; | 347 | return 0; |
310 | } | 348 | } |
@@ -313,10 +351,9 @@ static int mac80211_hwsim_add_interface(struct ieee80211_hw *hw, | |||
313 | static void mac80211_hwsim_remove_interface( | 351 | static void mac80211_hwsim_remove_interface( |
314 | struct ieee80211_hw *hw, struct ieee80211_if_init_conf *conf) | 352 | struct ieee80211_hw *hw, struct ieee80211_if_init_conf *conf) |
315 | { | 353 | { |
316 | DECLARE_MAC_BUF(mac); | 354 | printk(KERN_DEBUG "%s:%s (type=%d mac_addr=%pM)\n", |
317 | printk(KERN_DEBUG "%s:%s (type=%d mac_addr=%s)\n", | ||
318 | wiphy_name(hw->wiphy), __func__, conf->type, | 355 | wiphy_name(hw->wiphy), __func__, conf->type, |
319 | print_mac(mac, conf->mac_addr)); | 356 | conf->mac_addr); |
320 | hwsim_check_magic(conf->vif); | 357 | hwsim_check_magic(conf->vif); |
321 | hwsim_clear_magic(conf->vif); | 358 | hwsim_clear_magic(conf->vif); |
322 | } | 359 | } |
@@ -361,10 +398,10 @@ static void mac80211_hwsim_beacon(unsigned long arg) | |||
361 | } | 398 | } |
362 | 399 | ||
363 | 400 | ||
364 | static int mac80211_hwsim_config(struct ieee80211_hw *hw, | 401 | static int mac80211_hwsim_config(struct ieee80211_hw *hw, u32 changed) |
365 | struct ieee80211_conf *conf) | ||
366 | { | 402 | { |
367 | struct mac80211_hwsim_data *data = hw->priv; | 403 | struct mac80211_hwsim_data *data = hw->priv; |
404 | struct ieee80211_conf *conf = &hw->conf; | ||
368 | 405 | ||
369 | printk(KERN_DEBUG "%s:%s (freq=%d radio_enabled=%d beacon_int=%d)\n", | 406 | printk(KERN_DEBUG "%s:%s (freq=%d radio_enabled=%d beacon_int=%d)\n", |
370 | wiphy_name(hw->wiphy), __func__, | 407 | wiphy_name(hw->wiphy), __func__, |
@@ -409,7 +446,16 @@ static int mac80211_hwsim_config_interface(struct ieee80211_hw *hw, | |||
409 | struct ieee80211_vif *vif, | 446 | struct ieee80211_vif *vif, |
410 | struct ieee80211_if_conf *conf) | 447 | struct ieee80211_if_conf *conf) |
411 | { | 448 | { |
449 | struct hwsim_vif_priv *vp = (void *)vif->drv_priv; | ||
450 | |||
412 | hwsim_check_magic(vif); | 451 | hwsim_check_magic(vif); |
452 | if (conf->changed & IEEE80211_IFCC_BSSID) { | ||
453 | DECLARE_MAC_BUF(mac); | ||
454 | printk(KERN_DEBUG "%s:%s: BSSID changed: %s\n", | ||
455 | wiphy_name(hw->wiphy), __func__, | ||
456 | print_mac(mac, conf->bssid)); | ||
457 | memcpy(vp->bssid, conf->bssid, ETH_ALEN); | ||
458 | } | ||
413 | return 0; | 459 | return 0; |
414 | } | 460 | } |
415 | 461 | ||
@@ -418,7 +464,48 @@ static void mac80211_hwsim_bss_info_changed(struct ieee80211_hw *hw, | |||
418 | struct ieee80211_bss_conf *info, | 464 | struct ieee80211_bss_conf *info, |
419 | u32 changed) | 465 | u32 changed) |
420 | { | 466 | { |
467 | struct hwsim_vif_priv *vp = (void *)vif->drv_priv; | ||
468 | |||
421 | hwsim_check_magic(vif); | 469 | hwsim_check_magic(vif); |
470 | |||
471 | printk(KERN_DEBUG "%s:%s(changed=0x%x)\n", | ||
472 | wiphy_name(hw->wiphy), __func__, changed); | ||
473 | |||
474 | if (changed & BSS_CHANGED_ASSOC) { | ||
475 | printk(KERN_DEBUG " %s: ASSOC: assoc=%d aid=%d\n", | ||
476 | wiphy_name(hw->wiphy), info->assoc, info->aid); | ||
477 | vp->assoc = info->assoc; | ||
478 | vp->aid = info->aid; | ||
479 | } | ||
480 | |||
481 | if (changed & BSS_CHANGED_ERP_CTS_PROT) { | ||
482 | printk(KERN_DEBUG " %s: ERP_CTS_PROT: %d\n", | ||
483 | wiphy_name(hw->wiphy), info->use_cts_prot); | ||
484 | } | ||
485 | |||
486 | if (changed & BSS_CHANGED_ERP_PREAMBLE) { | ||
487 | printk(KERN_DEBUG " %s: ERP_PREAMBLE: %d\n", | ||
488 | wiphy_name(hw->wiphy), info->use_short_preamble); | ||
489 | } | ||
490 | |||
491 | if (changed & BSS_CHANGED_ERP_SLOT) { | ||
492 | printk(KERN_DEBUG " %s: ERP_SLOT: %d\n", | ||
493 | wiphy_name(hw->wiphy), info->use_short_slot); | ||
494 | } | ||
495 | |||
496 | if (changed & BSS_CHANGED_HT) { | ||
497 | printk(KERN_DEBUG " %s: HT: sec_ch_offs=%d width_40_ok=%d " | ||
498 | "op_mode=%d\n", | ||
499 | wiphy_name(hw->wiphy), | ||
500 | info->ht.secondary_channel_offset, | ||
501 | info->ht.width_40_ok, info->ht.operation_mode); | ||
502 | } | ||
503 | |||
504 | if (changed & BSS_CHANGED_BASIC_RATES) { | ||
505 | printk(KERN_DEBUG " %s: BASIC_RATES: 0x%llx\n", | ||
506 | wiphy_name(hw->wiphy), | ||
507 | (unsigned long long) info->basic_rates); | ||
508 | } | ||
422 | } | 509 | } |
423 | 510 | ||
424 | static void mac80211_hwsim_sta_notify(struct ieee80211_hw *hw, | 511 | static void mac80211_hwsim_sta_notify(struct ieee80211_hw *hw, |
@@ -445,6 +532,17 @@ static int mac80211_hwsim_set_tim(struct ieee80211_hw *hw, | |||
445 | return 0; | 532 | return 0; |
446 | } | 533 | } |
447 | 534 | ||
535 | static int mac80211_hwsim_conf_tx( | ||
536 | struct ieee80211_hw *hw, u16 queue, | ||
537 | const struct ieee80211_tx_queue_params *params) | ||
538 | { | ||
539 | printk(KERN_DEBUG "%s:%s (queue=%d txop=%d cw_min=%d cw_max=%d " | ||
540 | "aifs=%d)\n", | ||
541 | wiphy_name(hw->wiphy), __func__, queue, | ||
542 | params->txop, params->cw_min, params->cw_max, params->aifs); | ||
543 | return 0; | ||
544 | } | ||
545 | |||
448 | static const struct ieee80211_ops mac80211_hwsim_ops = | 546 | static const struct ieee80211_ops mac80211_hwsim_ops = |
449 | { | 547 | { |
450 | .tx = mac80211_hwsim_tx, | 548 | .tx = mac80211_hwsim_tx, |
@@ -458,6 +556,7 @@ static const struct ieee80211_ops mac80211_hwsim_ops = | |||
458 | .bss_info_changed = mac80211_hwsim_bss_info_changed, | 556 | .bss_info_changed = mac80211_hwsim_bss_info_changed, |
459 | .sta_notify = mac80211_hwsim_sta_notify, | 557 | .sta_notify = mac80211_hwsim_sta_notify, |
460 | .set_tim = mac80211_hwsim_set_tim, | 558 | .set_tim = mac80211_hwsim_set_tim, |
559 | .conf_tx = mac80211_hwsim_conf_tx, | ||
461 | }; | 560 | }; |
462 | 561 | ||
463 | 562 | ||
@@ -474,6 +573,8 @@ static void mac80211_hwsim_free(void) | |||
474 | spin_unlock_bh(&hwsim_radio_lock); | 573 | spin_unlock_bh(&hwsim_radio_lock); |
475 | 574 | ||
476 | list_for_each_entry(data, &tmplist, list) { | 575 | list_for_each_entry(data, &tmplist, list) { |
576 | debugfs_remove(data->debugfs_ps); | ||
577 | debugfs_remove(data->debugfs); | ||
477 | ieee80211_unregister_hw(data->hw); | 578 | ieee80211_unregister_hw(data->hw); |
478 | device_unregister(data->dev); | 579 | device_unregister(data->dev); |
479 | ieee80211_free_hw(data->hw); | 580 | ieee80211_free_hw(data->hw); |
@@ -499,13 +600,133 @@ static void hwsim_mon_setup(struct net_device *dev) | |||
499 | } | 600 | } |
500 | 601 | ||
501 | 602 | ||
603 | static void hwsim_send_ps_poll(void *dat, u8 *mac, struct ieee80211_vif *vif) | ||
604 | { | ||
605 | struct mac80211_hwsim_data *data = dat; | ||
606 | struct hwsim_vif_priv *vp = (void *)vif->drv_priv; | ||
607 | DECLARE_MAC_BUF(buf); | ||
608 | struct sk_buff *skb; | ||
609 | struct ieee80211_pspoll *pspoll; | ||
610 | |||
611 | if (!vp->assoc) | ||
612 | return; | ||
613 | |||
614 | printk(KERN_DEBUG "%s:%s: send PS-Poll to %s for aid %d\n", | ||
615 | wiphy_name(data->hw->wiphy), __func__, | ||
616 | print_mac(buf, vp->bssid), vp->aid); | ||
617 | |||
618 | skb = dev_alloc_skb(sizeof(*pspoll)); | ||
619 | if (!skb) | ||
620 | return; | ||
621 | pspoll = (void *) skb_put(skb, sizeof(*pspoll)); | ||
622 | pspoll->frame_control = cpu_to_le16(IEEE80211_FTYPE_CTL | | ||
623 | IEEE80211_STYPE_PSPOLL | | ||
624 | IEEE80211_FCTL_PM); | ||
625 | pspoll->aid = cpu_to_le16(0xc000 | vp->aid); | ||
626 | memcpy(pspoll->bssid, vp->bssid, ETH_ALEN); | ||
627 | memcpy(pspoll->ta, mac, ETH_ALEN); | ||
628 | if (data->radio_enabled && | ||
629 | !mac80211_hwsim_tx_frame(data->hw, skb)) | ||
630 | printk(KERN_DEBUG "%s: PS-Poll frame not ack'ed\n", __func__); | ||
631 | dev_kfree_skb(skb); | ||
632 | } | ||
633 | |||
634 | |||
635 | static void hwsim_send_nullfunc(struct mac80211_hwsim_data *data, u8 *mac, | ||
636 | struct ieee80211_vif *vif, int ps) | ||
637 | { | ||
638 | struct hwsim_vif_priv *vp = (void *)vif->drv_priv; | ||
639 | DECLARE_MAC_BUF(buf); | ||
640 | struct sk_buff *skb; | ||
641 | struct ieee80211_hdr *hdr; | ||
642 | |||
643 | if (!vp->assoc) | ||
644 | return; | ||
645 | |||
646 | printk(KERN_DEBUG "%s:%s: send data::nullfunc to %s ps=%d\n", | ||
647 | wiphy_name(data->hw->wiphy), __func__, | ||
648 | print_mac(buf, vp->bssid), ps); | ||
649 | |||
650 | skb = dev_alloc_skb(sizeof(*hdr)); | ||
651 | if (!skb) | ||
652 | return; | ||
653 | hdr = (void *) skb_put(skb, sizeof(*hdr) - ETH_ALEN); | ||
654 | hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA | | ||
655 | IEEE80211_STYPE_NULLFUNC | | ||
656 | (ps ? IEEE80211_FCTL_PM : 0)); | ||
657 | hdr->duration_id = cpu_to_le16(0); | ||
658 | memcpy(hdr->addr1, vp->bssid, ETH_ALEN); | ||
659 | memcpy(hdr->addr2, mac, ETH_ALEN); | ||
660 | memcpy(hdr->addr3, vp->bssid, ETH_ALEN); | ||
661 | if (data->radio_enabled && | ||
662 | !mac80211_hwsim_tx_frame(data->hw, skb)) | ||
663 | printk(KERN_DEBUG "%s: nullfunc frame not ack'ed\n", __func__); | ||
664 | dev_kfree_skb(skb); | ||
665 | } | ||
666 | |||
667 | |||
668 | static void hwsim_send_nullfunc_ps(void *dat, u8 *mac, | ||
669 | struct ieee80211_vif *vif) | ||
670 | { | ||
671 | struct mac80211_hwsim_data *data = dat; | ||
672 | hwsim_send_nullfunc(data, mac, vif, 1); | ||
673 | } | ||
674 | |||
675 | |||
676 | static void hwsim_send_nullfunc_no_ps(void *dat, u8 *mac, | ||
677 | struct ieee80211_vif *vif) | ||
678 | { | ||
679 | struct mac80211_hwsim_data *data = dat; | ||
680 | hwsim_send_nullfunc(data, mac, vif, 0); | ||
681 | } | ||
682 | |||
683 | |||
684 | static int hwsim_fops_ps_read(void *dat, u64 *val) | ||
685 | { | ||
686 | struct mac80211_hwsim_data *data = dat; | ||
687 | *val = data->ps; | ||
688 | return 0; | ||
689 | } | ||
690 | |||
691 | static int hwsim_fops_ps_write(void *dat, u64 val) | ||
692 | { | ||
693 | struct mac80211_hwsim_data *data = dat; | ||
694 | enum ps_mode old_ps; | ||
695 | |||
696 | if (val != PS_DISABLED && val != PS_ENABLED && val != PS_AUTO_POLL && | ||
697 | val != PS_MANUAL_POLL) | ||
698 | return -EINVAL; | ||
699 | |||
700 | old_ps = data->ps; | ||
701 | data->ps = val; | ||
702 | |||
703 | if (val == PS_MANUAL_POLL) { | ||
704 | ieee80211_iterate_active_interfaces(data->hw, | ||
705 | hwsim_send_ps_poll, data); | ||
706 | data->ps_poll_pending = true; | ||
707 | } else if (old_ps == PS_DISABLED && val != PS_DISABLED) { | ||
708 | ieee80211_iterate_active_interfaces(data->hw, | ||
709 | hwsim_send_nullfunc_ps, | ||
710 | data); | ||
711 | } else if (old_ps != PS_DISABLED && val == PS_DISABLED) { | ||
712 | ieee80211_iterate_active_interfaces(data->hw, | ||
713 | hwsim_send_nullfunc_no_ps, | ||
714 | data); | ||
715 | } | ||
716 | |||
717 | return 0; | ||
718 | } | ||
719 | |||
720 | DEFINE_SIMPLE_ATTRIBUTE(hwsim_fops_ps, hwsim_fops_ps_read, hwsim_fops_ps_write, | ||
721 | "%llu\n"); | ||
722 | |||
723 | |||
502 | static int __init init_mac80211_hwsim(void) | 724 | static int __init init_mac80211_hwsim(void) |
503 | { | 725 | { |
504 | int i, err = 0; | 726 | int i, err = 0; |
505 | u8 addr[ETH_ALEN]; | 727 | u8 addr[ETH_ALEN]; |
506 | struct mac80211_hwsim_data *data; | 728 | struct mac80211_hwsim_data *data; |
507 | struct ieee80211_hw *hw; | 729 | struct ieee80211_hw *hw; |
508 | DECLARE_MAC_BUF(mac); | ||
509 | 730 | ||
510 | if (radios < 1 || radios > 100) | 731 | if (radios < 1 || radios > 100) |
511 | return -EINVAL; | 732 | return -EINVAL; |
@@ -566,19 +787,18 @@ static int __init init_mac80211_hwsim(void) | |||
566 | data->band.n_channels = ARRAY_SIZE(hwsim_channels); | 787 | data->band.n_channels = ARRAY_SIZE(hwsim_channels); |
567 | data->band.bitrates = data->rates; | 788 | data->band.bitrates = data->rates; |
568 | data->band.n_bitrates = ARRAY_SIZE(hwsim_rates); | 789 | data->band.n_bitrates = ARRAY_SIZE(hwsim_rates); |
569 | data->band.ht_info.ht_supported = 1; | 790 | data->band.ht_cap.ht_supported = true; |
570 | data->band.ht_info.cap = IEEE80211_HT_CAP_SUP_WIDTH | | 791 | data->band.ht_cap.cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 | |
571 | IEEE80211_HT_CAP_GRN_FLD | | 792 | IEEE80211_HT_CAP_GRN_FLD | |
572 | IEEE80211_HT_CAP_SGI_40 | | 793 | IEEE80211_HT_CAP_SGI_40 | |
573 | IEEE80211_HT_CAP_DSSSCCK40; | 794 | IEEE80211_HT_CAP_DSSSCCK40; |
574 | data->band.ht_info.ampdu_factor = 0x3; | 795 | data->band.ht_cap.ampdu_factor = 0x3; |
575 | data->band.ht_info.ampdu_density = 0x6; | 796 | data->band.ht_cap.ampdu_density = 0x6; |
576 | memset(data->band.ht_info.supp_mcs_set, 0, | 797 | memset(&data->band.ht_cap.mcs, 0, |
577 | sizeof(data->band.ht_info.supp_mcs_set)); | 798 | sizeof(data->band.ht_cap.mcs)); |
578 | data->band.ht_info.supp_mcs_set[0] = 0xff; | 799 | data->band.ht_cap.mcs.rx_mask[0] = 0xff; |
579 | data->band.ht_info.supp_mcs_set[1] = 0xff; | 800 | data->band.ht_cap.mcs.rx_mask[1] = 0xff; |
580 | data->band.ht_info.supp_mcs_set[12] = | 801 | data->band.ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; |
581 | IEEE80211_HT_CAP_MCS_TX_DEFINED; | ||
582 | hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &data->band; | 802 | hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &data->band; |
583 | 803 | ||
584 | err = ieee80211_register_hw(hw); | 804 | err = ieee80211_register_hw(hw); |
@@ -588,9 +808,15 @@ static int __init init_mac80211_hwsim(void) | |||
588 | goto failed_hw; | 808 | goto failed_hw; |
589 | } | 809 | } |
590 | 810 | ||
591 | printk(KERN_DEBUG "%s: hwaddr %s registered\n", | 811 | printk(KERN_DEBUG "%s: hwaddr %pM registered\n", |
592 | wiphy_name(hw->wiphy), | 812 | wiphy_name(hw->wiphy), |
593 | print_mac(mac, hw->wiphy->perm_addr)); | 813 | hw->wiphy->perm_addr); |
814 | |||
815 | data->debugfs = debugfs_create_dir("hwsim", | ||
816 | hw->wiphy->debugfsdir); | ||
817 | data->debugfs_ps = debugfs_create_file("ps", 0666, | ||
818 | data->debugfs, data, | ||
819 | &hwsim_fops_ps); | ||
594 | 820 | ||
595 | setup_timer(&data->beacon_timer, mac80211_hwsim_beacon, | 821 | setup_timer(&data->beacon_timer, mac80211_hwsim_beacon, |
596 | (unsigned long) hw); | 822 | (unsigned long) hw); |