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