• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
35 
36 #include "nl80211_copy.h"
37 #include "sync.h"
38 
39 #define LOG_TAG  "WifiHAL"
40 
41 #include <log/log.h>
42 
43 #include <hardware_legacy/wifi_hal.h>
44 #include "common.h"
45 #include "cpp_bindings.h"
46 
47 typedef enum {
48     WIFI_OFFLOAD_START_MKEEP_ALIVE = ANDROID_NL80211_SUBCMD_WIFI_OFFLOAD_RANGE_START,
49     WIFI_OFFLOAD_STOP_MKEEP_ALIVE,
50 } WIFI_OFFLOAD_SUB_COMMAND;
51 
52 typedef enum {
53     MKEEP_ALIVE_ATTRIBUTE_INVALID               = 0,
54     MKEEP_ALIVE_ATTRIBUTE_ID                    = 1,
55     MKEEP_ALIVE_ATTRIBUTE_IP_PKT                = 2,
56     MKEEP_ALIVE_ATTRIBUTE_IP_PKT_LEN		= 3,
57     MKEEP_ALIVE_ATTRIBUTE_SRC_MAC_ADDR		= 4,
58     MKEEP_ALIVE_ATTRIBUTE_DST_MAC_ADDR		= 5,
59     MKEEP_ALIVE_ATTRIBUTE_PERIOD_MSEC		= 6,
60     MKEEP_ALIVE_ATTRIBUTE_ETHER_TYPE		= 7,
61     /* Add new attributes just above this */
62     MKEEP_ALIVE_ATTRIBUTE_MAX
63 } WIFI_MKEEP_ALIVE_ATTRIBUTE;
64 
65 typedef enum {
66     START_MKEEP_ALIVE,
67     STOP_MKEEP_ALIVE,
68 } GetCmdType;
69 
70 ///////////////////////////////////////////////////////////////////////////////
71 class MKeepAliveCommand : public WifiCommand
72 {
73     u8 mIndex;
74     u8 *mIpPkt;
75     u16 mIpPktLen;
76     u8 *mSrcMacAddr;
77     u8 *mDstMacAddr;
78     u32 mPeriodMsec;
79     GetCmdType mType;
80     u16 mEther_type;
81 
82 public:
83 
84     // constructor for start sending
MKeepAliveCommand(wifi_interface_handle iface,u8 index,u16 ether_type,u8 * ip_packet,u16 ip_packet_len,u8 * src_mac_addr,u8 * dst_mac_addr,u32 period_msec,GetCmdType cmdType)85     MKeepAliveCommand(wifi_interface_handle iface, u8 index, u16 ether_type, u8 *ip_packet, u16 ip_packet_len,
86             u8 *src_mac_addr, u8 *dst_mac_addr, u32 period_msec, GetCmdType cmdType)
87         : WifiCommand("MKeepAliveCommand", iface, 0), mIndex(index), mEther_type(ether_type), mIpPkt(ip_packet),
88         mIpPktLen(ip_packet_len), mSrcMacAddr(src_mac_addr), mDstMacAddr(dst_mac_addr),
89         mPeriodMsec(period_msec), mType(cmdType)
90     { }
91 
92     // constructor for stop sending
MKeepAliveCommand(wifi_interface_handle iface,u8 index,GetCmdType cmdType)93     MKeepAliveCommand(wifi_interface_handle iface, u8 index, GetCmdType cmdType)
94         : WifiCommand("MKeepAliveCommand", iface, 0), mIndex(index), mType(cmdType)
95     {
96         mIpPkt = NULL;
97         mIpPktLen = 0;
98         mSrcMacAddr = NULL;
99         mDstMacAddr = NULL;
100         mPeriodMsec = 0;
101         mEther_type = 0;
102     }
103 
createRequest(WifiRequest & request)104     int createRequest(WifiRequest &request) {
105         int result = WIFI_SUCCESS;
106 
107         switch (mType) {
108             case START_MKEEP_ALIVE:
109             {
110                 result = request.create(GOOGLE_OUI, WIFI_OFFLOAD_START_MKEEP_ALIVE);
111                 if (result != WIFI_SUCCESS) {
112                     ALOGE("Failed to create start keep alive request; result = %d", result);
113                     return result;
114                 }
115 
116                 nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
117 
118                 result = request.put_u8(MKEEP_ALIVE_ATTRIBUTE_ID, mIndex);
119                 if (result < 0) {
120                     ALOGE("Failed to put id request; result = %d", result);
121                     return result;
122                 }
123 
124                 result = request.put_u16(MKEEP_ALIVE_ATTRIBUTE_IP_PKT_LEN, mIpPktLen);
125                 if (result < 0) {
126                     ALOGE("Failed to put ip pkt len request; result = %d", result);
127                     return result;
128                 }
129 
130                 result = request.put(MKEEP_ALIVE_ATTRIBUTE_IP_PKT, (u8*)mIpPkt, mIpPktLen);
131                 if (result < 0) {
132                     ALOGE("Failed to put ip pkt request; result = %d", result);
133                     return result;
134                 }
135 
136                 result = request.put_addr(MKEEP_ALIVE_ATTRIBUTE_SRC_MAC_ADDR, mSrcMacAddr);
137                 if (result < 0) {
138                     ALOGE("Failed to put src mac address request; result = %d", result);
139                     return result;
140                 }
141 
142                 result = request.put_addr(MKEEP_ALIVE_ATTRIBUTE_DST_MAC_ADDR, mDstMacAddr);
143                 if (result < 0) {
144                     ALOGE("Failed to put dst mac address request; result = %d", result);
145                     return result;
146                 }
147 
148                 result = request.put_u32(MKEEP_ALIVE_ATTRIBUTE_PERIOD_MSEC, mPeriodMsec);
149                 if (result < 0) {
150                     ALOGE("Failed to put period request; result = %d", result);
151                     return result;
152                 }
153                 result = request.put_u16(MKEEP_ALIVE_ATTRIBUTE_ETHER_TYPE, mEther_type);
154                 if (result < 0) {
155                     ALOGE("Failed to put ether type; result = %d", result);
156                     return result;
157                 }
158 
159                 request.attr_end(data);
160                 break;
161             }
162 
163             case STOP_MKEEP_ALIVE:
164             {
165                 result = request.create(GOOGLE_OUI, WIFI_OFFLOAD_STOP_MKEEP_ALIVE);
166                 if (result != WIFI_SUCCESS) {
167                     ALOGE("Failed to create stop keep alive request; result = %d", result);
168                     return result;
169                 }
170 
171                 nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
172 
173                 result = request.put_u8(MKEEP_ALIVE_ATTRIBUTE_ID, mIndex);
174                 if (result < 0) {
175                     ALOGE("Failed to put id request; result = %d", result);
176                     return result;
177                 }
178 
179                 request.attr_end(data);
180                 break;
181             }
182 
183             default:
184                 ALOGE("Unknown wifi keep alive command");
185                 result = WIFI_ERROR_UNKNOWN;
186         }
187         return result;
188     }
189 
start()190     int start() {
191         ALOGD("Start mkeep_alive command");
192         WifiRequest request(familyId(), ifaceId());
193         int result = createRequest(request);
194         if (result != WIFI_SUCCESS) {
195             ALOGE("Failed to create keep alive request; result = %d", result);
196             return result;
197         }
198 
199         result = requestResponse(request);
200         if (result != WIFI_SUCCESS) {
201             ALOGE("Failed to register keep alive response; result = %d", result);
202         }
203         return result;
204     }
205 
handleResponse(WifiEvent & reply)206     virtual int handleResponse(WifiEvent& reply) {
207         ALOGD("In MKeepAliveCommand::handleResponse");
208 
209         if (reply.get_cmd() != NL80211_CMD_VENDOR) {
210             ALOGD("Ignoring reply with cmd = %d", reply.get_cmd());
211             return NL_SKIP;
212         }
213 
214         switch (mType) {
215             case START_MKEEP_ALIVE:
216             case STOP_MKEEP_ALIVE:
217                 break;
218 
219             default:
220                 ALOGW("Unknown mkeep_alive command");
221         }
222         return NL_OK;
223     }
224 
handleEvent(WifiEvent & event)225     virtual int handleEvent(WifiEvent& event) {
226         /* NO events! */
227         return NL_SKIP;
228     }
229 };
230 
231 
232 /* API to send specified mkeep_alive packet periodically. */
wifi_start_sending_offloaded_packet(wifi_request_id index,wifi_interface_handle iface,u16 ether_type,u8 * ip_packet,u16 ip_packet_len,u8 * src_mac_addr,u8 * dst_mac_addr,u32 period_msec)233 wifi_error wifi_start_sending_offloaded_packet(wifi_request_id index, wifi_interface_handle iface,
234         u16 ether_type, u8 *ip_packet, u16 ip_packet_len, u8 *src_mac_addr, u8 *dst_mac_addr,
235         u32 period_msec)
236 {
237     if ((index > 0 && index <= N_AVAIL_ID) && (ip_packet != NULL) && (src_mac_addr != NULL)
238             && (dst_mac_addr != NULL) && (period_msec > 0)
239             && (ip_packet_len <= MKEEP_ALIVE_IP_PKT_MAX) && ((ether_type == ETHERTYPE_IP) ||
240             (ether_type == ETHERTYPE_IPV6))) {
241         MKeepAliveCommand *cmd = new MKeepAliveCommand(iface, index, ether_type, ip_packet, ip_packet_len,
242                 src_mac_addr, dst_mac_addr, period_msec, START_MKEEP_ALIVE);
243         NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
244         wifi_error result = (wifi_error)cmd->start();
245         cmd->releaseRef();
246         return result;
247     } else {
248         ALOGE("Invalid mkeep_alive parameters");
249         return  WIFI_ERROR_INVALID_ARGS;
250     }
251 }
252 
253 /* API to stop sending mkeep_alive packet. */
wifi_stop_sending_offloaded_packet(wifi_request_id index,wifi_interface_handle iface)254 wifi_error wifi_stop_sending_offloaded_packet(wifi_request_id index, wifi_interface_handle iface)
255 {
256     if (index > 0 && index <= N_AVAIL_ID) {
257         MKeepAliveCommand *cmd = new MKeepAliveCommand(iface, index, STOP_MKEEP_ALIVE);
258         NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
259         wifi_error result = (wifi_error)cmd->start();
260         cmd->releaseRef();
261         return result;
262     } else {
263         ALOGE("Invalid mkeep_alive parameters");
264         return  WIFI_ERROR_INVALID_ARGS;
265     }
266 }
267