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/handlers.h> 35 36 #include "wifi_hal.h" 37 #include "common.h" 38 #include "cpp_bindings.h" 39 40 interface_info *getIfaceInfo(wifi_interface_handle handle) 41 { 42 return (interface_info *)handle; 43 } 44 45 wifi_handle getWifiHandle(wifi_interface_handle handle) 46 { 47 return getIfaceInfo(handle)->handle; 48 } 49 50 hal_info *getHalInfo(wifi_handle handle) 51 { 52 return (hal_info *)handle; 53 } 54 55 hal_info *getHalInfo(wifi_interface_handle handle) 56 { 57 return getHalInfo(getWifiHandle(handle)); 58 } 59 60 wifi_handle getWifiHandle(hal_info *info) 61 { 62 return (wifi_handle)info; 63 } 64 65 wifi_interface_handle getIfaceHandle(interface_info *info) 66 { 67 return (wifi_interface_handle)info; 68 } 69 70 wifi_error wifi_register_handler(wifi_handle handle, int cmd, nl_recvmsg_msg_cb_t func, void *arg) 71 { 72 hal_info *info = (hal_info *)handle; 73 74 /* TODO: check for multiple handlers? */ 75 pthread_mutex_lock(&info->cb_lock); 76 77 wifi_error result = WIFI_ERROR_OUT_OF_MEMORY; 78 79 if (info->num_event_cb < info->alloc_event_cb) { 80 info->event_cb[info->num_event_cb].nl_cmd = cmd; 81 info->event_cb[info->num_event_cb].vendor_id = 0; 82 info->event_cb[info->num_event_cb].vendor_subcmd = 0; 83 info->event_cb[info->num_event_cb].cb_func = func; 84 info->event_cb[info->num_event_cb].cb_arg = arg; 85 ALOGV("Successfully added event handler %p:%p for command %d at %d", 86 arg, func, cmd, info->num_event_cb); 87 info->num_event_cb++; 88 result = WIFI_SUCCESS; 89 } 90 91 pthread_mutex_unlock(&info->cb_lock); 92 return result; 93 } 94 95 wifi_error wifi_register_vendor_handler(wifi_handle handle, 96 uint32_t id, int subcmd, nl_recvmsg_msg_cb_t func, void *arg) 97 { 98 hal_info *info = (hal_info *)handle; 99 100 /* TODO: check for multiple handlers? */ 101 pthread_mutex_lock(&info->cb_lock); 102 103 wifi_error result = WIFI_ERROR_OUT_OF_MEMORY; 104 105 if (info->num_event_cb < info->alloc_event_cb) { 106 info->event_cb[info->num_event_cb].nl_cmd = NL80211_CMD_VENDOR; 107 info->event_cb[info->num_event_cb].vendor_id = id; 108 info->event_cb[info->num_event_cb].vendor_subcmd = subcmd; 109 info->event_cb[info->num_event_cb].cb_func = func; 110 info->event_cb[info->num_event_cb].cb_arg = arg; 111 ALOGV("Added event handler %p:%p for vendor 0x%0x and subcmd 0x%0x at %d", 112 arg, func, id, subcmd, info->num_event_cb); 113 info->num_event_cb++; 114 result = WIFI_SUCCESS; 115 } 116 117 pthread_mutex_unlock(&info->cb_lock); 118 return result; 119 } 120 121 void wifi_unregister_handler(wifi_handle handle, int cmd) 122 { 123 hal_info *info = (hal_info *)handle; 124 125 if (cmd == NL80211_CMD_VENDOR) { 126 ALOGE("Must use wifi_unregister_vendor_handler to remove vendor handlers"); 127 return; 128 } 129 130 pthread_mutex_lock(&info->cb_lock); 131 132 for (int i = 0; i < info->num_event_cb; i++) { 133 if (info->event_cb[i].nl_cmd == cmd) { 134 ALOGV("Successfully removed event handler %p:%p for cmd = 0x%0x from %d", 135 info->event_cb[i].cb_arg, info->event_cb[i].cb_func, cmd, i); 136 137 memmove(&info->event_cb[i], &info->event_cb[i+1], 138 (info->num_event_cb - i - 1) * sizeof(cb_info)); 139 info->num_event_cb--; 140 break; 141 } 142 } 143 144 pthread_mutex_unlock(&info->cb_lock); 145 } 146 147 void wifi_unregister_vendor_handler(wifi_handle handle, uint32_t id, int subcmd) 148 { 149 hal_info *info = (hal_info *)handle; 150 151 pthread_mutex_lock(&info->cb_lock); 152 153 for (int i = 0; i < info->num_event_cb; i++) { 154 155 if (info->event_cb[i].nl_cmd == NL80211_CMD_VENDOR 156 && info->event_cb[i].vendor_id == id 157 && info->event_cb[i].vendor_subcmd == subcmd) { 158 ALOGV("Successfully removed event handler %p:%p for vendor 0x%0x, subcmd 0x%0x from %d", 159 info->event_cb[i].cb_arg, info->event_cb[i].cb_func, id, subcmd, i); 160 memmove(&info->event_cb[i], &info->event_cb[i+1], 161 (info->num_event_cb - i - 1) * sizeof(cb_info)); 162 info->num_event_cb--; 163 break; 164 } 165 } 166 167 pthread_mutex_unlock(&info->cb_lock); 168 } 169 170 171 wifi_error wifi_register_cmd(wifi_handle handle, int id, WifiCommand *cmd) 172 { 173 hal_info *info = (hal_info *)handle; 174 175 ALOGV("registering command %d", id); 176 177 wifi_error result = WIFI_ERROR_OUT_OF_MEMORY; 178 179 if (info->num_cmd < info->alloc_cmd) { 180 info->cmd[info->num_cmd].id = id; 181 info->cmd[info->num_cmd].cmd = cmd; 182 ALOGV("Successfully added command %d: %p at %d", id, cmd, info->num_cmd); 183 info->num_cmd++; 184 result = WIFI_SUCCESS; 185 } else { 186 ALOGE("Failed to add command %d: %p at %d, reached max limit %d", 187 id, cmd, info->num_cmd, info->alloc_cmd); 188 } 189 190 return result; 191 } 192 193 WifiCommand *wifi_unregister_cmd(wifi_handle handle, int id) 194 { 195 hal_info *info = (hal_info *)handle; 196 197 ALOGV("un-registering command %d", id); 198 199 WifiCommand *cmd = NULL; 200 201 for (int i = 0; i < info->num_cmd; i++) { 202 if (info->cmd[i].id == id) { 203 cmd = info->cmd[i].cmd; 204 memmove(&info->cmd[i], &info->cmd[i+1], (info->num_cmd - i - 1) * sizeof(cmd_info)); 205 info->num_cmd--; 206 ALOGV("Successfully removed command %d: %p from %d", id, cmd, i); 207 break; 208 } 209 } 210 211 if (!cmd) { 212 ALOGI("Failed to remove command %d: %p", id, cmd); 213 } 214 215 return cmd; 216 } 217 218 WifiCommand *wifi_get_cmd(wifi_handle handle, int id) 219 { 220 hal_info *info = (hal_info *)handle; 221 222 WifiCommand *cmd = NULL; 223 224 for (int i = 0; i < info->num_cmd; i++) { 225 if (info->cmd[i].id == id) { 226 cmd = info->cmd[i].cmd; 227 break; 228 } 229 } 230 231 return cmd; 232 } 233 234 void wifi_unregister_cmd(wifi_handle handle, WifiCommand *cmd) 235 { 236 hal_info *info = (hal_info *)handle; 237 238 for (int i = 0; i < info->num_cmd; i++) { 239 if (info->cmd[i].cmd == cmd) { 240 int id = info->cmd[i].id; 241 memmove(&info->cmd[i], &info->cmd[i+1], (info->num_cmd - i - 1) * sizeof(cmd_info)); 242 info->num_cmd--; 243 ALOGV("Successfully removed command %d: %p from %d", id, cmd, i); 244 break; 245 } 246 } 247 } 248 249 wifi_error wifi_cancel_cmd(wifi_request_id id, wifi_interface_handle iface) 250 { 251 wifi_handle handle = getWifiHandle(iface); 252 253 WifiCommand *cmd = wifi_unregister_cmd(handle, id); 254 ALOGV("Cancel WifiCommand = %p", cmd); 255 if (cmd) { 256 cmd->cancel(); 257 cmd->releaseRef(); 258 return WIFI_SUCCESS; 259 } 260 261 return WIFI_ERROR_INVALID_ARGS; 262 } 263 264