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
9static const struct nla_policy
10iwl_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
21static 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, approxlen: 200);
40 if (!skb) {
41 err = -ENOMEM;
42 goto out_unlock;
43 }
44
45 if (nla_put_u32(skb, attrtype: IWL_MVM_VENDOR_ATTR_AUTH_MODE,
46 value: csme_conn_info->conn_info.auth_mode) ||
47 nla_put(skb, attrtype: IWL_MVM_VENDOR_ATTR_SSID,
48 attrlen: csme_conn_info->conn_info.ssid_len,
49 data: csme_conn_info->conn_info.ssid) ||
50 nla_put_u32(skb, attrtype: IWL_MVM_VENDOR_ATTR_STA_CIPHER,
51 value: csme_conn_info->conn_info.pairwise_cipher) ||
52 nla_put_u8(skb, attrtype: IWL_MVM_VENDOR_ATTR_CHANNEL_NUM,
53 value: csme_conn_info->conn_info.channel) ||
54 nla_put(skb, attrtype: IWL_MVM_VENDOR_ATTR_ADDR, ETH_ALEN,
55 data: csme_conn_info->conn_info.bssid)) {
56 kfree_skb(skb);
57 err = -ENOBUFS;
58 }
59
60out_unlock:
61 mutex_unlock(lock: &mvm->mutex);
62 if (err)
63 return err;
64
65 return cfg80211_vendor_cmd_reply(skb);
66}
67
68static 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 int ret;
75
76 mutex_lock(&mvm->mutex);
77 ret = iwl_mvm_mei_get_ownership(mvm);
78 mutex_unlock(lock: &mvm->mutex);
79
80 return ret;
81}
82
83static const struct wiphy_vendor_command iwl_mvm_vendor_commands[] = {
84 {
85 .info = {
86 .vendor_id = INTEL_OUI,
87 .subcmd = IWL_MVM_VENDOR_CMD_GET_CSME_CONN_INFO,
88 },
89 .doit = iwl_mvm_vendor_get_csme_conn_info,
90 .flags = WIPHY_VENDOR_CMD_NEED_WDEV,
91 .policy = iwl_mvm_vendor_attr_policy,
92 .maxattr = MAX_IWL_MVM_VENDOR_ATTR,
93 },
94 {
95 .info = {
96 .vendor_id = INTEL_OUI,
97 .subcmd = IWL_MVM_VENDOR_CMD_HOST_GET_OWNERSHIP,
98 },
99 .doit = iwl_mvm_vendor_host_get_ownership,
100 .flags = WIPHY_VENDOR_CMD_NEED_WDEV,
101 .policy = iwl_mvm_vendor_attr_policy,
102 .maxattr = MAX_IWL_MVM_VENDOR_ATTR,
103 },
104};
105
106enum iwl_mvm_vendor_events_idx {
107 /* 0x0 - 0x3 are deprecated */
108 IWL_MVM_VENDOR_EVENT_IDX_ROAMING_FORBIDDEN = 4,
109 NUM_IWL_MVM_VENDOR_EVENT_IDX
110};
111
112static const struct nl80211_vendor_cmd_info
113iwl_mvm_vendor_events[NUM_IWL_MVM_VENDOR_EVENT_IDX] = {
114 [IWL_MVM_VENDOR_EVENT_IDX_ROAMING_FORBIDDEN] = {
115 .vendor_id = INTEL_OUI,
116 .subcmd = IWL_MVM_VENDOR_CMD_ROAMING_FORBIDDEN_EVENT,
117 },
118};
119
120void iwl_mvm_vendor_cmds_register(struct iwl_mvm *mvm)
121{
122 mvm->hw->wiphy->vendor_commands = iwl_mvm_vendor_commands;
123 mvm->hw->wiphy->n_vendor_commands = ARRAY_SIZE(iwl_mvm_vendor_commands);
124 mvm->hw->wiphy->vendor_events = iwl_mvm_vendor_events;
125 mvm->hw->wiphy->n_vendor_events = ARRAY_SIZE(iwl_mvm_vendor_events);
126}
127
128void iwl_mvm_send_roaming_forbidden_event(struct iwl_mvm *mvm,
129 struct ieee80211_vif *vif,
130 bool forbidden)
131{
132 struct sk_buff *msg =
133 cfg80211_vendor_event_alloc(wiphy: mvm->hw->wiphy,
134 wdev: ieee80211_vif_to_wdev(vif),
135 approxlen: 200, event_idx: IWL_MVM_VENDOR_EVENT_IDX_ROAMING_FORBIDDEN,
136 GFP_ATOMIC);
137 if (!msg)
138 return;
139
140 if (WARN_ON(!vif))
141 return;
142
143 if (nla_put(skb: msg, attrtype: IWL_MVM_VENDOR_ATTR_VIF_ADDR,
144 ETH_ALEN, data: vif->addr) ||
145 nla_put_u8(skb: msg, attrtype: IWL_MVM_VENDOR_ATTR_ROAMING_FORBIDDEN, value: forbidden))
146 goto nla_put_failure;
147
148 cfg80211_vendor_event(skb: msg, GFP_ATOMIC);
149 return;
150
151 nla_put_failure:
152 kfree_skb(skb: msg);
153}
154

source code of linux/drivers/net/wireless/intel/iwlwifi/mvm/vendor-cmd.c