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_get_sync(wl->dev); 57 if (ret < 0) { 58 pm_runtime_put_noidle(wl->dev); 59 goto out; 60 } 61 62 ret = wlcore_smart_config_start(wl, 63 nla_get_u32(tb[WLCORE_VENDOR_ATTR_GROUP_ID])); 64 65 pm_runtime_mark_last_busy(wl->dev); 66 pm_runtime_put_autosuspend(wl->dev); 67 out: 68 mutex_unlock(&wl->mutex); 69 70 return ret; 71 } 72 73 static int 74 wlcore_vendor_cmd_smart_config_stop(struct wiphy *wiphy, 75 struct wireless_dev *wdev, 76 const void *data, int data_len) 77 { 78 struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); 79 struct wl1271 *wl = hw->priv; 80 int ret; 81 82 wl1271_debug(DEBUG_CMD, "testmode cmd smart config stop"); 83 84 mutex_lock(&wl->mutex); 85 86 if (unlikely(wl->state != WLCORE_STATE_ON)) { 87 ret = -EINVAL; 88 goto out; 89 } 90 91 ret = pm_runtime_get_sync(wl->dev); 92 if (ret < 0) { 93 pm_runtime_put_noidle(wl->dev); 94 goto out; 95 } 96 97 ret = wlcore_smart_config_stop(wl); 98 99 pm_runtime_mark_last_busy(wl->dev); 100 pm_runtime_put_autosuspend(wl->dev); 101 out: 102 mutex_unlock(&wl->mutex); 103 104 return ret; 105 } 106 107 static int 108 wlcore_vendor_cmd_smart_config_set_group_key(struct wiphy *wiphy, 109 struct wireless_dev *wdev, 110 const void *data, int data_len) 111 { 112 struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); 113 struct wl1271 *wl = hw->priv; 114 struct nlattr *tb[NUM_WLCORE_VENDOR_ATTR]; 115 int ret; 116 117 wl1271_debug(DEBUG_CMD, "testmode cmd smart config set group key"); 118 119 if (!data) 120 return -EINVAL; 121 122 ret = nla_parse_deprecated(tb, MAX_WLCORE_VENDOR_ATTR, data, data_len, 123 wlcore_vendor_attr_policy, NULL); 124 if (ret) 125 return ret; 126 127 if (!tb[WLCORE_VENDOR_ATTR_GROUP_ID] || 128 !tb[WLCORE_VENDOR_ATTR_GROUP_KEY]) 129 return -EINVAL; 130 131 mutex_lock(&wl->mutex); 132 133 if (unlikely(wl->state != WLCORE_STATE_ON)) { 134 ret = -EINVAL; 135 goto out; 136 } 137 138 ret = pm_runtime_get_sync(wl->dev); 139 if (ret < 0) { 140 pm_runtime_put_noidle(wl->dev); 141 goto out; 142 } 143 144 ret = wlcore_smart_config_set_group_key(wl, 145 nla_get_u32(tb[WLCORE_VENDOR_ATTR_GROUP_ID]), 146 nla_len(tb[WLCORE_VENDOR_ATTR_GROUP_KEY]), 147 nla_data(tb[WLCORE_VENDOR_ATTR_GROUP_KEY])); 148 149 pm_runtime_mark_last_busy(wl->dev); 150 pm_runtime_put_autosuspend(wl->dev); 151 out: 152 mutex_unlock(&wl->mutex); 153 154 return ret; 155 } 156 157 static const struct wiphy_vendor_command wlcore_vendor_commands[] = { 158 { 159 .info = { 160 .vendor_id = TI_OUI, 161 .subcmd = WLCORE_VENDOR_CMD_SMART_CONFIG_START, 162 }, 163 .flags = WIPHY_VENDOR_CMD_NEED_NETDEV | 164 WIPHY_VENDOR_CMD_NEED_RUNNING, 165 .doit = wlcore_vendor_cmd_smart_config_start, 166 }, 167 { 168 .info = { 169 .vendor_id = TI_OUI, 170 .subcmd = WLCORE_VENDOR_CMD_SMART_CONFIG_STOP, 171 }, 172 .flags = WIPHY_VENDOR_CMD_NEED_NETDEV | 173 WIPHY_VENDOR_CMD_NEED_RUNNING, 174 .doit = wlcore_vendor_cmd_smart_config_stop, 175 }, 176 { 177 .info = { 178 .vendor_id = TI_OUI, 179 .subcmd = WLCORE_VENDOR_CMD_SMART_CONFIG_SET_GROUP_KEY, 180 }, 181 .flags = WIPHY_VENDOR_CMD_NEED_NETDEV | 182 WIPHY_VENDOR_CMD_NEED_RUNNING, 183 .doit = wlcore_vendor_cmd_smart_config_set_group_key, 184 }, 185 }; 186 187 static const struct nl80211_vendor_cmd_info wlcore_vendor_events[] = { 188 { 189 .vendor_id = TI_OUI, 190 .subcmd = WLCORE_VENDOR_EVENT_SC_SYNC, 191 }, 192 { 193 .vendor_id = TI_OUI, 194 .subcmd = WLCORE_VENDOR_EVENT_SC_DECODE, 195 }, 196 }; 197 198 void wlcore_set_vendor_commands(struct wiphy *wiphy) 199 { 200 wiphy->vendor_commands = wlcore_vendor_commands; 201 wiphy->n_vendor_commands = ARRAY_SIZE(wlcore_vendor_commands); 202 wiphy->vendor_events = wlcore_vendor_events; 203 wiphy->n_vendor_events = ARRAY_SIZE(wlcore_vendor_events); 204 } 205