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