vendor_cmd.c (4712B)
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 18static const 19struct 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 26static int 27wlcore_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); 65out: 66 mutex_unlock(&wl->mutex); 67 68 return ret; 69} 70 71static int 72wlcore_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); 97out: 98 mutex_unlock(&wl->mutex); 99 100 return ret; 101} 102 103static int 104wlcore_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); 145out: 146 mutex_unlock(&wl->mutex); 147 148 return ret; 149} 150 151static 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 184static 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 195void 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}