1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (C) 2021 Intel Corporation 4 */ 5 #include "mvm.h" 6 #include <linux/nl80211-vnd-intel.h> 7 #include <net/netlink.h> 8 9 static const struct nla_policy 10 iwl_mvm_vendor_attr_policy[NUM_IWL_MVM_VENDOR_ATTR] = { 11 [IWL_MVM_VENDOR_ATTR_ROAMING_FORBIDDEN] = { .type = NLA_U8 }, 12 [IWL_MVM_VENDOR_ATTR_AUTH_MODE] = { .type = NLA_U32 }, 13 [IWL_MVM_VENDOR_ATTR_CHANNEL_NUM] = { .type = NLA_U8 }, 14 [IWL_MVM_VENDOR_ATTR_SSID] = { .type = NLA_BINARY, 15 .len = IEEE80211_MAX_SSID_LEN }, 16 [IWL_MVM_VENDOR_ATTR_BAND] = { .type = NLA_U8 }, 17 [IWL_MVM_VENDOR_ATTR_COLLOC_CHANNEL] = { .type = NLA_U8 }, 18 [IWL_MVM_VENDOR_ATTR_COLLOC_ADDR] = { .type = NLA_BINARY, .len = ETH_ALEN }, 19 }; 20 21 static int iwl_mvm_vendor_get_csme_conn_info(struct wiphy *wiphy, 22 struct wireless_dev *wdev, 23 const void *data, int data_len) 24 { 25 struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); 26 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); 27 struct iwl_mvm_csme_conn_info *csme_conn_info; 28 struct sk_buff *skb; 29 int err = 0; 30 31 mutex_lock(&mvm->mutex); 32 csme_conn_info = iwl_mvm_get_csme_conn_info(mvm); 33 34 if (!csme_conn_info) { 35 err = -EINVAL; 36 goto out_unlock; 37 } 38 39 skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, 200); 40 if (!skb) { 41 err = -ENOMEM; 42 goto out_unlock; 43 } 44 45 if (nla_put_u32(skb, IWL_MVM_VENDOR_ATTR_AUTH_MODE, 46 csme_conn_info->conn_info.auth_mode) || 47 nla_put(skb, IWL_MVM_VENDOR_ATTR_SSID, 48 csme_conn_info->conn_info.ssid_len, 49 csme_conn_info->conn_info.ssid) || 50 nla_put_u32(skb, IWL_MVM_VENDOR_ATTR_STA_CIPHER, 51 csme_conn_info->conn_info.pairwise_cipher) || 52 nla_put_u8(skb, IWL_MVM_VENDOR_ATTR_CHANNEL_NUM, 53 csme_conn_info->conn_info.channel) || 54 nla_put(skb, IWL_MVM_VENDOR_ATTR_ADDR, ETH_ALEN, 55 csme_conn_info->conn_info.bssid)) { 56 kfree_skb(skb); 57 err = -ENOBUFS; 58 } 59 60 out_unlock: 61 mutex_unlock(&mvm->mutex); 62 if (err) 63 return err; 64 65 return cfg80211_vendor_cmd_reply(skb); 66 } 67 68 static int iwl_mvm_vendor_host_get_ownership(struct wiphy *wiphy, 69 struct wireless_dev *wdev, 70 const void *data, int data_len) 71 { 72 struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); 73 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); 74 75 mutex_lock(&mvm->mutex); 76 iwl_mvm_mei_get_ownership(mvm); 77 mutex_unlock(&mvm->mutex); 78 79 return 0; 80 } 81 82 static const struct wiphy_vendor_command iwl_mvm_vendor_commands[] = { 83 { 84 .info = { 85 .vendor_id = INTEL_OUI, 86 .subcmd = IWL_MVM_VENDOR_CMD_GET_CSME_CONN_INFO, 87 }, 88 .doit = iwl_mvm_vendor_get_csme_conn_info, 89 .flags = WIPHY_VENDOR_CMD_NEED_WDEV, 90 .policy = iwl_mvm_vendor_attr_policy, 91 .maxattr = MAX_IWL_MVM_VENDOR_ATTR, 92 }, 93 { 94 .info = { 95 .vendor_id = INTEL_OUI, 96 .subcmd = IWL_MVM_VENDOR_CMD_HOST_GET_OWNERSHIP, 97 }, 98 .doit = iwl_mvm_vendor_host_get_ownership, 99 .flags = WIPHY_VENDOR_CMD_NEED_WDEV, 100 .policy = iwl_mvm_vendor_attr_policy, 101 .maxattr = MAX_IWL_MVM_VENDOR_ATTR, 102 }, 103 }; 104 105 enum iwl_mvm_vendor_events_idx { 106 /* 0x0 - 0x3 are deprecated */ 107 IWL_MVM_VENDOR_EVENT_IDX_ROAMING_FORBIDDEN = 4, 108 NUM_IWL_MVM_VENDOR_EVENT_IDX 109 }; 110 111 static const struct nl80211_vendor_cmd_info 112 iwl_mvm_vendor_events[NUM_IWL_MVM_VENDOR_EVENT_IDX] = { 113 [IWL_MVM_VENDOR_EVENT_IDX_ROAMING_FORBIDDEN] = { 114 .vendor_id = INTEL_OUI, 115 .subcmd = IWL_MVM_VENDOR_CMD_ROAMING_FORBIDDEN_EVENT, 116 }, 117 }; 118 119 void iwl_mvm_vendor_cmds_register(struct iwl_mvm *mvm) 120 { 121 mvm->hw->wiphy->vendor_commands = iwl_mvm_vendor_commands; 122 mvm->hw->wiphy->n_vendor_commands = ARRAY_SIZE(iwl_mvm_vendor_commands); 123 mvm->hw->wiphy->vendor_events = iwl_mvm_vendor_events; 124 mvm->hw->wiphy->n_vendor_events = ARRAY_SIZE(iwl_mvm_vendor_events); 125 } 126 127 void iwl_mvm_send_roaming_forbidden_event(struct iwl_mvm *mvm, 128 struct ieee80211_vif *vif, 129 bool forbidden) 130 { 131 struct sk_buff *msg = 132 cfg80211_vendor_event_alloc(mvm->hw->wiphy, 133 ieee80211_vif_to_wdev(vif), 134 200, IWL_MVM_VENDOR_EVENT_IDX_ROAMING_FORBIDDEN, 135 GFP_ATOMIC); 136 if (!msg) 137 return; 138 139 if (WARN_ON(!vif)) 140 return; 141 142 if (nla_put(msg, IWL_MVM_VENDOR_ATTR_VIF_ADDR, 143 ETH_ALEN, vif->addr) || 144 nla_put_u8(msg, IWL_MVM_VENDOR_ATTR_ROAMING_FORBIDDEN, forbidden)) 145 goto nla_put_failure; 146 147 cfg80211_vendor_event(msg, GFP_ATOMIC); 148 return; 149 150 nla_put_failure: 151 kfree_skb(msg); 152 } 153