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