1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Portions copyright (C) 2020 Broadcom Limited 5 * 6 * Licensed under the Apache License, Version 2.0 (the "License"); 7 * you may not use this file except in compliance with the License. 8 * You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, software 13 * distributed under the License is distributed on an "AS IS" BASIS, 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 * See the License for the specific language governing permissions and 16 * limitations under the License. 17 */ 18 19 #include <stdint.h> 20 #include <fcntl.h> 21 #include <sys/socket.h> 22 #include <netlink/genl/genl.h> 23 #include <netlink/genl/family.h> 24 #include <netlink/genl/ctrl.h> 25 #include <linux/rtnetlink.h> 26 #include <netpacket/packet.h> 27 #include <linux/filter.h> 28 #include <linux/errqueue.h> 29 30 #include <linux/pkt_sched.h> 31 #include <netlink/object-api.h> 32 #include <netlink/netlink.h> 33 #include <netlink/socket.h> 34 #include <netlink/handlers.h> 35 36 #include "sync.h" 37 38 #define LOG_TAG "WifiHAL" 39 40 #include <utils/Log.h> 41 42 #include "wifi_hal.h" 43 #include "common.h" 44 #include "cpp_bindings.h" 45 46 static const char *TwtCmdToString(int cmd); 47 static void EventGetAttributeData(u8 sub_event_type, nlattr *vendor_data); 48 typedef void *TwtRequest; 49 50 #define C2S(x) case x: return #x; 51 52 typedef struct _twt_hal_info { 53 void *twt_handle; 54 void *twt_feature_request; 55 } twt_hal_info_t; 56 57 twt_hal_info_t twt_info; 58 59 #define TWT_HANDLE(twt_info) ((twt_info).twt_handle) 60 #define GET_TWT_HANDLE(twt_info) ((TwtHandle *)twt_info.twt_handle) 61 62 #define WL_TWT_CAP_FLAGS_REQ_SUPPORT (1u << 0u) 63 #define WL_TWT_CAP_FLAGS_RESP_SUPPORT (1u << 1u) 64 #define WL_TWT_CAP_FLAGS_BTWT_SUPPORT (1u << 2u) 65 #define WL_TWT_CAP_FLAGS_FLEX_SUPPORT (1u << 3u) 66 67 class TwtHandle 68 { 69 public: 70 TwtCallbackHandler mHandlers; 71 TwtHandle(wifi_handle handle, TwtCallbackHandler handlers):mHandlers(handlers) 72 {} 73 74 }; 75 76 77 static const char *TwtCmdToString(int cmd) 78 { 79 switch (cmd) { 80 C2S(TWT_SETUP_REQUEST); 81 C2S(TWT_INFO_FRAME_REQUEST); 82 C2S(TWT_TEAR_DOWN_REQUEST); 83 default: 84 return "UNKNOWN_NAN_CMD"; 85 } 86 } 87 88 static bool is_twt_sub_event(int sub_event_type) 89 { 90 bool is_twt_event = false; 91 switch (sub_event_type) { 92 case TWT_SETUP_RESPONSE: 93 case TWT_TEARDOWN_COMPLETION: 94 case TWT_INFORM_FRAME: 95 case TWT_NOTIFY: 96 is_twt_event = true; 97 } 98 return is_twt_event; 99 } 100 101 void EventGetAttributeData(u8 sub_event_type, nlattr *vendor_data) 102 { 103 u8 attr_type = 0; 104 105 switch (sub_event_type) { 106 case TWT_SETUP_RESPONSE: 107 TwtSetupResponse setup_response; 108 for (nl_iterator it(vendor_data); it.has_next(); it.next()) { 109 attr_type = it.get_type(); 110 switch (attr_type) { 111 case TWT_ATTRIBUTE_CONFIG_ID: 112 ALOGI("config_id = %u\n", it.get_u8()); 113 setup_response.config_id = it.get_u8(); 114 break; 115 case TWT_ATTRIBUTE_NEG_TYPE: 116 ALOGI("neg type = %u\n", it.get_u8()); 117 setup_response.negotiation_type = it.get_u8(); 118 break; 119 case TWT_ATTRIBUTE_REASON_CODE: 120 setup_response.reason_code = (TwtSetupReasonCode)it.get_u8(); 121 ALOGI("reason code = %u\n", setup_response.reason_code); 122 break; 123 case TWT_ATTRIBUTE_STATUS: 124 setup_response.status = it.get_u8(); 125 ALOGI("status = %u\n", setup_response.status); 126 break; 127 case TWT_ATTRIBUTE_TRIGGER_TYPE: 128 setup_response.trigger_type = it.get_u8(); 129 ALOGI("trigger type = %u\n", setup_response.trigger_type); 130 break; 131 case TWT_ATTRIBUTE_WAKE_DUR_US: 132 setup_response.wake_dur_us = it.get_u32(); 133 ALOGI("wake_dur_us = %d\n", setup_response.wake_dur_us); 134 break; 135 case TWT_ATTRIBUTE_WAKE_INT_US: 136 setup_response.wake_int_us = it.get_u32(); 137 ALOGI("wake_int_us = %d\n", setup_response.wake_int_us); 138 break; 139 case TWT_ATTRIBUTE_WAKE_TIME_OFF_US: 140 setup_response.wake_time_off_us = it.get_u32(); 141 ALOGI("wake_time_off_us = %d\n", setup_response.wake_time_off_us); 142 break; 143 default: 144 if (attr_type != TWT_ATTRIBUTE_SUB_EVENT) { 145 ALOGE("Unknown attr_type: %d\n", attr_type); 146 } 147 break; 148 } 149 } 150 GET_TWT_HANDLE(twt_info)->mHandlers.EventTwtSetupResponse(&setup_response); 151 break; 152 case TWT_TEARDOWN_COMPLETION: 153 TwtTeardownCompletion teardown_event; 154 for (nl_iterator it(vendor_data); it.has_next(); it.next()) { 155 attr_type = it.get_type(); 156 switch (attr_type) { 157 case TWT_ATTRIBUTE_CONFIG_ID: 158 ALOGI("config_id = %u\n", it.get_u8()); 159 teardown_event.config_id = it.get_u8(); 160 break; 161 case TWT_ATTRIBUTE_STATUS: 162 teardown_event.status = it.get_u8(); 163 ALOGI("status = %u\n", teardown_event.status); 164 break; 165 case TWT_ATTRIBUTE_ALL_TWT: 166 teardown_event.all_twt = it.get_u8(); 167 ALOGI("all_twt = %d\n", teardown_event.all_twt); 168 break; 169 case TWT_ATTRIBUTE_REASON_CODE: 170 teardown_event.reason = (TwtTeardownReason)it.get_u8(); 171 ALOGI("reason = %u\n", teardown_event.reason); 172 break; 173 default: 174 if (attr_type != TWT_ATTRIBUTE_SUB_EVENT) { 175 ALOGE("Unknown attr_type: %d\n", attr_type); 176 } 177 break; 178 } 179 } 180 GET_TWT_HANDLE(twt_info)->mHandlers.EventTwtTeardownCompletion(&teardown_event); 181 break; 182 case TWT_INFORM_FRAME: 183 TwtInfoFrameReceived info_frame_event; 184 for (nl_iterator it(vendor_data); it.has_next(); it.next()) { 185 attr_type = it.get_type(); 186 switch (attr_type) { 187 case TWT_ATTRIBUTE_CONFIG_ID: 188 ALOGI("config_id = %u\n", it.get_u8()); 189 info_frame_event.config_id = it.get_u8(); 190 break; 191 case TWT_ATTRIBUTE_REASON_CODE: 192 info_frame_event.reason = (TwtInfoFrameReason)it.get_u8(); 193 ALOGI("reason = %u\n", info_frame_event.reason); 194 break; 195 case TWT_ATTRIBUTE_STATUS: 196 info_frame_event.status = it.get_u8(); 197 ALOGI("status = %u\n", info_frame_event.status); 198 break; 199 case TWT_ATTRIBUTE_ALL_TWT: 200 info_frame_event.all_twt = it.get_u8(); 201 ALOGI("all_twt = %d\n", info_frame_event.all_twt); 202 break; 203 case TWT_ATTRIBUTE_RESUMED: 204 info_frame_event.twt_resumed = it.get_u8(); 205 ALOGI("twt_resumed = %u\n", info_frame_event.twt_resumed); 206 break; 207 default: 208 if (attr_type != TWT_ATTRIBUTE_SUB_EVENT) { 209 ALOGE("Unknown attr_type: %d\n", attr_type); 210 } 211 break; 212 } 213 } 214 GET_TWT_HANDLE(twt_info)->mHandlers.EventTwtInfoFrameReceived(&info_frame_event); 215 break; 216 case TWT_NOTIFY: 217 TwtDeviceNotify notif_event; 218 for (nl_iterator it(vendor_data); it.has_next(); it.next()) { 219 attr_type = it.get_type(); 220 switch (attr_type) { 221 case TWT_ATTRIBUTE_NOTIFICATION: 222 notif_event.notification = (TwtNotification)it.get_u8(); 223 ALOGI("notification = %u\n", notif_event.notification); 224 break; 225 default: 226 if (attr_type != TWT_ATTRIBUTE_SUB_EVENT) { 227 ALOGE("Unknown attr_type: %d\n", attr_type); 228 } 229 break; 230 } 231 } 232 GET_TWT_HANDLE(twt_info)->mHandlers.EventTwtDeviceNotify(¬if_event); 233 break; 234 default: 235 ALOGE("Unknown event_type: %d\n", sub_event_type); 236 break; 237 } 238 return; 239 } 240 241 void HandleTwtEvent(nlattr *vendor_data) { 242 u8 sub_event_type = 0; 243 u8 event_type = 0; 244 245 for (nl_iterator it(vendor_data); it.has_next(); it.next()) { 246 event_type = it.get_type(); 247 if (event_type == TWT_ATTRIBUTE_SUB_EVENT) { 248 sub_event_type = it.get_u8(); 249 if (is_twt_sub_event(sub_event_type)) { 250 EventGetAttributeData(sub_event_type, vendor_data); 251 } 252 } 253 } 254 return; 255 } 256 257 class TwtEventCap : public WifiCommand 258 { 259 public: 260 TwtEventCap(wifi_interface_handle iface, int id) 261 : WifiCommand("TwtCommand", iface, id) 262 {} 263 264 int start() 265 { 266 registerTwtVendorEvents(); 267 return WIFI_SUCCESS; 268 } 269 270 int handleResponse(WifiEvent& reply) { 271 return NL_SKIP; 272 } 273 274 void registerTwtVendorEvents() 275 { 276 registerVendorHandler(BRCM_OUI, BRCM_VENDOR_EVENT_TWT); 277 } 278 279 void unregisterTwtVendorEvents() 280 { 281 unregisterVendorHandler(BRCM_OUI, BRCM_VENDOR_EVENT_TWT); 282 } 283 284 int handleEvent(WifiEvent& event) { 285 u16 attr_type; 286 TwtEventType twt_event; 287 288 nlattr *vendor_data = event.get_attribute(NL80211_ATTR_VENDOR_DATA); 289 int len = event.get_vendor_data_len(); 290 int event_id = event.get_vendor_subcmd(); 291 292 ALOGI("EventCapture: Received TWT event: %d\n", event_id); 293 if (!vendor_data || len == 0) { 294 ALOGE("No event data found"); 295 return NL_SKIP; 296 } 297 298 switch (event_id) { 299 case BRCM_VENDOR_EVENT_TWT: { 300 ALOGE("Handle TWT event: %d\n", event_id); 301 HandleTwtEvent(vendor_data); 302 break; 303 } 304 default: 305 break; 306 } 307 return NL_SKIP; 308 } 309 }; 310 311 /* To see event prints in console */ 312 wifi_error twt_event_check_request(transaction_id id, wifi_interface_handle iface) 313 { 314 TwtEventCap *cmd = new TwtEventCap(iface, id); 315 if (cmd == NULL) { 316 return WIFI_ERROR_NOT_SUPPORTED; 317 } 318 return (wifi_error)cmd->start(); 319 } 320 321 ////////////////////////////////////////////////////////////////////////// 322 class GetTwtCapabilitiesCommand : public WifiCommand 323 { 324 TwtCapabilitySet *mCapabilities; 325 public: 326 GetTwtCapabilitiesCommand(wifi_interface_handle iface, TwtCapabilitySet *capabilities) 327 : WifiCommand("GetTwtCapabilitiesCommand", iface, 0), mCapabilities(capabilities) 328 { 329 memset(mCapabilities, 0, sizeof(*mCapabilities)); 330 } 331 332 virtual int create() { 333 ALOGD("Creating message to get twt capabilities; iface\n"); 334 335 int ret = mMsg.create(GOOGLE_OUI, TWT_SUBCMD_GETCAPABILITY); 336 if (ret < 0) { 337 ALOGE("Failed to send the twt cap cmd, err = %d\n", ret); 338 } 339 ALOGD("Success to send twt cap cmd, err = %d\n", ret); 340 return ret; 341 } 342 343 private: 344 TwtCapability parseTwtCap(uint32_t twt_peer_cap) { 345 TwtCapability cap; 346 cap.requester_supported = (twt_peer_cap & WL_TWT_CAP_FLAGS_REQ_SUPPORT) ? 1 : 0; 347 cap.responder_supported = (twt_peer_cap & WL_TWT_CAP_FLAGS_RESP_SUPPORT) ? 1 : 0; 348 cap.broadcast_twt_supported = (twt_peer_cap & WL_TWT_CAP_FLAGS_BTWT_SUPPORT) ? 1 : 0; 349 cap.flexibile_twt_supported = (twt_peer_cap & WL_TWT_CAP_FLAGS_FLEX_SUPPORT) ? 1 : 0; 350 return cap; 351 } 352 353 protected: 354 virtual int handleResponse(WifiEvent& reply) { 355 356 ALOGI("In GetTwtCapabilitiesCommand::handleResponse"); 357 358 if (reply.get_cmd() != NL80211_CMD_VENDOR) { 359 ALOGD("Ignoring reply with cmd = %d", reply.get_cmd()); 360 return NL_SKIP; 361 } 362 363 int id = reply.get_vendor_id(); 364 int subcmd = reply.get_vendor_subcmd(); 365 uint32_t twt_device_cap, twt_peer_cap; 366 367 nlattr *data = reply.get_attribute(NL80211_ATTR_VENDOR_DATA); 368 int len = reply.get_vendor_data_len(); 369 370 ALOGD("Id = %0x, subcmd = %d, len = %d, expected len = %d", id, subcmd, len); 371 if (data == NULL || len == 0) { 372 ALOGE("no vendor data in GetTwtCapabilitiesCommand response; ignoring it\n"); 373 return NL_SKIP; 374 } 375 376 for (nl_iterator it(data); it.has_next(); it.next()) { 377 switch (it.get_type()) { 378 case TWT_ATTRIBUTE_DEVICE_CAP: 379 twt_device_cap = it.get_u32(); 380 mCapabilities->device_capability = parseTwtCap(twt_device_cap); 381 break; 382 case TWT_ATTRIBUTE_PEER_CAP: 383 twt_peer_cap = it.get_u32(); 384 mCapabilities->peer_capability = parseTwtCap(twt_peer_cap); 385 break; 386 default: 387 ALOGE("Ignoring invalid attribute type = %d, size = %d\n", 388 it.get_type(), it.get_len()); 389 break; 390 } 391 } 392 393 ALOGE("Out GetTwtCapabilitiesCommand::handleResponse\n"); 394 return NL_OK; 395 } 396 }; 397 398 /* API to get TWT capability */ 399 wifi_error twt_get_capability(wifi_interface_handle iface, 400 TwtCapabilitySet *twt_cap_set) 401 { 402 if (iface == NULL) { 403 ALOGE("twt_get_capability: NULL iface pointer provided." 404 " Exit."); 405 return WIFI_ERROR_INVALID_ARGS; 406 } 407 408 if (twt_cap_set == NULL) { 409 ALOGE("twt_get_capability: NULL capabilities pointer provided." 410 " Exit."); 411 return WIFI_ERROR_INVALID_ARGS; 412 } 413 414 GetTwtCapabilitiesCommand command(iface, twt_cap_set); 415 return (wifi_error) command.requestResponse(); 416 } 417 418 ////////////////////////////////////////////////////////////////////////// 419 class GetTwtStatsCommand : public WifiCommand 420 { 421 TwtStats* mStats; 422 u8 mConfig_id; 423 public: 424 GetTwtStatsCommand(wifi_interface_handle iface, u8 config_id, TwtStats *stats) 425 : WifiCommand("GetTwtStatsCommand", iface, 0), mConfig_id(config_id), mStats(stats) 426 { 427 memset(mStats, 0, sizeof(*mStats)); 428 } 429 430 virtual int create() { 431 ALOGD("Creating message to get twt stats; iface = %d", mIfaceInfo->id); 432 433 int ret = mMsg.create(GOOGLE_OUI, TWT_SUBCMD_GETSTATS); 434 if (ret < 0) { 435 return ret; 436 } 437 438 nlattr *data = mMsg.attr_start(NL80211_ATTR_VENDOR_DATA); 439 ret = mMsg.put_u8(TWT_ATTRIBUTE_CONFIG_ID, mConfig_id); 440 if (ret < 0) { 441 ALOGE("Failed to set mConfig_id %d\n", mConfig_id); 442 return ret; 443 } 444 445 ALOGI("Successfully configured config id %d\n", mConfig_id); 446 mMsg.attr_end(data); 447 return WIFI_SUCCESS; 448 } 449 450 protected: 451 virtual int handleResponse(WifiEvent& reply) { 452 453 ALOGI("In GetTwtStatsCommand::handleResponse"); 454 455 if (reply.get_cmd() != NL80211_CMD_VENDOR) { 456 ALOGD("Ignoring reply with cmd = %d", reply.get_cmd()); 457 return NL_SKIP; 458 } 459 460 int id = reply.get_vendor_id(); 461 int subcmd = reply.get_vendor_subcmd(); 462 463 nlattr *data = reply.get_attribute(NL80211_ATTR_VENDOR_DATA); 464 int len = reply.get_vendor_data_len(); 465 466 ALOGD("Id = %0x, subcmd = %d, len = %d, expected len = %d", id, subcmd, len); 467 if (data == NULL || len == 0) { 468 ALOGE("no vendor data in GetTwtStatsCommand response; ignoring it\n"); 469 return NL_SKIP; 470 } 471 472 for (nl_iterator it(data); it.has_next(); it.next()) { 473 switch (it.get_type()) { 474 case TWT_ATTRIBUTE_CONFIG_ID: 475 mStats->config_id = it.get_u8(); 476 break; 477 case TWT_ATTRIBUTE_AVG_PKT_NUM_TX: 478 mStats->avg_pkt_num_tx = it.get_u32(); 479 break; 480 case TWT_ATTRIBUTE_AVG_PKT_NUM_RX: 481 mStats->avg_pkt_num_rx = it.get_u32(); 482 break; 483 case TWT_ATTRIBUTE_AVG_PKT_SIZE_TX: 484 mStats->avg_tx_pkt_size = it.get_u32(); 485 break; 486 case TWT_ATTRIBUTE_AVG_PKT_SIZE_RX: 487 mStats->avg_rx_pkt_size = it.get_u32(); 488 break; 489 case TWT_ATTRIBUTE_AVG_EOSP_DUR: 490 mStats->avg_eosp_dur_us = it.get_u32(); 491 break; 492 case TWT_ATTRIBUTE_EOSP_COUNT: 493 mStats->eosp_count = it.get_u32(); 494 break; 495 case TWT_ATTRIBUTE_NUM_SP: 496 mStats->num_sp = it.get_u32(); 497 break; 498 default: 499 ALOGE("Ignoring invalid attribute type = %d, size = %d\n", 500 it.get_type(), it.get_len()); 501 break; 502 } 503 } 504 505 return NL_OK; 506 } 507 }; 508 509 /* API to get TWT stats */ 510 wifi_error twt_get_stats(wifi_interface_handle iface, u8 config_id, TwtStats* stats) 511 { 512 if (iface == NULL) { 513 ALOGE("twt_get_stats: NULL iface pointer provided." 514 " Exit."); 515 return WIFI_ERROR_INVALID_ARGS; 516 } 517 518 if (stats == NULL) { 519 ALOGE("TwtCapabilitySet: NULL capabilities pointer provided." 520 " Exit."); 521 return WIFI_ERROR_INVALID_ARGS; 522 } 523 524 GetTwtStatsCommand command(iface, config_id, stats); 525 return (wifi_error) command.requestResponse(); 526 } 527 528 ////////////////////////////////////////////////////////////////////////////////////// 529 class ClearTwtStatsCommand : public WifiCommand 530 { 531 u8 mConfig_id; 532 public: 533 ClearTwtStatsCommand(wifi_interface_handle iface, u8 config_id) 534 : WifiCommand("ClearTwtStatsCommand", iface, 0), mConfig_id(config_id) 535 { 536 } 537 538 virtual int create() { 539 ALOGD("Creating message to clear twt stats; config_id = %d\n", mConfig_id); 540 541 int ret = mMsg.create(GOOGLE_OUI, TWT_SUBCMD_CLR_STATS); 542 if (ret < 0) { 543 return ret; 544 } 545 546 nlattr *data = mMsg.attr_start(NL80211_ATTR_VENDOR_DATA); 547 ret = mMsg.put_u8(TWT_ATTRIBUTE_CONFIG_ID, mConfig_id); 548 if (ret < 0) { 549 ALOGE("Failed to set mConfig_id %d\n", mConfig_id); 550 return ret; 551 } 552 553 ALOGI("Successfully configured config id %d\n", mConfig_id); 554 mMsg.attr_end(data); 555 return WIFI_SUCCESS; 556 } 557 558 protected: 559 virtual int handleResponse(WifiEvent& reply) { 560 ALOGD("In ClearTwtStatsCommand::handleResponse"); 561 /* Nothing to do on response! */ 562 return NL_SKIP; 563 } 564 }; 565 566 /* API to clear TWT stats */ 567 wifi_error twt_clear_stats(wifi_interface_handle iface, u8 config_id) 568 { 569 if (iface == NULL || !config_id) { 570 ALOGE("twt_clear_stats: NULL iface pointer provided." 571 " Exit."); 572 return WIFI_ERROR_INVALID_ARGS; 573 } 574 ALOGE("twt_clear_stats: config id: %d\n", config_id); 575 576 ClearTwtStatsCommand command(iface, config_id); 577 return (wifi_error) command.requestResponse(); 578 } 579 580 //////////////////////////////////////////////////////////////////////////////// 581 class TwtFeatureRequest : public WifiCommand 582 { 583 TwtRequest reqContext; 584 TwtRequestType mType; 585 586 public: 587 TwtFeatureRequest(wifi_interface_handle iface, 588 TwtRequest params, TwtRequestType cmdType) 589 : WifiCommand("TwtFeatureRequest", iface, 0), reqContext(params), mType(cmdType) 590 { 591 } 592 593 int createRequest(WifiRequest& request) 594 { 595 ALOGI("TWT CMD: %s\n", TwtCmdToString(mType)); 596 if (mType == TWT_SETUP_REQUEST) { 597 return createTwtSetupRequest(request, (TwtSetupRequest *)reqContext); 598 } else if (mType == TWT_INFO_FRAME_REQUEST) { 599 return createInfoFrameRequest(request, (TwtInfoFrameRequest *)reqContext); 600 } else if (mType == TWT_TEAR_DOWN_REQUEST) { 601 return createTearDownRequest(request, (TwtTeardownRequest *)reqContext); 602 } else { 603 ALOGE("%s: Unknown TWT request: %d\n", __func__, mType); 604 return WIFI_ERROR_UNKNOWN; 605 } 606 607 return WIFI_SUCCESS; 608 } 609 610 int createTwtSetupRequest(WifiRequest& request, TwtSetupRequest *mParams) 611 { 612 int result = request.create(GOOGLE_OUI, TWT_SUBCMD_SETUP_REQUEST); 613 if (result < 0) { 614 ALOGE("%s Failed to create request, result = %d\n", __func__, result); 615 return result; 616 } 617 618 /* If handle is 0xFFFF, then update instance_id in response of this request 619 * otherwise, update not needed 620 */ 621 nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); 622 if (mParams->config_id) { 623 result = request.put_u8(TWT_ATTRIBUTE_CONFIG_ID, mParams->config_id); 624 if (result < 0) { 625 ALOGE("%s: Failed to fill config_id = %d, result = %d\n", 626 __func__, mParams->config_id, result); 627 return result; 628 } 629 } 630 631 if (mParams->negotiation_type) { 632 result = request.put_u8(TWT_ATTRIBUTE_NEG_TYPE, mParams->negotiation_type); 633 if (result < 0) { 634 ALOGE("%s: Failed to fill negotiation_type = %d, result = %d\n", 635 __func__, mParams->negotiation_type, result); 636 return result; 637 } 638 } 639 if (mParams->trigger_type) { 640 result = request.put_u8(TWT_ATTRIBUTE_TRIGGER_TYPE, mParams->trigger_type); 641 if (result < 0) { 642 ALOGE("%s: Failed to fill trigger_type = %d, result = %d\n", 643 __func__, mParams->trigger_type, result); 644 return result; 645 } 646 } 647 if (mParams->wake_dur_us) { 648 result = request.put_u32(TWT_ATTRIBUTE_WAKE_DUR_US, mParams->wake_dur_us); 649 if (result < 0) { 650 ALOGE("%s: Failed to fill wake_dur_us = %d, result = %d\n", 651 __func__, mParams->wake_dur_us, result); 652 return result; 653 } 654 } 655 if (mParams->wake_int_us) { 656 result = request.put_u32(TWT_ATTRIBUTE_WAKE_INT_US, mParams->wake_int_us); 657 if (result < 0) { 658 ALOGE("%s: Failed to fill wake_int_us = %d, result = %d\n", 659 __func__, mParams->wake_int_us, result); 660 return result; 661 } 662 } 663 if (mParams->wake_int_min_us) { 664 result = request.put_u32(TWT_ATTRIBUTE_WAKE_INT_MIN_US, mParams->wake_int_min_us); 665 if (result < 0) { 666 ALOGE("%s: Failed to fill wake_int_min_us = %d, result = %d\n", 667 __func__, mParams->wake_int_min_us, result); 668 return result; 669 } 670 } 671 if (mParams->wake_int_max_us) { 672 result = request.put_u32(TWT_ATTRIBUTE_WAKE_INT_MAX_US, mParams->wake_int_max_us); 673 if (result < 0) { 674 ALOGE("%s: Failed to fill wake_int_max_us = %d, result = %d\n", 675 __func__, mParams->wake_int_max_us, result); 676 return result; 677 } 678 } 679 if (mParams->wake_dur_min_us) { 680 result = request.put_u32(TWT_ATTRIBUTE_WAKE_DUR_MIN_US, mParams->wake_dur_min_us); 681 if (result < 0) { 682 ALOGE("%s: Failed to fill wake_dur_min_us = %d, result = %d\n", 683 __func__, mParams->wake_dur_min_us, result); 684 return result; 685 } 686 } 687 if (mParams->wake_dur_max_us) { 688 result = request.put_u32(TWT_ATTRIBUTE_WAKE_DUR_MAX_US, mParams->wake_dur_max_us); 689 if (result < 0) { 690 ALOGE("%s: Failed to fill wake_dur_max_us = %d, result = %d\n", 691 __func__, mParams->wake_dur_max_us, result); 692 return result; 693 } 694 } 695 if (mParams->avg_pkt_size) { 696 result = request.put_u32(TWT_ATTRIBUTE_AVG_PKT_SIZE, mParams->avg_pkt_size); 697 if (result < 0) { 698 ALOGE("%s: Failed to fill avg_pkt_size = %d, result = %d\n", 699 __func__, mParams->avg_pkt_size, result); 700 return result; 701 } 702 } 703 if (mParams->avg_pkt_num) { 704 result = request.put_u32(TWT_ATTRIBUTE_AVG_PKT_NUM, mParams->avg_pkt_num); 705 if (result < 0) { 706 ALOGE("%s: Failed to fill avg_pkt_num = %d, result = %d\n", 707 __func__, mParams->avg_pkt_num, result); 708 return result; 709 } 710 } 711 if (mParams->wake_time_off_us) { 712 result = request.put_u32(TWT_ATTRIBUTE_WAKE_TIME_OFF_US, mParams->wake_time_off_us); 713 if (result < 0) { 714 ALOGE("%s: Failed to fill wake_time_off_us = %d, result = %d\n", 715 __func__, mParams->wake_time_off_us, result); 716 return result; 717 } 718 } 719 request.attr_end(data); 720 721 ALOGI("Returning successfully\n"); 722 return result; 723 } 724 725 int createInfoFrameRequest(WifiRequest& request, TwtInfoFrameRequest *mParams) 726 { 727 int result = request.create(GOOGLE_OUI, TWT_SUBCMD_INFO_FRAME_REQUEST); 728 if (result < 0) { 729 ALOGE("%s: Failed to create request, result = %d\n", __func__, result); 730 return result; 731 } 732 733 nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); 734 if (mParams->config_id) { 735 result = request.put_u8(TWT_ATTRIBUTE_CONFIG_ID, mParams->config_id); 736 if (result < 0) { 737 ALOGE("%s: Failed to fill config_id = %d, result = %d\n", 738 __func__, mParams->config_id, result); 739 return result; 740 } 741 } 742 if (mParams->resume_time_us) { 743 result = request.put_u32(TWT_ATTRIBUTE_RESUME_TIME_US, mParams->resume_time_us); 744 if (result < 0) { 745 ALOGE("%s: Failed to fill resume_time_us = %d, result = %d\n", 746 __func__, mParams->resume_time_us, result); 747 return result; 748 } 749 } 750 if (mParams->all_twt) { 751 result = request.put_u8(TWT_ATTRIBUTE_ALL_TWT, mParams->all_twt); 752 if (result < 0) { 753 ALOGE("%s: Failed to fill all_twt = %d, result = %d\n", 754 __func__, mParams->all_twt, result); 755 return result; 756 } 757 } 758 request.attr_end(data); 759 return WIFI_SUCCESS; 760 } 761 762 int createTearDownRequest(WifiRequest& request, TwtTeardownRequest *mParams) 763 { 764 int result = request.create(GOOGLE_OUI, TWT_SUBCMD_TEAR_DOWN_REQUEST); 765 if (result < 0) { 766 ALOGE("%s: Failed to create request, result = %d\n", __func__, result); 767 return result; 768 } 769 770 nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); 771 if (mParams->config_id) { 772 result = request.put_u8(TWT_ATTRIBUTE_CONFIG_ID, mParams->config_id); 773 if (result < 0) { 774 ALOGE("%s: Failed to fill config_id = %d, result = %d\n", 775 __func__, mParams->config_id, result); 776 return result; 777 } 778 } 779 if (mParams->negotiation_type) { 780 result = request.put_u8(TWT_ATTRIBUTE_NEG_TYPE, mParams->negotiation_type); 781 if (result < 0) { 782 ALOGE("%s: Failed to fill negotiation_type = %d, result = %d\n", 783 __func__, mParams->negotiation_type, result); 784 return result; 785 } 786 } 787 if (mParams->all_twt) { 788 result = request.put_u8(TWT_ATTRIBUTE_ALL_TWT, mParams->all_twt); 789 if (result < 0) { 790 ALOGE("%s: Failed to fill all_twt = %d, result = %d\n", 791 __func__, mParams->all_twt, result); 792 return result; 793 } 794 } 795 request.attr_end(data); 796 return WIFI_SUCCESS; 797 } 798 799 int open() 800 { 801 WifiRequest request(familyId(), ifaceId()); 802 int result = createRequest(request); 803 if (result != WIFI_SUCCESS) { 804 ALOGE("%s: failed to create setup request; result = %d", __func__, result); 805 return result; 806 } 807 808 result = requestResponse(request); 809 if (result != WIFI_SUCCESS) { 810 ALOGE("%s: failed to configure setup; result = %d", __func__, result); 811 return result; 812 } 813 814 request.destroy(); 815 return WIFI_SUCCESS; 816 } 817 818 void registerTwtVendorEvents() 819 { 820 registerVendorHandler(BRCM_OUI, BRCM_VENDOR_EVENT_TWT); 821 } 822 823 void unregisterTwtVendorEvents() 824 { 825 unregisterVendorHandler(BRCM_OUI, BRCM_VENDOR_EVENT_TWT); 826 } 827 828 virtual int handleResponse(WifiEvent& reply) { 829 ALOGD("Request complete!"); 830 /* Nothing to do on response! */ 831 return NL_SKIP; 832 } 833 834 int handleEvent(WifiEvent& event) { 835 u16 attr_type; 836 TwtEventType twt_event; 837 838 nlattr *vendor_data = event.get_attribute(NL80211_ATTR_VENDOR_DATA); 839 int len = event.get_vendor_data_len(); 840 int event_id = event.get_vendor_subcmd(); 841 ALOGI("Received TWT event: %d\n", event_id); 842 843 if (!vendor_data || len == 0) { 844 ALOGE("No event data found"); 845 return NL_SKIP; 846 } 847 848 switch (event_id) { 849 case BRCM_VENDOR_EVENT_TWT: { 850 HandleTwtEvent(vendor_data); 851 break; 852 } 853 default: 854 ALOGE("Unknown event: %d\n", event_id); 855 break; 856 } 857 return NL_SKIP; 858 } 859 860 }; 861 862 void twt_deinit_handler() 863 { 864 if (twt_info.twt_feature_request) { 865 /* register for Twt vendor events with info mac class*/ 866 TwtFeatureRequest *cmd_event = (TwtFeatureRequest*)(twt_info.twt_feature_request); 867 cmd_event->unregisterTwtVendorEvents(); 868 delete (TwtFeatureRequest*)twt_info.twt_feature_request; 869 twt_info.twt_feature_request = NULL; 870 } 871 if (TWT_HANDLE(twt_info)) { 872 delete GET_TWT_HANDLE(twt_info); 873 TWT_HANDLE(twt_info) = NULL; 874 } 875 ALOGI("wifi twt internal clean up done"); 876 return; 877 } 878 879 wifi_error twt_register_handler(wifi_interface_handle iface, 880 TwtCallbackHandler handlers) 881 { 882 wifi_handle handle = getWifiHandle(iface); 883 if (TWT_HANDLE(twt_info)) { 884 /* cleanup and re-register */ 885 twt_deinit_handler(); 886 } 887 memset(&twt_info, 0, sizeof(twt_info)); 888 TWT_HANDLE(twt_info) = new TwtHandle(handle, handlers); 889 twt_info.twt_feature_request = 890 (void*)new TwtFeatureRequest(iface, NULL, TWT_LAST); 891 NULL_CHECK_RETURN(twt_info.twt_feature_request, 892 "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); 893 TwtFeatureRequest *cmd_event = (TwtFeatureRequest*)(twt_info.twt_feature_request); 894 cmd_event->registerTwtVendorEvents(); 895 return WIFI_SUCCESS; 896 } 897 898 wifi_error twt_setup_request(wifi_interface_handle iface, TwtSetupRequest* msg) 899 { 900 wifi_error ret = WIFI_SUCCESS; 901 TwtFeatureRequest *cmd; 902 TwtRequestType cmdType = TWT_SETUP_REQUEST; 903 904 cmd = new TwtFeatureRequest(iface, (void *)msg, cmdType); 905 NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); 906 907 ret = (wifi_error)cmd->open(); 908 if (ret != WIFI_SUCCESS) { 909 ALOGE("%s : failed in open, error = %d\n", __func__, ret); 910 } 911 cmd->releaseRef(); 912 return ret; 913 } 914 915 wifi_error twt_info_frame_request(wifi_interface_handle iface, TwtInfoFrameRequest* msg) 916 { 917 wifi_error ret = WIFI_SUCCESS; 918 TwtFeatureRequest *cmd; 919 TwtRequestType cmdType = TWT_INFO_FRAME_REQUEST; 920 921 cmd = new TwtFeatureRequest(iface, (void *)msg, cmdType); 922 NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); 923 924 ret = (wifi_error)cmd->open(); 925 if (ret != WIFI_SUCCESS) { 926 ALOGE("%s : failed in open, error = %d\n", __func__, ret); 927 } 928 cmd->releaseRef(); 929 return ret; 930 } 931 932 wifi_error twt_teardown_request(wifi_interface_handle iface, TwtTeardownRequest* msg) 933 { 934 wifi_error ret = WIFI_SUCCESS; 935 TwtFeatureRequest *cmd; 936 TwtRequestType cmdType = TWT_TEAR_DOWN_REQUEST; 937 938 cmd = new TwtFeatureRequest(iface, (void *)msg, cmdType); 939 NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); 940 941 ret = (wifi_error)cmd->open(); 942 if (ret != WIFI_SUCCESS) { 943 ALOGE("%s : failed in open, error = %d\n", __func__, ret); 944 } 945 cmd->releaseRef(); 946 return ret; 947 } 948