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