1 /* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include <stdlib.h> 18 #include <linux/pkt_sched.h> 19 #include <netlink/object-api.h> 20 #include <netlink-types.h> 21 22 #include "wifi_hal.h" 23 #include "common.h" 24 #include <netlink-types.h> 25 26 interface_info *getIfaceInfo(wifi_interface_handle handle) 27 { 28 return (interface_info *)handle; 29 } 30 31 wifi_handle getWifiHandle(wifi_interface_handle handle) 32 { 33 return getIfaceInfo(handle)->handle; 34 } 35 36 hal_info *getHalInfo(wifi_handle handle) 37 { 38 return (hal_info *)handle; 39 } 40 41 hal_info *getHalInfo(wifi_interface_handle handle) 42 { 43 return getHalInfo(getWifiHandle(handle)); 44 } 45 46 wifi_handle getWifiHandle(hal_info *info) 47 { 48 return (wifi_handle)info; 49 } 50 51 wifi_interface_handle getIfaceHandle(interface_info *info) 52 { 53 return (wifi_interface_handle)info; 54 } 55 56 wifi_error wifi_register_handler(wifi_handle handle, int cmd, nl_recvmsg_msg_cb_t func, void *arg) 57 { 58 hal_info *info = (hal_info *)handle; 59 60 pthread_mutex_lock(&info->cb_lock); 61 62 wifi_error result = WIFI_ERROR_OUT_OF_MEMORY; 63 64 for (int i = 0; i < info->num_event_cb; i++) { 65 if(info->event_cb[i].nl_cmd == cmd && 66 info->event_cb[i].cb_arg == arg) { 67 info->event_cb[i].cb_func = func; 68 ALOGI("Updated event handler %p for nl_cmd 0x%0x" 69 " and arg %p", func, cmd, arg); 70 result = WIFI_SUCCESS; 71 } 72 } 73 74 if (info->num_event_cb < info->alloc_event_cb) { 75 info->event_cb[info->num_event_cb].nl_cmd = cmd; 76 info->event_cb[info->num_event_cb].vendor_id = 0; 77 info->event_cb[info->num_event_cb].vendor_subcmd = 0; 78 info->event_cb[info->num_event_cb].cb_func = func; 79 info->event_cb[info->num_event_cb].cb_arg = arg; 80 info->num_event_cb++; 81 ALOGI("Successfully added event handler %p for command %d", func, cmd); 82 result = WIFI_SUCCESS; 83 } else { 84 result = WIFI_ERROR_OUT_OF_MEMORY; 85 } 86 87 pthread_mutex_unlock(&info->cb_lock); 88 return result; 89 } 90 91 wifi_error wifi_register_vendor_handler(wifi_handle handle, 92 uint32_t id, int subcmd, nl_recvmsg_msg_cb_t func, void *arg) 93 { 94 hal_info *info = (hal_info *)handle; 95 96 pthread_mutex_lock(&info->cb_lock); 97 98 wifi_error result = WIFI_ERROR_OUT_OF_MEMORY; 99 100 for (int i = 0; i < info->num_event_cb; i++) { 101 if(info->event_cb[i].vendor_id == id && 102 info->event_cb[i].vendor_subcmd == subcmd) 103 { 104 info->event_cb[i].cb_func = func; 105 info->event_cb[i].cb_arg = arg; 106 ALOGI("Updated event handler %p for vendor 0x%0x, subcmd 0x%0x" 107 " and arg %p", func, id, subcmd, arg); 108 result = WIFI_SUCCESS; 109 } 110 } 111 112 if (info->num_event_cb < info->alloc_event_cb) { 113 info->event_cb[info->num_event_cb].nl_cmd = NL80211_CMD_VENDOR; 114 info->event_cb[info->num_event_cb].vendor_id = id; 115 info->event_cb[info->num_event_cb].vendor_subcmd = subcmd; 116 info->event_cb[info->num_event_cb].cb_func = func; 117 info->event_cb[info->num_event_cb].cb_arg = arg; 118 info->num_event_cb++; 119 ALOGI("Added event handler %p for vendor 0x%0x, subcmd 0x%0x and arg" 120 " %p", func, id, subcmd, arg); 121 result = WIFI_SUCCESS; 122 } else { 123 result = WIFI_ERROR_OUT_OF_MEMORY; 124 } 125 126 pthread_mutex_unlock(&info->cb_lock); 127 return result; 128 } 129 130 void wifi_unregister_handler(wifi_handle handle, int cmd) 131 { 132 hal_info *info = (hal_info *)handle; 133 134 if (cmd == NL80211_CMD_VENDOR) { 135 ALOGE("Must use wifi_unregister_vendor_handler to remove vendor handlers"); 136 return; 137 } 138 139 pthread_mutex_lock(&info->cb_lock); 140 141 for (int i = 0; i < info->num_event_cb; i++) { 142 if (info->event_cb[i].nl_cmd == cmd) { 143 if(i < info->num_event_cb-1) { 144 /* No need to memmove if only one entry exist and deleting 145 * the same, as the num_event_cb will become 0 in this case. 146 */ 147 memmove(&info->event_cb[i], &info->event_cb[i+1], 148 (info->num_event_cb - i) * sizeof(cb_info)); 149 } 150 info->num_event_cb--; 151 ALOGI("Successfully removed event handler for command %d", cmd); 152 break; 153 } 154 } 155 156 pthread_mutex_unlock(&info->cb_lock); 157 } 158 159 void wifi_unregister_vendor_handler(wifi_handle handle, uint32_t id, int subcmd) 160 { 161 hal_info *info = (hal_info *)handle; 162 163 pthread_mutex_lock(&info->cb_lock); 164 165 for (int i = 0; i < info->num_event_cb; i++) { 166 167 if (info->event_cb[i].nl_cmd == NL80211_CMD_VENDOR 168 && info->event_cb[i].vendor_id == id 169 && info->event_cb[i].vendor_subcmd == subcmd) { 170 if(i < info->num_event_cb-1) { 171 /* No need to memmove if only one entry exist and deleting 172 * the same, as the num_event_cb will become 0 in this case. 173 */ 174 memmove(&info->event_cb[i], &info->event_cb[i+1], 175 (info->num_event_cb - i) * sizeof(cb_info)); 176 } 177 info->num_event_cb--; 178 ALOGI("Successfully removed event handler for vendor 0x%0x", id); 179 break; 180 } 181 } 182 183 pthread_mutex_unlock(&info->cb_lock); 184 } 185 186 187 wifi_error wifi_register_cmd(wifi_handle handle, int id, WifiCommand *cmd) 188 { 189 hal_info *info = (hal_info *)handle; 190 191 ALOGD("registering command %d", id); 192 193 if (info->num_cmd < info->alloc_cmd) { 194 info->cmd[info->num_cmd].id = id; 195 info->cmd[info->num_cmd].cmd = cmd; 196 info->num_cmd++; 197 ALOGI("Successfully added command %d: %p", id, cmd); 198 return WIFI_SUCCESS; 199 } else { 200 return WIFI_ERROR_OUT_OF_MEMORY; 201 } 202 } 203 204 WifiCommand *wifi_unregister_cmd(wifi_handle handle, int id) 205 { 206 hal_info *info = (hal_info *)handle; 207 208 ALOGD("un-registering command %d", id); 209 210 for (int i = 0; i < info->num_cmd; i++) { 211 if (info->cmd[i].id == id) { 212 WifiCommand *cmd = info->cmd[i].cmd; 213 memmove(&info->cmd[i], &info->cmd[i+1], (info->num_cmd - i) * sizeof(cmd_info)); 214 info->num_cmd--; 215 ALOGI("Successfully removed command %d: %p", id, cmd); 216 return cmd; 217 } 218 } 219 220 return NULL; 221 } 222 223 void wifi_unregister_cmd(wifi_handle handle, WifiCommand *cmd) 224 { 225 hal_info *info = (hal_info *)handle; 226 227 for (int i = 0; i < info->num_cmd; i++) { 228 if (info->cmd[i].cmd == cmd) { 229 int id = info->cmd[i].id; 230 memmove(&info->cmd[i], &info->cmd[i+1], (info->num_cmd - i) * sizeof(cmd_info)); 231 info->num_cmd--; 232 ALOGI("Successfully removed command %d: %p", id, cmd); 233 return; 234 } 235 } 236 } 237 238 #ifdef __cplusplus 239 extern "C" 240 { 241 #endif /* __cplusplus */ 242 243 void hexdump(void *buf, u16 len) 244 { 245 int i=0; 246 char *bytes = (char *)buf; 247 ALOGI("******HexDump len:%d*********", len); 248 for (i = 0; ((i + 7) < len); i+=8) { 249 ALOGI("%02x %02x %02x %02x %02x %02x %02x %02x", 250 bytes[i], bytes[i+1], 251 bytes[i+2], bytes[i+3], 252 bytes[i+4], bytes[i+5], 253 bytes[i+6], bytes[i+7]); 254 } 255 if ((len - i) >= 4) { 256 ALOGI("%02x %02x %02x %02x", 257 bytes[i], bytes[i+1], 258 bytes[i+2], bytes[i+3]); 259 i+=4; 260 } 261 for (;i < len;i++) { 262 ALOGI("%02x", bytes[i]); 263 } 264 ALOGI("******HexDump End***********"); 265 } 266 267 #ifdef __cplusplus 268 } 269 #endif /* __cplusplus */ 270