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
getIfaceInfo(wifi_interface_handle handle)40 interface_info *getIfaceInfo(wifi_interface_handle handle)
41 {
42 return (interface_info *)handle;
43 }
44
getWifiHandle(wifi_interface_handle handle)45 wifi_handle getWifiHandle(wifi_interface_handle handle)
46 {
47 return getIfaceInfo(handle)->handle;
48 }
49
getHalInfo(wifi_handle handle)50 hal_info *getHalInfo(wifi_handle handle)
51 {
52 return (hal_info *)handle;
53 }
54
getHalInfo(wifi_interface_handle handle)55 hal_info *getHalInfo(wifi_interface_handle handle)
56 {
57 return getHalInfo(getWifiHandle(handle));
58 }
59
getWifiHandle(hal_info * info)60 wifi_handle getWifiHandle(hal_info *info)
61 {
62 return (wifi_handle)info;
63 }
64
getIfaceHandle(interface_info * info)65 wifi_interface_handle getIfaceHandle(interface_info *info)
66 {
67 return (wifi_interface_handle)info;
68 }
69
wifi_register_handler(wifi_handle handle,int cmd,nl_recvmsg_msg_cb_t func,void * arg)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
wifi_register_vendor_handler(wifi_handle handle,uint32_t id,int subcmd,nl_recvmsg_msg_cb_t func,void * arg)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
wifi_unregister_handler(wifi_handle handle,int cmd)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
wifi_unregister_vendor_handler(wifi_handle handle,uint32_t id,int subcmd)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
wifi_register_cmd(wifi_handle handle,int id,WifiCommand * cmd)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
wifi_unregister_cmd(wifi_handle handle,int id)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
wifi_get_cmd(wifi_handle handle,int id)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
wifi_unregister_cmd(wifi_handle handle,WifiCommand * cmd)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
wifi_cancel_cmd(wifi_request_id id,wifi_interface_handle iface)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