1 /*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <stdint.h>
18 #include <fcntl.h>
19 #include <sys/socket.h>
20 #include <netlink/genl/genl.h>
21 #include <netlink/genl/family.h>
22 #include <netlink/genl/ctrl.h>
23 #include <linux/rtnetlink.h>
24 #include <netpacket/packet.h>
25 #include <linux/filter.h>
26 #include <linux/errqueue.h>
27
28 #include <linux/pkt_sched.h>
29 #include <netlink/object-api.h>
30 #include <netlink/netlink.h>
31 #include <netlink/socket.h>
32 #include <netlink-types.h>
33
34 #include "nl80211_copy.h"
35
36 #include <dirent.h>
37 #include <net/if.h>
38
39 #include "sync.h"
40
41 #define LOG_TAG "WifiHAL"
42
43 #include <utils/Log.h>
44
45 #include "wifi_hal.h"
46 #include "common.h"
47 #include "cpp_bindings.h"
48
49 /*
50 BUGBUG: normally, libnl allocates ports for all connections it makes; but
51 being a static library, it doesn't really know how many other netlink connections
52 are made by the same process, if connections come from different shared libraries.
53 These port assignments exist to solve that problem - temporarily. We need to fix
54 libnl to try and allocate ports across the entire process.
55 */
56
57 #define WIFI_HAL_CMD_SOCK_PORT 644
58 #define WIFI_HAL_EVENT_SOCK_PORT 645
59
60 static void internal_event_handler(wifi_handle handle, int events);
61 static int internal_valid_message_handler(nl_msg *msg, void *arg);
62 static int wifi_get_multicast_id(wifi_handle handle, const char *name, const char *group);
63 static int wifi_add_membership(wifi_handle handle, const char *group);
64 static wifi_error wifi_init_interfaces(wifi_handle handle);
65
66 /* Initialize/Cleanup */
67
wifi_socket_set_local_port(struct nl_sock * sock,uint32_t port)68 void wifi_socket_set_local_port(struct nl_sock *sock, uint32_t port)
69 {
70 uint32_t pid = getpid() & 0x3FFFFF;
71
72 if (port == 0) {
73 sock->s_flags &= ~NL_OWN_PORT;
74 } else {
75 sock->s_flags |= NL_OWN_PORT;
76 }
77
78 sock->s_local.nl_pid = pid + (port << 22);
79 }
80
wifi_create_nl_socket(int port)81 static nl_sock * wifi_create_nl_socket(int port)
82 {
83 // ALOGI("Creating socket");
84 struct nl_sock *sock = nl_socket_alloc();
85 if (sock == NULL) {
86 ALOGE("Could not create handle");
87 return NULL;
88 }
89
90 wifi_socket_set_local_port(sock, port);
91
92 struct sockaddr_nl *addr_nl = &(sock->s_local);
93 /* ALOGI("socket address is %d:%d:%d:%d",
94 addr_nl->nl_family, addr_nl->nl_pad, addr_nl->nl_pid, addr_nl->nl_groups); */
95
96 struct sockaddr *addr = NULL;
97 // ALOGI("sizeof(sockaddr) = %d, sizeof(sockaddr_nl) = %d", sizeof(*addr), sizeof(*addr_nl));
98
99 // ALOGI("Connecting socket");
100 if (nl_connect(sock, NETLINK_GENERIC)) {
101 ALOGE("Could not connect handle");
102 nl_socket_free(sock);
103 return NULL;
104 }
105
106 ALOGI("Socket Value:%p", sock);
107 return sock;
108 }
109
ack_handler(struct nl_msg * msg,void * arg)110 int ack_handler(struct nl_msg *msg, void *arg)
111 {
112 int *err = (int *)arg;
113 *err = 0;
114 ALOGD("%s invoked",__func__);
115 return NL_STOP;
116 }
117
finish_handler(struct nl_msg * msg,void * arg)118 int finish_handler(struct nl_msg *msg, void *arg)
119 {
120 int *ret = (int *)arg;
121 *ret = 0;
122 ALOGD("%s called",__func__);
123 return NL_SKIP;
124 }
125
error_handler(struct sockaddr_nl * nla,struct nlmsgerr * err,void * arg)126 int error_handler(struct sockaddr_nl *nla,
127 struct nlmsgerr *err, void *arg)
128 {
129 int *ret = (int *)arg;
130 *ret = err->error;
131
132 ALOGD("%s invoked with error: %d", __func__, err->error);
133 return NL_SKIP;
134 }
no_seq_check(struct nl_msg * msg,void * arg)135 static int no_seq_check(struct nl_msg *msg, void *arg)
136 {
137 ALOGD("no_seq_check received");
138 return NL_OK;
139 }
140
wifi_initialize(wifi_handle * handle)141 wifi_error wifi_initialize(wifi_handle *handle)
142 {
143 int err = 0;
144 srand(getpid());
145
146 ALOGI("Initializing wifi");
147 hal_info *info = (hal_info *)malloc(sizeof(hal_info));
148 if (info == NULL) {
149 ALOGE("Could not allocate hal_info");
150 return WIFI_ERROR_UNKNOWN;
151 }
152
153 memset(info, 0, sizeof(*info));
154
155 ALOGI("Creating socket");
156 struct nl_sock *cmd_sock = wifi_create_nl_socket(WIFI_HAL_CMD_SOCK_PORT);
157 if (cmd_sock == NULL) {
158 ALOGE("Could not create handle");
159 return WIFI_ERROR_UNKNOWN;
160 }
161
162 struct nl_sock *event_sock = wifi_create_nl_socket(WIFI_HAL_EVENT_SOCK_PORT);
163 if (event_sock == NULL) {
164 ALOGE("Could not create handle");
165 nl_socket_free(cmd_sock);
166 return WIFI_ERROR_UNKNOWN;
167 }
168
169 struct nl_cb *cb = nl_socket_get_cb(event_sock);
170 if (cb == NULL) {
171 ALOGE("Could not create handle");
172 return WIFI_ERROR_UNKNOWN;
173 }
174
175 err = 1;
176 nl_cb_set(cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, no_seq_check, NULL);
177 nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &err);
178 nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, &err);
179 nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &err);
180
181 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, internal_valid_message_handler, info);
182 nl_cb_put(cb);
183
184 info->cmd_sock = cmd_sock;
185 info->event_sock = event_sock;
186 info->clean_up = false;
187 info->in_event_loop = false;
188
189 info->event_cb = (cb_info *)malloc(sizeof(cb_info) * DEFAULT_EVENT_CB_SIZE);
190 info->alloc_event_cb = DEFAULT_EVENT_CB_SIZE;
191 info->num_event_cb = 0;
192
193 info->cmd = (cmd_info *)malloc(sizeof(cmd_info) * DEFAULT_CMD_SIZE);
194 info->alloc_cmd = DEFAULT_CMD_SIZE;
195 info->num_cmd = 0;
196
197 info->nl80211_family_id = genl_ctrl_resolve(cmd_sock, "nl80211");
198 if (info->nl80211_family_id < 0) {
199 ALOGE("Could not resolve nl80211 familty id");
200 nl_socket_free(cmd_sock);
201 nl_socket_free(event_sock);
202 free(info);
203 return WIFI_ERROR_UNKNOWN;
204 }
205 ALOGI("%s: family_id:%d", __func__, info->nl80211_family_id);
206
207 *handle = (wifi_handle) info;
208
209 wifi_add_membership(*handle, "scan");
210 wifi_add_membership(*handle, "mlme");
211 wifi_add_membership(*handle, "regulatory");
212 wifi_add_membership(*handle, "vendor");
213
214 wifi_init_interfaces(*handle);
215 // ALOGI("Found %d interfaces", info->num_interfaces);
216
217 ALOGI("Initialized Wifi HAL Successfully; vendor cmd = %d handle %p", NL80211_CMD_VENDOR ,
218 *handle);
219 return WIFI_SUCCESS;
220 }
221
wifi_add_membership(wifi_handle handle,const char * group)222 static int wifi_add_membership(wifi_handle handle, const char *group)
223 {
224 hal_info *info = getHalInfo(handle);
225
226 int id = wifi_get_multicast_id(handle, "nl80211", group);
227 if (id < 0) {
228 ALOGE("Could not find group %s", group);
229 return id;
230 }
231
232 int ret = nl_socket_add_membership(info->event_sock, id);
233 if (ret < 0) {
234 ALOGE("Could not add membership to group %s", group);
235 }
236
237 // ALOGI("Successfully added membership for group %s", group);
238 return ret;
239 }
240
internal_cleaned_up_handler(wifi_handle handle)241 static void internal_cleaned_up_handler(wifi_handle handle)
242 {
243 hal_info *info = getHalInfo(handle);
244 wifi_cleaned_up_handler cleaned_up_handler = info->cleaned_up_handler;
245
246 if (info->cmd_sock != 0) {
247 nl_socket_free(info->cmd_sock);
248 nl_socket_free(info->event_sock);
249 info->cmd_sock = NULL;
250 info->event_sock = NULL;
251 }
252
253 (*cleaned_up_handler)(handle);
254 free(info);
255
256 ALOGI("Internal cleanup completed");
257 }
258
wifi_cleanup(wifi_handle handle,wifi_cleaned_up_handler handler)259 void wifi_cleanup(wifi_handle handle, wifi_cleaned_up_handler handler)
260 {
261 hal_info *info = getHalInfo(handle);
262 info->cleaned_up_handler = handler;
263 info->clean_up = true;
264
265 ALOGI("Wifi cleanup completed");
266 }
267
internal_pollin_handler(wifi_handle handle)268 static int internal_pollin_handler(wifi_handle handle)
269 {
270 hal_info *info = getHalInfo(handle);
271 struct nl_cb *cb = nl_socket_get_cb(info->event_sock);
272 int res = nl_recvmsgs(info->event_sock, cb);
273 nl_cb_put(cb);
274 return res;
275 }
276
internal_event_handler(wifi_handle handle,int events)277 static void internal_event_handler(wifi_handle handle, int events)
278 {
279 if (events & POLLERR) {
280 ALOGE("Error reading from socket");
281 } else if (events & POLLHUP) {
282 ALOGE("Remote side hung up");
283 } else if (events & POLLIN) {
284 ALOGI("Found some events!!!");
285 internal_pollin_handler(handle);
286 } else {
287 ALOGE("Unknown event - %0x", events);
288 }
289 }
290
291 /* Run event handler */
wifi_event_loop(wifi_handle handle)292 void wifi_event_loop(wifi_handle handle)
293 {
294 hal_info *info = getHalInfo(handle);
295 if (info->in_event_loop) {
296 return;
297 } else {
298 info->in_event_loop = true;
299 }
300
301 pollfd pfd;
302 memset(&pfd, 0, sizeof(pfd));
303
304 pfd.fd = nl_socket_get_fd(info->event_sock);
305 pfd.events = POLLIN;
306
307 /* TODO: Add support for timeouts */
308
309 do {
310 int timeout = -1; /* Infinite timeout */
311 pfd.revents = 0;
312 //ALOGI("Polling socket");
313 int result = poll(&pfd, 1, -1);
314 ALOGI("Poll result = %0x", result);
315 if (result < 0) {
316 ALOGE("Error polling socket");
317 } else if (pfd.revents & (POLLIN | POLLHUP | POLLERR)) {
318 internal_event_handler(handle, pfd.revents);
319 }
320 } while (!info->clean_up);
321
322
323 ALOGI("Cleaning up");
324 internal_cleaned_up_handler(handle);
325 }
326
327 ///////////////////////////////////////////////////////////////////////////////////////
328
internal_valid_message_handler(nl_msg * msg,void * arg)329 static int internal_valid_message_handler(nl_msg *msg, void *arg)
330 {
331 wifi_handle handle = (wifi_handle)arg;
332 hal_info *info = getHalInfo(handle);
333
334 WifiEvent event(msg);
335 int res = event.parse();
336 if (res < 0) {
337 ALOGE("Failed to parse event: %d", res);
338 return NL_SKIP;
339 }
340
341 int cmd = event.get_cmd();
342 uint32_t vendor_id = 0;
343 int subcmd = 0;
344
345 if (cmd == NL80211_CMD_VENDOR) {
346 vendor_id = event.get_u32(NL80211_ATTR_VENDOR_ID);
347 subcmd = event.get_u32(NL80211_ATTR_VENDOR_SUBCMD);
348 ALOGI("event received %s, vendor_id = 0x%0x, subcmd = 0x%0x",
349 event.get_cmdString(), vendor_id, subcmd);
350 } else {
351 ALOGI("event received %s", event.get_cmdString());
352 }
353
354 ALOGI("event received %s, vendor_id = 0x%0x", event.get_cmdString(), vendor_id);
355 // event.log();
356
357 bool dispatched = false;
358 for (int i = 0; i < info->num_event_cb; i++) {
359 if (cmd == info->event_cb[i].nl_cmd) {
360 if (cmd == NL80211_CMD_VENDOR
361 && ((vendor_id != info->event_cb[i].vendor_id)
362 || (subcmd != info->event_cb[i].vendor_subcmd)))
363 {
364 /* event for a different vendor, ignore it */
365 continue;
366 }
367
368 cb_info *cbi = &(info->event_cb[i]);
369 (*(cbi->cb_func))(msg, cbi->cb_arg);
370 dispatched = true;
371 }
372 }
373
374 if (!dispatched) {
375 ALOGI("event ignored!!");
376 }
377
378 return NL_OK;
379 }
380
381 ///////////////////////////////////////////////////////////////////////////////////////
382
383 class GetMulticastIdCommand : public WifiCommand
384 {
385 private:
386 const char *mName;
387 const char *mGroup;
388 int mId;
389 public:
GetMulticastIdCommand(wifi_handle handle,const char * name,const char * group)390 GetMulticastIdCommand(wifi_handle handle, const char *name, const char *group)
391 : WifiCommand(handle, 0)
392 {
393 mName = name;
394 mGroup = group;
395 mId = -1;
396 }
397
getId()398 int getId() {
399 return mId;
400 }
401
create()402 virtual int create() {
403 int nlctrlFamily = genl_ctrl_resolve(mInfo->cmd_sock, "nlctrl");
404 // ALOGI("ctrl family = %d", nlctrlFamily);
405 int ret = mMsg.create(nlctrlFamily, CTRL_CMD_GETFAMILY, 0, 0);
406 if (ret < 0) {
407 return ret;
408 }
409 ret = mMsg.put_string(CTRL_ATTR_FAMILY_NAME, mName);
410 return ret;
411 }
412
handleResponse(WifiEvent & reply)413 virtual int handleResponse(WifiEvent& reply) {
414
415 // ALOGI("handling reponse in %s", __func__);
416
417 struct nlattr **tb = reply.attributes();
418 struct genlmsghdr *gnlh = reply.header();
419 struct nlattr *mcgrp = NULL;
420 int i;
421
422 if (!tb[CTRL_ATTR_MCAST_GROUPS]) {
423 ALOGI("No multicast groups found");
424 return NL_SKIP;
425 } else {
426 // ALOGI("Multicast groups attr size = %d", nla_len(tb[CTRL_ATTR_MCAST_GROUPS]));
427 }
428
429 for_each_attr(mcgrp, tb[CTRL_ATTR_MCAST_GROUPS], i) {
430
431 // ALOGI("Processing group");
432 struct nlattr *tb2[CTRL_ATTR_MCAST_GRP_MAX + 1];
433 nla_parse(tb2, CTRL_ATTR_MCAST_GRP_MAX, (nlattr *)nla_data(mcgrp),
434 nla_len(mcgrp), NULL);
435 if (!tb2[CTRL_ATTR_MCAST_GRP_NAME] || !tb2[CTRL_ATTR_MCAST_GRP_ID]) {
436 continue;
437 }
438
439 char *grpName = (char *)nla_data(tb2[CTRL_ATTR_MCAST_GRP_NAME]);
440 int grpNameLen = nla_len(tb2[CTRL_ATTR_MCAST_GRP_NAME]);
441
442 // ALOGI("Found group name %s", grpName);
443
444 if (strncmp(grpName, mGroup, grpNameLen) != 0)
445 continue;
446
447 mId = nla_get_u32(tb2[CTRL_ATTR_MCAST_GRP_ID]);
448 break;
449 }
450
451 return NL_SKIP;
452 }
453
454 };
455
wifi_get_multicast_id(wifi_handle handle,const char * name,const char * group)456 static int wifi_get_multicast_id(wifi_handle handle, const char *name, const char *group)
457 {
458 GetMulticastIdCommand cmd(handle, name, group);
459 int res = cmd.requestResponse();
460 if (res < 0)
461 return res;
462 else
463 return cmd.getId();
464 }
465
466 /////////////////////////////////////////////////////////////////////////
467
is_wifi_interface(const char * name)468 static bool is_wifi_interface(const char *name)
469 {
470 if (strncmp(name, "wlan", 4) != 0 && strncmp(name, "p2p", 3) != 0) {
471 /* not a wifi interface; ignore it */
472 return false;
473 } else {
474 return true;
475 }
476 }
477
get_interface(const char * name,interface_info * info)478 static int get_interface(const char *name, interface_info *info)
479 {
480 strcpy(info->name, name);
481 info->id = if_nametoindex(name);
482 // ALOGI("found an interface : %s, id = %d", name, info->id);
483 return WIFI_SUCCESS;
484 }
485
wifi_init_interfaces(wifi_handle handle)486 wifi_error wifi_init_interfaces(wifi_handle handle)
487 {
488 hal_info *info = (hal_info *)handle;
489
490 struct dirent *de;
491
492 DIR *d = opendir("/sys/class/net");
493 if (d == 0)
494 return WIFI_ERROR_UNKNOWN;
495
496 int n = 0;
497 while ((de = readdir(d))) {
498 if (de->d_name[0] == '.')
499 continue;
500 if (is_wifi_interface(de->d_name) ) {
501 n++;
502 }
503 }
504
505 closedir(d);
506
507 d = opendir("/sys/class/net");
508 if (d == 0)
509 return WIFI_ERROR_UNKNOWN;
510
511 info->interfaces = (interface_info **)malloc(sizeof(interface_info *) * n);
512
513 int i = 0;
514 while ((de = readdir(d))) {
515 if (de->d_name[0] == '.')
516 continue;
517 if (is_wifi_interface(de->d_name)) {
518 interface_info *ifinfo = (interface_info *)malloc(sizeof(interface_info));
519 if (get_interface(de->d_name, ifinfo) != WIFI_SUCCESS) {
520 free(ifinfo);
521 continue;
522 }
523 ifinfo->handle = handle;
524 info->interfaces[i] = ifinfo;
525 i++;
526 }
527 }
528
529 closedir(d);
530
531 info->num_interfaces = n;
532 return WIFI_SUCCESS;
533 }
534
wifi_get_ifaces(wifi_handle handle,int * num,wifi_interface_handle ** interfaces)535 wifi_error wifi_get_ifaces(wifi_handle handle, int *num, wifi_interface_handle **interfaces)
536 {
537 hal_info *info = (hal_info *)handle;
538
539 *interfaces = (wifi_interface_handle *)info->interfaces;
540 *num = info->num_interfaces;
541
542 return WIFI_SUCCESS;
543 }
544
wifi_get_iface_name(wifi_interface_handle handle,char * name,size_t size)545 wifi_error wifi_get_iface_name(wifi_interface_handle handle, char *name, size_t size)
546 {
547 interface_info *info = (interface_info *)handle;
548 strcpy(name, info->name);
549 return WIFI_SUCCESS;
550 }
551
wifi_get_iface_handle(wifi_handle handle,char * name)552 wifi_interface_handle wifi_get_iface_handle(wifi_handle handle, char *name)
553 {
554 hal_info *info = (hal_info *)handle;
555 for (int i=0;i<info->num_interfaces;i++)
556 {
557 if (!strcmp(info->interfaces[i]->name, name))
558 {
559 return ((wifi_interface_handle )(info->interfaces)[i]);
560 }
561 }
562 return NULL;
563 }
564
565 /////////////////////////////////////////////////////////////////////////////
566
wifi_get_supported_feature_set(wifi_interface_handle handle,feature_set * set)567 wifi_error wifi_get_supported_feature_set(wifi_interface_handle handle, feature_set *set) {
568 return WIFI_ERROR_NOT_SUPPORTED;
569 }
570
wifi_get_concurrency_matrix(wifi_interface_handle handle,int max_size,feature_set * matrix,int * size)571 wifi_error wifi_get_concurrency_matrix(wifi_interface_handle handle, int max_size,
572 feature_set *matrix, int *size) {
573 return WIFI_ERROR_NOT_SUPPORTED;
574 }
575
576