diff options
Diffstat (limited to 'drivers/net/wireless/mac80211_hwsim.c')
-rw-r--r-- | drivers/net/wireless/mac80211_hwsim.c | 294 |
1 files changed, 261 insertions, 33 deletions
diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 1a019e98dac3..f83d69e813d3 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 | } |
@@ -331,7 +368,8 @@ static void mac80211_hwsim_beacon_tx(void *arg, u8 *mac, | |||
331 | 368 | ||
332 | hwsim_check_magic(vif); | 369 | hwsim_check_magic(vif); |
333 | 370 | ||
334 | if (vif->type != NL80211_IFTYPE_AP) | 371 | if (vif->type != NL80211_IFTYPE_AP && |
372 | vif->type != NL80211_IFTYPE_MESH_POINT) | ||
335 | return; | 373 | return; |
336 | 374 | ||
337 | skb = ieee80211_beacon_get(hw, vif); | 375 | skb = ieee80211_beacon_get(hw, vif); |
@@ -361,10 +399,10 @@ static void mac80211_hwsim_beacon(unsigned long arg) | |||
361 | } | 399 | } |
362 | 400 | ||
363 | 401 | ||
364 | static int mac80211_hwsim_config(struct ieee80211_hw *hw, | 402 | static int mac80211_hwsim_config(struct ieee80211_hw *hw, u32 changed) |
365 | struct ieee80211_conf *conf) | ||
366 | { | 403 | { |
367 | struct mac80211_hwsim_data *data = hw->priv; | 404 | struct mac80211_hwsim_data *data = hw->priv; |
405 | struct ieee80211_conf *conf = &hw->conf; | ||
368 | 406 | ||
369 | printk(KERN_DEBUG "%s:%s (freq=%d radio_enabled=%d beacon_int=%d)\n", | 407 | printk(KERN_DEBUG "%s:%s (freq=%d radio_enabled=%d beacon_int=%d)\n", |
370 | wiphy_name(hw->wiphy), __func__, | 408 | wiphy_name(hw->wiphy), __func__, |
@@ -409,7 +447,16 @@ static int mac80211_hwsim_config_interface(struct ieee80211_hw *hw, | |||
409 | struct ieee80211_vif *vif, | 447 | struct ieee80211_vif *vif, |
410 | struct ieee80211_if_conf *conf) | 448 | struct ieee80211_if_conf *conf) |
411 | { | 449 | { |
450 | struct hwsim_vif_priv *vp = (void *)vif->drv_priv; | ||
451 | |||
412 | hwsim_check_magic(vif); | 452 | hwsim_check_magic(vif); |
453 | if (conf->changed & IEEE80211_IFCC_BSSID) { | ||
454 | DECLARE_MAC_BUF(mac); | ||
455 | printk(KERN_DEBUG "%s:%s: BSSID changed: %pM\n", | ||
456 | wiphy_name(hw->wiphy), __func__, | ||
457 | conf->bssid); | ||
458 | memcpy(vp->bssid, conf->bssid, ETH_ALEN); | ||
459 | } | ||
413 | return 0; | 460 | return 0; |
414 | } | 461 | } |
415 | 462 | ||
@@ -418,7 +465,46 @@ static void mac80211_hwsim_bss_info_changed(struct ieee80211_hw *hw, | |||
418 | struct ieee80211_bss_conf *info, | 465 | struct ieee80211_bss_conf *info, |
419 | u32 changed) | 466 | u32 changed) |
420 | { | 467 | { |
468 | struct hwsim_vif_priv *vp = (void *)vif->drv_priv; | ||
469 | |||
421 | hwsim_check_magic(vif); | 470 | hwsim_check_magic(vif); |
471 | |||
472 | printk(KERN_DEBUG "%s:%s(changed=0x%x)\n", | ||
473 | wiphy_name(hw->wiphy), __func__, changed); | ||
474 | |||
475 | if (changed & BSS_CHANGED_ASSOC) { | ||
476 | printk(KERN_DEBUG " %s: ASSOC: assoc=%d aid=%d\n", | ||
477 | wiphy_name(hw->wiphy), info->assoc, info->aid); | ||
478 | vp->assoc = info->assoc; | ||
479 | vp->aid = info->aid; | ||
480 | } | ||
481 | |||
482 | if (changed & BSS_CHANGED_ERP_CTS_PROT) { | ||
483 | printk(KERN_DEBUG " %s: ERP_CTS_PROT: %d\n", | ||
484 | wiphy_name(hw->wiphy), info->use_cts_prot); | ||
485 | } | ||
486 | |||
487 | if (changed & BSS_CHANGED_ERP_PREAMBLE) { | ||
488 | printk(KERN_DEBUG " %s: ERP_PREAMBLE: %d\n", | ||
489 | wiphy_name(hw->wiphy), info->use_short_preamble); | ||
490 | } | ||
491 | |||
492 | if (changed & BSS_CHANGED_ERP_SLOT) { | ||
493 | printk(KERN_DEBUG " %s: ERP_SLOT: %d\n", | ||
494 | wiphy_name(hw->wiphy), info->use_short_slot); | ||
495 | } | ||
496 | |||
497 | if (changed & BSS_CHANGED_HT) { | ||
498 | printk(KERN_DEBUG " %s: HT: op_mode=0x%x\n", | ||
499 | wiphy_name(hw->wiphy), | ||
500 | info->ht.operation_mode); | ||
501 | } | ||
502 | |||
503 | if (changed & BSS_CHANGED_BASIC_RATES) { | ||
504 | printk(KERN_DEBUG " %s: BASIC_RATES: 0x%llx\n", | ||
505 | wiphy_name(hw->wiphy), | ||
506 | (unsigned long long) info->basic_rates); | ||
507 | } | ||
422 | } | 508 | } |
423 | 509 | ||
424 | static void mac80211_hwsim_sta_notify(struct ieee80211_hw *hw, | 510 | static void mac80211_hwsim_sta_notify(struct ieee80211_hw *hw, |
@@ -434,6 +520,10 @@ static void mac80211_hwsim_sta_notify(struct ieee80211_hw *hw, | |||
434 | case STA_NOTIFY_REMOVE: | 520 | case STA_NOTIFY_REMOVE: |
435 | hwsim_clear_sta_magic(sta); | 521 | hwsim_clear_sta_magic(sta); |
436 | break; | 522 | break; |
523 | case STA_NOTIFY_SLEEP: | ||
524 | case STA_NOTIFY_AWAKE: | ||
525 | /* TODO: make good use of these flags */ | ||
526 | break; | ||
437 | } | 527 | } |
438 | } | 528 | } |
439 | 529 | ||
@@ -445,6 +535,17 @@ static int mac80211_hwsim_set_tim(struct ieee80211_hw *hw, | |||
445 | return 0; | 535 | return 0; |
446 | } | 536 | } |
447 | 537 | ||
538 | static int mac80211_hwsim_conf_tx( | ||
539 | struct ieee80211_hw *hw, u16 queue, | ||
540 | const struct ieee80211_tx_queue_params *params) | ||
541 | { | ||
542 | printk(KERN_DEBUG "%s:%s (queue=%d txop=%d cw_min=%d cw_max=%d " | ||
543 | "aifs=%d)\n", | ||
544 | wiphy_name(hw->wiphy), __func__, queue, | ||
545 | params->txop, params->cw_min, params->cw_max, params->aifs); | ||
546 | return 0; | ||
547 | } | ||
548 | |||
448 | static const struct ieee80211_ops mac80211_hwsim_ops = | 549 | static const struct ieee80211_ops mac80211_hwsim_ops = |
449 | { | 550 | { |
450 | .tx = mac80211_hwsim_tx, | 551 | .tx = mac80211_hwsim_tx, |
@@ -458,6 +559,7 @@ static const struct ieee80211_ops mac80211_hwsim_ops = | |||
458 | .bss_info_changed = mac80211_hwsim_bss_info_changed, | 559 | .bss_info_changed = mac80211_hwsim_bss_info_changed, |
459 | .sta_notify = mac80211_hwsim_sta_notify, | 560 | .sta_notify = mac80211_hwsim_sta_notify, |
460 | .set_tim = mac80211_hwsim_set_tim, | 561 | .set_tim = mac80211_hwsim_set_tim, |
562 | .conf_tx = mac80211_hwsim_conf_tx, | ||
461 | }; | 563 | }; |
462 | 564 | ||
463 | 565 | ||
@@ -474,6 +576,8 @@ static void mac80211_hwsim_free(void) | |||
474 | spin_unlock_bh(&hwsim_radio_lock); | 576 | spin_unlock_bh(&hwsim_radio_lock); |
475 | 577 | ||
476 | list_for_each_entry(data, &tmplist, list) { | 578 | list_for_each_entry(data, &tmplist, list) { |
579 | debugfs_remove(data->debugfs_ps); | ||
580 | debugfs_remove(data->debugfs); | ||
477 | ieee80211_unregister_hw(data->hw); | 581 | ieee80211_unregister_hw(data->hw); |
478 | device_unregister(data->dev); | 582 | device_unregister(data->dev); |
479 | ieee80211_free_hw(data->hw); | 583 | ieee80211_free_hw(data->hw); |
@@ -499,13 +603,131 @@ static void hwsim_mon_setup(struct net_device *dev) | |||
499 | } | 603 | } |
500 | 604 | ||
501 | 605 | ||
606 | static void hwsim_send_ps_poll(void *dat, u8 *mac, struct ieee80211_vif *vif) | ||
607 | { | ||
608 | struct mac80211_hwsim_data *data = dat; | ||
609 | struct hwsim_vif_priv *vp = (void *)vif->drv_priv; | ||
610 | DECLARE_MAC_BUF(buf); | ||
611 | struct sk_buff *skb; | ||
612 | struct ieee80211_pspoll *pspoll; | ||
613 | |||
614 | if (!vp->assoc) | ||
615 | return; | ||
616 | |||
617 | printk(KERN_DEBUG "%s:%s: send PS-Poll to %pM for aid %d\n", | ||
618 | wiphy_name(data->hw->wiphy), __func__, vp->bssid, vp->aid); | ||
619 | |||
620 | skb = dev_alloc_skb(sizeof(*pspoll)); | ||
621 | if (!skb) | ||
622 | return; | ||
623 | pspoll = (void *) skb_put(skb, sizeof(*pspoll)); | ||
624 | pspoll->frame_control = cpu_to_le16(IEEE80211_FTYPE_CTL | | ||
625 | IEEE80211_STYPE_PSPOLL | | ||
626 | IEEE80211_FCTL_PM); | ||
627 | pspoll->aid = cpu_to_le16(0xc000 | vp->aid); | ||
628 | memcpy(pspoll->bssid, vp->bssid, ETH_ALEN); | ||
629 | memcpy(pspoll->ta, mac, ETH_ALEN); | ||
630 | if (data->radio_enabled && | ||
631 | !mac80211_hwsim_tx_frame(data->hw, skb)) | ||
632 | printk(KERN_DEBUG "%s: PS-Poll frame not ack'ed\n", __func__); | ||
633 | dev_kfree_skb(skb); | ||
634 | } | ||
635 | |||
636 | |||
637 | static void hwsim_send_nullfunc(struct mac80211_hwsim_data *data, u8 *mac, | ||
638 | struct ieee80211_vif *vif, int ps) | ||
639 | { | ||
640 | struct hwsim_vif_priv *vp = (void *)vif->drv_priv; | ||
641 | DECLARE_MAC_BUF(buf); | ||
642 | struct sk_buff *skb; | ||
643 | struct ieee80211_hdr *hdr; | ||
644 | |||
645 | if (!vp->assoc) | ||
646 | return; | ||
647 | |||
648 | printk(KERN_DEBUG "%s:%s: send data::nullfunc to %pM ps=%d\n", | ||
649 | wiphy_name(data->hw->wiphy), __func__, vp->bssid, ps); | ||
650 | |||
651 | skb = dev_alloc_skb(sizeof(*hdr)); | ||
652 | if (!skb) | ||
653 | return; | ||
654 | hdr = (void *) skb_put(skb, sizeof(*hdr) - ETH_ALEN); | ||
655 | hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA | | ||
656 | IEEE80211_STYPE_NULLFUNC | | ||
657 | (ps ? IEEE80211_FCTL_PM : 0)); | ||
658 | hdr->duration_id = cpu_to_le16(0); | ||
659 | memcpy(hdr->addr1, vp->bssid, ETH_ALEN); | ||
660 | memcpy(hdr->addr2, mac, ETH_ALEN); | ||
661 | memcpy(hdr->addr3, vp->bssid, ETH_ALEN); | ||
662 | if (data->radio_enabled && | ||
663 | !mac80211_hwsim_tx_frame(data->hw, skb)) | ||
664 | printk(KERN_DEBUG "%s: nullfunc frame not ack'ed\n", __func__); | ||
665 | dev_kfree_skb(skb); | ||
666 | } | ||
667 | |||
668 | |||
669 | static void hwsim_send_nullfunc_ps(void *dat, u8 *mac, | ||
670 | struct ieee80211_vif *vif) | ||
671 | { | ||
672 | struct mac80211_hwsim_data *data = dat; | ||
673 | hwsim_send_nullfunc(data, mac, vif, 1); | ||
674 | } | ||
675 | |||
676 | |||
677 | static void hwsim_send_nullfunc_no_ps(void *dat, u8 *mac, | ||
678 | struct ieee80211_vif *vif) | ||
679 | { | ||
680 | struct mac80211_hwsim_data *data = dat; | ||
681 | hwsim_send_nullfunc(data, mac, vif, 0); | ||
682 | } | ||
683 | |||
684 | |||
685 | static int hwsim_fops_ps_read(void *dat, u64 *val) | ||
686 | { | ||
687 | struct mac80211_hwsim_data *data = dat; | ||
688 | *val = data->ps; | ||
689 | return 0; | ||
690 | } | ||
691 | |||
692 | static int hwsim_fops_ps_write(void *dat, u64 val) | ||
693 | { | ||
694 | struct mac80211_hwsim_data *data = dat; | ||
695 | enum ps_mode old_ps; | ||
696 | |||
697 | if (val != PS_DISABLED && val != PS_ENABLED && val != PS_AUTO_POLL && | ||
698 | val != PS_MANUAL_POLL) | ||
699 | return -EINVAL; | ||
700 | |||
701 | old_ps = data->ps; | ||
702 | data->ps = val; | ||
703 | |||
704 | if (val == PS_MANUAL_POLL) { | ||
705 | ieee80211_iterate_active_interfaces(data->hw, | ||
706 | hwsim_send_ps_poll, data); | ||
707 | data->ps_poll_pending = true; | ||
708 | } else if (old_ps == PS_DISABLED && val != PS_DISABLED) { | ||
709 | ieee80211_iterate_active_interfaces(data->hw, | ||
710 | hwsim_send_nullfunc_ps, | ||
711 | data); | ||
712 | } else if (old_ps != PS_DISABLED && val == PS_DISABLED) { | ||
713 | ieee80211_iterate_active_interfaces(data->hw, | ||
714 | hwsim_send_nullfunc_no_ps, | ||
715 | data); | ||
716 | } | ||
717 | |||
718 | return 0; | ||
719 | } | ||
720 | |||
721 | DEFINE_SIMPLE_ATTRIBUTE(hwsim_fops_ps, hwsim_fops_ps_read, hwsim_fops_ps_write, | ||
722 | "%llu\n"); | ||
723 | |||
724 | |||
502 | static int __init init_mac80211_hwsim(void) | 725 | static int __init init_mac80211_hwsim(void) |
503 | { | 726 | { |
504 | int i, err = 0; | 727 | int i, err = 0; |
505 | u8 addr[ETH_ALEN]; | 728 | u8 addr[ETH_ALEN]; |
506 | struct mac80211_hwsim_data *data; | 729 | struct mac80211_hwsim_data *data; |
507 | struct ieee80211_hw *hw; | 730 | struct ieee80211_hw *hw; |
508 | DECLARE_MAC_BUF(mac); | ||
509 | 731 | ||
510 | if (radios < 1 || radios > 100) | 732 | if (radios < 1 || radios > 100) |
511 | return -EINVAL; | 733 | return -EINVAL; |
@@ -553,7 +775,8 @@ static int __init init_mac80211_hwsim(void) | |||
553 | hw->queues = 4; | 775 | hw->queues = 4; |
554 | hw->wiphy->interface_modes = | 776 | hw->wiphy->interface_modes = |
555 | BIT(NL80211_IFTYPE_STATION) | | 777 | BIT(NL80211_IFTYPE_STATION) | |
556 | BIT(NL80211_IFTYPE_AP); | 778 | BIT(NL80211_IFTYPE_AP) | |
779 | BIT(NL80211_IFTYPE_MESH_POINT); | ||
557 | hw->ampdu_queues = 1; | 780 | hw->ampdu_queues = 1; |
558 | 781 | ||
559 | /* ask mac80211 to reserve space for magic */ | 782 | /* ask mac80211 to reserve space for magic */ |
@@ -566,19 +789,18 @@ static int __init init_mac80211_hwsim(void) | |||
566 | data->band.n_channels = ARRAY_SIZE(hwsim_channels); | 789 | data->band.n_channels = ARRAY_SIZE(hwsim_channels); |
567 | data->band.bitrates = data->rates; | 790 | data->band.bitrates = data->rates; |
568 | data->band.n_bitrates = ARRAY_SIZE(hwsim_rates); | 791 | data->band.n_bitrates = ARRAY_SIZE(hwsim_rates); |
569 | data->band.ht_info.ht_supported = 1; | 792 | data->band.ht_cap.ht_supported = true; |
570 | data->band.ht_info.cap = IEEE80211_HT_CAP_SUP_WIDTH | | 793 | data->band.ht_cap.cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 | |
571 | IEEE80211_HT_CAP_GRN_FLD | | 794 | IEEE80211_HT_CAP_GRN_FLD | |
572 | IEEE80211_HT_CAP_SGI_40 | | 795 | IEEE80211_HT_CAP_SGI_40 | |
573 | IEEE80211_HT_CAP_DSSSCCK40; | 796 | IEEE80211_HT_CAP_DSSSCCK40; |
574 | data->band.ht_info.ampdu_factor = 0x3; | 797 | data->band.ht_cap.ampdu_factor = 0x3; |
575 | data->band.ht_info.ampdu_density = 0x6; | 798 | data->band.ht_cap.ampdu_density = 0x6; |
576 | memset(data->band.ht_info.supp_mcs_set, 0, | 799 | memset(&data->band.ht_cap.mcs, 0, |
577 | sizeof(data->band.ht_info.supp_mcs_set)); | 800 | sizeof(data->band.ht_cap.mcs)); |
578 | data->band.ht_info.supp_mcs_set[0] = 0xff; | 801 | data->band.ht_cap.mcs.rx_mask[0] = 0xff; |
579 | data->band.ht_info.supp_mcs_set[1] = 0xff; | 802 | data->band.ht_cap.mcs.rx_mask[1] = 0xff; |
580 | data->band.ht_info.supp_mcs_set[12] = | 803 | 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; | 804 | hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &data->band; |
583 | 805 | ||
584 | err = ieee80211_register_hw(hw); | 806 | err = ieee80211_register_hw(hw); |
@@ -588,9 +810,15 @@ static int __init init_mac80211_hwsim(void) | |||
588 | goto failed_hw; | 810 | goto failed_hw; |
589 | } | 811 | } |
590 | 812 | ||
591 | printk(KERN_DEBUG "%s: hwaddr %s registered\n", | 813 | printk(KERN_DEBUG "%s: hwaddr %pM registered\n", |
592 | wiphy_name(hw->wiphy), | 814 | wiphy_name(hw->wiphy), |
593 | print_mac(mac, hw->wiphy->perm_addr)); | 815 | hw->wiphy->perm_addr); |
816 | |||
817 | data->debugfs = debugfs_create_dir("hwsim", | ||
818 | hw->wiphy->debugfsdir); | ||
819 | data->debugfs_ps = debugfs_create_file("ps", 0666, | ||
820 | data->debugfs, data, | ||
821 | &hwsim_fops_ps); | ||
594 | 822 | ||
595 | setup_timer(&data->beacon_timer, mac80211_hwsim_beacon, | 823 | setup_timer(&data->beacon_timer, mac80211_hwsim_beacon, |
596 | (unsigned long) hw); | 824 | (unsigned long) hw); |