iwlwifi: mvm: add vendor commands needed for iwlmei
authorEmmanuel Grumbach <emmanuel.grumbach@intel.com>
Fri, 12 Nov 2021 06:28:13 +0000 (08:28 +0200)
committerKalle Valo <kvalo@codeaurora.org>
Fri, 26 Nov 2021 16:31:48 +0000 (18:31 +0200)
Add the vendor commands that must be used by the network manager
to allow proper operation of iwlmei.

* Send information on the AP CSME is connected to
* Notify the userspace when roaming is forbidden
* Allow the userspace to require ownership

Co-Developed-by: Ayala Beker <ayala.beker@intel.com>
Signed-off-by: Ayala Beker <ayala.beker@intel.com>
Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
v6: remove the VENDOR_CMDS Kconfig option and make the whole infra
    depend on IWLMEI directly
v7: remove // comments
    remove an unneeded function
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
Link: https://lore.kernel.org/r/20211112062814.7502-5-emmanuel.grumbach@intel.com
drivers/net/wireless/intel/iwlwifi/mvm/Makefile
drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
drivers/net/wireless/intel/iwlwifi/mvm/vendor-cmd.c [new file with mode: 0644]

index 75fc2d935e5d2de1eed1cc5901dd3123b5735b43..11e814b7cad03b8db6f351759840dd5aaf696d01 100644 (file)
@@ -10,5 +10,6 @@ iwlmvm-y += rfi.o
 iwlmvm-$(CONFIG_IWLWIFI_DEBUGFS) += debugfs.o debugfs-vif.o
 iwlmvm-$(CONFIG_IWLWIFI_LEDS) += led.o
 iwlmvm-$(CONFIG_PM) += d3.o
+iwlmvm-$(CONFIG_IWLMEI) += vendor-cmd.o
 
 ccflags-y += -I $(srctree)/$(src)/../
index c96a0ece8066c10bc8c0d468d1ef572bef956554..9a666cc259f4af05d45e44954d21231e94434082 100644 (file)
@@ -720,6 +720,8 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
                wiphy_ext_feature_set(hw->wiphy,
                                      NL80211_EXT_FEATURE_PROTECTED_TWT);
 
+       iwl_mvm_vendor_cmds_register(mvm);
+
        hw->wiphy->available_antennas_tx = iwl_mvm_get_valid_tx_ant(mvm);
        hw->wiphy->available_antennas_rx = iwl_mvm_get_valid_rx_ant(mvm);
 
index 515591b29b0c233202f2b976799ecd4fe0444c51..34b4a280a293409d9cfa3e089a00ebfe454722f7 100644 (file)
@@ -1959,6 +1959,17 @@ void iwl_mvm_enter_ctkill(struct iwl_mvm *mvm);
 int iwl_mvm_send_temp_report_ths_cmd(struct iwl_mvm *mvm);
 int iwl_mvm_ctdp_command(struct iwl_mvm *mvm, u32 op, u32 budget);
 
+#if IS_ENABLED(CONFIG_IWLMEI)
+
+/* vendor commands */
+void iwl_mvm_vendor_cmds_register(struct iwl_mvm *mvm);
+
+#else
+
+static inline void iwl_mvm_vendor_cmds_register(struct iwl_mvm *mvm) {}
+
+#endif
+
 /* Location Aware Regulatory */
 struct iwl_mcc_update_resp *
 iwl_mvm_update_mcc(struct iwl_mvm *mvm, const char *alpha2,
@@ -2213,11 +2224,8 @@ static inline void iwl_mvm_mei_set_sw_rfkill_state(struct iwl_mvm *mvm, bool sw_
                iwl_mei_set_rfkill_state(iwl_mvm_is_radio_killed(mvm), sw_rfkill);
 }
 
-static inline void iwl_mvm_send_roaming_forbidden_event(struct iwl_mvm *mvm,
-                                                       struct ieee80211_vif *vif,
-                                                       bool forbidden)
-{
-       /* TODO */
-}
+void iwl_mvm_send_roaming_forbidden_event(struct iwl_mvm *mvm,
+                                         struct ieee80211_vif *vif,
+                                         bool forbidden);
 
 #endif /* __IWL_MVM_H__ */
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/vendor-cmd.c b/drivers/net/wireless/intel/iwlwifi/mvm/vendor-cmd.c
new file mode 100644 (file)
index 0000000..f702ad8
--- /dev/null
@@ -0,0 +1,151 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2021 Intel Corporation
+ */
+#include "mvm.h"
+#include <linux/nl80211-vnd-intel.h>
+
+static const struct nla_policy
+iwl_mvm_vendor_attr_policy[NUM_IWL_MVM_VENDOR_ATTR] = {
+       [IWL_MVM_VENDOR_ATTR_ROAMING_FORBIDDEN] = { .type = NLA_U8 },
+       [IWL_MVM_VENDOR_ATTR_AUTH_MODE] = { .type = NLA_U32 },
+       [IWL_MVM_VENDOR_ATTR_CHANNEL_NUM] = { .type = NLA_U8 },
+       [IWL_MVM_VENDOR_ATTR_SSID] = { .type = NLA_BINARY,
+                                      .len = IEEE80211_MAX_SSID_LEN },
+       [IWL_MVM_VENDOR_ATTR_BAND] = { .type = NLA_U8 },
+       [IWL_MVM_VENDOR_ATTR_COLLOC_CHANNEL] = { .type = NLA_U8 },
+       [IWL_MVM_VENDOR_ATTR_COLLOC_ADDR] = { .type = NLA_BINARY, .len = ETH_ALEN },
+};
+
+static int iwl_mvm_vendor_get_csme_conn_info(struct wiphy *wiphy,
+                                            struct wireless_dev *wdev,
+                                            const void *data, int data_len)
+{
+       struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
+       struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+       struct iwl_mvm_csme_conn_info *csme_conn_info;
+       struct sk_buff *skb;
+       int err = 0;
+
+       mutex_lock(&mvm->mutex);
+       csme_conn_info = iwl_mvm_get_csme_conn_info(mvm);
+
+       if (!csme_conn_info) {
+               err = -EINVAL;
+               goto out_unlock;
+       }
+
+       skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, 200);
+       if (!skb) {
+               err = -ENOMEM;
+               goto out_unlock;
+       }
+
+       if (nla_put_u32(skb, IWL_MVM_VENDOR_ATTR_AUTH_MODE,
+                       csme_conn_info->conn_info.auth_mode) ||
+           nla_put(skb, IWL_MVM_VENDOR_ATTR_SSID,
+                   csme_conn_info->conn_info.ssid_len,
+                   csme_conn_info->conn_info.ssid) ||
+           nla_put_u32(skb, IWL_MVM_VENDOR_ATTR_STA_CIPHER,
+                       csme_conn_info->conn_info.pairwise_cipher) ||
+           nla_put_u8(skb, IWL_MVM_VENDOR_ATTR_CHANNEL_NUM,
+                      csme_conn_info->conn_info.channel) ||
+           nla_put(skb, IWL_MVM_VENDOR_ATTR_ADDR, ETH_ALEN,
+                   csme_conn_info->conn_info.bssid)) {
+               kfree_skb(skb);
+               err = -ENOBUFS;
+       }
+
+out_unlock:
+       mutex_unlock(&mvm->mutex);
+       if (err)
+               return err;
+
+       return cfg80211_vendor_cmd_reply(skb);
+}
+
+static int iwl_mvm_vendor_host_get_ownership(struct wiphy *wiphy,
+                                            struct wireless_dev *wdev,
+                                            const void *data, int data_len)
+{
+       struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
+       struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+
+       mutex_lock(&mvm->mutex);
+       iwl_mvm_mei_get_ownership(mvm);
+       mutex_unlock(&mvm->mutex);
+
+       return 0;
+}
+
+static const struct wiphy_vendor_command iwl_mvm_vendor_commands[] = {
+       {
+               .info = {
+                       .vendor_id = INTEL_OUI,
+                       .subcmd = IWL_MVM_VENDOR_CMD_GET_CSME_CONN_INFO,
+               },
+               .doit = iwl_mvm_vendor_get_csme_conn_info,
+               .flags = WIPHY_VENDOR_CMD_NEED_WDEV,
+               .policy = iwl_mvm_vendor_attr_policy,
+               .maxattr = MAX_IWL_MVM_VENDOR_ATTR,
+       },
+       {
+               .info = {
+                       .vendor_id = INTEL_OUI,
+                       .subcmd = IWL_MVM_VENDOR_CMD_HOST_GET_OWNERSHIP,
+               },
+               .doit = iwl_mvm_vendor_host_get_ownership,
+               .flags = WIPHY_VENDOR_CMD_NEED_WDEV,
+               .policy = iwl_mvm_vendor_attr_policy,
+               .maxattr = MAX_IWL_MVM_VENDOR_ATTR,
+       },
+};
+
+enum iwl_mvm_vendor_events_idx {
+        /* 0x0 - 0x3 are deprecated */
+        IWL_MVM_VENDOR_EVENT_IDX_ROAMING_FORBIDDEN = 4,
+        NUM_IWL_MVM_VENDOR_EVENT_IDX
+};
+
+static const struct nl80211_vendor_cmd_info
+iwl_mvm_vendor_events[NUM_IWL_MVM_VENDOR_EVENT_IDX] = {
+       [IWL_MVM_VENDOR_EVENT_IDX_ROAMING_FORBIDDEN] = {
+               .vendor_id = INTEL_OUI,
+               .subcmd = IWL_MVM_VENDOR_CMD_ROAMING_FORBIDDEN_EVENT,
+       },
+};
+
+void iwl_mvm_vendor_cmds_register(struct iwl_mvm *mvm)
+{
+       mvm->hw->wiphy->vendor_commands = iwl_mvm_vendor_commands;
+       mvm->hw->wiphy->n_vendor_commands = ARRAY_SIZE(iwl_mvm_vendor_commands);
+       mvm->hw->wiphy->vendor_events = iwl_mvm_vendor_events;
+       mvm->hw->wiphy->n_vendor_events = ARRAY_SIZE(iwl_mvm_vendor_events);
+}
+
+void iwl_mvm_send_roaming_forbidden_event(struct iwl_mvm *mvm,
+                                         struct ieee80211_vif *vif,
+                                         bool forbidden)
+{
+       struct sk_buff *msg =
+               cfg80211_vendor_event_alloc(mvm->hw->wiphy,
+                                           ieee80211_vif_to_wdev(vif),
+                                           200, IWL_MVM_VENDOR_EVENT_IDX_ROAMING_FORBIDDEN,
+                                           GFP_ATOMIC);
+       if (!msg)
+               return;
+
+       if (WARN_ON(!vif))
+               return;
+
+       if (nla_put(msg, IWL_MVM_VENDOR_ATTR_VIF_ADDR,
+                   ETH_ALEN, vif->addr) ||
+           nla_put_u8(msg, IWL_MVM_VENDOR_ATTR_ROAMING_FORBIDDEN, forbidden))
+               goto nla_put_failure;
+
+       cfg80211_vendor_event(msg, GFP_ATOMIC);
+       return;
+
+ nla_put_failure:
+       kfree_skb(msg);
+}