diff options
-rw-r--r-- | drivers/net/wireless/mac80211_hwsim.c | 826 |
1 files changed, 413 insertions, 413 deletions
diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index ca156a5ed305..1c51c33c385f 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c | |||
@@ -215,10 +215,53 @@ static const struct ieee80211_rate hwsim_rates[] = { | |||
215 | { .bitrate = 540 } | 215 | { .bitrate = 540 } |
216 | }; | 216 | }; |
217 | 217 | ||
218 | static const struct ieee80211_iface_limit hwsim_if_limits[] = { | ||
219 | { .max = 1, .types = BIT(NL80211_IFTYPE_ADHOC) }, | ||
220 | { .max = 2048, .types = BIT(NL80211_IFTYPE_STATION) | | ||
221 | BIT(NL80211_IFTYPE_P2P_CLIENT) | | ||
222 | #ifdef CONFIG_MAC80211_MESH | ||
223 | BIT(NL80211_IFTYPE_MESH_POINT) | | ||
224 | #endif | ||
225 | BIT(NL80211_IFTYPE_AP) | | ||
226 | BIT(NL80211_IFTYPE_P2P_GO) }, | ||
227 | { .max = 1, .types = BIT(NL80211_IFTYPE_P2P_DEVICE) }, | ||
228 | }; | ||
229 | |||
230 | static const struct ieee80211_iface_limit hwsim_if_dfs_limits[] = { | ||
231 | { .max = 8, .types = BIT(NL80211_IFTYPE_AP) }, | ||
232 | }; | ||
233 | |||
234 | static const struct ieee80211_iface_combination hwsim_if_comb[] = { | ||
235 | { | ||
236 | .limits = hwsim_if_limits, | ||
237 | .n_limits = ARRAY_SIZE(hwsim_if_limits), | ||
238 | .max_interfaces = 2048, | ||
239 | .num_different_channels = 1, | ||
240 | }, | ||
241 | { | ||
242 | .limits = hwsim_if_dfs_limits, | ||
243 | .n_limits = ARRAY_SIZE(hwsim_if_dfs_limits), | ||
244 | .max_interfaces = 8, | ||
245 | .num_different_channels = 1, | ||
246 | .radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) | | ||
247 | BIT(NL80211_CHAN_WIDTH_20) | | ||
248 | BIT(NL80211_CHAN_WIDTH_40) | | ||
249 | BIT(NL80211_CHAN_WIDTH_80) | | ||
250 | BIT(NL80211_CHAN_WIDTH_160), | ||
251 | } | ||
252 | }; | ||
253 | |||
218 | static spinlock_t hwsim_radio_lock; | 254 | static spinlock_t hwsim_radio_lock; |
219 | static struct list_head hwsim_radios; | 255 | static struct list_head hwsim_radios; |
220 | static int hwsim_radio_idx; | 256 | static int hwsim_radio_idx; |
221 | 257 | ||
258 | static struct platform_driver mac80211_hwsim_driver = { | ||
259 | .driver = { | ||
260 | .name = "mac80211_hwsim", | ||
261 | .owner = THIS_MODULE, | ||
262 | }, | ||
263 | }; | ||
264 | |||
222 | struct mac80211_hwsim_data { | 265 | struct mac80211_hwsim_data { |
223 | struct list_head list; | 266 | struct list_head list; |
224 | struct ieee80211_hw *hw; | 267 | struct ieee80211_hw *hw; |
@@ -311,6 +354,161 @@ static struct nla_policy hwsim_genl_policy[HWSIM_ATTR_MAX + 1] = { | |||
311 | [HWSIM_ATTR_COOKIE] = { .type = NLA_U64 }, | 354 | [HWSIM_ATTR_COOKIE] = { .type = NLA_U64 }, |
312 | }; | 355 | }; |
313 | 356 | ||
357 | static void mac80211_hwsim_tx_frame(struct ieee80211_hw *hw, | ||
358 | struct sk_buff *skb, | ||
359 | struct ieee80211_channel *chan); | ||
360 | |||
361 | /* sysfs attributes */ | ||
362 | static void hwsim_send_ps_poll(void *dat, u8 *mac, struct ieee80211_vif *vif) | ||
363 | { | ||
364 | struct mac80211_hwsim_data *data = dat; | ||
365 | struct hwsim_vif_priv *vp = (void *)vif->drv_priv; | ||
366 | struct sk_buff *skb; | ||
367 | struct ieee80211_pspoll *pspoll; | ||
368 | |||
369 | if (!vp->assoc) | ||
370 | return; | ||
371 | |||
372 | wiphy_debug(data->hw->wiphy, | ||
373 | "%s: send PS-Poll to %pM for aid %d\n", | ||
374 | __func__, vp->bssid, vp->aid); | ||
375 | |||
376 | skb = dev_alloc_skb(sizeof(*pspoll)); | ||
377 | if (!skb) | ||
378 | return; | ||
379 | pspoll = (void *) skb_put(skb, sizeof(*pspoll)); | ||
380 | pspoll->frame_control = cpu_to_le16(IEEE80211_FTYPE_CTL | | ||
381 | IEEE80211_STYPE_PSPOLL | | ||
382 | IEEE80211_FCTL_PM); | ||
383 | pspoll->aid = cpu_to_le16(0xc000 | vp->aid); | ||
384 | memcpy(pspoll->bssid, vp->bssid, ETH_ALEN); | ||
385 | memcpy(pspoll->ta, mac, ETH_ALEN); | ||
386 | |||
387 | rcu_read_lock(); | ||
388 | mac80211_hwsim_tx_frame(data->hw, skb, | ||
389 | rcu_dereference(vif->chanctx_conf)->def.chan); | ||
390 | rcu_read_unlock(); | ||
391 | } | ||
392 | |||
393 | static void hwsim_send_nullfunc(struct mac80211_hwsim_data *data, u8 *mac, | ||
394 | struct ieee80211_vif *vif, int ps) | ||
395 | { | ||
396 | struct hwsim_vif_priv *vp = (void *)vif->drv_priv; | ||
397 | struct sk_buff *skb; | ||
398 | struct ieee80211_hdr *hdr; | ||
399 | |||
400 | if (!vp->assoc) | ||
401 | return; | ||
402 | |||
403 | wiphy_debug(data->hw->wiphy, | ||
404 | "%s: send data::nullfunc to %pM ps=%d\n", | ||
405 | __func__, vp->bssid, ps); | ||
406 | |||
407 | skb = dev_alloc_skb(sizeof(*hdr)); | ||
408 | if (!skb) | ||
409 | return; | ||
410 | hdr = (void *) skb_put(skb, sizeof(*hdr) - ETH_ALEN); | ||
411 | hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA | | ||
412 | IEEE80211_STYPE_NULLFUNC | | ||
413 | (ps ? IEEE80211_FCTL_PM : 0)); | ||
414 | hdr->duration_id = cpu_to_le16(0); | ||
415 | memcpy(hdr->addr1, vp->bssid, ETH_ALEN); | ||
416 | memcpy(hdr->addr2, mac, ETH_ALEN); | ||
417 | memcpy(hdr->addr3, vp->bssid, ETH_ALEN); | ||
418 | |||
419 | rcu_read_lock(); | ||
420 | mac80211_hwsim_tx_frame(data->hw, skb, | ||
421 | rcu_dereference(vif->chanctx_conf)->def.chan); | ||
422 | rcu_read_unlock(); | ||
423 | } | ||
424 | |||
425 | |||
426 | static void hwsim_send_nullfunc_ps(void *dat, u8 *mac, | ||
427 | struct ieee80211_vif *vif) | ||
428 | { | ||
429 | struct mac80211_hwsim_data *data = dat; | ||
430 | hwsim_send_nullfunc(data, mac, vif, 1); | ||
431 | } | ||
432 | |||
433 | static void hwsim_send_nullfunc_no_ps(void *dat, u8 *mac, | ||
434 | struct ieee80211_vif *vif) | ||
435 | { | ||
436 | struct mac80211_hwsim_data *data = dat; | ||
437 | hwsim_send_nullfunc(data, mac, vif, 0); | ||
438 | } | ||
439 | |||
440 | static int hwsim_fops_ps_read(void *dat, u64 *val) | ||
441 | { | ||
442 | struct mac80211_hwsim_data *data = dat; | ||
443 | *val = data->ps; | ||
444 | return 0; | ||
445 | } | ||
446 | |||
447 | static int hwsim_fops_ps_write(void *dat, u64 val) | ||
448 | { | ||
449 | struct mac80211_hwsim_data *data = dat; | ||
450 | enum ps_mode old_ps; | ||
451 | |||
452 | if (val != PS_DISABLED && val != PS_ENABLED && val != PS_AUTO_POLL && | ||
453 | val != PS_MANUAL_POLL) | ||
454 | return -EINVAL; | ||
455 | |||
456 | old_ps = data->ps; | ||
457 | data->ps = val; | ||
458 | |||
459 | if (val == PS_MANUAL_POLL) { | ||
460 | ieee80211_iterate_active_interfaces(data->hw, | ||
461 | IEEE80211_IFACE_ITER_NORMAL, | ||
462 | hwsim_send_ps_poll, data); | ||
463 | data->ps_poll_pending = true; | ||
464 | } else if (old_ps == PS_DISABLED && val != PS_DISABLED) { | ||
465 | ieee80211_iterate_active_interfaces(data->hw, | ||
466 | IEEE80211_IFACE_ITER_NORMAL, | ||
467 | hwsim_send_nullfunc_ps, | ||
468 | data); | ||
469 | } else if (old_ps != PS_DISABLED && val == PS_DISABLED) { | ||
470 | ieee80211_iterate_active_interfaces(data->hw, | ||
471 | IEEE80211_IFACE_ITER_NORMAL, | ||
472 | hwsim_send_nullfunc_no_ps, | ||
473 | data); | ||
474 | } | ||
475 | |||
476 | return 0; | ||
477 | } | ||
478 | |||
479 | DEFINE_SIMPLE_ATTRIBUTE(hwsim_fops_ps, hwsim_fops_ps_read, hwsim_fops_ps_write, | ||
480 | "%llu\n"); | ||
481 | |||
482 | static int hwsim_write_simulate_radar(void *dat, u64 val) | ||
483 | { | ||
484 | struct mac80211_hwsim_data *data = dat; | ||
485 | |||
486 | ieee80211_radar_detected(data->hw); | ||
487 | |||
488 | return 0; | ||
489 | } | ||
490 | |||
491 | DEFINE_SIMPLE_ATTRIBUTE(hwsim_simulate_radar, NULL, | ||
492 | hwsim_write_simulate_radar, "%llu\n"); | ||
493 | |||
494 | static int hwsim_fops_group_read(void *dat, u64 *val) | ||
495 | { | ||
496 | struct mac80211_hwsim_data *data = dat; | ||
497 | *val = data->group; | ||
498 | return 0; | ||
499 | } | ||
500 | |||
501 | static int hwsim_fops_group_write(void *dat, u64 val) | ||
502 | { | ||
503 | struct mac80211_hwsim_data *data = dat; | ||
504 | data->group = val; | ||
505 | return 0; | ||
506 | } | ||
507 | |||
508 | DEFINE_SIMPLE_ATTRIBUTE(hwsim_fops_group, | ||
509 | hwsim_fops_group_read, hwsim_fops_group_write, | ||
510 | "%llx\n"); | ||
511 | |||
314 | static netdev_tx_t hwsim_mon_xmit(struct sk_buff *skb, | 512 | static netdev_tx_t hwsim_mon_xmit(struct sk_buff *skb, |
315 | struct net_device *dev) | 513 | struct net_device *dev) |
316 | { | 514 | { |
@@ -1283,8 +1481,6 @@ static const struct nla_policy hwsim_testmode_policy[HWSIM_TM_ATTR_MAX + 1] = { | |||
1283 | [HWSIM_TM_ATTR_PS] = { .type = NLA_U32 }, | 1481 | [HWSIM_TM_ATTR_PS] = { .type = NLA_U32 }, |
1284 | }; | 1482 | }; |
1285 | 1483 | ||
1286 | static int hwsim_fops_ps_write(void *dat, u64 val); | ||
1287 | |||
1288 | static int mac80211_hwsim_testmode_cmd(struct ieee80211_hw *hw, | 1484 | static int mac80211_hwsim_testmode_cmd(struct ieee80211_hw *hw, |
1289 | struct ieee80211_vif *vif, | 1485 | struct ieee80211_vif *vif, |
1290 | void *data, int len) | 1486 | void *data, int len) |
@@ -1622,6 +1818,221 @@ static const struct ieee80211_ops mac80211_hwsim_ops = { | |||
1622 | 1818 | ||
1623 | static struct ieee80211_ops mac80211_hwsim_mchan_ops; | 1819 | static struct ieee80211_ops mac80211_hwsim_mchan_ops; |
1624 | 1820 | ||
1821 | static int __init mac80211_hwsim_create_radio(void) | ||
1822 | { | ||
1823 | int err; | ||
1824 | u8 addr[ETH_ALEN]; | ||
1825 | struct mac80211_hwsim_data *data; | ||
1826 | struct ieee80211_hw *hw; | ||
1827 | enum ieee80211_band band; | ||
1828 | const struct ieee80211_ops *ops = &mac80211_hwsim_ops; | ||
1829 | int idx; | ||
1830 | |||
1831 | spin_lock_bh(&hwsim_radio_lock); | ||
1832 | idx = hwsim_radio_idx++; | ||
1833 | spin_unlock_bh(&hwsim_radio_lock); | ||
1834 | |||
1835 | if (channels > 1) | ||
1836 | ops = &mac80211_hwsim_mchan_ops; | ||
1837 | hw = ieee80211_alloc_hw(sizeof(*data), ops); | ||
1838 | if (!hw) { | ||
1839 | printk(KERN_DEBUG "mac80211_hwsim: ieee80211_alloc_hw failed\n"); | ||
1840 | err = -ENOMEM; | ||
1841 | goto failed; | ||
1842 | } | ||
1843 | data = hw->priv; | ||
1844 | data->hw = hw; | ||
1845 | |||
1846 | data->dev = device_create(hwsim_class, NULL, 0, hw, "hwsim%d", idx); | ||
1847 | if (IS_ERR(data->dev)) { | ||
1848 | printk(KERN_DEBUG | ||
1849 | "mac80211_hwsim: device_create failed (%ld)\n", | ||
1850 | PTR_ERR(data->dev)); | ||
1851 | err = -ENOMEM; | ||
1852 | goto failed_drvdata; | ||
1853 | } | ||
1854 | data->dev->driver = &mac80211_hwsim_driver.driver; | ||
1855 | err = device_bind_driver(data->dev); | ||
1856 | if (err != 0) { | ||
1857 | printk(KERN_DEBUG "mac80211_hwsim: device_bind_driver failed (%d)\n", | ||
1858 | err); | ||
1859 | goto failed_hw; | ||
1860 | } | ||
1861 | |||
1862 | skb_queue_head_init(&data->pending); | ||
1863 | |||
1864 | SET_IEEE80211_DEV(hw, data->dev); | ||
1865 | memset(addr, 0, ETH_ALEN); | ||
1866 | addr[0] = 0x02; | ||
1867 | addr[3] = idx >> 8; | ||
1868 | addr[4] = idx; | ||
1869 | memcpy(data->addresses[0].addr, addr, ETH_ALEN); | ||
1870 | memcpy(data->addresses[1].addr, addr, ETH_ALEN); | ||
1871 | data->addresses[1].addr[0] |= 0x40; | ||
1872 | hw->wiphy->n_addresses = 2; | ||
1873 | hw->wiphy->addresses = data->addresses; | ||
1874 | |||
1875 | data->channels = channels; | ||
1876 | |||
1877 | if (data->channels > 1) { | ||
1878 | hw->wiphy->max_scan_ssids = 255; | ||
1879 | hw->wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN; | ||
1880 | hw->wiphy->max_remain_on_channel_duration = 1000; | ||
1881 | /* For channels > 1 DFS is not allowed */ | ||
1882 | hw->wiphy->n_iface_combinations = 1; | ||
1883 | hw->wiphy->iface_combinations = &data->if_combination; | ||
1884 | data->if_combination = hwsim_if_comb[0]; | ||
1885 | data->if_combination.num_different_channels = data->channels; | ||
1886 | } else { | ||
1887 | hw->wiphy->iface_combinations = hwsim_if_comb; | ||
1888 | hw->wiphy->n_iface_combinations = ARRAY_SIZE(hwsim_if_comb); | ||
1889 | } | ||
1890 | |||
1891 | INIT_DELAYED_WORK(&data->roc_done, hw_roc_done); | ||
1892 | INIT_DELAYED_WORK(&data->hw_scan, hw_scan_work); | ||
1893 | |||
1894 | hw->queues = 5; | ||
1895 | hw->offchannel_tx_hw_queue = 4; | ||
1896 | hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | | ||
1897 | BIT(NL80211_IFTYPE_AP) | | ||
1898 | BIT(NL80211_IFTYPE_P2P_CLIENT) | | ||
1899 | BIT(NL80211_IFTYPE_P2P_GO) | | ||
1900 | BIT(NL80211_IFTYPE_ADHOC) | | ||
1901 | BIT(NL80211_IFTYPE_MESH_POINT) | | ||
1902 | BIT(NL80211_IFTYPE_P2P_DEVICE); | ||
1903 | |||
1904 | hw->flags = IEEE80211_HW_MFP_CAPABLE | | ||
1905 | IEEE80211_HW_SIGNAL_DBM | | ||
1906 | IEEE80211_HW_SUPPORTS_STATIC_SMPS | | ||
1907 | IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS | | ||
1908 | IEEE80211_HW_AMPDU_AGGREGATION | | ||
1909 | IEEE80211_HW_WANT_MONITOR_VIF | | ||
1910 | IEEE80211_HW_QUEUE_CONTROL | | ||
1911 | IEEE80211_HW_SUPPORTS_HT_CCK_RATES; | ||
1912 | if (rctbl) | ||
1913 | hw->flags |= IEEE80211_HW_SUPPORTS_RC_TABLE; | ||
1914 | |||
1915 | hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS | | ||
1916 | WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL | | ||
1917 | WIPHY_FLAG_AP_UAPSD; | ||
1918 | hw->wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR; | ||
1919 | |||
1920 | /* ask mac80211 to reserve space for magic */ | ||
1921 | hw->vif_data_size = sizeof(struct hwsim_vif_priv); | ||
1922 | hw->sta_data_size = sizeof(struct hwsim_sta_priv); | ||
1923 | hw->chanctx_data_size = sizeof(struct hwsim_chanctx_priv); | ||
1924 | |||
1925 | memcpy(data->channels_2ghz, hwsim_channels_2ghz, | ||
1926 | sizeof(hwsim_channels_2ghz)); | ||
1927 | memcpy(data->channels_5ghz, hwsim_channels_5ghz, | ||
1928 | sizeof(hwsim_channels_5ghz)); | ||
1929 | memcpy(data->rates, hwsim_rates, sizeof(hwsim_rates)); | ||
1930 | |||
1931 | for (band = IEEE80211_BAND_2GHZ; band < IEEE80211_NUM_BANDS; band++) { | ||
1932 | struct ieee80211_supported_band *sband = &data->bands[band]; | ||
1933 | switch (band) { | ||
1934 | case IEEE80211_BAND_2GHZ: | ||
1935 | sband->channels = data->channels_2ghz; | ||
1936 | sband->n_channels = ARRAY_SIZE(hwsim_channels_2ghz); | ||
1937 | sband->bitrates = data->rates; | ||
1938 | sband->n_bitrates = ARRAY_SIZE(hwsim_rates); | ||
1939 | break; | ||
1940 | case IEEE80211_BAND_5GHZ: | ||
1941 | sband->channels = data->channels_5ghz; | ||
1942 | sband->n_channels = ARRAY_SIZE(hwsim_channels_5ghz); | ||
1943 | sband->bitrates = data->rates + 4; | ||
1944 | sband->n_bitrates = ARRAY_SIZE(hwsim_rates) - 4; | ||
1945 | break; | ||
1946 | default: | ||
1947 | continue; | ||
1948 | } | ||
1949 | |||
1950 | sband->ht_cap.ht_supported = true; | ||
1951 | sband->ht_cap.cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 | | ||
1952 | IEEE80211_HT_CAP_GRN_FLD | | ||
1953 | IEEE80211_HT_CAP_SGI_40 | | ||
1954 | IEEE80211_HT_CAP_DSSSCCK40; | ||
1955 | sband->ht_cap.ampdu_factor = 0x3; | ||
1956 | sband->ht_cap.ampdu_density = 0x6; | ||
1957 | memset(&sband->ht_cap.mcs, 0, | ||
1958 | sizeof(sband->ht_cap.mcs)); | ||
1959 | sband->ht_cap.mcs.rx_mask[0] = 0xff; | ||
1960 | sband->ht_cap.mcs.rx_mask[1] = 0xff; | ||
1961 | sband->ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; | ||
1962 | |||
1963 | hw->wiphy->bands[band] = sband; | ||
1964 | |||
1965 | sband->vht_cap.vht_supported = true; | ||
1966 | sband->vht_cap.cap = | ||
1967 | IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454 | | ||
1968 | IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ | | ||
1969 | IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ | | ||
1970 | IEEE80211_VHT_CAP_RXLDPC | | ||
1971 | IEEE80211_VHT_CAP_SHORT_GI_80 | | ||
1972 | IEEE80211_VHT_CAP_SHORT_GI_160 | | ||
1973 | IEEE80211_VHT_CAP_TXSTBC | | ||
1974 | IEEE80211_VHT_CAP_RXSTBC_1 | | ||
1975 | IEEE80211_VHT_CAP_RXSTBC_2 | | ||
1976 | IEEE80211_VHT_CAP_RXSTBC_3 | | ||
1977 | IEEE80211_VHT_CAP_RXSTBC_4 | | ||
1978 | IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK; | ||
1979 | sband->vht_cap.vht_mcs.rx_mcs_map = | ||
1980 | cpu_to_le16(IEEE80211_VHT_MCS_SUPPORT_0_8 << 0 | | ||
1981 | IEEE80211_VHT_MCS_SUPPORT_0_8 << 2 | | ||
1982 | IEEE80211_VHT_MCS_SUPPORT_0_9 << 4 | | ||
1983 | IEEE80211_VHT_MCS_SUPPORT_0_8 << 6 | | ||
1984 | IEEE80211_VHT_MCS_SUPPORT_0_8 << 8 | | ||
1985 | IEEE80211_VHT_MCS_SUPPORT_0_9 << 10 | | ||
1986 | IEEE80211_VHT_MCS_SUPPORT_0_9 << 12 | | ||
1987 | IEEE80211_VHT_MCS_SUPPORT_0_8 << 14); | ||
1988 | sband->vht_cap.vht_mcs.tx_mcs_map = | ||
1989 | sband->vht_cap.vht_mcs.rx_mcs_map; | ||
1990 | } | ||
1991 | |||
1992 | /* By default all radios belong to the first group */ | ||
1993 | data->group = 1; | ||
1994 | mutex_init(&data->mutex); | ||
1995 | |||
1996 | /* Enable frame retransmissions for lossy channels */ | ||
1997 | hw->max_rates = 4; | ||
1998 | hw->max_rate_tries = 11; | ||
1999 | |||
2000 | err = ieee80211_register_hw(hw); | ||
2001 | if (err < 0) { | ||
2002 | printk(KERN_DEBUG "mac80211_hwsim: ieee80211_register_hw failed (%d)\n", | ||
2003 | err); | ||
2004 | goto failed_hw; | ||
2005 | } | ||
2006 | |||
2007 | wiphy_debug(hw->wiphy, "hwaddr %pM registered\n", hw->wiphy->perm_addr); | ||
2008 | |||
2009 | data->debugfs = debugfs_create_dir("hwsim", hw->wiphy->debugfsdir); | ||
2010 | debugfs_create_file("ps", 0666, data->debugfs, data, &hwsim_fops_ps); | ||
2011 | debugfs_create_file("group", 0666, data->debugfs, data, | ||
2012 | &hwsim_fops_group); | ||
2013 | if (data->channels == 1) | ||
2014 | debugfs_create_file("dfs_simulate_radar", 0222, | ||
2015 | data->debugfs, | ||
2016 | data, &hwsim_simulate_radar); | ||
2017 | |||
2018 | tasklet_hrtimer_init(&data->beacon_timer, | ||
2019 | mac80211_hwsim_beacon, | ||
2020 | CLOCK_MONOTONIC_RAW, HRTIMER_MODE_ABS); | ||
2021 | |||
2022 | spin_lock_bh(&hwsim_radio_lock); | ||
2023 | list_add_tail(&data->list, &hwsim_radios); | ||
2024 | spin_unlock_bh(&hwsim_radio_lock); | ||
2025 | |||
2026 | return 0; | ||
2027 | |||
2028 | failed_hw: | ||
2029 | device_unregister(data->dev); | ||
2030 | failed_drvdata: | ||
2031 | ieee80211_free_hw(hw); | ||
2032 | failed: | ||
2033 | return err; | ||
2034 | } | ||
2035 | |||
1625 | static void mac80211_hwsim_destroy_radio(struct mac80211_hwsim_data *data) | 2036 | static void mac80211_hwsim_destroy_radio(struct mac80211_hwsim_data *data) |
1626 | { | 2037 | { |
1627 | debugfs_remove_recursive(data->debugfs); | 2038 | debugfs_remove_recursive(data->debugfs); |
@@ -1648,13 +2059,6 @@ static void mac80211_hwsim_free(void) | |||
1648 | class_destroy(hwsim_class); | 2059 | class_destroy(hwsim_class); |
1649 | } | 2060 | } |
1650 | 2061 | ||
1651 | static struct platform_driver mac80211_hwsim_driver = { | ||
1652 | .driver = { | ||
1653 | .name = "mac80211_hwsim", | ||
1654 | .owner = THIS_MODULE, | ||
1655 | }, | ||
1656 | }; | ||
1657 | |||
1658 | static const struct net_device_ops hwsim_netdev_ops = { | 2062 | static const struct net_device_ops hwsim_netdev_ops = { |
1659 | .ndo_start_xmit = hwsim_mon_xmit, | 2063 | .ndo_start_xmit = hwsim_mon_xmit, |
1660 | .ndo_change_mtu = eth_change_mtu, | 2064 | .ndo_change_mtu = eth_change_mtu, |
@@ -1673,159 +2077,6 @@ static void hwsim_mon_setup(struct net_device *dev) | |||
1673 | dev->dev_addr[0] = 0x12; | 2077 | dev->dev_addr[0] = 0x12; |
1674 | } | 2078 | } |
1675 | 2079 | ||
1676 | |||
1677 | static void hwsim_send_ps_poll(void *dat, u8 *mac, struct ieee80211_vif *vif) | ||
1678 | { | ||
1679 | struct mac80211_hwsim_data *data = dat; | ||
1680 | struct hwsim_vif_priv *vp = (void *)vif->drv_priv; | ||
1681 | struct sk_buff *skb; | ||
1682 | struct ieee80211_pspoll *pspoll; | ||
1683 | |||
1684 | if (!vp->assoc) | ||
1685 | return; | ||
1686 | |||
1687 | wiphy_debug(data->hw->wiphy, | ||
1688 | "%s: send PS-Poll to %pM for aid %d\n", | ||
1689 | __func__, vp->bssid, vp->aid); | ||
1690 | |||
1691 | skb = dev_alloc_skb(sizeof(*pspoll)); | ||
1692 | if (!skb) | ||
1693 | return; | ||
1694 | pspoll = (void *) skb_put(skb, sizeof(*pspoll)); | ||
1695 | pspoll->frame_control = cpu_to_le16(IEEE80211_FTYPE_CTL | | ||
1696 | IEEE80211_STYPE_PSPOLL | | ||
1697 | IEEE80211_FCTL_PM); | ||
1698 | pspoll->aid = cpu_to_le16(0xc000 | vp->aid); | ||
1699 | memcpy(pspoll->bssid, vp->bssid, ETH_ALEN); | ||
1700 | memcpy(pspoll->ta, mac, ETH_ALEN); | ||
1701 | |||
1702 | rcu_read_lock(); | ||
1703 | mac80211_hwsim_tx_frame(data->hw, skb, | ||
1704 | rcu_dereference(vif->chanctx_conf)->def.chan); | ||
1705 | rcu_read_unlock(); | ||
1706 | } | ||
1707 | |||
1708 | static void hwsim_send_nullfunc(struct mac80211_hwsim_data *data, u8 *mac, | ||
1709 | struct ieee80211_vif *vif, int ps) | ||
1710 | { | ||
1711 | struct hwsim_vif_priv *vp = (void *)vif->drv_priv; | ||
1712 | struct sk_buff *skb; | ||
1713 | struct ieee80211_hdr *hdr; | ||
1714 | |||
1715 | if (!vp->assoc) | ||
1716 | return; | ||
1717 | |||
1718 | wiphy_debug(data->hw->wiphy, | ||
1719 | "%s: send data::nullfunc to %pM ps=%d\n", | ||
1720 | __func__, vp->bssid, ps); | ||
1721 | |||
1722 | skb = dev_alloc_skb(sizeof(*hdr)); | ||
1723 | if (!skb) | ||
1724 | return; | ||
1725 | hdr = (void *) skb_put(skb, sizeof(*hdr) - ETH_ALEN); | ||
1726 | hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA | | ||
1727 | IEEE80211_STYPE_NULLFUNC | | ||
1728 | (ps ? IEEE80211_FCTL_PM : 0)); | ||
1729 | hdr->duration_id = cpu_to_le16(0); | ||
1730 | memcpy(hdr->addr1, vp->bssid, ETH_ALEN); | ||
1731 | memcpy(hdr->addr2, mac, ETH_ALEN); | ||
1732 | memcpy(hdr->addr3, vp->bssid, ETH_ALEN); | ||
1733 | |||
1734 | rcu_read_lock(); | ||
1735 | mac80211_hwsim_tx_frame(data->hw, skb, | ||
1736 | rcu_dereference(vif->chanctx_conf)->def.chan); | ||
1737 | rcu_read_unlock(); | ||
1738 | } | ||
1739 | |||
1740 | |||
1741 | static void hwsim_send_nullfunc_ps(void *dat, u8 *mac, | ||
1742 | struct ieee80211_vif *vif) | ||
1743 | { | ||
1744 | struct mac80211_hwsim_data *data = dat; | ||
1745 | hwsim_send_nullfunc(data, mac, vif, 1); | ||
1746 | } | ||
1747 | |||
1748 | |||
1749 | static void hwsim_send_nullfunc_no_ps(void *dat, u8 *mac, | ||
1750 | struct ieee80211_vif *vif) | ||
1751 | { | ||
1752 | struct mac80211_hwsim_data *data = dat; | ||
1753 | hwsim_send_nullfunc(data, mac, vif, 0); | ||
1754 | } | ||
1755 | |||
1756 | |||
1757 | static int hwsim_fops_ps_read(void *dat, u64 *val) | ||
1758 | { | ||
1759 | struct mac80211_hwsim_data *data = dat; | ||
1760 | *val = data->ps; | ||
1761 | return 0; | ||
1762 | } | ||
1763 | |||
1764 | static int hwsim_fops_ps_write(void *dat, u64 val) | ||
1765 | { | ||
1766 | struct mac80211_hwsim_data *data = dat; | ||
1767 | enum ps_mode old_ps; | ||
1768 | |||
1769 | if (val != PS_DISABLED && val != PS_ENABLED && val != PS_AUTO_POLL && | ||
1770 | val != PS_MANUAL_POLL) | ||
1771 | return -EINVAL; | ||
1772 | |||
1773 | old_ps = data->ps; | ||
1774 | data->ps = val; | ||
1775 | |||
1776 | if (val == PS_MANUAL_POLL) { | ||
1777 | ieee80211_iterate_active_interfaces(data->hw, | ||
1778 | IEEE80211_IFACE_ITER_NORMAL, | ||
1779 | hwsim_send_ps_poll, data); | ||
1780 | data->ps_poll_pending = true; | ||
1781 | } else if (old_ps == PS_DISABLED && val != PS_DISABLED) { | ||
1782 | ieee80211_iterate_active_interfaces(data->hw, | ||
1783 | IEEE80211_IFACE_ITER_NORMAL, | ||
1784 | hwsim_send_nullfunc_ps, | ||
1785 | data); | ||
1786 | } else if (old_ps != PS_DISABLED && val == PS_DISABLED) { | ||
1787 | ieee80211_iterate_active_interfaces(data->hw, | ||
1788 | IEEE80211_IFACE_ITER_NORMAL, | ||
1789 | hwsim_send_nullfunc_no_ps, | ||
1790 | data); | ||
1791 | } | ||
1792 | |||
1793 | return 0; | ||
1794 | } | ||
1795 | |||
1796 | DEFINE_SIMPLE_ATTRIBUTE(hwsim_fops_ps, hwsim_fops_ps_read, hwsim_fops_ps_write, | ||
1797 | "%llu\n"); | ||
1798 | |||
1799 | static int hwsim_write_simulate_radar(void *dat, u64 val) | ||
1800 | { | ||
1801 | struct mac80211_hwsim_data *data = dat; | ||
1802 | |||
1803 | ieee80211_radar_detected(data->hw); | ||
1804 | |||
1805 | return 0; | ||
1806 | } | ||
1807 | |||
1808 | DEFINE_SIMPLE_ATTRIBUTE(hwsim_simulate_radar, NULL, | ||
1809 | hwsim_write_simulate_radar, "%llu\n"); | ||
1810 | |||
1811 | static int hwsim_fops_group_read(void *dat, u64 *val) | ||
1812 | { | ||
1813 | struct mac80211_hwsim_data *data = dat; | ||
1814 | *val = data->group; | ||
1815 | return 0; | ||
1816 | } | ||
1817 | |||
1818 | static int hwsim_fops_group_write(void *dat, u64 val) | ||
1819 | { | ||
1820 | struct mac80211_hwsim_data *data = dat; | ||
1821 | data->group = val; | ||
1822 | return 0; | ||
1823 | } | ||
1824 | |||
1825 | DEFINE_SIMPLE_ATTRIBUTE(hwsim_fops_group, | ||
1826 | hwsim_fops_group_read, hwsim_fops_group_write, | ||
1827 | "%llx\n"); | ||
1828 | |||
1829 | static struct mac80211_hwsim_data *get_hwsim_data_ref_from_addr(const u8 *addr) | 2080 | static struct mac80211_hwsim_data *get_hwsim_data_ref_from_addr(const u8 *addr) |
1830 | { | 2081 | { |
1831 | struct mac80211_hwsim_data *data; | 2082 | struct mac80211_hwsim_data *data; |
@@ -2073,257 +2324,6 @@ static void hwsim_exit_netlink(void) | |||
2073 | genl_unregister_family(&hwsim_genl_family); | 2324 | genl_unregister_family(&hwsim_genl_family); |
2074 | } | 2325 | } |
2075 | 2326 | ||
2076 | static const struct ieee80211_iface_limit hwsim_if_limits[] = { | ||
2077 | { .max = 1, .types = BIT(NL80211_IFTYPE_ADHOC) }, | ||
2078 | { .max = 2048, .types = BIT(NL80211_IFTYPE_STATION) | | ||
2079 | BIT(NL80211_IFTYPE_P2P_CLIENT) | | ||
2080 | #ifdef CONFIG_MAC80211_MESH | ||
2081 | BIT(NL80211_IFTYPE_MESH_POINT) | | ||
2082 | #endif | ||
2083 | BIT(NL80211_IFTYPE_AP) | | ||
2084 | BIT(NL80211_IFTYPE_P2P_GO) }, | ||
2085 | { .max = 1, .types = BIT(NL80211_IFTYPE_P2P_DEVICE) }, | ||
2086 | }; | ||
2087 | |||
2088 | static const struct ieee80211_iface_limit hwsim_if_dfs_limits[] = { | ||
2089 | { .max = 8, .types = BIT(NL80211_IFTYPE_AP) }, | ||
2090 | }; | ||
2091 | |||
2092 | static const struct ieee80211_iface_combination hwsim_if_comb[] = { | ||
2093 | { | ||
2094 | .limits = hwsim_if_limits, | ||
2095 | .n_limits = ARRAY_SIZE(hwsim_if_limits), | ||
2096 | .max_interfaces = 2048, | ||
2097 | .num_different_channels = 1, | ||
2098 | }, | ||
2099 | { | ||
2100 | .limits = hwsim_if_dfs_limits, | ||
2101 | .n_limits = ARRAY_SIZE(hwsim_if_dfs_limits), | ||
2102 | .max_interfaces = 8, | ||
2103 | .num_different_channels = 1, | ||
2104 | .radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) | | ||
2105 | BIT(NL80211_CHAN_WIDTH_20) | | ||
2106 | BIT(NL80211_CHAN_WIDTH_40) | | ||
2107 | BIT(NL80211_CHAN_WIDTH_80) | | ||
2108 | BIT(NL80211_CHAN_WIDTH_160), | ||
2109 | } | ||
2110 | }; | ||
2111 | |||
2112 | static int __init mac80211_hwsim_create_radio(void) | ||
2113 | { | ||
2114 | int err; | ||
2115 | u8 addr[ETH_ALEN]; | ||
2116 | struct mac80211_hwsim_data *data; | ||
2117 | struct ieee80211_hw *hw; | ||
2118 | enum ieee80211_band band; | ||
2119 | const struct ieee80211_ops *ops = &mac80211_hwsim_ops; | ||
2120 | int idx; | ||
2121 | |||
2122 | spin_lock_bh(&hwsim_radio_lock); | ||
2123 | idx = hwsim_radio_idx++; | ||
2124 | spin_unlock_bh(&hwsim_radio_lock); | ||
2125 | |||
2126 | if (channels > 1) | ||
2127 | ops = &mac80211_hwsim_mchan_ops; | ||
2128 | hw = ieee80211_alloc_hw(sizeof(*data), ops); | ||
2129 | if (!hw) { | ||
2130 | printk(KERN_DEBUG "mac80211_hwsim: ieee80211_alloc_hw failed\n"); | ||
2131 | err = -ENOMEM; | ||
2132 | goto failed; | ||
2133 | } | ||
2134 | data = hw->priv; | ||
2135 | data->hw = hw; | ||
2136 | |||
2137 | data->dev = device_create(hwsim_class, NULL, 0, hw, "hwsim%d", idx); | ||
2138 | if (IS_ERR(data->dev)) { | ||
2139 | printk(KERN_DEBUG | ||
2140 | "mac80211_hwsim: device_create failed (%ld)\n", | ||
2141 | PTR_ERR(data->dev)); | ||
2142 | err = -ENOMEM; | ||
2143 | goto failed_drvdata; | ||
2144 | } | ||
2145 | data->dev->driver = &mac80211_hwsim_driver.driver; | ||
2146 | err = device_bind_driver(data->dev); | ||
2147 | if (err != 0) { | ||
2148 | printk(KERN_DEBUG "mac80211_hwsim: device_bind_driver failed (%d)\n", | ||
2149 | err); | ||
2150 | goto failed_hw; | ||
2151 | } | ||
2152 | |||
2153 | skb_queue_head_init(&data->pending); | ||
2154 | |||
2155 | SET_IEEE80211_DEV(hw, data->dev); | ||
2156 | memset(addr, 0, ETH_ALEN); | ||
2157 | addr[0] = 0x02; | ||
2158 | addr[3] = idx >> 8; | ||
2159 | addr[4] = idx; | ||
2160 | memcpy(data->addresses[0].addr, addr, ETH_ALEN); | ||
2161 | memcpy(data->addresses[1].addr, addr, ETH_ALEN); | ||
2162 | data->addresses[1].addr[0] |= 0x40; | ||
2163 | hw->wiphy->n_addresses = 2; | ||
2164 | hw->wiphy->addresses = data->addresses; | ||
2165 | |||
2166 | data->channels = channels; | ||
2167 | |||
2168 | if (data->channels > 1) { | ||
2169 | hw->wiphy->max_scan_ssids = 255; | ||
2170 | hw->wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN; | ||
2171 | hw->wiphy->max_remain_on_channel_duration = 1000; | ||
2172 | /* For channels > 1 DFS is not allowed */ | ||
2173 | hw->wiphy->n_iface_combinations = 1; | ||
2174 | hw->wiphy->iface_combinations = &data->if_combination; | ||
2175 | data->if_combination = hwsim_if_comb[0]; | ||
2176 | data->if_combination.num_different_channels = data->channels; | ||
2177 | } else { | ||
2178 | hw->wiphy->iface_combinations = hwsim_if_comb; | ||
2179 | hw->wiphy->n_iface_combinations = ARRAY_SIZE(hwsim_if_comb); | ||
2180 | } | ||
2181 | |||
2182 | INIT_DELAYED_WORK(&data->roc_done, hw_roc_done); | ||
2183 | INIT_DELAYED_WORK(&data->hw_scan, hw_scan_work); | ||
2184 | |||
2185 | hw->queues = 5; | ||
2186 | hw->offchannel_tx_hw_queue = 4; | ||
2187 | hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | | ||
2188 | BIT(NL80211_IFTYPE_AP) | | ||
2189 | BIT(NL80211_IFTYPE_P2P_CLIENT) | | ||
2190 | BIT(NL80211_IFTYPE_P2P_GO) | | ||
2191 | BIT(NL80211_IFTYPE_ADHOC) | | ||
2192 | BIT(NL80211_IFTYPE_MESH_POINT) | | ||
2193 | BIT(NL80211_IFTYPE_P2P_DEVICE); | ||
2194 | |||
2195 | hw->flags = IEEE80211_HW_MFP_CAPABLE | | ||
2196 | IEEE80211_HW_SIGNAL_DBM | | ||
2197 | IEEE80211_HW_SUPPORTS_STATIC_SMPS | | ||
2198 | IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS | | ||
2199 | IEEE80211_HW_AMPDU_AGGREGATION | | ||
2200 | IEEE80211_HW_WANT_MONITOR_VIF | | ||
2201 | IEEE80211_HW_QUEUE_CONTROL | | ||
2202 | IEEE80211_HW_SUPPORTS_HT_CCK_RATES; | ||
2203 | if (rctbl) | ||
2204 | hw->flags |= IEEE80211_HW_SUPPORTS_RC_TABLE; | ||
2205 | |||
2206 | hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS | | ||
2207 | WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL | | ||
2208 | WIPHY_FLAG_AP_UAPSD; | ||
2209 | hw->wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR; | ||
2210 | |||
2211 | /* ask mac80211 to reserve space for magic */ | ||
2212 | hw->vif_data_size = sizeof(struct hwsim_vif_priv); | ||
2213 | hw->sta_data_size = sizeof(struct hwsim_sta_priv); | ||
2214 | hw->chanctx_data_size = sizeof(struct hwsim_chanctx_priv); | ||
2215 | |||
2216 | memcpy(data->channels_2ghz, hwsim_channels_2ghz, | ||
2217 | sizeof(hwsim_channels_2ghz)); | ||
2218 | memcpy(data->channels_5ghz, hwsim_channels_5ghz, | ||
2219 | sizeof(hwsim_channels_5ghz)); | ||
2220 | memcpy(data->rates, hwsim_rates, sizeof(hwsim_rates)); | ||
2221 | |||
2222 | for (band = IEEE80211_BAND_2GHZ; band < IEEE80211_NUM_BANDS; band++) { | ||
2223 | struct ieee80211_supported_band *sband = &data->bands[band]; | ||
2224 | switch (band) { | ||
2225 | case IEEE80211_BAND_2GHZ: | ||
2226 | sband->channels = data->channels_2ghz; | ||
2227 | sband->n_channels = ARRAY_SIZE(hwsim_channels_2ghz); | ||
2228 | sband->bitrates = data->rates; | ||
2229 | sband->n_bitrates = ARRAY_SIZE(hwsim_rates); | ||
2230 | break; | ||
2231 | case IEEE80211_BAND_5GHZ: | ||
2232 | sband->channels = data->channels_5ghz; | ||
2233 | sband->n_channels = ARRAY_SIZE(hwsim_channels_5ghz); | ||
2234 | sband->bitrates = data->rates + 4; | ||
2235 | sband->n_bitrates = ARRAY_SIZE(hwsim_rates) - 4; | ||
2236 | break; | ||
2237 | default: | ||
2238 | continue; | ||
2239 | } | ||
2240 | |||
2241 | sband->ht_cap.ht_supported = true; | ||
2242 | sband->ht_cap.cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 | | ||
2243 | IEEE80211_HT_CAP_GRN_FLD | | ||
2244 | IEEE80211_HT_CAP_SGI_40 | | ||
2245 | IEEE80211_HT_CAP_DSSSCCK40; | ||
2246 | sband->ht_cap.ampdu_factor = 0x3; | ||
2247 | sband->ht_cap.ampdu_density = 0x6; | ||
2248 | memset(&sband->ht_cap.mcs, 0, | ||
2249 | sizeof(sband->ht_cap.mcs)); | ||
2250 | sband->ht_cap.mcs.rx_mask[0] = 0xff; | ||
2251 | sband->ht_cap.mcs.rx_mask[1] = 0xff; | ||
2252 | sband->ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; | ||
2253 | |||
2254 | hw->wiphy->bands[band] = sband; | ||
2255 | |||
2256 | sband->vht_cap.vht_supported = true; | ||
2257 | sband->vht_cap.cap = | ||
2258 | IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454 | | ||
2259 | IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ | | ||
2260 | IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ | | ||
2261 | IEEE80211_VHT_CAP_RXLDPC | | ||
2262 | IEEE80211_VHT_CAP_SHORT_GI_80 | | ||
2263 | IEEE80211_VHT_CAP_SHORT_GI_160 | | ||
2264 | IEEE80211_VHT_CAP_TXSTBC | | ||
2265 | IEEE80211_VHT_CAP_RXSTBC_1 | | ||
2266 | IEEE80211_VHT_CAP_RXSTBC_2 | | ||
2267 | IEEE80211_VHT_CAP_RXSTBC_3 | | ||
2268 | IEEE80211_VHT_CAP_RXSTBC_4 | | ||
2269 | IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK; | ||
2270 | sband->vht_cap.vht_mcs.rx_mcs_map = | ||
2271 | cpu_to_le16(IEEE80211_VHT_MCS_SUPPORT_0_8 << 0 | | ||
2272 | IEEE80211_VHT_MCS_SUPPORT_0_8 << 2 | | ||
2273 | IEEE80211_VHT_MCS_SUPPORT_0_9 << 4 | | ||
2274 | IEEE80211_VHT_MCS_SUPPORT_0_8 << 6 | | ||
2275 | IEEE80211_VHT_MCS_SUPPORT_0_8 << 8 | | ||
2276 | IEEE80211_VHT_MCS_SUPPORT_0_9 << 10 | | ||
2277 | IEEE80211_VHT_MCS_SUPPORT_0_9 << 12 | | ||
2278 | IEEE80211_VHT_MCS_SUPPORT_0_8 << 14); | ||
2279 | sband->vht_cap.vht_mcs.tx_mcs_map = | ||
2280 | sband->vht_cap.vht_mcs.rx_mcs_map; | ||
2281 | } | ||
2282 | |||
2283 | /* By default all radios belong to the first group */ | ||
2284 | data->group = 1; | ||
2285 | mutex_init(&data->mutex); | ||
2286 | |||
2287 | /* Enable frame retransmissions for lossy channels */ | ||
2288 | hw->max_rates = 4; | ||
2289 | hw->max_rate_tries = 11; | ||
2290 | |||
2291 | err = ieee80211_register_hw(hw); | ||
2292 | if (err < 0) { | ||
2293 | printk(KERN_DEBUG "mac80211_hwsim: ieee80211_register_hw failed (%d)\n", | ||
2294 | err); | ||
2295 | goto failed_hw; | ||
2296 | } | ||
2297 | |||
2298 | wiphy_debug(hw->wiphy, "hwaddr %pM registered\n", hw->wiphy->perm_addr); | ||
2299 | |||
2300 | data->debugfs = debugfs_create_dir("hwsim", hw->wiphy->debugfsdir); | ||
2301 | debugfs_create_file("ps", 0666, data->debugfs, data, &hwsim_fops_ps); | ||
2302 | debugfs_create_file("group", 0666, data->debugfs, data, | ||
2303 | &hwsim_fops_group); | ||
2304 | if (data->channels == 1) | ||
2305 | debugfs_create_file("dfs_simulate_radar", 0222, | ||
2306 | data->debugfs, | ||
2307 | data, &hwsim_simulate_radar); | ||
2308 | |||
2309 | tasklet_hrtimer_init(&data->beacon_timer, | ||
2310 | mac80211_hwsim_beacon, | ||
2311 | CLOCK_MONOTONIC_RAW, HRTIMER_MODE_ABS); | ||
2312 | |||
2313 | spin_lock_bh(&hwsim_radio_lock); | ||
2314 | list_add_tail(&data->list, &hwsim_radios); | ||
2315 | spin_unlock_bh(&hwsim_radio_lock); | ||
2316 | |||
2317 | return 0; | ||
2318 | |||
2319 | failed_hw: | ||
2320 | device_unregister(data->dev); | ||
2321 | failed_drvdata: | ||
2322 | ieee80211_free_hw(hw); | ||
2323 | failed: | ||
2324 | return err; | ||
2325 | } | ||
2326 | |||
2327 | static int __init init_mac80211_hwsim(void) | 2327 | static int __init init_mac80211_hwsim(void) |
2328 | { | 2328 | { |
2329 | int i, err; | 2329 | int i, err; |