diff options
Diffstat (limited to 'drivers/net/wireless/mac80211_hwsim.c')
-rw-r--r-- | drivers/net/wireless/mac80211_hwsim.c | 103 |
1 files changed, 91 insertions, 12 deletions
diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index d56b7859a437..d5c0a1af08b9 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c | |||
@@ -330,6 +330,83 @@ static const struct ieee80211_rate hwsim_rates[] = { | |||
330 | { .bitrate = 540 } | 330 | { .bitrate = 540 } |
331 | }; | 331 | }; |
332 | 332 | ||
333 | #define OUI_QCA 0x001374 | ||
334 | #define QCA_NL80211_SUBCMD_TEST 1 | ||
335 | enum qca_nl80211_vendor_subcmds { | ||
336 | QCA_WLAN_VENDOR_ATTR_TEST = 8, | ||
337 | QCA_WLAN_VENDOR_ATTR_MAX = QCA_WLAN_VENDOR_ATTR_TEST | ||
338 | }; | ||
339 | |||
340 | static const struct nla_policy | ||
341 | hwsim_vendor_test_policy[QCA_WLAN_VENDOR_ATTR_MAX + 1] = { | ||
342 | [QCA_WLAN_VENDOR_ATTR_MAX] = { .type = NLA_U32 }, | ||
343 | }; | ||
344 | |||
345 | static int mac80211_hwsim_vendor_cmd_test(struct wiphy *wiphy, | ||
346 | struct wireless_dev *wdev, | ||
347 | const void *data, int data_len) | ||
348 | { | ||
349 | struct sk_buff *skb; | ||
350 | struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_MAX + 1]; | ||
351 | int err; | ||
352 | u32 val; | ||
353 | |||
354 | err = nla_parse(tb, QCA_WLAN_VENDOR_ATTR_MAX, data, data_len, | ||
355 | hwsim_vendor_test_policy); | ||
356 | if (err) | ||
357 | return err; | ||
358 | if (!tb[QCA_WLAN_VENDOR_ATTR_TEST]) | ||
359 | return -EINVAL; | ||
360 | val = nla_get_u32(tb[QCA_WLAN_VENDOR_ATTR_TEST]); | ||
361 | wiphy_debug(wiphy, "%s: test=%u\n", __func__, val); | ||
362 | |||
363 | /* Send a vendor event as a test. Note that this would not normally be | ||
364 | * done within a command handler, but rather, based on some other | ||
365 | * trigger. For simplicity, this command is used to trigger the event | ||
366 | * here. | ||
367 | * | ||
368 | * event_idx = 0 (index in mac80211_hwsim_vendor_commands) | ||
369 | */ | ||
370 | skb = cfg80211_vendor_event_alloc(wiphy, wdev, 100, 0, GFP_KERNEL); | ||
371 | if (skb) { | ||
372 | /* skb_put() or nla_put() will fill up data within | ||
373 | * NL80211_ATTR_VENDOR_DATA. | ||
374 | */ | ||
375 | |||
376 | /* Add vendor data */ | ||
377 | nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_TEST, val + 1); | ||
378 | |||
379 | /* Send the event - this will call nla_nest_end() */ | ||
380 | cfg80211_vendor_event(skb, GFP_KERNEL); | ||
381 | } | ||
382 | |||
383 | /* Send a response to the command */ | ||
384 | skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, 10); | ||
385 | if (!skb) | ||
386 | return -ENOMEM; | ||
387 | |||
388 | /* skb_put() or nla_put() will fill up data within | ||
389 | * NL80211_ATTR_VENDOR_DATA | ||
390 | */ | ||
391 | nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_TEST, val + 2); | ||
392 | |||
393 | return cfg80211_vendor_cmd_reply(skb); | ||
394 | } | ||
395 | |||
396 | static struct wiphy_vendor_command mac80211_hwsim_vendor_commands[] = { | ||
397 | { | ||
398 | .info = { .vendor_id = OUI_QCA, | ||
399 | .subcmd = QCA_NL80211_SUBCMD_TEST }, | ||
400 | .flags = WIPHY_VENDOR_CMD_NEED_NETDEV, | ||
401 | .doit = mac80211_hwsim_vendor_cmd_test, | ||
402 | } | ||
403 | }; | ||
404 | |||
405 | /* Advertise support vendor specific events */ | ||
406 | static const struct nl80211_vendor_cmd_info mac80211_hwsim_vendor_events[] = { | ||
407 | { .vendor_id = OUI_QCA, .subcmd = 1 }, | ||
408 | }; | ||
409 | |||
333 | static const struct ieee80211_iface_limit hwsim_if_limits[] = { | 410 | static const struct ieee80211_iface_limit hwsim_if_limits[] = { |
334 | { .max = 1, .types = BIT(NL80211_IFTYPE_ADHOC) }, | 411 | { .max = 1, .types = BIT(NL80211_IFTYPE_ADHOC) }, |
335 | { .max = 2048, .types = BIT(NL80211_IFTYPE_STATION) | | 412 | { .max = 2048, .types = BIT(NL80211_IFTYPE_STATION) | |
@@ -906,8 +983,7 @@ static void mac80211_hwsim_tx_frame_nl(struct ieee80211_hw *hw, | |||
906 | goto nla_put_failure; | 983 | goto nla_put_failure; |
907 | } | 984 | } |
908 | 985 | ||
909 | if (nla_put(skb, HWSIM_ATTR_ADDR_TRANSMITTER, | 986 | if (nla_put(skb, HWSIM_ATTR_ADDR_TRANSMITTER, ETH_ALEN, hdr->addr2)) |
910 | ETH_ALEN, data->addresses[1].addr)) | ||
911 | goto nla_put_failure; | 987 | goto nla_put_failure; |
912 | 988 | ||
913 | /* We get the skb->data */ | 989 | /* We get the skb->data */ |
@@ -1522,21 +1598,16 @@ static void mac80211_hwsim_bss_info_changed(struct ieee80211_hw *hw, | |||
1522 | vp->aid = info->aid; | 1598 | vp->aid = info->aid; |
1523 | } | 1599 | } |
1524 | 1600 | ||
1525 | if (changed & BSS_CHANGED_BEACON_INT) { | ||
1526 | wiphy_debug(hw->wiphy, " BCNINT: %d\n", info->beacon_int); | ||
1527 | data->beacon_int = info->beacon_int * 1024; | ||
1528 | } | ||
1529 | |||
1530 | if (changed & BSS_CHANGED_BEACON_ENABLED) { | 1601 | if (changed & BSS_CHANGED_BEACON_ENABLED) { |
1531 | wiphy_debug(hw->wiphy, " BCN EN: %d\n", info->enable_beacon); | 1602 | wiphy_debug(hw->wiphy, " BCN EN: %d (BI=%u)\n", |
1603 | info->enable_beacon, info->beacon_int); | ||
1532 | vp->bcn_en = info->enable_beacon; | 1604 | vp->bcn_en = info->enable_beacon; |
1533 | if (data->started && | 1605 | if (data->started && |
1534 | !hrtimer_is_queued(&data->beacon_timer.timer) && | 1606 | !hrtimer_is_queued(&data->beacon_timer.timer) && |
1535 | info->enable_beacon) { | 1607 | info->enable_beacon) { |
1536 | u64 tsf, until_tbtt; | 1608 | u64 tsf, until_tbtt; |
1537 | u32 bcn_int; | 1609 | u32 bcn_int; |
1538 | if (WARN_ON(!data->beacon_int)) | 1610 | data->beacon_int = info->beacon_int * 1024; |
1539 | data->beacon_int = 1000 * 1024; | ||
1540 | tsf = mac80211_hwsim_get_tsf(hw, vif); | 1611 | tsf = mac80211_hwsim_get_tsf(hw, vif); |
1541 | bcn_int = data->beacon_int; | 1612 | bcn_int = data->beacon_int; |
1542 | until_tbtt = bcn_int - do_div(tsf, bcn_int); | 1613 | until_tbtt = bcn_int - do_div(tsf, bcn_int); |
@@ -1550,8 +1621,10 @@ static void mac80211_hwsim_bss_info_changed(struct ieee80211_hw *hw, | |||
1550 | mac80211_hwsim_bcn_en_iter, &count); | 1621 | mac80211_hwsim_bcn_en_iter, &count); |
1551 | wiphy_debug(hw->wiphy, " beaconing vifs remaining: %u", | 1622 | wiphy_debug(hw->wiphy, " beaconing vifs remaining: %u", |
1552 | count); | 1623 | count); |
1553 | if (count == 0) | 1624 | if (count == 0) { |
1554 | tasklet_hrtimer_cancel(&data->beacon_timer); | 1625 | tasklet_hrtimer_cancel(&data->beacon_timer); |
1626 | data->beacon_int = 0; | ||
1627 | } | ||
1555 | } | 1628 | } |
1556 | } | 1629 | } |
1557 | 1630 | ||
@@ -2420,6 +2493,12 @@ static int mac80211_hwsim_new_radio(struct genl_info *info, | |||
2420 | hw->max_rates = 4; | 2493 | hw->max_rates = 4; |
2421 | hw->max_rate_tries = 11; | 2494 | hw->max_rate_tries = 11; |
2422 | 2495 | ||
2496 | hw->wiphy->vendor_commands = mac80211_hwsim_vendor_commands; | ||
2497 | hw->wiphy->n_vendor_commands = | ||
2498 | ARRAY_SIZE(mac80211_hwsim_vendor_commands); | ||
2499 | hw->wiphy->vendor_events = mac80211_hwsim_vendor_events; | ||
2500 | hw->wiphy->n_vendor_events = ARRAY_SIZE(mac80211_hwsim_vendor_events); | ||
2501 | |||
2423 | if (param->reg_strict) | 2502 | if (param->reg_strict) |
2424 | hw->wiphy->regulatory_flags |= REGULATORY_STRICT_REG; | 2503 | hw->wiphy->regulatory_flags |= REGULATORY_STRICT_REG; |
2425 | if (param->regd) { | 2504 | if (param->regd) { |
@@ -2611,7 +2690,7 @@ static struct mac80211_hwsim_data *get_hwsim_data_ref_from_addr(const u8 *addr) | |||
2611 | 2690 | ||
2612 | spin_lock_bh(&hwsim_radio_lock); | 2691 | spin_lock_bh(&hwsim_radio_lock); |
2613 | list_for_each_entry(data, &hwsim_radios, list) { | 2692 | list_for_each_entry(data, &hwsim_radios, list) { |
2614 | if (memcmp(data->addresses[1].addr, addr, ETH_ALEN) == 0) { | 2693 | if (mac80211_hwsim_addr_match(data, addr)) { |
2615 | _found = true; | 2694 | _found = true; |
2616 | break; | 2695 | break; |
2617 | } | 2696 | } |