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