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 /* test mode flag for halutil only */
41 bool halutil_mode = false;
getIfaceInfo(wifi_interface_handle handle)42 interface_info *getIfaceInfo(wifi_interface_handle handle)
43 {
44     return (interface_info *)handle;
45 }
46 
getWifiHandle(wifi_interface_handle handle)47 wifi_handle getWifiHandle(wifi_interface_handle handle)
48 {
49     return getIfaceInfo(handle)->handle;
50 }
51 
getHalInfo(wifi_handle handle)52 hal_info *getHalInfo(wifi_handle handle)
53 {
54     return (hal_info *)handle;
55 }
56 
getHalInfo(wifi_interface_handle handle)57 hal_info *getHalInfo(wifi_interface_handle handle)
58 {
59     return getHalInfo(getWifiHandle(handle));
60 }
61 
getWifiHandle(hal_info * info)62 wifi_handle getWifiHandle(hal_info *info)
63 {
64     return (wifi_handle)info;
65 }
66 
getIfaceHandle(interface_info * info)67 wifi_interface_handle getIfaceHandle(interface_info *info)
68 {
69     return (wifi_interface_handle)info;
70 }
71 
wifi_register_handler(wifi_handle handle,int cmd,nl_recvmsg_msg_cb_t func,void * arg)72 wifi_error wifi_register_handler(wifi_handle handle, int cmd, nl_recvmsg_msg_cb_t func, void *arg)
73 {
74     hal_info *info = (hal_info *)handle;
75 
76     /* TODO: check for multiple handlers? */
77     pthread_mutex_lock(&info->cb_lock);
78 
79     wifi_error result = WIFI_ERROR_OUT_OF_MEMORY;
80 
81     if (info->num_event_cb < info->alloc_event_cb) {
82         info->event_cb[info->num_event_cb].nl_cmd  = cmd;
83         info->event_cb[info->num_event_cb].vendor_id  = 0;
84         info->event_cb[info->num_event_cb].vendor_subcmd  = 0;
85         info->event_cb[info->num_event_cb].cb_func = func;
86         info->event_cb[info->num_event_cb].cb_arg  = arg;
87         ALOGV("Successfully added event handler %p:%p for command %d at %d",
88                 arg, func, cmd, info->num_event_cb);
89         info->num_event_cb++;
90         result = WIFI_SUCCESS;
91     }
92 
93     pthread_mutex_unlock(&info->cb_lock);
94     return result;
95 }
96 
wifi_register_vendor_handler(wifi_handle handle,uint32_t id,int subcmd,nl_recvmsg_msg_cb_t func,void * arg)97 wifi_error wifi_register_vendor_handler(wifi_handle handle,
98         uint32_t id, int subcmd, nl_recvmsg_msg_cb_t func, void *arg)
99 {
100     hal_info *info = (hal_info *)handle;
101 
102     /* TODO: check for multiple handlers? */
103     pthread_mutex_lock(&info->cb_lock);
104 
105     wifi_error result = WIFI_ERROR_OUT_OF_MEMORY;
106 
107     if (info->num_event_cb < info->alloc_event_cb) {
108         /* To avoid an unwanted duplication of the record, find first.
109          * Update it if the same record is already exist.
110          * KEY => [nl_cmd, vendor_id, vendor_subcmd]
111          */
112         int i = 0;
113         bool is_update = false;
114         for (i = 0; i < info->num_event_cb; i++) {
115             if ((info->event_cb[i].nl_cmd == NL80211_CMD_VENDOR) &&
116                     (info->event_cb[i].vendor_id == id) &&
117                     (info->event_cb[i].vendor_subcmd == subcmd)) {
118                 is_update = true;
119                 break;
120             }
121         }
122 
123         if (is_update) {
124             info->event_cb[i].cb_func = func;
125             info->event_cb[i].cb_arg = arg;
126         } else {
127             info->event_cb[info->num_event_cb].nl_cmd  = NL80211_CMD_VENDOR;
128             info->event_cb[info->num_event_cb].vendor_id  = id;
129             info->event_cb[info->num_event_cb].vendor_subcmd  = subcmd;
130             info->event_cb[info->num_event_cb].cb_func = func;
131             info->event_cb[info->num_event_cb].cb_arg  = arg;
132             info->num_event_cb++;
133         }
134         ALOGI("%s ""event handler %p:%p for vendor 0x%0x and subcmd 0x%0x at %d",
135             is_update ? "Updated" : "Added", arg, func, id, subcmd, info->num_event_cb);
136         result = WIFI_SUCCESS;
137     }
138 
139     pthread_mutex_unlock(&info->cb_lock);
140     return result;
141 }
142 
wifi_unregister_handler(wifi_handle handle,int cmd)143 void wifi_unregister_handler(wifi_handle handle, int cmd)
144 {
145     hal_info *info = (hal_info *)handle;
146 
147     if (cmd == NL80211_CMD_VENDOR) {
148         ALOGE("Must use wifi_unregister_vendor_handler to remove vendor handlers");
149         return;
150     }
151 
152     pthread_mutex_lock(&info->cb_lock);
153 
154     for (int i = 0; i < info->num_event_cb; i++) {
155         if (info->event_cb[i].nl_cmd == cmd) {
156             ALOGV("Successfully removed event handler %p:%p for cmd = 0x%0x from %d",
157                     info->event_cb[i].cb_arg, info->event_cb[i].cb_func, cmd, i);
158 
159             memmove(&info->event_cb[i], &info->event_cb[i+1],
160                 (info->num_event_cb - i - 1) * sizeof(cb_info));
161             info->num_event_cb--;
162             break;
163         }
164     }
165 
166     pthread_mutex_unlock(&info->cb_lock);
167 }
168 
wifi_unregister_vendor_handler_without_lock(wifi_handle handle,uint32_t id,int subcmd)169 void wifi_unregister_vendor_handler_without_lock(wifi_handle handle, uint32_t id, int subcmd)
170 {
171     hal_info *info = (hal_info *)handle;
172 
173     for (int i = 0; i < info->num_event_cb; i++) {
174         if (info->event_cb[i].nl_cmd == NL80211_CMD_VENDOR
175                 && info->event_cb[i].vendor_id == id
176                 && info->event_cb[i].vendor_subcmd == subcmd) {
177             ALOGI("Successfully removed event handler %p:%p for vendor 0x%0x, subcmd 0x%0x from %d",
178                     info->event_cb[i].cb_arg, info->event_cb[i].cb_func, id, subcmd, i);
179             memmove(&info->event_cb[i], &info->event_cb[i+1],
180                 (info->num_event_cb - i - 1) * sizeof(cb_info));
181             info->num_event_cb--;
182             break;
183         }
184     }
185 }
186 
wifi_unregister_vendor_handler(wifi_handle handle,uint32_t id,int subcmd)187 void wifi_unregister_vendor_handler(wifi_handle handle, uint32_t id, int subcmd)
188 {
189     hal_info *info = (hal_info *)handle;
190 
191     pthread_mutex_lock(&info->cb_lock);
192     wifi_unregister_vendor_handler_without_lock(handle, id, subcmd);
193     pthread_mutex_unlock(&info->cb_lock);
194 }
195 
wifi_register_cmd(wifi_handle handle,int id,WifiCommand * cmd)196 wifi_error wifi_register_cmd(wifi_handle handle, int id, WifiCommand *cmd)
197 {
198     hal_info *info = (hal_info *)handle;
199 
200     ALOGV("registering command %d", id);
201 
202     wifi_error result = WIFI_ERROR_OUT_OF_MEMORY;
203 
204     if (info->num_cmd < info->alloc_cmd) {
205         info->cmd[info->num_cmd].id   = id;
206         info->cmd[info->num_cmd].cmd  = cmd;
207         ALOGV("Successfully added command %d: %p at %d", id, cmd, info->num_cmd);
208         info->num_cmd++;
209         result = WIFI_SUCCESS;
210     } else {
211         ALOGE("Failed to add command %d: %p at %d, reached max limit %d",
212                 id, cmd, info->num_cmd, info->alloc_cmd);
213     }
214 
215     return result;
216 }
217 
wifi_unregister_cmd(wifi_handle handle,int id)218 WifiCommand *wifi_unregister_cmd(wifi_handle handle, int id)
219 {
220     hal_info *info = (hal_info *)handle;
221 
222     ALOGV("un-registering command %d", id);
223 
224     WifiCommand *cmd = NULL;
225 
226     for (int i = 0; i < info->num_cmd; i++) {
227         if (info->cmd[i].id == id) {
228             cmd = info->cmd[i].cmd;
229             memmove(&info->cmd[i], &info->cmd[i+1], (info->num_cmd - i - 1) * sizeof(cmd_info));
230             info->num_cmd--;
231             ALOGV("Successfully removed command %d: %p from %d", id, cmd, i);
232             break;
233         }
234     }
235 
236     if (!cmd) {
237         ALOGI("Failed to remove command %d: %p", id, cmd);
238     }
239 
240     return cmd;
241 }
242 
wifi_get_cmd(wifi_handle handle,int id)243 WifiCommand *wifi_get_cmd(wifi_handle handle, int id)
244 {
245     hal_info *info = (hal_info *)handle;
246 
247     WifiCommand *cmd = NULL;
248 
249     for (int i = 0; i < info->num_cmd; i++) {
250         if (info->cmd[i].id == id) {
251             cmd = info->cmd[i].cmd;
252             break;
253         }
254     }
255 
256     return cmd;
257 }
258 
wifi_unregister_cmd(wifi_handle handle,WifiCommand * cmd)259 void wifi_unregister_cmd(wifi_handle handle, WifiCommand *cmd)
260 {
261     hal_info *info = (hal_info *)handle;
262 
263     for (int i = 0; i < info->num_cmd; i++) {
264         if (info->cmd[i].cmd == cmd) {
265             int id = info->cmd[i].id;
266             memmove(&info->cmd[i], &info->cmd[i+1], (info->num_cmd - i - 1) * sizeof(cmd_info));
267             info->num_cmd--;
268             ALOGV("Successfully removed command %d: %p from %d", id, cmd, i);
269             break;
270         }
271     }
272 }
273 
wifi_cancel_cmd(wifi_request_id id,wifi_interface_handle iface)274 wifi_error wifi_cancel_cmd(wifi_request_id id, wifi_interface_handle iface)
275 {
276     wifi_handle handle = getWifiHandle(iface);
277 
278     WifiCommand *cmd = wifi_unregister_cmd(handle, id);
279     ALOGV("Cancel WifiCommand = %p", cmd);
280     if (cmd) {
281         cmd->cancel();
282         cmd->releaseRef();
283         return WIFI_SUCCESS;
284     }
285 
286     return WIFI_ERROR_INVALID_ARGS;
287 }
288 
wifi_get_cancel_cmd(wifi_request_id id,wifi_interface_handle iface)289 wifi_error wifi_get_cancel_cmd(wifi_request_id id, wifi_interface_handle iface)
290 {
291     wifi_handle handle = getWifiHandle(iface);
292     WifiCommand *cmd = wifi_get_cmd(handle, id);
293     ALOGV("Get Cancel WifiCommand = %p", cmd);
294     if (cmd) {
295         cmd->cancel();
296         cmd->releaseRef();
297         return WIFI_SUCCESS;
298     }
299 
300     return WIFI_ERROR_INVALID_ARGS;
301 }
set_hautil_mode(bool util_mode)302 void set_hautil_mode(bool util_mode)
303 {
304     halutil_mode = util_mode;
305 }
get_halutil_mode()306 bool get_halutil_mode()
307 {
308     return halutil_mode;
309 }
310