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 }
168
169 return result;
170 }
171
wifi_unregister_cmd(wifi_handle handle,int id)172 WifiCommand *wifi_unregister_cmd(wifi_handle handle, int id)
173 {
174 hal_info *info = (hal_info *)handle;
175
176 ALOGV("un-registering command %d", id);
177
178 WifiCommand *cmd = NULL;
179
180 for (int i = 0; i < info->num_cmd; i++) {
181 if (info->cmd[i].id == id) {
182 cmd = info->cmd[i].cmd;
183 memmove(&info->cmd[i], &info->cmd[i+1], (info->num_cmd - i - 1) * sizeof(cmd_info));
184 info->num_cmd--;
185 ALOGV("Successfully removed command %d: %p from %d", id, cmd, i);
186 break;
187 }
188 }
189
190 return cmd;
191 }
192
wifi_get_cmd(wifi_handle handle,int id)193 WifiCommand *wifi_get_cmd(wifi_handle handle, int id)
194 {
195 hal_info *info = (hal_info *)handle;
196
197 WifiCommand *cmd = NULL;
198
199 for (int i = 0; i < info->num_cmd; i++) {
200 if (info->cmd[i].id == id) {
201 cmd = info->cmd[i].cmd;
202 break;
203 }
204 }
205
206 return cmd;
207 }
208
wifi_unregister_cmd(wifi_handle handle,WifiCommand * cmd)209 void wifi_unregister_cmd(wifi_handle handle, WifiCommand *cmd)
210 {
211 hal_info *info = (hal_info *)handle;
212
213 for (int i = 0; i < info->num_cmd; i++) {
214 if (info->cmd[i].cmd == cmd) {
215 int id = info->cmd[i].id;
216 memmove(&info->cmd[i], &info->cmd[i+1], (info->num_cmd - i - 1) * sizeof(cmd_info));
217 info->num_cmd--;
218 ALOGV("Successfully removed command %d: %p from %d", id, cmd, i);
219 break;
220 }
221 }
222 }
223
wifi_cancel_cmd(wifi_request_id id,wifi_interface_handle iface)224 wifi_error wifi_cancel_cmd(wifi_request_id id, wifi_interface_handle iface)
225 {
226 wifi_handle handle = getWifiHandle(iface);
227
228 WifiCommand *cmd = wifi_unregister_cmd(handle, id);
229 ALOGV("Cancel WifiCommand = %p", cmd);
230 if (cmd) {
231 cmd->cancel();
232 cmd->releaseRef();
233 return WIFI_SUCCESS;
234 }
235
236 return WIFI_ERROR_INVALID_ARGS;
237 }
238
239