Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright (C) 2021 Intel Corporation
0004  */
0005 #include "mvm.h"
0006 #include <linux/nl80211-vnd-intel.h>
0007 #include <net/netlink.h>
0008 
0009 static const struct nla_policy
0010 iwl_mvm_vendor_attr_policy[NUM_IWL_MVM_VENDOR_ATTR] = {
0011     [IWL_MVM_VENDOR_ATTR_ROAMING_FORBIDDEN] = { .type = NLA_U8 },
0012     [IWL_MVM_VENDOR_ATTR_AUTH_MODE] = { .type = NLA_U32 },
0013     [IWL_MVM_VENDOR_ATTR_CHANNEL_NUM] = { .type = NLA_U8 },
0014     [IWL_MVM_VENDOR_ATTR_SSID] = { .type = NLA_BINARY,
0015                        .len = IEEE80211_MAX_SSID_LEN },
0016     [IWL_MVM_VENDOR_ATTR_BAND] = { .type = NLA_U8 },
0017     [IWL_MVM_VENDOR_ATTR_COLLOC_CHANNEL] = { .type = NLA_U8 },
0018     [IWL_MVM_VENDOR_ATTR_COLLOC_ADDR] = { .type = NLA_BINARY, .len = ETH_ALEN },
0019 };
0020 
0021 static int iwl_mvm_vendor_get_csme_conn_info(struct wiphy *wiphy,
0022                          struct wireless_dev *wdev,
0023                          const void *data, int data_len)
0024 {
0025     struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
0026     struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
0027     struct iwl_mvm_csme_conn_info *csme_conn_info;
0028     struct sk_buff *skb;
0029     int err = 0;
0030 
0031     mutex_lock(&mvm->mutex);
0032     csme_conn_info = iwl_mvm_get_csme_conn_info(mvm);
0033 
0034     if (!csme_conn_info) {
0035         err = -EINVAL;
0036         goto out_unlock;
0037     }
0038 
0039     skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, 200);
0040     if (!skb) {
0041         err = -ENOMEM;
0042         goto out_unlock;
0043     }
0044 
0045     if (nla_put_u32(skb, IWL_MVM_VENDOR_ATTR_AUTH_MODE,
0046             csme_conn_info->conn_info.auth_mode) ||
0047         nla_put(skb, IWL_MVM_VENDOR_ATTR_SSID,
0048             csme_conn_info->conn_info.ssid_len,
0049             csme_conn_info->conn_info.ssid) ||
0050         nla_put_u32(skb, IWL_MVM_VENDOR_ATTR_STA_CIPHER,
0051             csme_conn_info->conn_info.pairwise_cipher) ||
0052         nla_put_u8(skb, IWL_MVM_VENDOR_ATTR_CHANNEL_NUM,
0053                csme_conn_info->conn_info.channel) ||
0054         nla_put(skb, IWL_MVM_VENDOR_ATTR_ADDR, ETH_ALEN,
0055             csme_conn_info->conn_info.bssid)) {
0056         kfree_skb(skb);
0057         err = -ENOBUFS;
0058     }
0059 
0060 out_unlock:
0061     mutex_unlock(&mvm->mutex);
0062     if (err)
0063         return err;
0064 
0065     return cfg80211_vendor_cmd_reply(skb);
0066 }
0067 
0068 static int iwl_mvm_vendor_host_get_ownership(struct wiphy *wiphy,
0069                          struct wireless_dev *wdev,
0070                          const void *data, int data_len)
0071 {
0072     struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
0073     struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
0074     int ret;
0075 
0076     mutex_lock(&mvm->mutex);
0077     ret = iwl_mvm_mei_get_ownership(mvm);
0078     mutex_unlock(&mvm->mutex);
0079 
0080     return ret;
0081 }
0082 
0083 static const struct wiphy_vendor_command iwl_mvm_vendor_commands[] = {
0084     {
0085         .info = {
0086             .vendor_id = INTEL_OUI,
0087             .subcmd = IWL_MVM_VENDOR_CMD_GET_CSME_CONN_INFO,
0088         },
0089         .doit = iwl_mvm_vendor_get_csme_conn_info,
0090         .flags = WIPHY_VENDOR_CMD_NEED_WDEV,
0091         .policy = iwl_mvm_vendor_attr_policy,
0092         .maxattr = MAX_IWL_MVM_VENDOR_ATTR,
0093     },
0094     {
0095         .info = {
0096             .vendor_id = INTEL_OUI,
0097             .subcmd = IWL_MVM_VENDOR_CMD_HOST_GET_OWNERSHIP,
0098         },
0099         .doit = iwl_mvm_vendor_host_get_ownership,
0100         .flags = WIPHY_VENDOR_CMD_NEED_WDEV,
0101         .policy = iwl_mvm_vendor_attr_policy,
0102         .maxattr = MAX_IWL_MVM_VENDOR_ATTR,
0103     },
0104 };
0105 
0106 enum iwl_mvm_vendor_events_idx {
0107         /* 0x0 - 0x3 are deprecated */
0108         IWL_MVM_VENDOR_EVENT_IDX_ROAMING_FORBIDDEN = 4,
0109         NUM_IWL_MVM_VENDOR_EVENT_IDX
0110 };
0111 
0112 static const struct nl80211_vendor_cmd_info
0113 iwl_mvm_vendor_events[NUM_IWL_MVM_VENDOR_EVENT_IDX] = {
0114     [IWL_MVM_VENDOR_EVENT_IDX_ROAMING_FORBIDDEN] = {
0115         .vendor_id = INTEL_OUI,
0116         .subcmd = IWL_MVM_VENDOR_CMD_ROAMING_FORBIDDEN_EVENT,
0117     },
0118 };
0119 
0120 void iwl_mvm_vendor_cmds_register(struct iwl_mvm *mvm)
0121 {
0122     mvm->hw->wiphy->vendor_commands = iwl_mvm_vendor_commands;
0123     mvm->hw->wiphy->n_vendor_commands = ARRAY_SIZE(iwl_mvm_vendor_commands);
0124     mvm->hw->wiphy->vendor_events = iwl_mvm_vendor_events;
0125     mvm->hw->wiphy->n_vendor_events = ARRAY_SIZE(iwl_mvm_vendor_events);
0126 }
0127 
0128 void iwl_mvm_send_roaming_forbidden_event(struct iwl_mvm *mvm,
0129                       struct ieee80211_vif *vif,
0130                       bool forbidden)
0131 {
0132     struct sk_buff *msg =
0133         cfg80211_vendor_event_alloc(mvm->hw->wiphy,
0134                         ieee80211_vif_to_wdev(vif),
0135                         200, IWL_MVM_VENDOR_EVENT_IDX_ROAMING_FORBIDDEN,
0136                         GFP_ATOMIC);
0137     if (!msg)
0138         return;
0139 
0140     if (WARN_ON(!vif))
0141         return;
0142 
0143     if (nla_put(msg, IWL_MVM_VENDOR_ATTR_VIF_ADDR,
0144             ETH_ALEN, vif->addr) ||
0145         nla_put_u8(msg, IWL_MVM_VENDOR_ATTR_ROAMING_FORBIDDEN, forbidden))
0146         goto nla_put_failure;
0147 
0148     cfg80211_vendor_event(msg, GFP_ATOMIC);
0149     return;
0150 
0151  nla_put_failure:
0152     kfree_skb(msg);
0153 }