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
60static void internal_event_handler(wifi_handle handle, int events);
61static int internal_valid_message_handler(nl_msg *msg, void *arg);
62static int wifi_get_multicast_id(wifi_handle handle, const char *name, const char *group);
63static int wifi_add_membership(wifi_handle handle, const char *group);
64static wifi_error wifi_init_interfaces(wifi_handle handle);
65
66/* Initialize/Cleanup */
67
68void 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
81static 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
110int 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
118int 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
126int 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}
135static int no_seq_check(struct nl_msg *msg, void *arg)
136{
137    ALOGD("no_seq_check received");
138    return NL_OK;
139}
140
141wifi_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
222static 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
241static 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
259void 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
268static 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
277static 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 */
292void 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
329static 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
383class GetMulticastIdCommand : public WifiCommand
384{
385private:
386    const char *mName;
387    const char *mGroup;
388    int   mId;
389public:
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
398    int getId() {
399        return mId;
400    }
401
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
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
456static 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
468static 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
478static 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
486wifi_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
535wifi_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
545wifi_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
552wifi_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
567wifi_error wifi_get_supported_feature_set(wifi_interface_handle handle, feature_set *set) {
568    return WIFI_ERROR_NOT_SUPPORTED;
569}
570
571wifi_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