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 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 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 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 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 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 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. */ 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. */ 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