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;
TwtHandle(wifi_handle handle,TwtCallbackHandler handlers)71 TwtHandle(wifi_handle handle, TwtCallbackHandler handlers):mHandlers(handlers)
72 {}
73
74 };
75
76
TwtCmdToString(int cmd)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
is_twt_sub_event(int sub_event_type)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
EventGetAttributeData(u8 sub_event_type,nlattr * vendor_data)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
HandleTwtEvent(nlattr * vendor_data)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:
TwtEventCap(wifi_interface_handle iface,int id)260 TwtEventCap(wifi_interface_handle iface, int id)
261 : WifiCommand("TwtCommand", iface, id)
262 {}
263
start()264 int start()
265 {
266 registerTwtVendorEvents();
267 return WIFI_SUCCESS;
268 }
269
handleResponse(WifiEvent & reply)270 int handleResponse(WifiEvent& reply) {
271 return NL_SKIP;
272 }
273
registerTwtVendorEvents()274 void registerTwtVendorEvents()
275 {
276 registerVendorHandler(BRCM_OUI, BRCM_VENDOR_EVENT_TWT);
277 }
278
unregisterTwtVendorEvents()279 void unregisterTwtVendorEvents()
280 {
281 unregisterVendorHandler(BRCM_OUI, BRCM_VENDOR_EVENT_TWT);
282 }
283
handleEvent(WifiEvent & event)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 */
twt_event_check_request(transaction_id id,wifi_interface_handle iface)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:
GetTwtCapabilitiesCommand(wifi_interface_handle iface,TwtCapabilitySet * capabilities)326 GetTwtCapabilitiesCommand(wifi_interface_handle iface, TwtCapabilitySet *capabilities)
327 : WifiCommand("GetTwtCapabilitiesCommand", iface, 0), mCapabilities(capabilities)
328 {
329 memset(mCapabilities, 0, sizeof(*mCapabilities));
330 }
331
create()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:
parseTwtCap(uint32_t twt_peer_cap)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:
handleResponse(WifiEvent & reply)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 */
twt_get_capability(wifi_interface_handle iface,TwtCapabilitySet * twt_cap_set)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:
GetTwtStatsCommand(wifi_interface_handle iface,u8 config_id,TwtStats * stats)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
create()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:
handleResponse(WifiEvent & reply)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 */
twt_get_stats(wifi_interface_handle iface,u8 config_id,TwtStats * 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:
ClearTwtStatsCommand(wifi_interface_handle iface,u8 config_id)533 ClearTwtStatsCommand(wifi_interface_handle iface, u8 config_id)
534 : WifiCommand("ClearTwtStatsCommand", iface, 0), mConfig_id(config_id)
535 {
536 }
537
create()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:
handleResponse(WifiEvent & reply)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 */
twt_clear_stats(wifi_interface_handle iface,u8 config_id)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:
TwtFeatureRequest(wifi_interface_handle iface,TwtRequest params,TwtRequestType cmdType)587 TwtFeatureRequest(wifi_interface_handle iface,
588 TwtRequest params, TwtRequestType cmdType)
589 : WifiCommand("TwtFeatureRequest", iface, 0), reqContext(params), mType(cmdType)
590 {
591 }
592
createRequest(WifiRequest & request)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
createTwtSetupRequest(WifiRequest & request,TwtSetupRequest * mParams)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
createInfoFrameRequest(WifiRequest & request,TwtInfoFrameRequest * mParams)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
createTearDownRequest(WifiRequest & request,TwtTeardownRequest * mParams)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
open()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
registerTwtVendorEvents()818 void registerTwtVendorEvents()
819 {
820 registerVendorHandler(BRCM_OUI, BRCM_VENDOR_EVENT_TWT);
821 }
822
unregisterTwtVendorEvents()823 void unregisterTwtVendorEvents()
824 {
825 unregisterVendorHandler(BRCM_OUI, BRCM_VENDOR_EVENT_TWT);
826 }
827
handleResponse(WifiEvent & reply)828 virtual int handleResponse(WifiEvent& reply) {
829 ALOGD("Request complete!");
830 /* Nothing to do on response! */
831 return NL_SKIP;
832 }
833
handleEvent(WifiEvent & event)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
twt_deinit_handler()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
twt_register_handler(wifi_interface_handle iface,TwtCallbackHandler handlers)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
twt_setup_request(wifi_interface_handle iface,TwtSetupRequest * msg)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
twt_info_frame_request(wifi_interface_handle iface,TwtInfoFrameRequest * msg)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
twt_teardown_request(wifi_interface_handle iface,TwtTeardownRequest * msg)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