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 <log/log.h> 26 27#include "wifi_hal.h" 28#include "common.h" 29#include "cpp_bindings.h" 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