Merge tag 'mac80211-next-for-davem-2015-03-30' of git://git.kernel.org/pub/scm/linux...
[cascardo/linux.git] / drivers / net / wireless / mac80211_hwsim.c
index d56b785..d5c0a1a 100644 (file)
@@ -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 */
@@ -1522,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);
@@ -1550,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;
+                       }
                }
        }
 
@@ -2420,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) {
@@ -2611,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;
                }