1 #include <stdint.h>
2 #include <fcntl.h>
3 #include <sys/socket.h>
4 #include <netlink/genl/genl.h>
5 #include <netlink/genl/family.h>
6 #include <netlink/genl/ctrl.h>
7 #include <linux/rtnetlink.h>
8 #include <netpacket/packet.h>
9 #include <linux/filter.h>
10 #include <linux/errqueue.h>
11 
12 #include <linux/pkt_sched.h>
13 #include <netlink/object-api.h>
14 #include <netlink/netlink.h>
15 #include <netlink/socket.h>
16 #include <netlink-private/object-api.h>
17 #include <netlink-private/types.h>
18 
19 
20 #include "nl80211_copy.h"
21 #include "sync.h"
22 
23 #define LOG_TAG  "WifiHAL"
24 
25 #include <utils/Log.h>
26 
27 #include "wifi_hal.h"
28 #include "common.h"
29 #include "cpp_bindings.h"
30 
31 using namespace android;
32 
33 typedef enum {
34     WIFI_OFFLOAD_START_MKEEP_ALIVE = ANDROID_NL80211_SUBCMD_WIFI_OFFLOAD_RANGE_START,
35     WIFI_OFFLOAD_STOP_MKEEP_ALIVE,
36 } WIFI_OFFLOAD_SUB_COMMAND;
37 
38 typedef enum {
39     MKEEP_ALIVE_ATTRIBUTE_ID,
40     MKEEP_ALIVE_ATTRIBUTE_IP_PKT,
41     MKEEP_ALIVE_ATTRIBUTE_IP_PKT_LEN,
42     MKEEP_ALIVE_ATTRIBUTE_SRC_MAC_ADDR,
43     MKEEP_ALIVE_ATTRIBUTE_DST_MAC_ADDR,
44     MKEEP_ALIVE_ATTRIBUTE_PERIOD_MSEC
45 } WIFI_MKEEP_ALIVE_ATTRIBUTE;
46 
47 typedef enum {
48     START_MKEEP_ALIVE,
49     STOP_MKEEP_ALIVE,
50 } GetCmdType;
51 
52 ///////////////////////////////////////////////////////////////////////////////
53 class MKeepAliveCommand : public WifiCommand
54 {
55     u8 mIndex;
56     u8 *mIpPkt;
57     u16 mIpPktLen;
58     u8 *mSrcMacAddr;
59     u8 *mDstMacAddr;
60     u32 mPeriodMsec;
61     GetCmdType mType;
62 
63 public:
64 
65     // constructor for start sending
MKeepAliveCommand(wifi_interface_handle iface,u8 index,u8 * ip_packet,u16 ip_packet_len,u8 * src_mac_addr,u8 * dst_mac_addr,u32 period_msec,GetCmdType cmdType)66     MKeepAliveCommand(wifi_interface_handle iface, u8 index, u8 *ip_packet, u16 ip_packet_len,
67             u8 *src_mac_addr, u8 *dst_mac_addr, u32 period_msec, GetCmdType cmdType)
68         : WifiCommand("MKeepAliveCommand", iface, 0), mIndex(index), mIpPkt(ip_packet),
69         mIpPktLen(ip_packet_len), mSrcMacAddr(src_mac_addr), mDstMacAddr(dst_mac_addr),
70         mPeriodMsec(period_msec), mType(cmdType)
71     { }
72 
73     // constructor for stop sending
MKeepAliveCommand(wifi_interface_handle iface,u8 index,GetCmdType cmdType)74     MKeepAliveCommand(wifi_interface_handle iface, u8 index, GetCmdType cmdType)
75         : WifiCommand("MKeepAliveCommand", iface, 0), mIndex(index), mType(cmdType)
76     { }
77 
createRequest(WifiRequest & request)78     int createRequest(WifiRequest &request) {
79         int result;
80 
81         switch (mType) {
82             case START_MKEEP_ALIVE:
83             {
84                 result = request.create(GOOGLE_OUI, WIFI_OFFLOAD_START_MKEEP_ALIVE);
85                 if (result != WIFI_SUCCESS) {
86                     ALOGE("Failed to create start keep alive request; result = %d", result);
87                     return result;
88                 }
89 
90                 nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
91 
92                 result = request.put_u8(MKEEP_ALIVE_ATTRIBUTE_ID, mIndex);
93                 if (result < 0) {
94                     ALOGE("Failed to put id request; result = %d", result);
95                     return result;
96                 }
97 
98                 result = request.put_u16(MKEEP_ALIVE_ATTRIBUTE_IP_PKT_LEN, mIpPktLen);
99                 if (result < 0) {
100                     ALOGE("Failed to put ip pkt len request; result = %d", result);
101                     return result;
102                 }
103 
104                 result = request.put(MKEEP_ALIVE_ATTRIBUTE_IP_PKT, (u8*)mIpPkt, mIpPktLen);
105                 if (result < 0) {
106                     ALOGE("Failed to put ip pkt request; result = %d", result);
107                     return result;
108                 }
109 
110                 result = request.put_addr(MKEEP_ALIVE_ATTRIBUTE_SRC_MAC_ADDR, mSrcMacAddr);
111                 if (result < 0) {
112                     ALOGE("Failed to put src mac address request; result = %d", result);
113                     return result;
114                 }
115 
116                 result = request.put_addr(MKEEP_ALIVE_ATTRIBUTE_DST_MAC_ADDR, mDstMacAddr);
117                 if (result < 0) {
118                     ALOGE("Failed to put dst mac address request; result = %d", result);
119                     return result;
120                 }
121 
122                 result = request.put_u32(MKEEP_ALIVE_ATTRIBUTE_PERIOD_MSEC, mPeriodMsec);
123                 if (result < 0) {
124                     ALOGE("Failed to put period request; result = %d", result);
125                     return result;
126                 }
127 
128                 request.attr_end(data);
129                 break;
130             }
131 
132             case STOP_MKEEP_ALIVE:
133             {
134                 result = request.create(GOOGLE_OUI, WIFI_OFFLOAD_STOP_MKEEP_ALIVE);
135                 if (result != WIFI_SUCCESS) {
136                     ALOGE("Failed to create stop keep alive request; result = %d", result);
137                     return result;
138                 }
139 
140                 nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
141 
142                 result = request.put_u8(MKEEP_ALIVE_ATTRIBUTE_ID, mIndex);
143                 if (result < 0) {
144                     ALOGE("Failed to put id request; result = %d", result);
145                     return result;
146                 }
147 
148                 request.attr_end(data);
149                 break;
150             }
151 
152             default:
153                 ALOGE("Unknown wifi keep alive command");
154                 result = WIFI_ERROR_UNKNOWN;
155         }
156         return result;
157     }
158 
start()159     int start() {
160         ALOGD("Start mkeep_alive command");
161         WifiRequest request(familyId(), ifaceId());
162         int result = createRequest(request);
163         if (result != WIFI_SUCCESS) {
164             ALOGE("Failed to create keep alive request; result = %d", result);
165             return result;
166         }
167 
168         result = requestResponse(request);
169         if (result != WIFI_SUCCESS) {
170             ALOGE("Failed to register keep alive response; result = %d", result);
171         }
172         return result;
173     }
174 
handleResponse(WifiEvent & reply)175     virtual int handleResponse(WifiEvent& reply) {
176         ALOGD("In MKeepAliveCommand::handleResponse");
177 
178         if (reply.get_cmd() != NL80211_CMD_VENDOR) {
179             ALOGD("Ignoring reply with cmd = %d", reply.get_cmd());
180             return NL_SKIP;
181         }
182 
183         switch (mType) {
184             case START_MKEEP_ALIVE:
185             case STOP_MKEEP_ALIVE:
186                 break;
187 
188             default:
189                 ALOGW("Unknown mkeep_alive command");
190         }
191         return NL_OK;
192     }
193 
handleEvent(WifiEvent & event)194     virtual int handleEvent(WifiEvent& event) {
195         /* NO events! */
196         return NL_SKIP;
197     }
198 };
199 
200 
201 /* API to send specified mkeep_alive packet periodically. */
wifi_start_sending_offloaded_packet(wifi_request_id index,wifi_interface_handle iface,u8 * ip_packet,u16 ip_packet_len,u8 * src_mac_addr,u8 * dst_mac_addr,u32 period_msec)202 wifi_error wifi_start_sending_offloaded_packet(wifi_request_id index, wifi_interface_handle iface,
203         u8 *ip_packet, u16 ip_packet_len, u8 *src_mac_addr, u8 *dst_mac_addr, u32 period_msec)
204 {
205     if ((index > 0 && index <= N_AVAIL_ID) && (ip_packet != NULL) && (src_mac_addr != NULL)
206             && (dst_mac_addr != NULL) && (period_msec > 0)
207             && (ip_packet_len <= MKEEP_ALIVE_IP_PKT_MAX)) {
208         MKeepAliveCommand *cmd = new MKeepAliveCommand(iface, index, ip_packet, ip_packet_len,
209                 src_mac_addr, dst_mac_addr, period_msec, START_MKEEP_ALIVE);
210         NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
211         wifi_error result = (wifi_error)cmd->start();
212         cmd->releaseRef();
213         return result;
214     } else {
215         ALOGE("Invalid mkeep_alive parameters");
216         return  WIFI_ERROR_INVALID_ARGS;
217     }
218 }
219 
220 /* API to stop sending mkeep_alive packet. */
wifi_stop_sending_offloaded_packet(wifi_request_id index,wifi_interface_handle iface)221 wifi_error wifi_stop_sending_offloaded_packet(wifi_request_id index, wifi_interface_handle iface)
222 {
223     if (index > 0 && index <= N_AVAIL_ID) {
224         MKeepAliveCommand *cmd = new MKeepAliveCommand(iface, index, STOP_MKEEP_ALIVE);
225         NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
226         wifi_error result = (wifi_error)cmd->start();
227         cmd->releaseRef();
228         return result;
229     } else {
230         ALOGE("Invalid mkeep_alive parameters");
231         return  WIFI_ERROR_INVALID_ARGS;
232     }
233 }
234