1 /* 2 * Copyright (c) 2016-2018, 2020 The Linux Foundation. All rights reserved. 3 * 4 * Permission to use, copy, modify, and/or distribute this software for 5 * any purpose with or without fee is hereby granted, provided that the 6 * above copyright notice and this permission notice appear in all 7 * copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL 10 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 11 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE 12 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 13 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 14 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 15 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 16 * PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include "wmi_unified_action_oui_tlv.h" 20 #include "wmi_unified_priv.h" 21 22 bool wmi_get_action_oui_id(enum action_oui_id action_id, 23 wmi_vendor_oui_action_id *id) 24 { 25 switch (action_id) { 26 27 case ACTION_OUI_CONNECT_1X1: 28 *id = WMI_VENDOR_OUI_ACTION_CONNECTION_1X1; 29 return true; 30 31 case ACTION_OUI_ITO_EXTENSION: 32 *id = WMI_VENDOR_OUI_ACTION_ITO_EXTENSION; 33 return true; 34 35 case ACTION_OUI_CCKM_1X1: 36 *id = WMI_VENDOR_OUI_ACTION_CCKM_1X1; 37 return true; 38 39 case ACTION_OUI_ITO_ALTERNATE: 40 *id = WMI_VENDOR_OUI_ACTION_ALT_ITO; 41 return true; 42 43 case ACTION_OUI_SWITCH_TO_11N_MODE: 44 *id = WMI_VENDOR_OUI_ACTION_SWITCH_TO_11N_MODE; 45 return true; 46 47 case ACTION_OUI_CONNECT_1X1_WITH_1_CHAIN: 48 *id = WMI_VENDOR_OUI_ACTION_CONNECTION_1X1_NUM_TX_RX_CHAINS_1; 49 return true; 50 51 case ACTION_OUI_DISABLE_AGGRESSIVE_TX: 52 *id = WMI_VENDOR_OUI_ACTION_DISABLE_AGGRESSIVE_TX; 53 return true; 54 55 case ACTION_OUI_DISABLE_TWT: 56 *id = WMI_VENDOR_OUI_ACTION_DISABLE_FW_TRIGGERED_TWT; 57 return true; 58 59 default: 60 return false; 61 } 62 } 63 64 uint32_t wmi_get_action_oui_info_mask(uint32_t info_mask) 65 { 66 uint32_t info_presence = 0; 67 68 if (info_mask & ACTION_OUI_INFO_OUI) 69 info_presence |= WMI_BEACON_INFO_PRESENCE_OUI_EXT; 70 71 if (info_mask & ACTION_OUI_INFO_MAC_ADDRESS) 72 info_presence |= WMI_BEACON_INFO_PRESENCE_MAC_ADDRESS; 73 74 if (info_mask & ACTION_OUI_INFO_AP_CAPABILITY_NSS) 75 info_presence |= WMI_BEACON_INFO_PRESENCE_AP_CAPABILITY_NSS; 76 77 if (info_mask & ACTION_OUI_INFO_AP_CAPABILITY_HT) 78 info_presence |= WMI_BEACON_INFO_PRESENCE_AP_CAPABILITY_HT; 79 80 if (info_mask & ACTION_OUI_INFO_AP_CAPABILITY_VHT) 81 info_presence |= WMI_BEACON_INFO_PRESENCE_AP_CAPABILITY_VHT; 82 83 if (info_mask & ACTION_OUI_INFO_AP_CAPABILITY_BAND) 84 info_presence |= WMI_BEACON_INFO_PRESENCE_AP_CAPABILITY_BAND; 85 86 return info_presence; 87 } 88 89 void wmi_fill_oui_extensions(struct action_oui_extension *extension, 90 uint32_t no_oui_extns, 91 wmi_vendor_oui_ext *cmd_ext) 92 { 93 uint32_t i; 94 uint32_t buffer_length; 95 96 for (i = 0; i < no_oui_extns; i++) { 97 WMITLV_SET_HDR(&cmd_ext->tlv_header, 98 WMITLV_TAG_STRUC_wmi_vendor_oui_ext, 99 WMITLV_GET_STRUCT_TLVLEN(wmi_vendor_oui_ext)); 100 cmd_ext->info_presence_bit_mask = 101 wmi_get_action_oui_info_mask(extension->info_mask); 102 103 cmd_ext->oui_header_length = extension->oui_length; 104 cmd_ext->oui_data_length = extension->data_length; 105 cmd_ext->mac_address_length = extension->mac_addr_length; 106 cmd_ext->capability_data_length = 107 extension->capability_length; 108 109 buffer_length = extension->oui_length + 110 extension->data_length + 111 extension->data_mask_length + 112 extension->mac_addr_length + 113 extension->mac_mask_length + 114 extension->capability_length; 115 116 cmd_ext->buf_data_length = buffer_length + 1; 117 118 cmd_ext++; 119 extension++; 120 } 121 122 } 123 124 QDF_STATUS 125 wmi_fill_oui_extensions_buffer(struct action_oui_extension *extension, 126 wmi_vendor_oui_ext *cmd_ext, 127 uint32_t no_oui_extns, uint32_t rem_var_buf_len, 128 uint8_t *var_buf) 129 { 130 uint8_t i; 131 132 for (i = 0; i < (uint8_t)no_oui_extns; i++) { 133 if ((rem_var_buf_len - cmd_ext->buf_data_length) < 0) { 134 wmi_err("Invalid action oui command length"); 135 return QDF_STATUS_E_INVAL; 136 } 137 138 var_buf[0] = i; 139 var_buf++; 140 141 if (extension->oui_length) { 142 qdf_mem_copy(var_buf, extension->oui, 143 extension->oui_length); 144 var_buf += extension->oui_length; 145 } 146 147 if (extension->data_length) { 148 qdf_mem_copy(var_buf, extension->data, 149 extension->data_length); 150 var_buf += extension->data_length; 151 } 152 153 if (extension->data_mask_length) { 154 qdf_mem_copy(var_buf, extension->data_mask, 155 extension->data_mask_length); 156 var_buf += extension->data_mask_length; 157 } 158 159 if (extension->mac_addr_length) { 160 qdf_mem_copy(var_buf, extension->mac_addr, 161 extension->mac_addr_length); 162 var_buf += extension->mac_addr_length; 163 } 164 165 if (extension->mac_mask_length) { 166 qdf_mem_copy(var_buf, extension->mac_mask, 167 extension->mac_mask_length); 168 var_buf += extension->mac_mask_length; 169 } 170 171 if (extension->capability_length) { 172 qdf_mem_copy(var_buf, extension->capability, 173 extension->capability_length); 174 var_buf += extension->capability_length; 175 } 176 177 rem_var_buf_len -= cmd_ext->buf_data_length; 178 cmd_ext++; 179 extension++; 180 } 181 182 return QDF_STATUS_SUCCESS; 183 } 184 185 QDF_STATUS 186 send_action_oui_cmd_tlv(wmi_unified_t wmi_handle, 187 struct action_oui_request *req) 188 { 189 wmi_pdev_config_vendor_oui_action_fixed_param *cmd; 190 wmi_vendor_oui_ext *cmd_ext; 191 wmi_buf_t wmi_buf; 192 struct action_oui_extension *extension; 193 uint32_t len; 194 uint32_t i; 195 uint8_t *buf_ptr; 196 uint32_t no_oui_extns; 197 uint32_t total_no_oui_extns; 198 uint32_t var_buf_len = 0; 199 wmi_vendor_oui_action_id action_id; 200 bool valid; 201 uint32_t rem_var_buf_len; 202 QDF_STATUS status; 203 204 if (!req) { 205 wmi_err("action oui is empty"); 206 return QDF_STATUS_E_INVAL; 207 } 208 209 no_oui_extns = req->no_oui_extensions; 210 total_no_oui_extns = req->total_no_oui_extensions; 211 212 len = sizeof(*cmd); 213 len += WMI_TLV_HDR_SIZE; /* Array of wmi_vendor_oui_ext structures */ 214 215 if (!no_oui_extns || 216 no_oui_extns > WMI_MAX_VENDOR_OUI_ACTION_SUPPORTED_PER_ACTION || 217 (total_no_oui_extns > WMI_VENDOR_OUI_ACTION_MAX_ACTION_ID * 218 WMI_MAX_VENDOR_OUI_ACTION_SUPPORTED_PER_ACTION)) { 219 wmi_err("Invalid number of action oui extensions"); 220 return QDF_STATUS_E_INVAL; 221 } 222 223 valid = wmi_get_action_oui_id(req->action_id, &action_id); 224 if (!valid) { 225 wmi_err("Invalid action id"); 226 return QDF_STATUS_E_INVAL; 227 } 228 229 len += no_oui_extns * sizeof(*cmd_ext); 230 len += WMI_TLV_HDR_SIZE; /* Variable length buffer */ 231 232 extension = req->extension; 233 for (i = 0; i < no_oui_extns; i++) { 234 var_buf_len += extension->oui_length + 235 extension->data_length + 236 extension->data_mask_length + 237 extension->mac_addr_length + 238 extension->mac_mask_length + 239 extension->capability_length; 240 extension++; 241 } 242 243 var_buf_len += no_oui_extns; /* to store indexes */ 244 rem_var_buf_len = var_buf_len; 245 var_buf_len = (var_buf_len + 3) & ~0x3; 246 len += var_buf_len; 247 248 wmi_buf = wmi_buf_alloc(wmi_handle, len); 249 if (!wmi_buf) { 250 wmi_err("Failed to allocate wmi buffer"); 251 return QDF_STATUS_E_FAILURE; 252 } 253 254 buf_ptr = (uint8_t *)wmi_buf_data(wmi_buf); 255 cmd = (wmi_pdev_config_vendor_oui_action_fixed_param *)buf_ptr; 256 257 WMITLV_SET_HDR(&cmd->tlv_header, 258 WMITLV_TAG_STRUC_wmi_pdev_config_vendor_oui_action_fixed_param, 259 WMITLV_GET_STRUCT_TLVLEN( 260 wmi_pdev_config_vendor_oui_action_fixed_param)); 261 262 cmd->action_id = action_id; 263 cmd->total_num_vendor_oui = total_no_oui_extns; 264 cmd->num_vendor_oui_ext = no_oui_extns; 265 266 buf_ptr += sizeof(*cmd); 267 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, 268 no_oui_extns * sizeof(*cmd_ext)); 269 buf_ptr += WMI_TLV_HDR_SIZE; 270 cmd_ext = (wmi_vendor_oui_ext *)buf_ptr; 271 wmi_fill_oui_extensions(req->extension, no_oui_extns, cmd_ext); 272 273 buf_ptr += no_oui_extns * sizeof(*cmd_ext); 274 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE, var_buf_len); 275 buf_ptr += WMI_TLV_HDR_SIZE; 276 status = wmi_fill_oui_extensions_buffer(req->extension, 277 cmd_ext, no_oui_extns, 278 rem_var_buf_len, buf_ptr); 279 if (!QDF_IS_STATUS_SUCCESS(status)) { 280 wmi_buf_free(wmi_buf); 281 wmi_buf = NULL; 282 return QDF_STATUS_E_INVAL; 283 } 284 285 buf_ptr += var_buf_len; 286 287 if (wmi_unified_cmd_send(wmi_handle, wmi_buf, len, 288 WMI_PDEV_CONFIG_VENDOR_OUI_ACTION_CMDID)) { 289 wmi_err("WMI_PDEV_CONFIG_VENDOR_OUI_ACTION send fail"); 290 wmi_buf_free(wmi_buf); 291 wmi_buf = NULL; 292 return QDF_STATUS_E_FAILURE; 293 } 294 295 return QDF_STATUS_SUCCESS; 296 } 297