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