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