summaryrefslogtreecommitdiff
path: root/drivers/net/wireless/mac80211_hwsim.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/mac80211_hwsim.c')
-rw-r--r--drivers/net/wireless/mac80211_hwsim.c114
1 files changed, 98 insertions, 16 deletions
diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c
index 4a4c6586a8d2..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[] = {
{ .bitrate = 540 }
};
+#define OUI_QCA 0x001374
+#define QCA_NL80211_SUBCMD_TEST 1
+enum qca_nl80211_vendor_subcmds {
+ QCA_WLAN_VENDOR_ATTR_TEST = 8,
+ QCA_WLAN_VENDOR_ATTR_MAX = QCA_WLAN_VENDOR_ATTR_TEST
+};
+
+static const struct nla_policy
+hwsim_vendor_test_policy[QCA_WLAN_VENDOR_ATTR_MAX + 1] = {
+ [QCA_WLAN_VENDOR_ATTR_MAX] = { .type = NLA_U32 },
+};
+
+static int mac80211_hwsim_vendor_cmd_test(struct wiphy *wiphy,
+ struct wireless_dev *wdev,
+ const void *data, int data_len)
+{
+ struct sk_buff *skb;
+ struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_MAX + 1];
+ int err;
+ u32 val;
+
+ err = nla_parse(tb, QCA_WLAN_VENDOR_ATTR_MAX, data, data_len,
+ hwsim_vendor_test_policy);
+ if (err)
+ return err;
+ if (!tb[QCA_WLAN_VENDOR_ATTR_TEST])
+ return -EINVAL;
+ val = nla_get_u32(tb[QCA_WLAN_VENDOR_ATTR_TEST]);
+ wiphy_debug(wiphy, "%s: test=%u\n", __func__, val);
+
+ /* Send a vendor event as a test. Note that this would not normally be
+ * done within a command handler, but rather, based on some other
+ * trigger. For simplicity, this command is used to trigger the event
+ * here.
+ *
+ * event_idx = 0 (index in mac80211_hwsim_vendor_commands)
+ */
+ skb = cfg80211_vendor_event_alloc(wiphy, wdev, 100, 0, GFP_KERNEL);
+ if (skb) {
+ /* skb_put() or nla_put() will fill up data within
+ * NL80211_ATTR_VENDOR_DATA.
+ */
+
+ /* Add vendor data */
+ nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_TEST, val + 1);
+
+ /* Send the event - this will call nla_nest_end() */
+ cfg80211_vendor_event(skb, GFP_KERNEL);
+ }
+
+ /* Send a response to the command */
+ skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, 10);
+ if (!skb)
+ return -ENOMEM;
+
+ /* skb_put() or nla_put() will fill up data within
+ * NL80211_ATTR_VENDOR_DATA
+ */
+ nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_TEST, val + 2);
+
+ return cfg80211_vendor_cmd_reply(skb);
+}
+
+static struct wiphy_vendor_command mac80211_hwsim_vendor_commands[] = {
+ {
+ .info = { .vendor_id = OUI_QCA,
+ .subcmd = QCA_NL80211_SUBCMD_TEST },
+ .flags = WIPHY_VENDOR_CMD_NEED_NETDEV,
+ .doit = mac80211_hwsim_vendor_cmd_test,
+ }
+};
+
+/* Advertise support vendor specific events */
+static const struct nl80211_vendor_cmd_info mac80211_hwsim_vendor_events[] = {
+ { .vendor_id = OUI_QCA, .subcmd = 1 },
+};
+
static const struct ieee80211_iface_limit hwsim_if_limits[] = {
{ .max = 1, .types = BIT(NL80211_IFTYPE_ADHOC) },
{ .max = 2048, .types = BIT(NL80211_IFTYPE_STATION) |
@@ -906,8 +983,7 @@ static void mac80211_hwsim_tx_frame_nl(struct ieee80211_hw *hw,
goto nla_put_failure;
}
- if (nla_put(skb, HWSIM_ATTR_ADDR_TRANSMITTER,
- ETH_ALEN, data->addresses[1].addr))
+ if (nla_put(skb, HWSIM_ATTR_ADDR_TRANSMITTER, ETH_ALEN, hdr->addr2))
goto nla_put_failure;
/* We get the skb->data */
@@ -946,7 +1022,8 @@ static void mac80211_hwsim_tx_frame_nl(struct ieee80211_hw *hw,
goto nla_put_failure;
genlmsg_end(skb, msg_head);
- genlmsg_unicast(&init_net, skb, dst_portid);
+ if (genlmsg_unicast(&init_net, skb, dst_portid))
+ goto err_free_txskb;
/* Enqueue the packet */
skb_queue_tail(&data->pending, my_skb);
@@ -955,6 +1032,8 @@ static void mac80211_hwsim_tx_frame_nl(struct ieee80211_hw *hw,
return;
nla_put_failure:
+ nlmsg_free(skb);
+err_free_txskb:
printk(KERN_DEBUG "mac80211_hwsim: error occurred in %s\n", __func__);
ieee80211_free_txskb(hw, my_skb);
data->tx_failed++;
@@ -1519,21 +1598,16 @@ static void mac80211_hwsim_bss_info_changed(struct ieee80211_hw *hw,
vp->aid = info->aid;
}
- if (changed & BSS_CHANGED_BEACON_INT) {
- wiphy_debug(hw->wiphy, " BCNINT: %d\n", info->beacon_int);
- data->beacon_int = info->beacon_int * 1024;
- }
-
if (changed & BSS_CHANGED_BEACON_ENABLED) {
- wiphy_debug(hw->wiphy, " BCN EN: %d\n", info->enable_beacon);
+ wiphy_debug(hw->wiphy, " BCN EN: %d (BI=%u)\n",
+ info->enable_beacon, info->beacon_int);
vp->bcn_en = info->enable_beacon;
if (data->started &&
!hrtimer_is_queued(&data->beacon_timer.timer) &&
info->enable_beacon) {
u64 tsf, until_tbtt;
u32 bcn_int;
- if (WARN_ON(!data->beacon_int))
- data->beacon_int = 1000 * 1024;
+ data->beacon_int = info->beacon_int * 1024;
tsf = mac80211_hwsim_get_tsf(hw, vif);
bcn_int = data->beacon_int;
until_tbtt = bcn_int - do_div(tsf, bcn_int);
@@ -1547,8 +1621,10 @@ static void mac80211_hwsim_bss_info_changed(struct ieee80211_hw *hw,
mac80211_hwsim_bcn_en_iter, &count);
wiphy_debug(hw->wiphy, " beaconing vifs remaining: %u",
count);
- if (count == 0)
+ if (count == 0) {
tasklet_hrtimer_cancel(&data->beacon_timer);
+ data->beacon_int = 0;
+ }
}
}
@@ -1908,7 +1984,7 @@ static void mac80211_hwsim_sw_scan_complete(struct ieee80211_hw *hw,
printk(KERN_DEBUG "hwsim sw_scan_complete\n");
hwsim->scanning = false;
- memset(hwsim->scan_addr, 0, ETH_ALEN);
+ eth_zero_addr(hwsim->scan_addr);
mutex_unlock(&hwsim->mutex);
}
@@ -2264,7 +2340,7 @@ static int mac80211_hwsim_new_radio(struct genl_info *info,
skb_queue_head_init(&data->pending);
SET_IEEE80211_DEV(hw, data->dev);
- memset(addr, 0, ETH_ALEN);
+ eth_zero_addr(addr);
addr[0] = 0x02;
addr[3] = idx >> 8;
addr[4] = idx;
@@ -2417,6 +2493,12 @@ static int mac80211_hwsim_new_radio(struct genl_info *info,
hw->max_rates = 4;
hw->max_rate_tries = 11;
+ hw->wiphy->vendor_commands = mac80211_hwsim_vendor_commands;
+ hw->wiphy->n_vendor_commands =
+ ARRAY_SIZE(mac80211_hwsim_vendor_commands);
+ hw->wiphy->vendor_events = mac80211_hwsim_vendor_events;
+ hw->wiphy->n_vendor_events = ARRAY_SIZE(mac80211_hwsim_vendor_events);
+
if (param->reg_strict)
hw->wiphy->regulatory_flags |= REGULATORY_STRICT_REG;
if (param->regd) {
@@ -2597,7 +2679,7 @@ static void hwsim_mon_setup(struct net_device *dev)
ether_setup(dev);
dev->tx_queue_len = 0;
dev->type = ARPHRD_IEEE80211_RADIOTAP;
- memset(dev->dev_addr, 0, ETH_ALEN);
+ eth_zero_addr(dev->dev_addr);
dev->dev_addr[0] = 0x12;
}
@@ -2608,7 +2690,7 @@ static struct mac80211_hwsim_data *get_hwsim_data_ref_from_addr(const u8 *addr)
spin_lock_bh(&hwsim_radio_lock);
list_for_each_entry(data, &hwsim_radios, list) {
- if (memcmp(data->addresses[1].addr, addr, ETH_ALEN) == 0) {
+ if (mac80211_hwsim_addr_match(data, addr)) {
_found = true;
break;
}