• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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