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