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(&notif_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