1 /* 2 * Copyright (c) 2018-2019 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 <osdep.h> 20 #include "wmi.h" 21 #include "wmi_unified_priv.h" 22 #include "wmi_unified_pmo_api.h" 23 24 #ifdef FEATURE_WLAN_D0WOW 25 /** 26 * send_d0wow_enable_cmd_tlv() - WMI d0 wow enable function 27 * @param wmi_handle: handle to WMI. 28 * @mac_id: radio context 29 * 30 * Return: 0 on success and error code on failure. 31 */ 32 static QDF_STATUS send_d0wow_enable_cmd_tlv(wmi_unified_t wmi_handle, 33 uint8_t mac_id) 34 { 35 wmi_d0_wow_enable_disable_cmd_fixed_param *cmd; 36 wmi_buf_t buf; 37 int32_t len; 38 QDF_STATUS status; 39 40 len = sizeof(wmi_d0_wow_enable_disable_cmd_fixed_param); 41 42 buf = wmi_buf_alloc(wmi_handle, len); 43 if (!buf) { 44 return QDF_STATUS_E_NOMEM; 45 } 46 cmd = (wmi_d0_wow_enable_disable_cmd_fixed_param *) wmi_buf_data(buf); 47 WMITLV_SET_HDR(&cmd->tlv_header, 48 WMITLV_TAG_STRUC_wmi_d0_wow_enable_disable_cmd_fixed_param, 49 WMITLV_GET_STRUCT_TLVLEN 50 (wmi_d0_wow_enable_disable_cmd_fixed_param)); 51 52 cmd->enable = true; 53 54 wmi_mtrace(WMI_D0_WOW_ENABLE_DISABLE_CMDID, NO_SESSION, 0); 55 status = wmi_unified_cmd_send(wmi_handle, buf, len, 56 WMI_D0_WOW_ENABLE_DISABLE_CMDID); 57 if (QDF_IS_STATUS_ERROR(status)) 58 wmi_buf_free(buf); 59 60 return status; 61 } 62 63 /** 64 * send_d0wow_disable_cmd_tlv() - WMI d0 wow disable function 65 * @param wmi_handle: handle to WMI. 66 * @mac_id: radio context 67 * 68 * Return: 0 on success and error code on failure. 69 */ 70 static QDF_STATUS send_d0wow_disable_cmd_tlv(wmi_unified_t wmi_handle, 71 uint8_t mac_id) 72 { 73 wmi_d0_wow_enable_disable_cmd_fixed_param *cmd; 74 wmi_buf_t buf; 75 int32_t len; 76 QDF_STATUS status; 77 78 len = sizeof(wmi_d0_wow_enable_disable_cmd_fixed_param); 79 80 buf = wmi_buf_alloc(wmi_handle, len); 81 if (!buf) { 82 return QDF_STATUS_E_NOMEM; 83 } 84 cmd = (wmi_d0_wow_enable_disable_cmd_fixed_param *) wmi_buf_data(buf); 85 WMITLV_SET_HDR(&cmd->tlv_header, 86 WMITLV_TAG_STRUC_wmi_d0_wow_enable_disable_cmd_fixed_param, 87 WMITLV_GET_STRUCT_TLVLEN 88 (wmi_d0_wow_enable_disable_cmd_fixed_param)); 89 90 cmd->enable = false; 91 92 wmi_mtrace(WMI_D0_WOW_ENABLE_DISABLE_CMDID, NO_SESSION, 0); 93 status = wmi_unified_cmd_send(wmi_handle, buf, len, 94 WMI_D0_WOW_ENABLE_DISABLE_CMDID); 95 if (QDF_IS_STATUS_ERROR(status)) 96 wmi_buf_free(buf); 97 98 return status; 99 } 100 101 void wmi_d0wow_attach_tlv(struct wmi_unified *wmi_handle) 102 { 103 struct wmi_ops *ops = wmi_handle->ops; 104 105 ops->send_d0wow_enable_cmd = send_d0wow_enable_cmd_tlv; 106 ops->send_d0wow_disable_cmd = send_d0wow_disable_cmd_tlv; 107 } 108 #endif /* FEATURE_WLAN_D0WOW */ 109 110 /** 111 * send_add_wow_wakeup_event_cmd_tlv() - Configures wow wakeup events. 112 * @wmi_handle: wmi handle 113 * @vdev_id: vdev id 114 * @bitmap: Event bitmap 115 * @enable: enable/disable 116 * 117 * Return: CDF status 118 */ 119 static QDF_STATUS send_add_wow_wakeup_event_cmd_tlv(wmi_unified_t wmi_handle, 120 uint32_t vdev_id, 121 uint32_t *bitmap, 122 bool enable) 123 { 124 WMI_WOW_ADD_DEL_EVT_CMD_fixed_param *cmd; 125 uint16_t len; 126 wmi_buf_t buf; 127 int ret; 128 129 len = sizeof(WMI_WOW_ADD_DEL_EVT_CMD_fixed_param); 130 buf = wmi_buf_alloc(wmi_handle, len); 131 if (!buf) { 132 return QDF_STATUS_E_NOMEM; 133 } 134 cmd = (WMI_WOW_ADD_DEL_EVT_CMD_fixed_param *) wmi_buf_data(buf); 135 WMITLV_SET_HDR(&cmd->tlv_header, 136 WMITLV_TAG_STRUC_WMI_WOW_ADD_DEL_EVT_CMD_fixed_param, 137 WMITLV_GET_STRUCT_TLVLEN 138 (WMI_WOW_ADD_DEL_EVT_CMD_fixed_param)); 139 cmd->vdev_id = vdev_id; 140 cmd->is_add = enable; 141 qdf_mem_copy(&(cmd->event_bitmaps[0]), bitmap, sizeof(uint32_t) * 142 WMI_WOW_MAX_EVENT_BM_LEN); 143 144 WMI_LOGD("Wakeup pattern 0x%x%x%x%x %s in fw", cmd->event_bitmaps[0], 145 cmd->event_bitmaps[1], cmd->event_bitmaps[2], 146 cmd->event_bitmaps[3], enable ? "enabled" : "disabled"); 147 148 wmi_mtrace(WMI_WOW_ENABLE_DISABLE_WAKE_EVENT_CMDID, cmd->vdev_id, 0); 149 ret = wmi_unified_cmd_send(wmi_handle, buf, len, 150 WMI_WOW_ENABLE_DISABLE_WAKE_EVENT_CMDID); 151 if (ret) { 152 WMI_LOGE("Failed to config wow wakeup event"); 153 wmi_buf_free(buf); 154 return QDF_STATUS_E_FAILURE; 155 } 156 157 return QDF_STATUS_SUCCESS; 158 } 159 160 /** 161 * send_wow_patterns_to_fw_cmd_tlv() - Sends WOW patterns to FW. 162 * @wmi_handle: wmi handle 163 * @vdev_id: vdev id 164 * @ptrn_id: pattern id 165 * @ptrn: pattern 166 * @ptrn_len: pattern length 167 * @ptrn_offset: pattern offset 168 * @mask: mask 169 * @mask_len: mask length 170 * @user: true for user configured pattern and false for default pattern 171 * @default_patterns: default patterns 172 * 173 * Return: CDF status 174 */ 175 static QDF_STATUS send_wow_patterns_to_fw_cmd_tlv(wmi_unified_t wmi_handle, 176 uint8_t vdev_id, uint8_t ptrn_id, 177 const uint8_t *ptrn, uint8_t ptrn_len, 178 uint8_t ptrn_offset, const uint8_t *mask, 179 uint8_t mask_len, bool user, 180 uint8_t default_patterns) 181 { 182 WMI_WOW_ADD_PATTERN_CMD_fixed_param *cmd; 183 WOW_BITMAP_PATTERN_T *bitmap_pattern; 184 wmi_buf_t buf; 185 uint8_t *buf_ptr; 186 int32_t len; 187 int ret; 188 189 len = sizeof(WMI_WOW_ADD_PATTERN_CMD_fixed_param) + 190 WMI_TLV_HDR_SIZE + 191 1 * sizeof(WOW_BITMAP_PATTERN_T) + 192 WMI_TLV_HDR_SIZE + 193 0 * sizeof(WOW_IPV4_SYNC_PATTERN_T) + 194 WMI_TLV_HDR_SIZE + 195 0 * sizeof(WOW_IPV6_SYNC_PATTERN_T) + 196 WMI_TLV_HDR_SIZE + 197 0 * sizeof(WOW_MAGIC_PATTERN_CMD) + 198 WMI_TLV_HDR_SIZE + 199 0 * sizeof(uint32_t) + WMI_TLV_HDR_SIZE + 1 * sizeof(uint32_t); 200 201 buf = wmi_buf_alloc(wmi_handle, len); 202 if (!buf) { 203 return QDF_STATUS_E_NOMEM; 204 } 205 206 cmd = (WMI_WOW_ADD_PATTERN_CMD_fixed_param *) wmi_buf_data(buf); 207 buf_ptr = (uint8_t *) cmd; 208 209 WMITLV_SET_HDR(&cmd->tlv_header, 210 WMITLV_TAG_STRUC_WMI_WOW_ADD_PATTERN_CMD_fixed_param, 211 WMITLV_GET_STRUCT_TLVLEN 212 (WMI_WOW_ADD_PATTERN_CMD_fixed_param)); 213 cmd->vdev_id = vdev_id; 214 cmd->pattern_id = ptrn_id; 215 216 cmd->pattern_type = WOW_BITMAP_PATTERN; 217 buf_ptr += sizeof(WMI_WOW_ADD_PATTERN_CMD_fixed_param); 218 219 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, 220 sizeof(WOW_BITMAP_PATTERN_T)); 221 buf_ptr += WMI_TLV_HDR_SIZE; 222 bitmap_pattern = (WOW_BITMAP_PATTERN_T *) buf_ptr; 223 224 WMITLV_SET_HDR(&bitmap_pattern->tlv_header, 225 WMITLV_TAG_STRUC_WOW_BITMAP_PATTERN_T, 226 WMITLV_GET_STRUCT_TLVLEN(WOW_BITMAP_PATTERN_T)); 227 228 qdf_mem_copy(&bitmap_pattern->patternbuf[0], ptrn, ptrn_len); 229 qdf_mem_copy(&bitmap_pattern->bitmaskbuf[0], mask, mask_len); 230 231 bitmap_pattern->pattern_offset = ptrn_offset; 232 bitmap_pattern->pattern_len = ptrn_len; 233 234 if (bitmap_pattern->pattern_len > WOW_DEFAULT_BITMAP_PATTERN_SIZE) 235 bitmap_pattern->pattern_len = WOW_DEFAULT_BITMAP_PATTERN_SIZE; 236 237 if (bitmap_pattern->pattern_len > WOW_DEFAULT_BITMASK_SIZE) 238 bitmap_pattern->pattern_len = WOW_DEFAULT_BITMASK_SIZE; 239 240 bitmap_pattern->bitmask_len = bitmap_pattern->pattern_len; 241 bitmap_pattern->pattern_id = ptrn_id; 242 243 WMI_LOGD("vdev: %d, ptrn id: %d, ptrn len: %d, ptrn offset: %d user %d", 244 cmd->vdev_id, cmd->pattern_id, bitmap_pattern->pattern_len, 245 bitmap_pattern->pattern_offset, user); 246 WMI_LOGD("Pattern : "); 247 QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_WMI, QDF_TRACE_LEVEL_DEBUG, 248 &bitmap_pattern->patternbuf[0], 249 bitmap_pattern->pattern_len); 250 251 WMI_LOGD("Mask : "); 252 QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_WMI, QDF_TRACE_LEVEL_DEBUG, 253 &bitmap_pattern->bitmaskbuf[0], 254 bitmap_pattern->pattern_len); 255 256 buf_ptr += sizeof(WOW_BITMAP_PATTERN_T); 257 258 /* Fill TLV for WMITLV_TAG_STRUC_WOW_IPV4_SYNC_PATTERN_T but no data. */ 259 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, 0); 260 buf_ptr += WMI_TLV_HDR_SIZE; 261 262 /* Fill TLV for WMITLV_TAG_STRUC_WOW_IPV6_SYNC_PATTERN_T but no data. */ 263 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, 0); 264 buf_ptr += WMI_TLV_HDR_SIZE; 265 266 /* Fill TLV for WMITLV_TAG_STRUC_WOW_MAGIC_PATTERN_CMD but no data. */ 267 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, 0); 268 buf_ptr += WMI_TLV_HDR_SIZE; 269 270 /* Fill TLV for pattern_info_timeout but no data. */ 271 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_UINT32, 0); 272 buf_ptr += WMI_TLV_HDR_SIZE; 273 274 /* Fill TLV for ratelimit_interval with dummy data as this fix elem */ 275 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_UINT32, 1 * sizeof(uint32_t)); 276 buf_ptr += WMI_TLV_HDR_SIZE; 277 *(uint32_t *) buf_ptr = 0; 278 279 wmi_mtrace(WMI_WOW_ADD_WAKE_PATTERN_CMDID, cmd->vdev_id, 0); 280 ret = wmi_unified_cmd_send(wmi_handle, buf, len, 281 WMI_WOW_ADD_WAKE_PATTERN_CMDID); 282 if (ret) { 283 WMI_LOGE("%s: Failed to send wow ptrn to fw", __func__); 284 wmi_buf_free(buf); 285 return QDF_STATUS_E_FAILURE; 286 } 287 288 return QDF_STATUS_SUCCESS; 289 } 290 291 /** 292 * fill_arp_offload_params_tlv() - Fill ARP offload data 293 * @wmi_handle: wmi handle 294 * @offload_req: offload request 295 * @buf_ptr: buffer pointer 296 * 297 * To fill ARP offload data to firmware 298 * when target goes to wow mode. 299 * 300 * Return: None 301 */ 302 static void fill_arp_offload_params_tlv(wmi_unified_t wmi_handle, 303 struct pmo_arp_offload_params *offload_req, uint8_t **buf_ptr) 304 { 305 306 int i; 307 WMI_ARP_OFFLOAD_TUPLE *arp_tuple; 308 bool enable_or_disable = offload_req->enable; 309 310 WMITLV_SET_HDR(*buf_ptr, WMITLV_TAG_ARRAY_STRUC, 311 (WMI_MAX_ARP_OFFLOADS*sizeof(WMI_ARP_OFFLOAD_TUPLE))); 312 *buf_ptr += WMI_TLV_HDR_SIZE; 313 for (i = 0; i < WMI_MAX_ARP_OFFLOADS; i++) { 314 arp_tuple = (WMI_ARP_OFFLOAD_TUPLE *)*buf_ptr; 315 WMITLV_SET_HDR(&arp_tuple->tlv_header, 316 WMITLV_TAG_STRUC_WMI_ARP_OFFLOAD_TUPLE, 317 WMITLV_GET_STRUCT_TLVLEN(WMI_ARP_OFFLOAD_TUPLE)); 318 319 /* Fill data for ARP and NS in the first tupple for LA */ 320 if ((enable_or_disable & PMO_OFFLOAD_ENABLE) && (i == 0)) { 321 /* Copy the target ip addr and flags */ 322 arp_tuple->flags = WMI_ARPOFF_FLAGS_VALID; 323 qdf_mem_copy(&arp_tuple->target_ipaddr, 324 offload_req->host_ipv4_addr, 325 WMI_IPV4_ADDR_LEN); 326 WMI_LOGD("ARPOffload IP4 address: %pI4", 327 offload_req->host_ipv4_addr); 328 } 329 *buf_ptr += sizeof(WMI_ARP_OFFLOAD_TUPLE); 330 } 331 } 332 333 #ifdef WLAN_NS_OFFLOAD 334 /** 335 * fill_ns_offload_params_tlv() - Fill NS offload data 336 * @wmi|_handle: wmi handle 337 * @offload_req: offload request 338 * @buf_ptr: buffer pointer 339 * 340 * To fill NS offload data to firmware 341 * when target goes to wow mode. 342 * 343 * Return: None 344 */ 345 static void fill_ns_offload_params_tlv(wmi_unified_t wmi_handle, 346 struct pmo_ns_offload_params *ns_req, uint8_t **buf_ptr) 347 { 348 349 int i; 350 WMI_NS_OFFLOAD_TUPLE *ns_tuple; 351 352 WMITLV_SET_HDR(*buf_ptr, WMITLV_TAG_ARRAY_STRUC, 353 (WMI_MAX_NS_OFFLOADS * sizeof(WMI_NS_OFFLOAD_TUPLE))); 354 *buf_ptr += WMI_TLV_HDR_SIZE; 355 for (i = 0; i < WMI_MAX_NS_OFFLOADS; i++) { 356 ns_tuple = (WMI_NS_OFFLOAD_TUPLE *)*buf_ptr; 357 WMITLV_SET_HDR(&ns_tuple->tlv_header, 358 WMITLV_TAG_STRUC_WMI_NS_OFFLOAD_TUPLE, 359 (sizeof(WMI_NS_OFFLOAD_TUPLE) - WMI_TLV_HDR_SIZE)); 360 361 /* 362 * Fill data only for NS offload in the first ARP tuple for LA 363 */ 364 if ((ns_req->enable & PMO_OFFLOAD_ENABLE)) { 365 ns_tuple->flags |= WMI_NSOFF_FLAGS_VALID; 366 /* Copy the target/solicitation/remote ip addr */ 367 if (ns_req->target_ipv6_addr_valid[i]) 368 qdf_mem_copy(&ns_tuple->target_ipaddr[0], 369 &ns_req->target_ipv6_addr[i], 370 sizeof(WMI_IPV6_ADDR)); 371 qdf_mem_copy(&ns_tuple->solicitation_ipaddr, 372 &ns_req->self_ipv6_addr[i], 373 sizeof(WMI_IPV6_ADDR)); 374 if (ns_req->target_ipv6_addr_ac_type[i]) { 375 ns_tuple->flags |= 376 WMI_NSOFF_FLAGS_IS_IPV6_ANYCAST; 377 } 378 WMI_LOGD("Index %d NS solicitedIp %pI6, targetIp %pI6", 379 i, &ns_req->self_ipv6_addr[i], 380 &ns_req->target_ipv6_addr[i]); 381 382 /* target MAC is optional, check if it is valid, 383 * if this is not valid, the target will use the known 384 * local MAC address rather than the tuple 385 */ 386 WMI_CHAR_ARRAY_TO_MAC_ADDR( 387 ns_req->self_macaddr.bytes, 388 &ns_tuple->target_mac); 389 if ((ns_tuple->target_mac.mac_addr31to0 != 0) || 390 (ns_tuple->target_mac.mac_addr47to32 != 0)) { 391 ns_tuple->flags |= WMI_NSOFF_FLAGS_MAC_VALID; 392 } 393 } 394 *buf_ptr += sizeof(WMI_NS_OFFLOAD_TUPLE); 395 } 396 } 397 398 /** 399 * fill_nsoffload_ext_tlv() - Fill NS offload ext data 400 * @wmi: wmi handle 401 * @offload_req: offload request 402 * @buf_ptr: buffer pointer 403 * 404 * To fill extended NS offload extended data to firmware 405 * when target goes to wow mode. 406 * 407 * Return: None 408 */ 409 static void fill_nsoffload_ext_tlv(wmi_unified_t wmi_handle, 410 struct pmo_ns_offload_params *ns_req, uint8_t **buf_ptr) 411 { 412 int i; 413 WMI_NS_OFFLOAD_TUPLE *ns_tuple; 414 uint32_t count, num_ns_ext_tuples; 415 416 count = ns_req->num_ns_offload_count; 417 num_ns_ext_tuples = ns_req->num_ns_offload_count - 418 WMI_MAX_NS_OFFLOADS; 419 420 /* Populate extended NS offload tuples */ 421 WMITLV_SET_HDR(*buf_ptr, WMITLV_TAG_ARRAY_STRUC, 422 (num_ns_ext_tuples * sizeof(WMI_NS_OFFLOAD_TUPLE))); 423 *buf_ptr += WMI_TLV_HDR_SIZE; 424 for (i = WMI_MAX_NS_OFFLOADS; i < count; i++) { 425 ns_tuple = (WMI_NS_OFFLOAD_TUPLE *)*buf_ptr; 426 WMITLV_SET_HDR(&ns_tuple->tlv_header, 427 WMITLV_TAG_STRUC_WMI_NS_OFFLOAD_TUPLE, 428 (sizeof(WMI_NS_OFFLOAD_TUPLE)-WMI_TLV_HDR_SIZE)); 429 430 /* 431 * Fill data only for NS offload in the first ARP tuple for LA 432 */ 433 if ((ns_req->enable & PMO_OFFLOAD_ENABLE)) { 434 ns_tuple->flags |= WMI_NSOFF_FLAGS_VALID; 435 /* Copy the target/solicitation/remote ip addr */ 436 if (ns_req->target_ipv6_addr_valid[i]) 437 qdf_mem_copy(&ns_tuple->target_ipaddr[0], 438 &ns_req->target_ipv6_addr[i], 439 sizeof(WMI_IPV6_ADDR)); 440 qdf_mem_copy(&ns_tuple->solicitation_ipaddr, 441 &ns_req->self_ipv6_addr[i], 442 sizeof(WMI_IPV6_ADDR)); 443 if (ns_req->target_ipv6_addr_ac_type[i]) { 444 ns_tuple->flags |= 445 WMI_NSOFF_FLAGS_IS_IPV6_ANYCAST; 446 } 447 WMI_LOGD("Index %d NS solicitedIp %pI6, targetIp %pI6", 448 i, &ns_req->self_ipv6_addr[i], 449 &ns_req->target_ipv6_addr[i]); 450 451 /* target MAC is optional, check if it is valid, 452 * if this is not valid, the target will use the 453 * known local MAC address rather than the tuple 454 */ 455 WMI_CHAR_ARRAY_TO_MAC_ADDR( 456 ns_req->self_macaddr.bytes, 457 &ns_tuple->target_mac); 458 if ((ns_tuple->target_mac.mac_addr31to0 != 0) || 459 (ns_tuple->target_mac.mac_addr47to32 != 0)) { 460 ns_tuple->flags |= WMI_NSOFF_FLAGS_MAC_VALID; 461 } 462 } 463 *buf_ptr += sizeof(WMI_NS_OFFLOAD_TUPLE); 464 } 465 } 466 #else 467 static void fill_ns_offload_params_tlv(wmi_unified_t wmi_handle, 468 struct pmo_ns_offload_params *ns_req, uint8_t **buf_ptr) 469 { 470 } 471 472 static void fill_nsoffload_ext_tlv(wmi_unified_t wmi_handle, 473 struct pmo_ns_offload_params *ns_req, uint8_t **buf_ptr) 474 { 475 } 476 #endif 477 478 /** 479 * send_enable_arp_ns_offload_cmd_tlv() - enable ARP NS offload 480 * @wma: wmi handle 481 * @arp_offload_req: arp offload request 482 * @ns_offload_req: ns offload request 483 * @arp_only: flag 484 * 485 * To configure ARP NS off load data to firmware 486 * when target goes to wow mode. 487 * 488 * Return: QDF Status 489 */ 490 static QDF_STATUS send_enable_arp_ns_offload_cmd_tlv(wmi_unified_t wmi_handle, 491 struct pmo_arp_offload_params *arp_offload_req, 492 struct pmo_ns_offload_params *ns_offload_req, 493 uint8_t vdev_id) 494 { 495 int32_t res; 496 WMI_SET_ARP_NS_OFFLOAD_CMD_fixed_param *cmd; 497 uint8_t *buf_ptr; 498 wmi_buf_t buf; 499 int32_t len; 500 uint32_t count = 0, num_ns_ext_tuples = 0; 501 502 count = ns_offload_req->num_ns_offload_count; 503 504 /* 505 * TLV place holder size for array of NS tuples 506 * TLV place holder size for array of ARP tuples 507 */ 508 len = sizeof(WMI_SET_ARP_NS_OFFLOAD_CMD_fixed_param) + 509 WMI_TLV_HDR_SIZE + 510 WMI_MAX_NS_OFFLOADS * sizeof(WMI_NS_OFFLOAD_TUPLE) + 511 WMI_TLV_HDR_SIZE + 512 WMI_MAX_ARP_OFFLOADS * sizeof(WMI_ARP_OFFLOAD_TUPLE); 513 514 /* 515 * If there are more than WMI_MAX_NS_OFFLOADS addresses then allocate 516 * extra length for extended NS offload tuples which follows ARP offload 517 * tuples. Host needs to fill this structure in following format: 518 * 2 NS ofload tuples 519 * 2 ARP offload tuples 520 * N numbers of extended NS offload tuples if HDD has given more than 521 * 2 NS offload addresses 522 */ 523 if (count > WMI_MAX_NS_OFFLOADS) { 524 num_ns_ext_tuples = count - WMI_MAX_NS_OFFLOADS; 525 len += WMI_TLV_HDR_SIZE + num_ns_ext_tuples 526 * sizeof(WMI_NS_OFFLOAD_TUPLE); 527 } 528 529 buf = wmi_buf_alloc(wmi_handle, len); 530 if (!buf) { 531 return QDF_STATUS_E_NOMEM; 532 } 533 534 buf_ptr = (uint8_t *) wmi_buf_data(buf); 535 cmd = (WMI_SET_ARP_NS_OFFLOAD_CMD_fixed_param *) buf_ptr; 536 WMITLV_SET_HDR(&cmd->tlv_header, 537 WMITLV_TAG_STRUC_WMI_SET_ARP_NS_OFFLOAD_CMD_fixed_param, 538 WMITLV_GET_STRUCT_TLVLEN 539 (WMI_SET_ARP_NS_OFFLOAD_CMD_fixed_param)); 540 cmd->flags = 0; 541 cmd->vdev_id = vdev_id; 542 cmd->num_ns_ext_tuples = num_ns_ext_tuples; 543 544 WMI_LOGD("ARP NS Offload vdev_id: %d", cmd->vdev_id); 545 546 buf_ptr += sizeof(WMI_SET_ARP_NS_OFFLOAD_CMD_fixed_param); 547 fill_ns_offload_params_tlv(wmi_handle, ns_offload_req, &buf_ptr); 548 fill_arp_offload_params_tlv(wmi_handle, arp_offload_req, &buf_ptr); 549 if (num_ns_ext_tuples) 550 fill_nsoffload_ext_tlv(wmi_handle, ns_offload_req, &buf_ptr); 551 552 wmi_mtrace(WMI_SET_ARP_NS_OFFLOAD_CMDID, cmd->vdev_id, 0); 553 res = wmi_unified_cmd_send(wmi_handle, buf, len, 554 WMI_SET_ARP_NS_OFFLOAD_CMDID); 555 if (res) { 556 WMI_LOGE("Failed to enable ARP NDP/NSffload"); 557 wmi_buf_free(buf); 558 return QDF_STATUS_E_FAILURE; 559 } 560 561 return QDF_STATUS_SUCCESS; 562 } 563 564 /** 565 * send_add_clear_mcbc_filter_cmd_tlv() - set mcast filter command to fw 566 * @wmi_handle: wmi handle 567 * @vdev_id: vdev id 568 * @multicastAddr: mcast address 569 * @clearList: clear list flag 570 * 571 * Return: QDF_STATUS_SUCCESS for success or error code 572 */ 573 static QDF_STATUS send_add_clear_mcbc_filter_cmd_tlv(wmi_unified_t wmi_handle, 574 uint8_t vdev_id, 575 struct qdf_mac_addr multicast_addr, 576 bool clearList) 577 { 578 WMI_SET_MCASTBCAST_FILTER_CMD_fixed_param *cmd; 579 wmi_buf_t buf; 580 int err; 581 582 buf = wmi_buf_alloc(wmi_handle, sizeof(*cmd)); 583 if (!buf) { 584 return QDF_STATUS_E_NOMEM; 585 } 586 587 cmd = (WMI_SET_MCASTBCAST_FILTER_CMD_fixed_param *) wmi_buf_data(buf); 588 qdf_mem_zero(cmd, sizeof(*cmd)); 589 590 WMITLV_SET_HDR(&cmd->tlv_header, 591 WMITLV_TAG_STRUC_WMI_SET_MCASTBCAST_FILTER_CMD_fixed_param, 592 WMITLV_GET_STRUCT_TLVLEN 593 (WMI_SET_MCASTBCAST_FILTER_CMD_fixed_param)); 594 cmd->action = 595 (clearList ? WMI_MCAST_FILTER_DELETE : WMI_MCAST_FILTER_SET); 596 cmd->vdev_id = vdev_id; 597 WMI_CHAR_ARRAY_TO_MAC_ADDR(multicast_addr.bytes, &cmd->mcastbdcastaddr); 598 599 WMI_LOGD("Action:%d; vdev_id:%d; clearList:%d; MCBC MAC Addr: %pM", 600 cmd->action, vdev_id, clearList, multicast_addr.bytes); 601 602 wmi_mtrace(WMI_SET_MCASTBCAST_FILTER_CMDID, cmd->vdev_id, 0); 603 err = wmi_unified_cmd_send(wmi_handle, buf, 604 sizeof(*cmd), 605 WMI_SET_MCASTBCAST_FILTER_CMDID); 606 if (err) { 607 WMI_LOGE("Failed to send set_param cmd"); 608 wmi_buf_free(buf); 609 return QDF_STATUS_E_FAILURE; 610 } 611 612 return QDF_STATUS_SUCCESS; 613 } 614 615 /** 616 * send_multiple_add_clear_mcbc_filter_cmd_tlv() - send multiple mcast filter 617 * command to fw 618 * @wmi_handle: wmi handle 619 * @vdev_id: vdev id 620 * @mcast_filter_params: mcast filter params 621 * 622 * Return: QDF_STATUS_SUCCESS for success or error code 623 */ 624 static QDF_STATUS send_multiple_add_clear_mcbc_filter_cmd_tlv( 625 wmi_unified_t wmi_handle, 626 uint8_t vdev_id, 627 struct pmo_mcast_filter_params *filter_param) 628 629 { 630 WMI_SET_MULTIPLE_MCAST_FILTER_CMD_fixed_param *cmd; 631 uint8_t *buf_ptr; 632 wmi_buf_t buf; 633 int err; 634 int i; 635 uint8_t *mac_addr_src_ptr = NULL; 636 wmi_mac_addr *mac_addr_dst_ptr; 637 uint32_t len = sizeof(*cmd) + WMI_TLV_HDR_SIZE + 638 sizeof(wmi_mac_addr) * filter_param->multicast_addr_cnt; 639 640 buf = wmi_buf_alloc(wmi_handle, len); 641 if (!buf) { 642 return QDF_STATUS_E_NOMEM; 643 } 644 645 buf_ptr = (uint8_t *) wmi_buf_data(buf); 646 cmd = (WMI_SET_MULTIPLE_MCAST_FILTER_CMD_fixed_param *) 647 wmi_buf_data(buf); 648 qdf_mem_zero(cmd, sizeof(*cmd)); 649 650 WMITLV_SET_HDR(&cmd->tlv_header, 651 WMITLV_TAG_STRUC_wmi_set_multiple_mcast_filter_cmd_fixed_param, 652 WMITLV_GET_STRUCT_TLVLEN 653 (WMI_SET_MULTIPLE_MCAST_FILTER_CMD_fixed_param)); 654 cmd->operation = 655 ((filter_param->action == 0) ? WMI_MULTIPLE_MCAST_FILTER_DELETE 656 : WMI_MULTIPLE_MCAST_FILTER_ADD); 657 cmd->vdev_id = vdev_id; 658 cmd->num_mcastaddrs = filter_param->multicast_addr_cnt; 659 660 buf_ptr += sizeof(*cmd); 661 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_FIXED_STRUC, 662 sizeof(wmi_mac_addr) * 663 filter_param->multicast_addr_cnt); 664 665 if (filter_param->multicast_addr_cnt == 0) 666 goto send_cmd; 667 668 mac_addr_src_ptr = (uint8_t *)&filter_param->multicast_addr; 669 mac_addr_dst_ptr = (wmi_mac_addr *) 670 (buf_ptr + WMI_TLV_HDR_SIZE); 671 672 for (i = 0; i < filter_param->multicast_addr_cnt; i++) { 673 WMI_CHAR_ARRAY_TO_MAC_ADDR(mac_addr_src_ptr, mac_addr_dst_ptr); 674 mac_addr_src_ptr += ATH_MAC_LEN; 675 mac_addr_dst_ptr++; 676 } 677 678 send_cmd: 679 wmi_mtrace(WMI_SET_MULTIPLE_MCAST_FILTER_CMDID, cmd->vdev_id, 0); 680 err = wmi_unified_cmd_send(wmi_handle, buf, 681 len, 682 WMI_SET_MULTIPLE_MCAST_FILTER_CMDID); 683 if (err) { 684 WMI_LOGE("Failed to send set_param cmd"); 685 wmi_buf_free(buf); 686 return QDF_STATUS_E_FAILURE; 687 } 688 689 return QDF_STATUS_SUCCESS; 690 } 691 692 static QDF_STATUS send_conf_hw_filter_cmd_tlv(wmi_unified_t wmi, 693 struct pmo_hw_filter_params *req) 694 { 695 QDF_STATUS status; 696 wmi_hw_data_filter_cmd_fixed_param *cmd; 697 wmi_buf_t wmi_buf; 698 699 if (!req) { 700 WMI_LOGE("req is null"); 701 return QDF_STATUS_E_INVAL; 702 } 703 704 wmi_buf = wmi_buf_alloc(wmi, sizeof(*cmd)); 705 if (!wmi_buf) { 706 return QDF_STATUS_E_NOMEM; 707 } 708 709 cmd = (wmi_hw_data_filter_cmd_fixed_param *)wmi_buf_data(wmi_buf); 710 WMITLV_SET_HDR(&cmd->tlv_header, 711 WMITLV_TAG_STRUC_wmi_hw_data_filter_cmd_fixed_param, 712 WMITLV_GET_STRUCT_TLVLEN(wmi_hw_data_filter_cmd_fixed_param)); 713 cmd->vdev_id = req->vdev_id; 714 cmd->enable = req->enable; 715 /* Set all modes in case of disable */ 716 if (!cmd->enable) 717 cmd->hw_filter_bitmap = ((uint32_t)~0U); 718 else 719 cmd->hw_filter_bitmap = req->mode_bitmap; 720 721 WMI_LOGD("Send %s hw filter mode: 0x%X for vdev id %d", 722 req->enable ? "enable" : "disable", req->mode_bitmap, 723 req->vdev_id); 724 725 wmi_mtrace(WMI_HW_DATA_FILTER_CMDID, cmd->vdev_id, 0); 726 status = wmi_unified_cmd_send(wmi, wmi_buf, sizeof(*cmd), 727 WMI_HW_DATA_FILTER_CMDID); 728 if (QDF_IS_STATUS_ERROR(status)) { 729 WMI_LOGE("Failed to configure hw filter"); 730 wmi_buf_free(wmi_buf); 731 } 732 733 return status; 734 } 735 736 static void 737 fill_fils_tlv_params(WMI_GTK_OFFLOAD_CMD_fixed_param *cmd, 738 uint8_t vdev_id, 739 struct pmo_gtk_req *params) 740 { 741 uint8_t *buf_ptr; 742 wmi_gtk_offload_fils_tlv_param *ext_param; 743 744 buf_ptr = (uint8_t *) cmd + sizeof(*cmd); 745 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, 746 sizeof(*ext_param)); 747 buf_ptr += WMI_TLV_HDR_SIZE; 748 749 ext_param = (wmi_gtk_offload_fils_tlv_param *)buf_ptr; 750 WMITLV_SET_HDR(&ext_param->tlv_header, 751 WMITLV_TAG_STRUC_wmi_gtk_offload_extended_tlv_param, 752 WMITLV_GET_STRUCT_TLVLEN( 753 wmi_gtk_offload_fils_tlv_param)); 754 ext_param->vdev_id = vdev_id; 755 ext_param->flags = cmd->flags; 756 ext_param->kek_len = params->kek_len; 757 qdf_mem_copy(ext_param->KEK, params->kek, params->kek_len); 758 qdf_mem_copy(ext_param->KCK, params->kck, 759 WMI_GTK_OFFLOAD_KCK_BYTES); 760 qdf_mem_copy(ext_param->replay_counter, ¶ms->replay_counter, 761 GTK_REPLAY_COUNTER_BYTES); 762 } 763 764 /** 765 * send_gtk_offload_cmd_tlv() - send GTK offload command to fw 766 * @wmi_handle: wmi handle 767 * @vdev_id: vdev id 768 * @params: GTK offload parameters 769 * 770 * Return: CDF status 771 */ 772 static 773 QDF_STATUS send_gtk_offload_cmd_tlv(wmi_unified_t wmi_handle, uint8_t vdev_id, 774 struct pmo_gtk_req *params, 775 bool enable_offload, 776 uint32_t gtk_offload_opcode) 777 { 778 int len; 779 wmi_buf_t buf; 780 WMI_GTK_OFFLOAD_CMD_fixed_param *cmd; 781 QDF_STATUS status = QDF_STATUS_SUCCESS; 782 783 WMI_LOGD("%s Enter", __func__); 784 785 len = sizeof(*cmd); 786 787 if (params->is_fils_connection) 788 len += WMI_TLV_HDR_SIZE + 789 sizeof(wmi_gtk_offload_fils_tlv_param); 790 791 /* alloc wmi buffer */ 792 buf = wmi_buf_alloc(wmi_handle, len); 793 if (!buf) { 794 status = QDF_STATUS_E_NOMEM; 795 goto out; 796 } 797 798 cmd = (WMI_GTK_OFFLOAD_CMD_fixed_param *) wmi_buf_data(buf); 799 WMITLV_SET_HDR(&cmd->tlv_header, 800 WMITLV_TAG_STRUC_WMI_GTK_OFFLOAD_CMD_fixed_param, 801 WMITLV_GET_STRUCT_TLVLEN 802 (WMI_GTK_OFFLOAD_CMD_fixed_param)); 803 804 cmd->vdev_id = vdev_id; 805 806 /* Request target to enable GTK offload */ 807 if (enable_offload == PMO_GTK_OFFLOAD_ENABLE) { 808 cmd->flags = gtk_offload_opcode; 809 810 /* Copy the keys and replay counter */ 811 qdf_mem_copy(cmd->KCK, params->kck, sizeof(cmd->KCK)); 812 qdf_mem_copy(cmd->KEK, params->kek, sizeof(cmd->KEK)); 813 qdf_mem_copy(cmd->replay_counter, ¶ms->replay_counter, 814 GTK_REPLAY_COUNTER_BYTES); 815 } else { 816 cmd->flags = gtk_offload_opcode; 817 } 818 if (params->is_fils_connection) 819 fill_fils_tlv_params(cmd, vdev_id, params); 820 821 WMI_LOGD("VDEVID: %d, GTK_FLAGS: x%x kek len %d", vdev_id, cmd->flags, params->kek_len); 822 /* send the wmi command */ 823 wmi_mtrace(WMI_GTK_OFFLOAD_CMDID, cmd->vdev_id, 0); 824 if (wmi_unified_cmd_send(wmi_handle, buf, len, 825 WMI_GTK_OFFLOAD_CMDID)) { 826 WMI_LOGE("Failed to send WMI_GTK_OFFLOAD_CMDID"); 827 wmi_buf_free(buf); 828 status = QDF_STATUS_E_FAILURE; 829 } 830 831 out: 832 WMI_LOGD("%s Exit", __func__); 833 return status; 834 } 835 836 /** 837 * send_process_gtk_offload_getinfo_cmd_tlv() - send GTK offload cmd to fw 838 * @wmi_handle: wmi handle 839 * @params: GTK offload params 840 * 841 * Return: CDF status 842 */ 843 static QDF_STATUS send_process_gtk_offload_getinfo_cmd_tlv( 844 wmi_unified_t wmi_handle, 845 uint8_t vdev_id, 846 uint64_t offload_req_opcode) 847 { 848 int len; 849 wmi_buf_t buf; 850 WMI_GTK_OFFLOAD_CMD_fixed_param *cmd; 851 QDF_STATUS status = QDF_STATUS_SUCCESS; 852 853 len = sizeof(*cmd); 854 855 /* alloc wmi buffer */ 856 buf = wmi_buf_alloc(wmi_handle, len); 857 if (!buf) { 858 status = QDF_STATUS_E_NOMEM; 859 goto out; 860 } 861 862 cmd = (WMI_GTK_OFFLOAD_CMD_fixed_param *) wmi_buf_data(buf); 863 WMITLV_SET_HDR(&cmd->tlv_header, 864 WMITLV_TAG_STRUC_WMI_GTK_OFFLOAD_CMD_fixed_param, 865 WMITLV_GET_STRUCT_TLVLEN 866 (WMI_GTK_OFFLOAD_CMD_fixed_param)); 867 868 /* Request for GTK offload status */ 869 cmd->flags = offload_req_opcode; 870 cmd->vdev_id = vdev_id; 871 872 /* send the wmi command */ 873 wmi_mtrace(WMI_GTK_OFFLOAD_CMDID, cmd->vdev_id, 0); 874 if (wmi_unified_cmd_send(wmi_handle, buf, len, 875 WMI_GTK_OFFLOAD_CMDID)) { 876 WMI_LOGE("Failed to send WMI_GTK_OFFLOAD_CMDID for req info"); 877 wmi_buf_free(buf); 878 status = QDF_STATUS_E_FAILURE; 879 } 880 881 out: 882 return status; 883 } 884 885 /** 886 * send_enable_enhance_multicast_offload_tlv() - send enhance multicast offload 887 * @wmi_handle: wmi handle 888 * @vdev_id: vdev id 889 * @action: true for enable else false 890 * 891 * To enable enhance multicast offload to firmware 892 * when target goes to wow mode. 893 * 894 * Return: QDF Status 895 */ 896 897 static 898 QDF_STATUS send_enable_enhance_multicast_offload_tlv( 899 wmi_unified_t wmi_handle, 900 uint8_t vdev_id, bool action) 901 { 902 QDF_STATUS status; 903 wmi_buf_t buf; 904 wmi_config_enhanced_mcast_filter_cmd_fixed_param *cmd; 905 906 buf = wmi_buf_alloc(wmi_handle, sizeof(*cmd)); 907 if (!buf) { 908 return QDF_STATUS_E_NOMEM; 909 } 910 911 cmd = (wmi_config_enhanced_mcast_filter_cmd_fixed_param *) 912 wmi_buf_data(buf); 913 914 WMITLV_SET_HDR(&cmd->tlv_header, 915 WMITLV_TAG_STRUC_wmi_config_enhanced_mcast_filter_fixed_param, 916 WMITLV_GET_STRUCT_TLVLEN( 917 wmi_config_enhanced_mcast_filter_cmd_fixed_param)); 918 919 cmd->vdev_id = vdev_id; 920 cmd->enable = ((action == 0) ? ENHANCED_MCAST_FILTER_DISABLED : 921 ENHANCED_MCAST_FILTER_ENABLED); 922 WMI_LOGD("%s: config enhance multicast offload action %d for vdev %d", 923 __func__, action, vdev_id); 924 wmi_mtrace(WMI_CONFIG_ENHANCED_MCAST_FILTER_CMDID, cmd->vdev_id, 0); 925 status = wmi_unified_cmd_send(wmi_handle, buf, 926 sizeof(*cmd), WMI_CONFIG_ENHANCED_MCAST_FILTER_CMDID); 927 if (status != QDF_STATUS_SUCCESS) { 928 wmi_buf_free(buf); 929 WMI_LOGE("%s:Failed to send ENHANCED_MCAST_FILTER_CMDID", 930 __func__); 931 } 932 933 return status; 934 } 935 936 /** 937 * extract_gtk_rsp_event_tlv() - extract gtk rsp params from event 938 * @wmi_handle: wmi handle 939 * @param evt_buf: pointer to event buffer 940 * @param hdr: Pointer to hold header 941 * @param bufp: Pointer to hold pointer to rx param buffer 942 * 943 * Return: QDF_STATUS_SUCCESS for success or error code 944 */ 945 static QDF_STATUS extract_gtk_rsp_event_tlv(wmi_unified_t wmi_handle, 946 void *evt_buf, struct pmo_gtk_rsp_params *gtk_rsp_param, uint32_t len) 947 { 948 WMI_GTK_OFFLOAD_STATUS_EVENT_fixed_param *fixed_param; 949 WMI_GTK_OFFLOAD_STATUS_EVENTID_param_tlvs *param_buf; 950 951 param_buf = (WMI_GTK_OFFLOAD_STATUS_EVENTID_param_tlvs *)evt_buf; 952 if (!param_buf) { 953 WMI_LOGE("gtk param_buf is NULL"); 954 return QDF_STATUS_E_INVAL; 955 } 956 957 if (len < sizeof(WMI_GTK_OFFLOAD_STATUS_EVENT_fixed_param)) { 958 WMI_LOGE("Invalid length for GTK status"); 959 return QDF_STATUS_E_INVAL; 960 } 961 962 fixed_param = (WMI_GTK_OFFLOAD_STATUS_EVENT_fixed_param *) 963 param_buf->fixed_param; 964 965 if (fixed_param->vdev_id >= WLAN_UMAC_PSOC_MAX_VDEVS) { 966 wmi_err_rl("Invalid vdev_id %u", fixed_param->vdev_id); 967 return QDF_STATUS_E_INVAL; 968 } 969 970 gtk_rsp_param->vdev_id = fixed_param->vdev_id; 971 gtk_rsp_param->status_flag = QDF_STATUS_SUCCESS; 972 gtk_rsp_param->refresh_cnt = fixed_param->refresh_cnt; 973 qdf_mem_copy(>k_rsp_param->replay_counter, 974 &fixed_param->replay_counter, 975 GTK_REPLAY_COUNTER_BYTES); 976 977 return QDF_STATUS_SUCCESS; 978 979 } 980 981 #ifdef FEATURE_WLAN_RA_FILTERING 982 /** 983 * send_wow_sta_ra_filter_cmd_tlv() - set RA filter pattern in fw 984 * @wmi_handle: wmi handle 985 * @vdev_id: vdev id 986 * 987 * Return: CDF status 988 */ 989 static QDF_STATUS send_wow_sta_ra_filter_cmd_tlv(wmi_unified_t wmi_handle, 990 uint8_t vdev_id, 991 uint8_t default_pattern, 992 uint16_t rate_limit_interval) 993 { 994 995 WMI_WOW_ADD_PATTERN_CMD_fixed_param *cmd; 996 wmi_buf_t buf; 997 uint8_t *buf_ptr; 998 int32_t len; 999 int ret; 1000 1001 len = sizeof(WMI_WOW_ADD_PATTERN_CMD_fixed_param) + 1002 WMI_TLV_HDR_SIZE + 1003 0 * sizeof(WOW_BITMAP_PATTERN_T) + 1004 WMI_TLV_HDR_SIZE + 1005 0 * sizeof(WOW_IPV4_SYNC_PATTERN_T) + 1006 WMI_TLV_HDR_SIZE + 1007 0 * sizeof(WOW_IPV6_SYNC_PATTERN_T) + 1008 WMI_TLV_HDR_SIZE + 1009 0 * sizeof(WOW_MAGIC_PATTERN_CMD) + 1010 WMI_TLV_HDR_SIZE + 1011 0 * sizeof(uint32_t) + WMI_TLV_HDR_SIZE + 1 * sizeof(uint32_t); 1012 1013 buf = wmi_buf_alloc(wmi_handle, len); 1014 if (!buf) { 1015 return QDF_STATUS_E_NOMEM; 1016 } 1017 1018 cmd = (WMI_WOW_ADD_PATTERN_CMD_fixed_param *) wmi_buf_data(buf); 1019 buf_ptr = (uint8_t *) cmd; 1020 1021 WMITLV_SET_HDR(&cmd->tlv_header, 1022 WMITLV_TAG_STRUC_WMI_WOW_ADD_PATTERN_CMD_fixed_param, 1023 WMITLV_GET_STRUCT_TLVLEN 1024 (WMI_WOW_ADD_PATTERN_CMD_fixed_param)); 1025 cmd->vdev_id = vdev_id; 1026 cmd->pattern_id = default_pattern, 1027 cmd->pattern_type = WOW_IPV6_RA_PATTERN; 1028 buf_ptr += sizeof(WMI_WOW_ADD_PATTERN_CMD_fixed_param); 1029 1030 /* Fill TLV for WMITLV_TAG_STRUC_WOW_BITMAP_PATTERN_T but no data. */ 1031 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, 0); 1032 buf_ptr += WMI_TLV_HDR_SIZE; 1033 1034 /* Fill TLV for WMITLV_TAG_STRUC_WOW_IPV4_SYNC_PATTERN_T but no data. */ 1035 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, 0); 1036 buf_ptr += WMI_TLV_HDR_SIZE; 1037 1038 /* Fill TLV for WMITLV_TAG_STRUC_WOW_IPV6_SYNC_PATTERN_T but no data. */ 1039 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, 0); 1040 buf_ptr += WMI_TLV_HDR_SIZE; 1041 1042 /* Fill TLV for WMITLV_TAG_STRUC_WOW_MAGIC_PATTERN_CMD but no data. */ 1043 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, 0); 1044 buf_ptr += WMI_TLV_HDR_SIZE; 1045 1046 /* Fill TLV for pattern_info_timeout but no data. */ 1047 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_UINT32, 0); 1048 buf_ptr += WMI_TLV_HDR_SIZE; 1049 1050 /* Fill TLV for ra_ratelimit_interval. */ 1051 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_UINT32, sizeof(uint32_t)); 1052 buf_ptr += WMI_TLV_HDR_SIZE; 1053 1054 *((uint32_t *) buf_ptr) = rate_limit_interval; 1055 1056 WMI_LOGD("%s: send RA rate limit [%d] to fw vdev = %d", __func__, 1057 rate_limit_interval, vdev_id); 1058 1059 wmi_mtrace(WMI_WOW_ADD_WAKE_PATTERN_CMDID, cmd->vdev_id, 0); 1060 ret = wmi_unified_cmd_send(wmi_handle, buf, len, 1061 WMI_WOW_ADD_WAKE_PATTERN_CMDID); 1062 if (ret) { 1063 WMI_LOGE("%s: Failed to send RA rate limit to fw", __func__); 1064 wmi_buf_free(buf); 1065 return QDF_STATUS_E_FAILURE; 1066 } 1067 1068 return QDF_STATUS_SUCCESS; 1069 } 1070 1071 void wmi_ra_filtering_attach_tlv(struct wmi_unified *wmi_handle) 1072 { 1073 struct wmi_ops *ops = wmi_handle->ops; 1074 1075 ops->send_wow_sta_ra_filter_cmd = send_wow_sta_ra_filter_cmd_tlv; 1076 } 1077 #endif /* FEATURE_WLAN_RA_FILTERING */ 1078 1079 /** 1080 * send_action_frame_patterns_cmd_tlv() - send wmi cmd of action filter params 1081 * @wmi_handle: wmi handler 1082 * @action_params: pointer to action_params 1083 * 1084 * Return: 0 for success, otherwise appropriate error code 1085 */ 1086 static QDF_STATUS send_action_frame_patterns_cmd_tlv(wmi_unified_t wmi_handle, 1087 struct pmo_action_wakeup_set_params *action_params) 1088 { 1089 WMI_WOW_SET_ACTION_WAKE_UP_CMD_fixed_param *cmd; 1090 wmi_buf_t buf; 1091 int i; 1092 int32_t err; 1093 uint32_t len = 0, *cmd_args; 1094 uint8_t *buf_ptr; 1095 1096 len = (PMO_SUPPORTED_ACTION_CATE * sizeof(uint32_t)) 1097 + WMI_TLV_HDR_SIZE + sizeof(*cmd); 1098 buf = wmi_buf_alloc(wmi_handle, len); 1099 if (!buf) { 1100 return QDF_STATUS_E_NOMEM; 1101 } 1102 cmd = (WMI_WOW_SET_ACTION_WAKE_UP_CMD_fixed_param *) wmi_buf_data(buf); 1103 buf_ptr = (uint8_t *)cmd; 1104 WMITLV_SET_HDR(&cmd->tlv_header, 1105 WMITLV_TAG_STRUC_wmi_wow_set_action_wake_up_cmd_fixed_param, 1106 WMITLV_GET_STRUCT_TLVLEN( 1107 WMI_WOW_SET_ACTION_WAKE_UP_CMD_fixed_param)); 1108 1109 cmd->vdev_id = action_params->vdev_id; 1110 cmd->operation = action_params->operation; 1111 1112 for (i = 0; i < MAX_SUPPORTED_ACTION_CATEGORY_ELE_LIST; i++) 1113 cmd->action_category_map[i] = 1114 action_params->action_category_map[i]; 1115 1116 buf_ptr += sizeof(WMI_WOW_SET_ACTION_WAKE_UP_CMD_fixed_param); 1117 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_UINT32, 1118 (PMO_SUPPORTED_ACTION_CATE * sizeof(uint32_t))); 1119 buf_ptr += WMI_TLV_HDR_SIZE; 1120 cmd_args = (uint32_t *) buf_ptr; 1121 for (i = 0; i < PMO_SUPPORTED_ACTION_CATE; i++) 1122 cmd_args[i] = action_params->action_per_category[i]; 1123 1124 wmi_mtrace(WMI_WOW_SET_ACTION_WAKE_UP_CMDID, cmd->vdev_id, 0); 1125 err = wmi_unified_cmd_send(wmi_handle, buf, 1126 len, WMI_WOW_SET_ACTION_WAKE_UP_CMDID); 1127 if (err) { 1128 WMI_LOGE("Failed to send ap_ps_egap cmd"); 1129 wmi_buf_free(buf); 1130 return QDF_STATUS_E_FAILURE; 1131 } 1132 1133 return QDF_STATUS_SUCCESS; 1134 } 1135 1136 #ifdef FEATURE_WLAN_LPHB 1137 /** 1138 * send_lphb_config_hbenable_cmd_tlv() - enable command of LPHB configuration 1139 * @wmi_handle: wmi handle 1140 * @lphb_conf_req: configuration info 1141 * 1142 * Return: CDF status 1143 */ 1144 static QDF_STATUS send_lphb_config_hbenable_cmd_tlv(wmi_unified_t wmi_handle, 1145 wmi_hb_set_enable_cmd_fixed_param *params) 1146 { 1147 QDF_STATUS status; 1148 wmi_buf_t buf = NULL; 1149 uint8_t *buf_ptr; 1150 wmi_hb_set_enable_cmd_fixed_param *hb_enable_fp; 1151 int len = sizeof(wmi_hb_set_enable_cmd_fixed_param); 1152 1153 buf = wmi_buf_alloc(wmi_handle, len); 1154 if (!buf) { 1155 return QDF_STATUS_E_NOMEM; 1156 } 1157 1158 buf_ptr = (uint8_t *) wmi_buf_data(buf); 1159 hb_enable_fp = (wmi_hb_set_enable_cmd_fixed_param *) buf_ptr; 1160 WMITLV_SET_HDR(&hb_enable_fp->tlv_header, 1161 WMITLV_TAG_STRUC_wmi_hb_set_enable_cmd_fixed_param, 1162 WMITLV_GET_STRUCT_TLVLEN 1163 (wmi_hb_set_enable_cmd_fixed_param)); 1164 1165 /* fill in values */ 1166 hb_enable_fp->vdev_id = params->session; 1167 hb_enable_fp->enable = params->enable; 1168 hb_enable_fp->item = params->item; 1169 hb_enable_fp->session = params->session; 1170 1171 wmi_mtrace(WMI_HB_SET_ENABLE_CMDID, NO_SESSION, 0); 1172 status = wmi_unified_cmd_send(wmi_handle, buf, 1173 len, WMI_HB_SET_ENABLE_CMDID); 1174 if (QDF_IS_STATUS_ERROR(status)) { 1175 WMI_LOGE("cmd_send WMI_HB_SET_ENABLE returned Error %d", 1176 status); 1177 wmi_buf_free(buf); 1178 } 1179 1180 return status; 1181 } 1182 1183 /** 1184 * send_lphb_config_tcp_params_cmd_tlv() - set tcp params of LPHB configuration 1185 * @wmi_handle: wmi handle 1186 * @lphb_conf_req: lphb config request 1187 * 1188 * Return: CDF status 1189 */ 1190 static QDF_STATUS send_lphb_config_tcp_params_cmd_tlv(wmi_unified_t wmi_handle, 1191 wmi_hb_set_tcp_params_cmd_fixed_param *lphb_conf_req) 1192 { 1193 QDF_STATUS status; 1194 wmi_buf_t buf = NULL; 1195 uint8_t *buf_ptr; 1196 wmi_hb_set_tcp_params_cmd_fixed_param *hb_tcp_params_fp; 1197 int len = sizeof(wmi_hb_set_tcp_params_cmd_fixed_param); 1198 1199 buf = wmi_buf_alloc(wmi_handle, len); 1200 if (!buf) { 1201 return QDF_STATUS_E_NOMEM; 1202 } 1203 1204 buf_ptr = (uint8_t *) wmi_buf_data(buf); 1205 hb_tcp_params_fp = (wmi_hb_set_tcp_params_cmd_fixed_param *) buf_ptr; 1206 WMITLV_SET_HDR(&hb_tcp_params_fp->tlv_header, 1207 WMITLV_TAG_STRUC_wmi_hb_set_tcp_params_cmd_fixed_param, 1208 WMITLV_GET_STRUCT_TLVLEN 1209 (wmi_hb_set_tcp_params_cmd_fixed_param)); 1210 1211 /* fill in values */ 1212 hb_tcp_params_fp->vdev_id = lphb_conf_req->vdev_id; 1213 hb_tcp_params_fp->srv_ip = lphb_conf_req->srv_ip; 1214 hb_tcp_params_fp->dev_ip = lphb_conf_req->dev_ip; 1215 hb_tcp_params_fp->seq = lphb_conf_req->seq; 1216 hb_tcp_params_fp->src_port = lphb_conf_req->src_port; 1217 hb_tcp_params_fp->dst_port = lphb_conf_req->dst_port; 1218 hb_tcp_params_fp->interval = lphb_conf_req->interval; 1219 hb_tcp_params_fp->timeout = lphb_conf_req->timeout; 1220 hb_tcp_params_fp->session = lphb_conf_req->session; 1221 qdf_mem_copy(&hb_tcp_params_fp->gateway_mac, 1222 &lphb_conf_req->gateway_mac, 1223 sizeof(hb_tcp_params_fp->gateway_mac)); 1224 1225 wmi_mtrace(WMI_HB_SET_TCP_PARAMS_CMDID, NO_SESSION, 0); 1226 status = wmi_unified_cmd_send(wmi_handle, buf, 1227 len, WMI_HB_SET_TCP_PARAMS_CMDID); 1228 if (QDF_IS_STATUS_ERROR(status)) { 1229 WMI_LOGE("cmd_send WMI_HB_SET_TCP_PARAMS returned Error %d", 1230 status); 1231 wmi_buf_free(buf); 1232 } 1233 1234 return status; 1235 } 1236 1237 /** 1238 * send_lphb_config_tcp_pkt_filter_cmd_tlv() - configure tcp packet filter cmd 1239 * @wmi_handle: wmi handle 1240 * @lphb_conf_req: lphb config request 1241 * 1242 * Return: CDF status 1243 */ 1244 static 1245 QDF_STATUS send_lphb_config_tcp_pkt_filter_cmd_tlv(wmi_unified_t wmi_handle, 1246 wmi_hb_set_tcp_pkt_filter_cmd_fixed_param *g_hb_tcp_filter_fp) 1247 { 1248 QDF_STATUS status; 1249 wmi_buf_t buf = NULL; 1250 uint8_t *buf_ptr; 1251 wmi_hb_set_tcp_pkt_filter_cmd_fixed_param *hb_tcp_filter_fp; 1252 int len = sizeof(wmi_hb_set_tcp_pkt_filter_cmd_fixed_param); 1253 1254 buf = wmi_buf_alloc(wmi_handle, len); 1255 if (!buf) { 1256 return QDF_STATUS_E_NOMEM; 1257 } 1258 1259 buf_ptr = (uint8_t *) wmi_buf_data(buf); 1260 hb_tcp_filter_fp = 1261 (wmi_hb_set_tcp_pkt_filter_cmd_fixed_param *) buf_ptr; 1262 WMITLV_SET_HDR(&hb_tcp_filter_fp->tlv_header, 1263 WMITLV_TAG_STRUC_wmi_hb_set_tcp_pkt_filter_cmd_fixed_param, 1264 WMITLV_GET_STRUCT_TLVLEN 1265 (wmi_hb_set_tcp_pkt_filter_cmd_fixed_param)); 1266 1267 /* fill in values */ 1268 hb_tcp_filter_fp->vdev_id = g_hb_tcp_filter_fp->vdev_id; 1269 hb_tcp_filter_fp->length = g_hb_tcp_filter_fp->length; 1270 hb_tcp_filter_fp->offset = g_hb_tcp_filter_fp->offset; 1271 hb_tcp_filter_fp->session = g_hb_tcp_filter_fp->session; 1272 memcpy((void *)&hb_tcp_filter_fp->filter, 1273 (void *)&g_hb_tcp_filter_fp->filter, 1274 WMI_WLAN_HB_MAX_FILTER_SIZE); 1275 1276 wmi_mtrace(WMI_HB_SET_TCP_PKT_FILTER_CMDID, NO_SESSION, 0); 1277 status = wmi_unified_cmd_send(wmi_handle, buf, 1278 len, WMI_HB_SET_TCP_PKT_FILTER_CMDID); 1279 if (QDF_IS_STATUS_ERROR(status)) { 1280 WMI_LOGE("cmd_send WMI_HB_SET_TCP_PKT_FILTER returned Error %d", 1281 status); 1282 wmi_buf_free(buf); 1283 } 1284 1285 return status; 1286 } 1287 1288 /** 1289 * send_lphb_config_udp_params_cmd_tlv() - configure udp param command of LPHB 1290 * @wmi_handle: wmi handle 1291 * @lphb_conf_req: lphb config request 1292 * 1293 * Return: CDF status 1294 */ 1295 static QDF_STATUS send_lphb_config_udp_params_cmd_tlv(wmi_unified_t wmi_handle, 1296 wmi_hb_set_udp_params_cmd_fixed_param *lphb_conf_req) 1297 { 1298 QDF_STATUS status; 1299 wmi_buf_t buf = NULL; 1300 uint8_t *buf_ptr; 1301 wmi_hb_set_udp_params_cmd_fixed_param *hb_udp_params_fp; 1302 int len = sizeof(wmi_hb_set_udp_params_cmd_fixed_param); 1303 1304 buf = wmi_buf_alloc(wmi_handle, len); 1305 if (!buf) { 1306 return QDF_STATUS_E_NOMEM; 1307 } 1308 1309 buf_ptr = (uint8_t *) wmi_buf_data(buf); 1310 hb_udp_params_fp = (wmi_hb_set_udp_params_cmd_fixed_param *) buf_ptr; 1311 WMITLV_SET_HDR(&hb_udp_params_fp->tlv_header, 1312 WMITLV_TAG_STRUC_wmi_hb_set_udp_params_cmd_fixed_param, 1313 WMITLV_GET_STRUCT_TLVLEN 1314 (wmi_hb_set_udp_params_cmd_fixed_param)); 1315 1316 /* fill in values */ 1317 hb_udp_params_fp->vdev_id = lphb_conf_req->vdev_id; 1318 hb_udp_params_fp->srv_ip = lphb_conf_req->srv_ip; 1319 hb_udp_params_fp->dev_ip = lphb_conf_req->dev_ip; 1320 hb_udp_params_fp->src_port = lphb_conf_req->src_port; 1321 hb_udp_params_fp->dst_port = lphb_conf_req->dst_port; 1322 hb_udp_params_fp->interval = lphb_conf_req->interval; 1323 hb_udp_params_fp->timeout = lphb_conf_req->timeout; 1324 hb_udp_params_fp->session = lphb_conf_req->session; 1325 qdf_mem_copy(&hb_udp_params_fp->gateway_mac, 1326 &lphb_conf_req->gateway_mac, 1327 sizeof(lphb_conf_req->gateway_mac)); 1328 1329 wmi_mtrace(WMI_HB_SET_UDP_PARAMS_CMDID, NO_SESSION, 0); 1330 status = wmi_unified_cmd_send(wmi_handle, buf, 1331 len, WMI_HB_SET_UDP_PARAMS_CMDID); 1332 if (QDF_IS_STATUS_ERROR(status)) { 1333 WMI_LOGE("cmd_send WMI_HB_SET_UDP_PARAMS returned Error %d", 1334 status); 1335 wmi_buf_free(buf); 1336 } 1337 1338 return status; 1339 } 1340 1341 /** 1342 * send_lphb_config_udp_pkt_filter_cmd_tlv() - configure udp pkt filter command 1343 * @wmi_handle: wmi handle 1344 * @lphb_conf_req: lphb config request 1345 * 1346 * Return: CDF status 1347 */ 1348 static 1349 QDF_STATUS send_lphb_config_udp_pkt_filter_cmd_tlv(wmi_unified_t wmi_handle, 1350 wmi_hb_set_udp_pkt_filter_cmd_fixed_param *lphb_conf_req) 1351 { 1352 QDF_STATUS status; 1353 wmi_buf_t buf = NULL; 1354 uint8_t *buf_ptr; 1355 wmi_hb_set_udp_pkt_filter_cmd_fixed_param *hb_udp_filter_fp; 1356 int len = sizeof(wmi_hb_set_udp_pkt_filter_cmd_fixed_param); 1357 1358 buf = wmi_buf_alloc(wmi_handle, len); 1359 if (!buf) { 1360 return QDF_STATUS_E_NOMEM; 1361 } 1362 1363 buf_ptr = (uint8_t *) wmi_buf_data(buf); 1364 hb_udp_filter_fp = 1365 (wmi_hb_set_udp_pkt_filter_cmd_fixed_param *) buf_ptr; 1366 WMITLV_SET_HDR(&hb_udp_filter_fp->tlv_header, 1367 WMITLV_TAG_STRUC_wmi_hb_set_udp_pkt_filter_cmd_fixed_param, 1368 WMITLV_GET_STRUCT_TLVLEN 1369 (wmi_hb_set_udp_pkt_filter_cmd_fixed_param)); 1370 1371 /* fill in values */ 1372 hb_udp_filter_fp->vdev_id = lphb_conf_req->vdev_id; 1373 hb_udp_filter_fp->length = lphb_conf_req->length; 1374 hb_udp_filter_fp->offset = lphb_conf_req->offset; 1375 hb_udp_filter_fp->session = lphb_conf_req->session; 1376 memcpy((void *)&hb_udp_filter_fp->filter, 1377 (void *)&lphb_conf_req->filter, 1378 WMI_WLAN_HB_MAX_FILTER_SIZE); 1379 1380 wmi_mtrace(WMI_HB_SET_UDP_PKT_FILTER_CMDID, NO_SESSION, 0); 1381 status = wmi_unified_cmd_send(wmi_handle, buf, 1382 len, WMI_HB_SET_UDP_PKT_FILTER_CMDID); 1383 if (QDF_IS_STATUS_ERROR(status)) { 1384 WMI_LOGE("cmd_send WMI_HB_SET_UDP_PKT_FILTER returned Error %d", 1385 status); 1386 wmi_buf_free(buf); 1387 } 1388 1389 return status; 1390 } 1391 1392 void wmi_lphb_attach_tlv(struct wmi_unified *wmi_handle) 1393 { 1394 struct wmi_ops *ops = wmi_handle->ops; 1395 1396 ops->send_lphb_config_hbenable_cmd = 1397 send_lphb_config_hbenable_cmd_tlv; 1398 ops->send_lphb_config_tcp_params_cmd = 1399 send_lphb_config_tcp_params_cmd_tlv; 1400 ops->send_lphb_config_tcp_pkt_filter_cmd = 1401 send_lphb_config_tcp_pkt_filter_cmd_tlv; 1402 ops->send_lphb_config_udp_params_cmd = 1403 send_lphb_config_udp_params_cmd_tlv; 1404 ops->send_lphb_config_udp_pkt_filter_cmd = 1405 send_lphb_config_udp_pkt_filter_cmd_tlv; 1406 } 1407 #endif /* FEATURE_WLAN_LPHB */ 1408 1409 #ifdef WLAN_FEATURE_PACKET_FILTERING 1410 /** 1411 * send_enable_disable_packet_filter_cmd_tlv() - enable/disable packet filter 1412 * @wmi_handle: wmi handle 1413 * @vdev_id: vdev id 1414 * @enable: Flag to enable/disable packet filter 1415 * 1416 * Return: QDF_STATUS_SUCCESS for success or error code 1417 */ 1418 static QDF_STATUS send_enable_disable_packet_filter_cmd_tlv( 1419 wmi_unified_t wmi_handle, uint8_t vdev_id, bool enable) 1420 { 1421 int32_t len; 1422 int ret = 0; 1423 wmi_buf_t buf; 1424 WMI_PACKET_FILTER_ENABLE_CMD_fixed_param *cmd; 1425 1426 len = sizeof(WMI_PACKET_FILTER_ENABLE_CMD_fixed_param); 1427 1428 buf = wmi_buf_alloc(wmi_handle, len); 1429 if (!buf) { 1430 return QDF_STATUS_E_NOMEM; 1431 } 1432 1433 cmd = (WMI_PACKET_FILTER_ENABLE_CMD_fixed_param *) wmi_buf_data(buf); 1434 WMITLV_SET_HDR(&cmd->tlv_header, 1435 WMITLV_TAG_STRUC_wmi_packet_filter_enable_fixed_param, 1436 WMITLV_GET_STRUCT_TLVLEN( 1437 WMI_PACKET_FILTER_ENABLE_CMD_fixed_param)); 1438 1439 cmd->vdev_id = vdev_id; 1440 if (enable) 1441 cmd->enable = PACKET_FILTER_SET_ENABLE; 1442 else 1443 cmd->enable = PACKET_FILTER_SET_DISABLE; 1444 1445 WMI_LOGE("%s: Packet filter enable %d for vdev_id %d", 1446 __func__, cmd->enable, vdev_id); 1447 1448 wmi_mtrace(WMI_PACKET_FILTER_ENABLE_CMDID, cmd->vdev_id, 0); 1449 ret = wmi_unified_cmd_send(wmi_handle, buf, len, 1450 WMI_PACKET_FILTER_ENABLE_CMDID); 1451 if (ret) { 1452 WMI_LOGE("Failed to send packet filter wmi cmd to fw"); 1453 wmi_buf_free(buf); 1454 } 1455 1456 return ret; 1457 } 1458 1459 /** 1460 * send_config_packet_filter_cmd_tlv() - configure packet filter in target 1461 * @wmi_handle: wmi handle 1462 * @vdev_id: vdev id 1463 * @rcv_filter_param: Packet filter parameters 1464 * @filter_id: Filter id 1465 * @enable: Flag to add/delete packet filter configuration 1466 * 1467 * Return: QDF_STATUS_SUCCESS for success or error code 1468 */ 1469 static QDF_STATUS send_config_packet_filter_cmd_tlv(wmi_unified_t wmi_handle, 1470 uint8_t vdev_id, struct pmo_rcv_pkt_fltr_cfg *rcv_filter_param, 1471 uint8_t filter_id, bool enable) 1472 { 1473 int len, i; 1474 int err = 0; 1475 wmi_buf_t buf; 1476 WMI_PACKET_FILTER_CONFIG_CMD_fixed_param *cmd; 1477 1478 /* allocate the memory */ 1479 len = sizeof(*cmd); 1480 buf = wmi_buf_alloc(wmi_handle, len); 1481 if (!buf) { 1482 return QDF_STATUS_E_NOMEM; 1483 } 1484 1485 cmd = (WMI_PACKET_FILTER_CONFIG_CMD_fixed_param *)wmi_buf_data(buf); 1486 WMITLV_SET_HDR(&cmd->tlv_header, 1487 WMITLV_TAG_STRUC_wmi_packet_filter_config_fixed_param, 1488 WMITLV_GET_STRUCT_TLVLEN 1489 (WMI_PACKET_FILTER_CONFIG_CMD_fixed_param)); 1490 1491 cmd->vdev_id = vdev_id; 1492 cmd->filter_id = filter_id; 1493 if (enable) 1494 cmd->filter_action = PACKET_FILTER_SET_ACTIVE; 1495 else 1496 cmd->filter_action = PACKET_FILTER_SET_INACTIVE; 1497 1498 if (enable) { 1499 cmd->num_params = QDF_MIN( 1500 WMI_PACKET_FILTER_MAX_CMP_PER_PACKET_FILTER, 1501 rcv_filter_param->num_params); 1502 cmd->filter_type = rcv_filter_param->filter_type; 1503 cmd->coalesce_time = rcv_filter_param->coalesce_time; 1504 1505 for (i = 0; i < cmd->num_params; i++) { 1506 cmd->paramsData[i].proto_type = 1507 rcv_filter_param->params_data[i].protocol_layer; 1508 cmd->paramsData[i].cmp_type = 1509 rcv_filter_param->params_data[i].compare_flag; 1510 cmd->paramsData[i].data_length = 1511 rcv_filter_param->params_data[i].data_length; 1512 cmd->paramsData[i].data_offset = 1513 rcv_filter_param->params_data[i].data_offset; 1514 memcpy(&cmd->paramsData[i].compareData, 1515 rcv_filter_param->params_data[i].compare_data, 1516 sizeof(cmd->paramsData[i].compareData)); 1517 memcpy(&cmd->paramsData[i].dataMask, 1518 rcv_filter_param->params_data[i].data_mask, 1519 sizeof(cmd->paramsData[i].dataMask)); 1520 } 1521 } 1522 1523 WMI_LOGE("Packet filter action %d filter with id: %d, num_params=%d", 1524 cmd->filter_action, cmd->filter_id, cmd->num_params); 1525 /* send the command along with data */ 1526 wmi_mtrace(WMI_PACKET_FILTER_CONFIG_CMDID, cmd->vdev_id, 0); 1527 err = wmi_unified_cmd_send(wmi_handle, buf, len, 1528 WMI_PACKET_FILTER_CONFIG_CMDID); 1529 if (err) { 1530 WMI_LOGE("Failed to send pkt_filter cmd"); 1531 wmi_buf_free(buf); 1532 return QDF_STATUS_E_FAILURE; 1533 } 1534 1535 return QDF_STATUS_SUCCESS; 1536 } 1537 1538 void wmi_packet_filtering_attach_tlv(struct wmi_unified *wmi_handle) 1539 { 1540 struct wmi_ops *ops = wmi_handle->ops; 1541 1542 ops->send_enable_disable_packet_filter_cmd = 1543 send_enable_disable_packet_filter_cmd_tlv; 1544 ops->send_config_packet_filter_cmd = 1545 send_config_packet_filter_cmd_tlv; 1546 } 1547 #endif /* WLAN_FEATURE_PACKET_FILTERING */ 1548 1549 /** 1550 * send_wow_delete_pattern_cmd_tlv() - delete wow pattern in target 1551 * @wmi_handle: wmi handle 1552 * @ptrn_id: pattern id 1553 * @vdev_id: vdev id 1554 * 1555 * Return: CDF status 1556 */ 1557 static QDF_STATUS send_wow_delete_pattern_cmd_tlv(wmi_unified_t wmi_handle, 1558 uint8_t ptrn_id, 1559 uint8_t vdev_id) 1560 { 1561 WMI_WOW_DEL_PATTERN_CMD_fixed_param *cmd; 1562 wmi_buf_t buf; 1563 int32_t len; 1564 int ret; 1565 1566 len = sizeof(WMI_WOW_DEL_PATTERN_CMD_fixed_param); 1567 1568 buf = wmi_buf_alloc(wmi_handle, len); 1569 if (!buf) { 1570 return QDF_STATUS_E_NOMEM; 1571 } 1572 1573 cmd = (WMI_WOW_DEL_PATTERN_CMD_fixed_param *) wmi_buf_data(buf); 1574 1575 WMITLV_SET_HDR(&cmd->tlv_header, 1576 WMITLV_TAG_STRUC_WMI_WOW_DEL_PATTERN_CMD_fixed_param, 1577 WMITLV_GET_STRUCT_TLVLEN( 1578 WMI_WOW_DEL_PATTERN_CMD_fixed_param)); 1579 cmd->vdev_id = vdev_id; 1580 cmd->pattern_id = ptrn_id; 1581 cmd->pattern_type = WOW_BITMAP_PATTERN; 1582 1583 wmi_mtrace(WMI_WOW_DEL_WAKE_PATTERN_CMDID, cmd->vdev_id, 0); 1584 ret = wmi_unified_cmd_send(wmi_handle, buf, len, 1585 WMI_WOW_DEL_WAKE_PATTERN_CMDID); 1586 if (ret) { 1587 WMI_LOGE("%s: Failed to delete wow ptrn from fw", __func__); 1588 wmi_buf_free(buf); 1589 return QDF_STATUS_E_FAILURE; 1590 } 1591 1592 return QDF_STATUS_SUCCESS; 1593 } 1594 1595 /** 1596 * send_host_wakeup_ind_to_fw_cmd_tlv() - send wakeup ind to fw 1597 * @wmi_handle: wmi handle 1598 * 1599 * Sends host wakeup indication to FW. On receiving this indication, 1600 * FW will come out of WOW. 1601 * 1602 * Return: CDF status 1603 */ 1604 static QDF_STATUS send_host_wakeup_ind_to_fw_cmd_tlv(wmi_unified_t wmi_handle) 1605 { 1606 wmi_wow_hostwakeup_from_sleep_cmd_fixed_param *cmd; 1607 wmi_buf_t buf; 1608 QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; 1609 int32_t len; 1610 int ret; 1611 1612 len = sizeof(wmi_wow_hostwakeup_from_sleep_cmd_fixed_param); 1613 1614 buf = wmi_buf_alloc(wmi_handle, len); 1615 if (!buf) { 1616 return QDF_STATUS_E_NOMEM; 1617 } 1618 1619 cmd = (wmi_wow_hostwakeup_from_sleep_cmd_fixed_param *) 1620 wmi_buf_data(buf); 1621 WMITLV_SET_HDR(&cmd->tlv_header, 1622 WMITLV_TAG_STRUC_wmi_wow_hostwakeup_from_sleep_cmd_fixed_param, 1623 WMITLV_GET_STRUCT_TLVLEN 1624 (wmi_wow_hostwakeup_from_sleep_cmd_fixed_param)); 1625 1626 wmi_mtrace(WMI_WOW_HOSTWAKEUP_FROM_SLEEP_CMDID, NO_SESSION, 0); 1627 ret = wmi_unified_cmd_send(wmi_handle, buf, len, 1628 WMI_WOW_HOSTWAKEUP_FROM_SLEEP_CMDID); 1629 if (ret) { 1630 WMI_LOGE("Failed to send host wakeup indication to fw"); 1631 wmi_buf_free(buf); 1632 return QDF_STATUS_E_FAILURE; 1633 } 1634 1635 return qdf_status; 1636 } 1637 1638 /** 1639 * send_wow_timer_pattern_cmd_tlv() - set timer pattern tlv, so that firmware 1640 * will wake up host after specified time is elapsed 1641 * @wmi_handle: wmi handle 1642 * @vdev_id: vdev id 1643 * @cookie: value to identify reason why host set up wake call. 1644 * @time: time in ms 1645 * 1646 * Return: QDF status 1647 */ 1648 static QDF_STATUS send_wow_timer_pattern_cmd_tlv(wmi_unified_t wmi_handle, 1649 uint8_t vdev_id, uint32_t cookie, uint32_t time) 1650 { 1651 WMI_WOW_ADD_PATTERN_CMD_fixed_param *cmd; 1652 wmi_buf_t buf; 1653 uint8_t *buf_ptr; 1654 int32_t len; 1655 int ret; 1656 1657 len = sizeof(WMI_WOW_ADD_PATTERN_CMD_fixed_param) + 1658 WMI_TLV_HDR_SIZE + 0 * sizeof(WOW_BITMAP_PATTERN_T) + 1659 WMI_TLV_HDR_SIZE + 0 * sizeof(WOW_IPV4_SYNC_PATTERN_T) + 1660 WMI_TLV_HDR_SIZE + 0 * sizeof(WOW_IPV6_SYNC_PATTERN_T) + 1661 WMI_TLV_HDR_SIZE + 0 * sizeof(WOW_MAGIC_PATTERN_CMD) + 1662 WMI_TLV_HDR_SIZE + 1 * sizeof(uint32_t) + 1663 WMI_TLV_HDR_SIZE + 1 * sizeof(uint32_t); 1664 1665 buf = wmi_buf_alloc(wmi_handle, len); 1666 if (!buf) { 1667 return QDF_STATUS_E_NOMEM; 1668 } 1669 1670 cmd = (WMI_WOW_ADD_PATTERN_CMD_fixed_param *) wmi_buf_data(buf); 1671 buf_ptr = (uint8_t *) cmd; 1672 1673 WMITLV_SET_HDR(&cmd->tlv_header, 1674 WMITLV_TAG_STRUC_WMI_WOW_ADD_PATTERN_CMD_fixed_param, 1675 WMITLV_GET_STRUCT_TLVLEN 1676 (WMI_WOW_ADD_PATTERN_CMD_fixed_param)); 1677 cmd->vdev_id = vdev_id; 1678 cmd->pattern_id = cookie, 1679 cmd->pattern_type = WOW_TIMER_PATTERN; 1680 buf_ptr += sizeof(WMI_WOW_ADD_PATTERN_CMD_fixed_param); 1681 1682 /* Fill TLV for WMITLV_TAG_STRUC_WOW_BITMAP_PATTERN_T but no data. */ 1683 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, 0); 1684 buf_ptr += WMI_TLV_HDR_SIZE; 1685 1686 /* Fill TLV for WMITLV_TAG_STRUC_WOW_IPV4_SYNC_PATTERN_T but no data. */ 1687 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, 0); 1688 buf_ptr += WMI_TLV_HDR_SIZE; 1689 1690 /* Fill TLV for WMITLV_TAG_STRUC_WOW_IPV6_SYNC_PATTERN_T but no data. */ 1691 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, 0); 1692 buf_ptr += WMI_TLV_HDR_SIZE; 1693 1694 /* Fill TLV for WMITLV_TAG_STRUC_WOW_MAGIC_PATTERN_CMD but no data. */ 1695 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, 0); 1696 buf_ptr += WMI_TLV_HDR_SIZE; 1697 1698 /* Fill TLV for pattern_info_timeout, and time value */ 1699 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_UINT32, sizeof(uint32_t)); 1700 buf_ptr += WMI_TLV_HDR_SIZE; 1701 *((uint32_t *) buf_ptr) = time; 1702 buf_ptr += sizeof(uint32_t); 1703 1704 /* Fill TLV for ra_ratelimit_interval. with dummy 0 value */ 1705 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_UINT32, sizeof(uint32_t)); 1706 buf_ptr += WMI_TLV_HDR_SIZE; 1707 *((uint32_t *) buf_ptr) = 0; 1708 1709 WMI_LOGD("%s: send wake timer pattern with time[%d] to fw vdev = %d", 1710 __func__, time, vdev_id); 1711 1712 wmi_mtrace(WMI_WOW_ADD_WAKE_PATTERN_CMDID, cmd->vdev_id, 0); 1713 ret = wmi_unified_cmd_send(wmi_handle, buf, len, 1714 WMI_WOW_ADD_WAKE_PATTERN_CMDID); 1715 if (ret) { 1716 WMI_LOGE("%s: Failed to send wake timer pattern to fw", 1717 __func__); 1718 wmi_buf_free(buf); 1719 return QDF_STATUS_E_FAILURE; 1720 } 1721 1722 return QDF_STATUS_SUCCESS; 1723 } 1724 1725 #ifdef WLAN_FEATURE_EXTWOW_SUPPORT 1726 /** 1727 * send_enable_ext_wow_cmd_tlv() - enable ext wow in fw 1728 * @wmi_handle: wmi handle 1729 * @params: ext wow params 1730 * 1731 * Return:0 for success or error code 1732 */ 1733 static QDF_STATUS send_enable_ext_wow_cmd_tlv(wmi_unified_t wmi_handle, 1734 struct ext_wow_params *params) 1735 { 1736 wmi_extwow_enable_cmd_fixed_param *cmd; 1737 wmi_buf_t buf; 1738 int32_t len; 1739 int ret; 1740 1741 len = sizeof(wmi_extwow_enable_cmd_fixed_param); 1742 buf = wmi_buf_alloc(wmi_handle, len); 1743 if (!buf) { 1744 return QDF_STATUS_E_NOMEM; 1745 } 1746 1747 cmd = (wmi_extwow_enable_cmd_fixed_param *) wmi_buf_data(buf); 1748 1749 WMITLV_SET_HDR(&cmd->tlv_header, 1750 WMITLV_TAG_STRUC_wmi_extwow_enable_cmd_fixed_param, 1751 WMITLV_GET_STRUCT_TLVLEN 1752 (wmi_extwow_enable_cmd_fixed_param)); 1753 1754 cmd->vdev_id = params->vdev_id; 1755 cmd->type = params->type; 1756 cmd->wakeup_pin_num = params->wakeup_pin_num; 1757 1758 WMI_LOGD("%s: vdev_id %d type %d Wakeup_pin_num %x", 1759 __func__, cmd->vdev_id, cmd->type, cmd->wakeup_pin_num); 1760 1761 wmi_mtrace(WMI_EXTWOW_ENABLE_CMDID, cmd->vdev_id, 0); 1762 ret = wmi_unified_cmd_send(wmi_handle, buf, len, 1763 WMI_EXTWOW_ENABLE_CMDID); 1764 if (ret) { 1765 WMI_LOGE("%s: Failed to set EXTWOW Enable", __func__); 1766 wmi_buf_free(buf); 1767 return QDF_STATUS_E_FAILURE; 1768 } 1769 1770 return QDF_STATUS_SUCCESS; 1771 1772 } 1773 1774 /** 1775 * send_set_app_type2_params_in_fw_cmd_tlv() - set app type2 params in fw 1776 * @wmi_handle: wmi handle 1777 * @appType2Params: app type2 params 1778 * 1779 * Return: CDF status 1780 */ 1781 static QDF_STATUS send_set_app_type2_params_in_fw_cmd_tlv(wmi_unified_t wmi_handle, 1782 struct app_type2_params *appType2Params) 1783 { 1784 wmi_extwow_set_app_type2_params_cmd_fixed_param *cmd; 1785 wmi_buf_t buf; 1786 int32_t len; 1787 int ret; 1788 1789 len = sizeof(wmi_extwow_set_app_type2_params_cmd_fixed_param); 1790 buf = wmi_buf_alloc(wmi_handle, len); 1791 if (!buf) { 1792 return QDF_STATUS_E_NOMEM; 1793 } 1794 1795 cmd = (wmi_extwow_set_app_type2_params_cmd_fixed_param *) 1796 wmi_buf_data(buf); 1797 1798 WMITLV_SET_HDR(&cmd->tlv_header, 1799 WMITLV_TAG_STRUC_wmi_extwow_set_app_type2_params_cmd_fixed_param, 1800 WMITLV_GET_STRUCT_TLVLEN 1801 (wmi_extwow_set_app_type2_params_cmd_fixed_param)); 1802 1803 cmd->vdev_id = appType2Params->vdev_id; 1804 1805 qdf_mem_copy(cmd->rc4_key, appType2Params->rc4_key, 16); 1806 cmd->rc4_key_len = appType2Params->rc4_key_len; 1807 1808 cmd->ip_id = appType2Params->ip_id; 1809 cmd->ip_device_ip = appType2Params->ip_device_ip; 1810 cmd->ip_server_ip = appType2Params->ip_server_ip; 1811 1812 cmd->tcp_src_port = appType2Params->tcp_src_port; 1813 cmd->tcp_dst_port = appType2Params->tcp_dst_port; 1814 cmd->tcp_seq = appType2Params->tcp_seq; 1815 cmd->tcp_ack_seq = appType2Params->tcp_ack_seq; 1816 1817 cmd->keepalive_init = appType2Params->keepalive_init; 1818 cmd->keepalive_min = appType2Params->keepalive_min; 1819 cmd->keepalive_max = appType2Params->keepalive_max; 1820 cmd->keepalive_inc = appType2Params->keepalive_inc; 1821 1822 WMI_CHAR_ARRAY_TO_MAC_ADDR(appType2Params->gateway_mac.bytes, 1823 &cmd->gateway_mac); 1824 cmd->tcp_tx_timeout_val = appType2Params->tcp_tx_timeout_val; 1825 cmd->tcp_rx_timeout_val = appType2Params->tcp_rx_timeout_val; 1826 1827 WMI_LOGD("%s: vdev_id %d gateway_mac %pM " 1828 "rc4_key %.16s rc4_key_len %u " 1829 "ip_id %x ip_device_ip %x ip_server_ip %x " 1830 "tcp_src_port %u tcp_dst_port %u tcp_seq %u " 1831 "tcp_ack_seq %u keepalive_init %u keepalive_min %u " 1832 "keepalive_max %u keepalive_inc %u " 1833 "tcp_tx_timeout_val %u tcp_rx_timeout_val %u", 1834 __func__, cmd->vdev_id, appType2Params->gateway_mac.bytes, 1835 cmd->rc4_key, cmd->rc4_key_len, 1836 cmd->ip_id, cmd->ip_device_ip, cmd->ip_server_ip, 1837 cmd->tcp_src_port, cmd->tcp_dst_port, cmd->tcp_seq, 1838 cmd->tcp_ack_seq, cmd->keepalive_init, cmd->keepalive_min, 1839 cmd->keepalive_max, cmd->keepalive_inc, 1840 cmd->tcp_tx_timeout_val, cmd->tcp_rx_timeout_val); 1841 1842 wmi_mtrace(WMI_EXTWOW_SET_APP_TYPE2_PARAMS_CMDID, cmd->vdev_id, 0); 1843 ret = wmi_unified_cmd_send(wmi_handle, buf, len, 1844 WMI_EXTWOW_SET_APP_TYPE2_PARAMS_CMDID); 1845 if (ret) { 1846 WMI_LOGE("%s: Failed to set APP TYPE2 PARAMS", __func__); 1847 wmi_buf_free(buf); 1848 return QDF_STATUS_E_FAILURE; 1849 } 1850 1851 return QDF_STATUS_SUCCESS; 1852 1853 } 1854 1855 /** 1856 * send_app_type1_params_in_fw_cmd_tlv() - set app type1 params in fw 1857 * @wmi_handle: wmi handle 1858 * @app_type1_params: app type1 params 1859 * 1860 * Return: CDF status 1861 */ 1862 static QDF_STATUS send_app_type1_params_in_fw_cmd_tlv(wmi_unified_t wmi_handle, 1863 struct app_type1_params *app_type1_params) 1864 { 1865 wmi_extwow_set_app_type1_params_cmd_fixed_param *cmd; 1866 wmi_buf_t buf; 1867 int32_t len; 1868 int ret; 1869 1870 len = sizeof(wmi_extwow_set_app_type1_params_cmd_fixed_param); 1871 buf = wmi_buf_alloc(wmi_handle, len); 1872 if (!buf) { 1873 return QDF_STATUS_E_NOMEM; 1874 } 1875 1876 cmd = (wmi_extwow_set_app_type1_params_cmd_fixed_param *) 1877 wmi_buf_data(buf); 1878 1879 WMITLV_SET_HDR(&cmd->tlv_header, 1880 WMITLV_TAG_STRUC_wmi_extwow_set_app_type1_params_cmd_fixed_param, 1881 WMITLV_GET_STRUCT_TLVLEN 1882 (wmi_extwow_set_app_type1_params_cmd_fixed_param)); 1883 1884 cmd->vdev_id = app_type1_params->vdev_id; 1885 WMI_CHAR_ARRAY_TO_MAC_ADDR(app_type1_params->wakee_mac_addr.bytes, 1886 &cmd->wakee_mac); 1887 qdf_mem_copy(cmd->ident, app_type1_params->identification_id, 8); 1888 cmd->ident_len = app_type1_params->id_length; 1889 qdf_mem_copy(cmd->passwd, app_type1_params->password, 16); 1890 cmd->passwd_len = app_type1_params->pass_length; 1891 1892 WMI_LOGD("%s: vdev_id %d wakee_mac_addr %pM " 1893 "identification_id %.8s id_length %u " 1894 "password %.16s pass_length %u", 1895 __func__, cmd->vdev_id, app_type1_params->wakee_mac_addr.bytes, 1896 cmd->ident, cmd->ident_len, cmd->passwd, cmd->passwd_len); 1897 1898 wmi_mtrace(WMI_EXTWOW_SET_APP_TYPE1_PARAMS_CMDID, cmd->vdev_id, 0); 1899 ret = wmi_unified_cmd_send(wmi_handle, buf, len, 1900 WMI_EXTWOW_SET_APP_TYPE1_PARAMS_CMDID); 1901 if (ret) { 1902 WMI_LOGE("%s: Failed to set APP TYPE1 PARAMS", __func__); 1903 wmi_buf_free(buf); 1904 return QDF_STATUS_E_FAILURE; 1905 } 1906 1907 return QDF_STATUS_SUCCESS; 1908 } 1909 1910 void wmi_extwow_attach_tlv(struct wmi_unified *wmi_handle) 1911 { 1912 struct wmi_ops *ops = wmi_handle->ops; 1913 1914 ops->send_enable_ext_wow_cmd = send_enable_ext_wow_cmd_tlv; 1915 ops->send_set_app_type2_params_in_fw_cmd = 1916 send_set_app_type2_params_in_fw_cmd_tlv; 1917 ops->send_app_type1_params_in_fw_cmd = 1918 send_app_type1_params_in_fw_cmd_tlv; 1919 } 1920 #endif /* WLAN_FEATURE_EXTWOW_SUPPORT */ 1921 1922 void wmi_pmo_attach_tlv(wmi_unified_t wmi_handle) 1923 { 1924 struct wmi_ops *ops = wmi_handle->ops; 1925 1926 ops->send_add_wow_wakeup_event_cmd = 1927 send_add_wow_wakeup_event_cmd_tlv; 1928 ops->send_wow_patterns_to_fw_cmd = send_wow_patterns_to_fw_cmd_tlv; 1929 ops->send_enable_arp_ns_offload_cmd = 1930 send_enable_arp_ns_offload_cmd_tlv; 1931 ops->send_add_clear_mcbc_filter_cmd = 1932 send_add_clear_mcbc_filter_cmd_tlv; 1933 ops->send_multiple_add_clear_mcbc_filter_cmd = 1934 send_multiple_add_clear_mcbc_filter_cmd_tlv; 1935 ops->send_conf_hw_filter_cmd = send_conf_hw_filter_cmd_tlv; 1936 ops->send_gtk_offload_cmd = send_gtk_offload_cmd_tlv; 1937 ops->send_process_gtk_offload_getinfo_cmd = 1938 send_process_gtk_offload_getinfo_cmd_tlv; 1939 ops->send_enable_enhance_multicast_offload_cmd = 1940 send_enable_enhance_multicast_offload_tlv; 1941 ops->extract_gtk_rsp_event = extract_gtk_rsp_event_tlv; 1942 ops->send_action_frame_patterns_cmd = 1943 send_action_frame_patterns_cmd_tlv; 1944 ops->send_wow_delete_pattern_cmd = send_wow_delete_pattern_cmd_tlv; 1945 ops->send_host_wakeup_ind_to_fw_cmd = 1946 send_host_wakeup_ind_to_fw_cmd_tlv; 1947 ops->send_wow_timer_pattern_cmd = send_wow_timer_pattern_cmd_tlv; 1948 1949 wmi_d0wow_attach_tlv(wmi_handle); 1950 wmi_ra_filtering_attach_tlv(wmi_handle); 1951 wmi_lphb_attach_tlv(wmi_handle); 1952 wmi_packet_filtering_attach_tlv(wmi_handle); 1953 wmi_extwow_attach_tlv(wmi_handle); 1954 } 1955