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