1cb8188ea5d3dbce3bf46522bc9e562ffa04db2e7Insun Song/*
2cb8188ea5d3dbce3bf46522bc9e562ffa04db2e7Insun Song * Copyright (C) 2017 The Android Open Source Project
3cb8188ea5d3dbce3bf46522bc9e562ffa04db2e7Insun Song *
4cb8188ea5d3dbce3bf46522bc9e562ffa04db2e7Insun Song * Portions copyright (C) 2017 Broadcom Limited
5cb8188ea5d3dbce3bf46522bc9e562ffa04db2e7Insun Song *
6cb8188ea5d3dbce3bf46522bc9e562ffa04db2e7Insun Song * Licensed under the Apache License, Version 2.0 (the "License");
7cb8188ea5d3dbce3bf46522bc9e562ffa04db2e7Insun Song * you may not use this file except in compliance with the License.
8cb8188ea5d3dbce3bf46522bc9e562ffa04db2e7Insun Song * You may obtain a copy of the License at
9cb8188ea5d3dbce3bf46522bc9e562ffa04db2e7Insun Song *
10cb8188ea5d3dbce3bf46522bc9e562ffa04db2e7Insun Song *     http://www.apache.org/licenses/LICENSE-2.0
11cb8188ea5d3dbce3bf46522bc9e562ffa04db2e7Insun Song *
12cb8188ea5d3dbce3bf46522bc9e562ffa04db2e7Insun Song * Unless required by applicable law or agreed to in writing, software
13cb8188ea5d3dbce3bf46522bc9e562ffa04db2e7Insun Song * distributed under the License is distributed on an "AS IS" BASIS,
14cb8188ea5d3dbce3bf46522bc9e562ffa04db2e7Insun Song * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15cb8188ea5d3dbce3bf46522bc9e562ffa04db2e7Insun Song * See the License for the specific language governing permissions and
16cb8188ea5d3dbce3bf46522bc9e562ffa04db2e7Insun Song * limitations under the License.
17cb8188ea5d3dbce3bf46522bc9e562ffa04db2e7Insun Song */
18cb8188ea5d3dbce3bf46522bc9e562ffa04db2e7Insun Song
198f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park#include <stdint.h>
208f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park#include <fcntl.h>
218f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park#include <sys/socket.h>
228f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park#include <netlink/genl/genl.h>
238f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park#include <netlink/genl/family.h>
248f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park#include <netlink/genl/ctrl.h>
258f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park#include <linux/rtnetlink.h>
268f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park#include <netpacket/packet.h>
278f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park#include <linux/filter.h>
288f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park#include <linux/errqueue.h>
298f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park
308f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park#include <linux/pkt_sched.h>
318f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park#include <netlink/object-api.h>
328f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park#include <netlink/netlink.h>
338f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park#include <netlink/socket.h>
34c4ca0d79752e6262b0800c971ea2b4bb6d4e0c58Paul Stewart#include <netlink-private/object-api.h>
35c4ca0d79752e6262b0800c971ea2b4bb6d4e0c58Paul Stewart#include <netlink-private/types.h>
36c4ca0d79752e6262b0800c971ea2b4bb6d4e0c58Paul Stewart
378f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park
388f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park#include "nl80211_copy.h"
398f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park#include "sync.h"
408f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park
418f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park#define LOG_TAG  "WifiHAL"
428f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park
433d58fa92a87578b0944aec2c47ca23ebbf5720e3Tom Cherry#include <log/log.h>
448f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park
458f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park#include "wifi_hal.h"
468f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park#include "common.h"
478f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park#include "cpp_bindings.h"
488f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park
498f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Parktypedef enum {
508f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park    WIFI_OFFLOAD_START_MKEEP_ALIVE = ANDROID_NL80211_SUBCMD_WIFI_OFFLOAD_RANGE_START,
518f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park    WIFI_OFFLOAD_STOP_MKEEP_ALIVE,
528f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park} WIFI_OFFLOAD_SUB_COMMAND;
538f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park
548f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Parktypedef enum {
558f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park    MKEEP_ALIVE_ATTRIBUTE_ID,
568f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park    MKEEP_ALIVE_ATTRIBUTE_IP_PKT,
578f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park    MKEEP_ALIVE_ATTRIBUTE_IP_PKT_LEN,
588f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park    MKEEP_ALIVE_ATTRIBUTE_SRC_MAC_ADDR,
598f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park    MKEEP_ALIVE_ATTRIBUTE_DST_MAC_ADDR,
608f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park    MKEEP_ALIVE_ATTRIBUTE_PERIOD_MSEC
618f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park} WIFI_MKEEP_ALIVE_ATTRIBUTE;
628f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park
638f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Parktypedef enum {
648f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park    START_MKEEP_ALIVE,
658f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park    STOP_MKEEP_ALIVE,
668f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park} GetCmdType;
678f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park
688f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park///////////////////////////////////////////////////////////////////////////////
698f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Parkclass MKeepAliveCommand : public WifiCommand
708f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park{
718f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park    u8 mIndex;
728f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park    u8 *mIpPkt;
738f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park    u16 mIpPktLen;
748f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park    u8 *mSrcMacAddr;
758f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park    u8 *mDstMacAddr;
768f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park    u32 mPeriodMsec;
778f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park    GetCmdType mType;
788f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park
798f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Parkpublic:
808f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park
818f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park    // constructor for start sending
828f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park    MKeepAliveCommand(wifi_interface_handle iface, u8 index, u8 *ip_packet, u16 ip_packet_len,
838f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park            u8 *src_mac_addr, u8 *dst_mac_addr, u32 period_msec, GetCmdType cmdType)
84d4f6adc737f93d75d3a1be8427a144f907a4dde6Vinit Deshpande        : WifiCommand("MKeepAliveCommand", iface, 0), mIndex(index), mIpPkt(ip_packet),
85d4f6adc737f93d75d3a1be8427a144f907a4dde6Vinit Deshpande        mIpPktLen(ip_packet_len), mSrcMacAddr(src_mac_addr), mDstMacAddr(dst_mac_addr),
86d4f6adc737f93d75d3a1be8427a144f907a4dde6Vinit Deshpande        mPeriodMsec(period_msec), mType(cmdType)
878f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park    { }
888f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park
898f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park    // constructor for stop sending
908f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park    MKeepAliveCommand(wifi_interface_handle iface, u8 index, GetCmdType cmdType)
91d4f6adc737f93d75d3a1be8427a144f907a4dde6Vinit Deshpande        : WifiCommand("MKeepAliveCommand", iface, 0), mIndex(index), mType(cmdType)
928f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park    { }
938f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park
948f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park    int createRequest(WifiRequest &request) {
958f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park        int result;
968f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park
978f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park        switch (mType) {
988f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park            case START_MKEEP_ALIVE:
998f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park            {
1008f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park                result = request.create(GOOGLE_OUI, WIFI_OFFLOAD_START_MKEEP_ALIVE);
1018f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park                if (result != WIFI_SUCCESS) {
1028f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park                    ALOGE("Failed to create start keep alive request; result = %d", result);
1038f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park                    return result;
1048f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park                }
1058f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park
1068f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park                nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
1078f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park
1088f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park                result = request.put_u8(MKEEP_ALIVE_ATTRIBUTE_ID, mIndex);
1098f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park                if (result < 0) {
1108f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park                    ALOGE("Failed to put id request; result = %d", result);
1118f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park                    return result;
1128f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park                }
1138f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park
1148f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park                result = request.put_u16(MKEEP_ALIVE_ATTRIBUTE_IP_PKT_LEN, mIpPktLen);
1158f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park                if (result < 0) {
1168f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park                    ALOGE("Failed to put ip pkt len request; result = %d", result);
1178f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park                    return result;
1188f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park                }
1198f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park
1208f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park                result = request.put(MKEEP_ALIVE_ATTRIBUTE_IP_PKT, (u8*)mIpPkt, mIpPktLen);
1218f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park                if (result < 0) {
1228f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park                    ALOGE("Failed to put ip pkt request; result = %d", result);
1238f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park                    return result;
1248f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park                }
1258f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park
1268f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park                result = request.put_addr(MKEEP_ALIVE_ATTRIBUTE_SRC_MAC_ADDR, mSrcMacAddr);
1278f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park                if (result < 0) {
1288f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park                    ALOGE("Failed to put src mac address request; result = %d", result);
1298f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park                    return result;
1308f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park                }
1318f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park
1328f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park                result = request.put_addr(MKEEP_ALIVE_ATTRIBUTE_DST_MAC_ADDR, mDstMacAddr);
1338f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park                if (result < 0) {
1348f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park                    ALOGE("Failed to put dst mac address request; result = %d", result);
1358f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park                    return result;
1368f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park                }
1378f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park
1388f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park                result = request.put_u32(MKEEP_ALIVE_ATTRIBUTE_PERIOD_MSEC, mPeriodMsec);
1398f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park                if (result < 0) {
1408f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park                    ALOGE("Failed to put period request; result = %d", result);
1418f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park                    return result;
1428f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park                }
1438f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park
1448f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park                request.attr_end(data);
1458f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park                break;
1468f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park            }
1478f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park
1488f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park            case STOP_MKEEP_ALIVE:
1498f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park            {
1508f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park                result = request.create(GOOGLE_OUI, WIFI_OFFLOAD_STOP_MKEEP_ALIVE);
1518f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park                if (result != WIFI_SUCCESS) {
1528f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park                    ALOGE("Failed to create stop keep alive request; result = %d", result);
1538f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park                    return result;
1548f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park                }
1558f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park
1568f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park                nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
1578f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park
1588f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park                result = request.put_u8(MKEEP_ALIVE_ATTRIBUTE_ID, mIndex);
1598f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park                if (result < 0) {
1608f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park                    ALOGE("Failed to put id request; result = %d", result);
1618f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park                    return result;
1628f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park                }
1638f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park
1648f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park                request.attr_end(data);
1658f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park                break;
1668f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park            }
1678f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park
1688f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park            default:
1698f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park                ALOGE("Unknown wifi keep alive command");
1708f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park                result = WIFI_ERROR_UNKNOWN;
1718f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park        }
1728f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park        return result;
1738f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park    }
1748f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park
1758f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park    int start() {
1768f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park        ALOGD("Start mkeep_alive command");
1778f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park        WifiRequest request(familyId(), ifaceId());
1788f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park        int result = createRequest(request);
1798f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park        if (result != WIFI_SUCCESS) {
1808f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park            ALOGE("Failed to create keep alive request; result = %d", result);
1818f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park            return result;
1828f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park        }
1838f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park
1848f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park        result = requestResponse(request);
1858f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park        if (result != WIFI_SUCCESS) {
1868f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park            ALOGE("Failed to register keep alive response; result = %d", result);
1878f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park        }
1888f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park        return result;
1898f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park    }
1908f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park
1918f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park    virtual int handleResponse(WifiEvent& reply) {
1928f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park        ALOGD("In MKeepAliveCommand::handleResponse");
1938f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park
1948f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park        if (reply.get_cmd() != NL80211_CMD_VENDOR) {
1958f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park            ALOGD("Ignoring reply with cmd = %d", reply.get_cmd());
1968f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park            return NL_SKIP;
1978f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park        }
1988f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park
1998f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park        switch (mType) {
2008f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park            case START_MKEEP_ALIVE:
2018f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park            case STOP_MKEEP_ALIVE:
2028f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park                break;
2038f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park
2048f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park            default:
2058f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park                ALOGW("Unknown mkeep_alive command");
2068f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park        }
2078f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park        return NL_OK;
2088f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park    }
2098f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park
2108f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park    virtual int handleEvent(WifiEvent& event) {
2118f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park        /* NO events! */
2128f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park        return NL_SKIP;
2138f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park    }
2148f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park};
2158f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park
2168f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park
2178f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park/* API to send specified mkeep_alive packet periodically. */
2188f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Parkwifi_error wifi_start_sending_offloaded_packet(wifi_request_id index, wifi_interface_handle iface,
2198f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park        u8 *ip_packet, u16 ip_packet_len, u8 *src_mac_addr, u8 *dst_mac_addr, u32 period_msec)
2208f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park{
2218f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park    if ((index > 0 && index <= N_AVAIL_ID) && (ip_packet != NULL) && (src_mac_addr != NULL)
2228f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park            && (dst_mac_addr != NULL) && (period_msec > 0)
2238f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park            && (ip_packet_len <= MKEEP_ALIVE_IP_PKT_MAX)) {
2248f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park        MKeepAliveCommand *cmd = new MKeepAliveCommand(iface, index, ip_packet, ip_packet_len,
2258f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park                src_mac_addr, dst_mac_addr, period_msec, START_MKEEP_ALIVE);
2266af064b77bfdc84a6f425a7c9d0941fad11f4489Sreenath Sharma        NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
2278f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park        wifi_error result = (wifi_error)cmd->start();
2286af064b77bfdc84a6f425a7c9d0941fad11f4489Sreenath Sharma        cmd->releaseRef();
2298f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park        return result;
2308f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park    } else {
2318f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park        ALOGE("Invalid mkeep_alive parameters");
2328f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park        return  WIFI_ERROR_INVALID_ARGS;
2338f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park    }
2348f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park}
2358f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park
2368f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park/* API to stop sending mkeep_alive packet. */
2378f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Parkwifi_error wifi_stop_sending_offloaded_packet(wifi_request_id index, wifi_interface_handle iface)
2388f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park{
2398f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park    if (index > 0 && index <= N_AVAIL_ID) {
2408f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park        MKeepAliveCommand *cmd = new MKeepAliveCommand(iface, index, STOP_MKEEP_ALIVE);
2416af064b77bfdc84a6f425a7c9d0941fad11f4489Sreenath Sharma        NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
2428f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park        wifi_error result = (wifi_error)cmd->start();
2436af064b77bfdc84a6f425a7c9d0941fad11f4489Sreenath Sharma        cmd->releaseRef();
2448f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park        return result;
2458f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park    } else {
2468f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park        ALOGE("Invalid mkeep_alive parameters");
2478f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park        return  WIFI_ERROR_INVALID_ARGS;
2488f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park    }
2498f1ec7e8e43ec37e94806764b2873c93368cf137Ecco Park}
250