Merge tag '6.10-rc-smb3-fixes-part2' of git://git.samba.org/sfrench/cifs-2.6
[sfrench/cifs-2.6.git] / drivers / net / wireless / ti / wlcore / vendor_cmd.c
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
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
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
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
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 }