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 
getIfaceInfo(wifi_interface_handle handle)22 interface_info *getIfaceInfo(wifi_interface_handle handle)
23 {
24     return (interface_info *)handle;
25 }
26 
getWifiHandle(wifi_interface_handle handle)27 wifi_handle getWifiHandle(wifi_interface_handle handle)
28 {
29     return getIfaceInfo(handle)->handle;
30 }
31 
getHalInfo(wifi_handle handle)32 hal_info *getHalInfo(wifi_handle handle)
33 {
34     return (hal_info *)handle;
35 }
36 
getHalInfo(wifi_interface_handle handle)37 hal_info *getHalInfo(wifi_interface_handle handle)
38 {
39     return getHalInfo(getWifiHandle(handle));
40 }
41 
getWifiHandle(hal_info * info)42 wifi_handle getWifiHandle(hal_info *info)
43 {
44     return (wifi_handle)info;
45 }
46 
getIfaceHandle(interface_info * info)47 wifi_interface_handle getIfaceHandle(interface_info *info)
48 {
49     return (wifi_interface_handle)info;
50 }
51 
wifi_register_handler(wifi_handle handle,int cmd,nl_recvmsg_msg_cb_t func,void * arg)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 
wifi_register_vendor_handler(wifi_handle handle,uint32_t id,int subcmd,nl_recvmsg_msg_cb_t func,void * arg)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 
wifi_unregister_handler(wifi_handle handle,int cmd)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 
wifi_unregister_vendor_handler(wifi_handle handle,uint32_t id,int subcmd)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 
wifi_register_cmd(wifi_handle handle,int id,WifiCommand * cmd)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 
wifi_unregister_cmd(wifi_handle handle,int id)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 
wifi_get_cmd(wifi_handle handle,int id)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 
wifi_unregister_cmd(wifi_handle handle,WifiCommand * cmd)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 
wifi_cancel_cmd(wifi_request_id id,wifi_interface_handle iface)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