1/* 2 * This file is part of wlcore 3 * 4 * Copyright (C) 2014 Texas Instruments. All rights reserved. 5 * 6 * This program is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU General Public License 8 * version 2 as published by the Free Software Foundation. 9 */ 10 11#include <net/mac80211.h> 12#include <net/netlink.h> 13 14#include "wlcore.h" 15#include "debug.h" 16#include "ps.h" 17#include "hw_ops.h" 18#include "vendor_cmd.h" 19 20static const 21struct nla_policy wlcore_vendor_attr_policy[NUM_WLCORE_VENDOR_ATTR] = { 22 [WLCORE_VENDOR_ATTR_FREQ] = { .type = NLA_U32 }, 23 [WLCORE_VENDOR_ATTR_GROUP_ID] = { .type = NLA_U32 }, 24 [WLCORE_VENDOR_ATTR_GROUP_KEY] = { .type = NLA_BINARY, 25 .len = WLAN_MAX_KEY_LEN }, 26}; 27 28static int 29wlcore_vendor_cmd_smart_config_start(struct wiphy *wiphy, 30 struct wireless_dev *wdev, 31 const void *data, int data_len) 32{ 33 struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); 34 struct wl1271 *wl = hw->priv; 35 struct nlattr *tb[NUM_WLCORE_VENDOR_ATTR]; 36 int ret; 37 38 wl1271_debug(DEBUG_CMD, "vendor cmd smart config start"); 39 40 if (!data) 41 return -EINVAL; 42 43 ret = nla_parse(tb, MAX_WLCORE_VENDOR_ATTR, data, data_len, 44 wlcore_vendor_attr_policy); 45 if (ret) 46 return ret; 47 48 if (!tb[WLCORE_VENDOR_ATTR_GROUP_ID]) 49 return -EINVAL; 50 51 mutex_lock(&wl->mutex); 52 53 if (unlikely(wl->state != WLCORE_STATE_ON)) { 54 ret = -EINVAL; 55 goto out; 56 } 57 58 ret = wl1271_ps_elp_wakeup(wl); 59 if (ret < 0) 60 goto out; 61 62 ret = wlcore_smart_config_start(wl, 63 nla_get_u32(tb[WLCORE_VENDOR_ATTR_GROUP_ID])); 64 65 wl1271_ps_elp_sleep(wl); 66out: 67 mutex_unlock(&wl->mutex); 68 69 return 0; 70} 71 72static int 73wlcore_vendor_cmd_smart_config_stop(struct wiphy *wiphy, 74 struct wireless_dev *wdev, 75 const void *data, int data_len) 76{ 77 struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); 78 struct wl1271 *wl = hw->priv; 79 int ret; 80 81 wl1271_debug(DEBUG_CMD, "testmode cmd smart config stop"); 82 83 mutex_lock(&wl->mutex); 84 85 if (unlikely(wl->state != WLCORE_STATE_ON)) { 86 ret = -EINVAL; 87 goto out; 88 } 89 90 ret = wl1271_ps_elp_wakeup(wl); 91 if (ret < 0) 92 goto out; 93 94 ret = wlcore_smart_config_stop(wl); 95 96 wl1271_ps_elp_sleep(wl); 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(tb, MAX_WLCORE_VENDOR_ATTR, data, data_len, 119 wlcore_vendor_attr_policy); 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 = wl1271_ps_elp_wakeup(wl); 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 wl1271_ps_elp_sleep(wl); 144out: 145 mutex_unlock(&wl->mutex); 146 147 return ret; 148} 149 150static const struct wiphy_vendor_command wlcore_vendor_commands[] = { 151 { 152 .info = { 153 .vendor_id = TI_OUI, 154 .subcmd = WLCORE_VENDOR_CMD_SMART_CONFIG_START, 155 }, 156 .flags = WIPHY_VENDOR_CMD_NEED_NETDEV | 157 WIPHY_VENDOR_CMD_NEED_RUNNING, 158 .doit = wlcore_vendor_cmd_smart_config_start, 159 }, 160 { 161 .info = { 162 .vendor_id = TI_OUI, 163 .subcmd = WLCORE_VENDOR_CMD_SMART_CONFIG_STOP, 164 }, 165 .flags = WIPHY_VENDOR_CMD_NEED_NETDEV | 166 WIPHY_VENDOR_CMD_NEED_RUNNING, 167 .doit = wlcore_vendor_cmd_smart_config_stop, 168 }, 169 { 170 .info = { 171 .vendor_id = TI_OUI, 172 .subcmd = WLCORE_VENDOR_CMD_SMART_CONFIG_SET_GROUP_KEY, 173 }, 174 .flags = WIPHY_VENDOR_CMD_NEED_NETDEV | 175 WIPHY_VENDOR_CMD_NEED_RUNNING, 176 .doit = wlcore_vendor_cmd_smart_config_set_group_key, 177 }, 178}; 179 180static const struct nl80211_vendor_cmd_info wlcore_vendor_events[] = { 181 { 182 .vendor_id = TI_OUI, 183 .subcmd = WLCORE_VENDOR_EVENT_SC_SYNC, 184 }, 185 { 186 .vendor_id = TI_OUI, 187 .subcmd = WLCORE_VENDOR_EVENT_SC_DECODE, 188 }, 189}; 190 191void wlcore_set_vendor_commands(struct wiphy *wiphy) 192{ 193 wiphy->vendor_commands = wlcore_vendor_commands; 194 wiphy->n_vendor_commands = ARRAY_SIZE(wlcore_vendor_commands); 195 wiphy->vendor_events = wlcore_vendor_events; 196 wiphy->n_vendor_events = ARRAY_SIZE(wlcore_vendor_events); 197} 198