1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * This file is part of wlcore
4 *
5 * Copyright (C) 2014 Texas Instruments. All rights reserved.
6 */
7
8 #include <linux/pm_runtime.h>
9
10 #include <net/mac80211.h>
11 #include <net/netlink.h>
12
13 #include "wlcore.h"
14 #include "debug.h"
15 #include "hw_ops.h"
16 #include "vendor_cmd.h"
17
18 static const
19 struct nla_policy wlcore_vendor_attr_policy[NUM_WLCORE_VENDOR_ATTR] = {
20 [WLCORE_VENDOR_ATTR_FREQ] = { .type = NLA_U32 },
21 [WLCORE_VENDOR_ATTR_GROUP_ID] = { .type = NLA_U32 },
22 [WLCORE_VENDOR_ATTR_GROUP_KEY] = { .type = NLA_BINARY,
23 .len = WLAN_MAX_KEY_LEN },
24 };
25
26 static int
wlcore_vendor_cmd_smart_config_start(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)27 wlcore_vendor_cmd_smart_config_start(struct wiphy *wiphy,
28 struct wireless_dev *wdev,
29 const void *data, int data_len)
30 {
31 struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
32 struct wl1271 *wl = hw->priv;
33 struct nlattr *tb[NUM_WLCORE_VENDOR_ATTR];
34 int ret;
35
36 wl1271_debug(DEBUG_CMD, "vendor cmd smart config start");
37
38 if (!data)
39 return -EINVAL;
40
41 ret = nla_parse_deprecated(tb, MAX_WLCORE_VENDOR_ATTR, data, data_len,
42 wlcore_vendor_attr_policy, NULL);
43 if (ret)
44 return ret;
45
46 if (!tb[WLCORE_VENDOR_ATTR_GROUP_ID])
47 return -EINVAL;
48
49 mutex_lock(&wl->mutex);
50
51 if (unlikely(wl->state != WLCORE_STATE_ON)) {
52 ret = -EINVAL;
53 goto out;
54 }
55
56 ret = pm_runtime_resume_and_get(wl->dev);
57 if (ret < 0)
58 goto out;
59
60 ret = wlcore_smart_config_start(wl,
61 nla_get_u32(tb[WLCORE_VENDOR_ATTR_GROUP_ID]));
62
63 pm_runtime_mark_last_busy(wl->dev);
64 pm_runtime_put_autosuspend(wl->dev);
65 out:
66 mutex_unlock(&wl->mutex);
67
68 return ret;
69 }
70
71 static int
wlcore_vendor_cmd_smart_config_stop(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)72 wlcore_vendor_cmd_smart_config_stop(struct wiphy *wiphy,
73 struct wireless_dev *wdev,
74 const void *data, int data_len)
75 {
76 struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
77 struct wl1271 *wl = hw->priv;
78 int ret;
79
80 wl1271_debug(DEBUG_CMD, "testmode cmd smart config stop");
81
82 mutex_lock(&wl->mutex);
83
84 if (unlikely(wl->state != WLCORE_STATE_ON)) {
85 ret = -EINVAL;
86 goto out;
87 }
88
89 ret = pm_runtime_resume_and_get(wl->dev);
90 if (ret < 0)
91 goto out;
92
93 ret = wlcore_smart_config_stop(wl);
94
95 pm_runtime_mark_last_busy(wl->dev);
96 pm_runtime_put_autosuspend(wl->dev);
97 out:
98 mutex_unlock(&wl->mutex);
99
100 return ret;
101 }
102
103 static int
wlcore_vendor_cmd_smart_config_set_group_key(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)104 wlcore_vendor_cmd_smart_config_set_group_key(struct wiphy *wiphy,
105 struct wireless_dev *wdev,
106 const void *data, int data_len)
107 {
108 struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
109 struct wl1271 *wl = hw->priv;
110 struct nlattr *tb[NUM_WLCORE_VENDOR_ATTR];
111 int ret;
112
113 wl1271_debug(DEBUG_CMD, "testmode cmd smart config set group key");
114
115 if (!data)
116 return -EINVAL;
117
118 ret = nla_parse_deprecated(tb, MAX_WLCORE_VENDOR_ATTR, data, data_len,
119 wlcore_vendor_attr_policy, NULL);
120 if (ret)
121 return ret;
122
123 if (!tb[WLCORE_VENDOR_ATTR_GROUP_ID] ||
124 !tb[WLCORE_VENDOR_ATTR_GROUP_KEY])
125 return -EINVAL;
126
127 mutex_lock(&wl->mutex);
128
129 if (unlikely(wl->state != WLCORE_STATE_ON)) {
130 ret = -EINVAL;
131 goto out;
132 }
133
134 ret = pm_runtime_resume_and_get(wl->dev);
135 if (ret < 0)
136 goto out;
137
138 ret = wlcore_smart_config_set_group_key(wl,
139 nla_get_u32(tb[WLCORE_VENDOR_ATTR_GROUP_ID]),
140 nla_len(tb[WLCORE_VENDOR_ATTR_GROUP_KEY]),
141 nla_data(tb[WLCORE_VENDOR_ATTR_GROUP_KEY]));
142
143 pm_runtime_mark_last_busy(wl->dev);
144 pm_runtime_put_autosuspend(wl->dev);
145 out:
146 mutex_unlock(&wl->mutex);
147
148 return ret;
149 }
150
151 static const struct wiphy_vendor_command wlcore_vendor_commands[] = {
152 {
153 .info = {
154 .vendor_id = TI_OUI,
155 .subcmd = WLCORE_VENDOR_CMD_SMART_CONFIG_START,
156 },
157 .flags = WIPHY_VENDOR_CMD_NEED_NETDEV |
158 WIPHY_VENDOR_CMD_NEED_RUNNING,
159 .doit = wlcore_vendor_cmd_smart_config_start,
160 .policy = wlcore_vendor_attr_policy,
161 },
162 {
163 .info = {
164 .vendor_id = TI_OUI,
165 .subcmd = WLCORE_VENDOR_CMD_SMART_CONFIG_STOP,
166 },
167 .flags = WIPHY_VENDOR_CMD_NEED_NETDEV |
168 WIPHY_VENDOR_CMD_NEED_RUNNING,
169 .doit = wlcore_vendor_cmd_smart_config_stop,
170 .policy = wlcore_vendor_attr_policy,
171 },
172 {
173 .info = {
174 .vendor_id = TI_OUI,
175 .subcmd = WLCORE_VENDOR_CMD_SMART_CONFIG_SET_GROUP_KEY,
176 },
177 .flags = WIPHY_VENDOR_CMD_NEED_NETDEV |
178 WIPHY_VENDOR_CMD_NEED_RUNNING,
179 .doit = wlcore_vendor_cmd_smart_config_set_group_key,
180 .policy = wlcore_vendor_attr_policy,
181 },
182 };
183
184 static const struct nl80211_vendor_cmd_info wlcore_vendor_events[] = {
185 {
186 .vendor_id = TI_OUI,
187 .subcmd = WLCORE_VENDOR_EVENT_SC_SYNC,
188 },
189 {
190 .vendor_id = TI_OUI,
191 .subcmd = WLCORE_VENDOR_EVENT_SC_DECODE,
192 },
193 };
194
wlcore_set_vendor_commands(struct wiphy * wiphy)195 void wlcore_set_vendor_commands(struct wiphy *wiphy)
196 {
197 wiphy->vendor_commands = wlcore_vendor_commands;
198 wiphy->n_vendor_commands = ARRAY_SIZE(wlcore_vendor_commands);
199 wiphy->vendor_events = wlcore_vendor_events;
200 wiphy->n_vendor_events = ARRAY_SIZE(wlcore_vendor_events);
201 }
202