PNO MAC rotation + Hotlist Lost event
[android/platform/hardware/broadcom/wlan.git] / bcmdhd / wifi_hal / wifi_hal.cpp
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 <dirent.h>
22 #include <net/if.h>
23
24 #include "sync.h"
25
26 #define LOG_TAG  "WifiHAL"
27
28 #include <utils/Log.h>
29
30 #include "wifi_hal.h"
31 #include "common.h"
32 #include "cpp_bindings.h"
33
34 /*
35  BUGBUG: normally, libnl allocates ports for all connections it makes; but
36  being a static library, it doesn't really know how many other netlink connections
37  are made by the same process, if connections come from different shared libraries.
38  These port assignments exist to solve that problem - temporarily. We need to fix
39  libnl to try and allocate ports across the entire process.
40  */
41
42 #define WIFI_HAL_CMD_SOCK_PORT       644
43 #define WIFI_HAL_EVENT_SOCK_PORT     645
44
45 #define FEATURE_SET                  0
46 #define FEATURE_SET_MATRIX           1
47
48 static void internal_event_handler(wifi_handle handle, int events);
49 static int internal_no_seq_check(nl_msg *msg, void *arg);
50 static int internal_valid_message_handler(nl_msg *msg, void *arg);
51 static int wifi_get_multicast_id(wifi_handle handle, const char *name, const char *group);
52 static int wifi_add_membership(wifi_handle handle, const char *group);
53 static wifi_error wifi_init_interfaces(wifi_handle handle);
54
55 typedef enum wifi_attr {
56     ANDR_WIFI_ATTRIBUTE_NUM_FEATURE_SET,
57     ANDR_WIFI_ATTRIBUTE_FEATURE_SET,
58     ANDR_WIFI_ATTRIBUTE_PNO_RANDOM_MAC_OUI
59 } wifi_attr_t;
60
61 /* Initialize/Cleanup */
62
63 void wifi_socket_set_local_port(struct nl_sock *sock, uint32_t port)
64 {
65     uint32_t pid = getpid() & 0x3FFFFF;
66     nl_socket_set_local_port(sock, pid + (port << 22));
67 }
68
69 static nl_sock * wifi_create_nl_socket(int port)
70 {
71     // ALOGI("Creating socket");
72     struct nl_sock *sock = nl_socket_alloc();
73     if (sock == NULL) {
74         ALOGE("Could not create handle");
75         return NULL;
76     }
77
78     wifi_socket_set_local_port(sock, port);
79
80     struct sockaddr *addr = NULL;
81     // ALOGI("sizeof(sockaddr) = %d, sizeof(sockaddr_nl) = %d", sizeof(*addr), sizeof(*addr_nl));
82
83     // ALOGI("Connecting socket");
84     if (nl_connect(sock, NETLINK_GENERIC)) {
85         ALOGE("Could not connect handle");
86         nl_socket_free(sock);
87         return NULL;
88     }
89
90     // ALOGI("Making socket nonblocking");
91     /*
92     if (nl_socket_set_nonblocking(sock)) {
93         ALOGE("Could make socket non-blocking");
94         nl_socket_free(sock);
95         return NULL;
96     }
97     */
98
99     return sock;
100 }
101
102 wifi_error wifi_initialize(wifi_handle *handle)
103 {
104     srand(getpid());
105
106     ALOGI("Initializing wifi");
107     hal_info *info = (hal_info *)malloc(sizeof(hal_info));
108     if (info == NULL) {
109         ALOGE("Could not allocate hal_info");
110         return WIFI_ERROR_UNKNOWN;
111     }
112
113     memset(info, 0, sizeof(*info));
114
115     ALOGI("Creating socket");
116     struct nl_sock *cmd_sock = wifi_create_nl_socket(WIFI_HAL_CMD_SOCK_PORT);
117     if (cmd_sock == NULL) {
118         ALOGE("Could not create handle");
119         return WIFI_ERROR_UNKNOWN;
120     }
121
122     struct nl_sock *event_sock = wifi_create_nl_socket(WIFI_HAL_EVENT_SOCK_PORT);
123     if (event_sock == NULL) {
124         ALOGE("Could not create handle");
125         nl_socket_free(cmd_sock);
126         return WIFI_ERROR_UNKNOWN;
127     }
128
129     struct nl_cb *cb = nl_socket_get_cb(event_sock);
130     if (cb == NULL) {
131         ALOGE("Could not create handle");
132         return WIFI_ERROR_UNKNOWN;
133     }
134
135     // ALOGI("cb->refcnt = %d", cb->cb_refcnt);
136     nl_cb_set(cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, internal_no_seq_check, info);
137     nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, internal_valid_message_handler, info);
138     nl_cb_put(cb);
139
140     info->cmd_sock = cmd_sock;
141     info->event_sock = event_sock;
142     info->clean_up = false;
143     info->in_event_loop = false;
144
145     info->event_cb = (cb_info *)malloc(sizeof(cb_info) * DEFAULT_EVENT_CB_SIZE);
146     info->alloc_event_cb = DEFAULT_EVENT_CB_SIZE;
147     info->num_event_cb = 0;
148
149     info->cmd = (cmd_info *)malloc(sizeof(cmd_info) * DEFAULT_CMD_SIZE);
150     info->alloc_cmd = DEFAULT_CMD_SIZE;
151     info->num_cmd = 0;
152
153     info->nl80211_family_id = genl_ctrl_resolve(cmd_sock, "nl80211");
154     if (info->nl80211_family_id < 0) {
155         ALOGE("Could not resolve nl80211 familty id");
156         nl_socket_free(cmd_sock);
157         nl_socket_free(event_sock);
158         free(info);
159         return WIFI_ERROR_UNKNOWN;
160     }
161
162     pthread_mutex_init(&info->cb_lock, NULL);
163
164     *handle = (wifi_handle) info;
165
166     wifi_add_membership(*handle, "scan");
167     wifi_add_membership(*handle, "mlme");
168     wifi_add_membership(*handle, "regulatory");
169     wifi_add_membership(*handle, "vendor");
170
171     wifi_init_interfaces(*handle);
172     // ALOGI("Found %d interfaces", info->num_interfaces);
173
174
175     ALOGI("Initialized Wifi HAL Successfully; vendor cmd = %d", NL80211_CMD_VENDOR);
176     return WIFI_SUCCESS;
177 }
178
179 static int wifi_add_membership(wifi_handle handle, const char *group)
180 {
181     hal_info *info = getHalInfo(handle);
182
183     int id = wifi_get_multicast_id(handle, "nl80211", group);
184     if (id < 0) {
185         ALOGE("Could not find group %s", group);
186         return id;
187     }
188
189     int ret = nl_socket_add_membership(info->event_sock, id);
190     if (ret < 0) {
191         ALOGE("Could not add membership to group %s", group);
192     }
193
194     // ALOGI("Successfully added membership for group %s", group);
195     return ret;
196 }
197
198 static void internal_cleaned_up_handler(wifi_handle handle)
199 {
200     hal_info *info = getHalInfo(handle);
201     wifi_cleaned_up_handler cleaned_up_handler = info->cleaned_up_handler;
202
203     if (info->cmd_sock != 0) {
204         nl_socket_free(info->cmd_sock);
205         nl_socket_free(info->event_sock);
206         info->cmd_sock = NULL;
207         info->event_sock = NULL;
208     }
209
210     (*cleaned_up_handler)(handle);
211     pthread_mutex_destroy(&info->cb_lock);
212     free(info);
213
214     ALOGI("Internal cleanup completed");
215 }
216
217 void wifi_cleanup(wifi_handle handle, wifi_cleaned_up_handler handler)
218 {
219     hal_info *info = getHalInfo(handle);
220     info->cleaned_up_handler = handler;
221     info->clean_up = true;
222
223     ALOGI("Wifi cleanup completed");
224 }
225
226 static int internal_pollin_handler(wifi_handle handle)
227 {
228     hal_info *info = getHalInfo(handle);
229     struct nl_cb *cb = nl_socket_get_cb(info->event_sock);
230     int res = nl_recvmsgs(info->event_sock, cb);
231     // ALOGD("nl_recvmsgs returned %d", res);
232     nl_cb_put(cb);
233     return res;
234 }
235
236 static void internal_event_handler(wifi_handle handle, int events)
237 {
238     if (events & POLLERR) {
239         ALOGE("Error reading from socket");
240     } else if (events & POLLHUP) {
241         ALOGE("Remote side hung up");
242     } else if (events & POLLIN) {
243         // ALOGI("Found some events!!!");
244         internal_pollin_handler(handle);
245     } else {
246         ALOGE("Unknown event - %0x", events);
247     }
248 }
249
250 /* Run event handler */
251 void wifi_event_loop(wifi_handle handle)
252 {
253     hal_info *info = getHalInfo(handle);
254     if (info->in_event_loop) {
255         return;
256     } else {
257         info->in_event_loop = true;
258     }
259
260     pollfd pfd;
261     memset(&pfd, 0, sizeof(pfd));
262
263     pfd.fd = nl_socket_get_fd(info->event_sock);
264     pfd.events = POLLIN;
265
266     /* TODO: Add support for timeouts */
267
268     do {
269         int timeout = -1;                   /* Infinite timeout */
270         pfd.revents = 0;
271         // ALOGI("Polling socket");
272         int result = poll(&pfd, 1, -1);
273         if (result < 0) {
274             ALOGE("Error polling socket");
275         } else if (pfd.revents & (POLLIN | POLLHUP | POLLERR)) {
276             internal_event_handler(handle, pfd.revents);
277         }
278     } while (!info->clean_up);
279
280
281     ALOGI("Cleaning up");
282     internal_cleaned_up_handler(handle);
283 }
284
285 ///////////////////////////////////////////////////////////////////////////////////////
286
287 static int internal_no_seq_check(struct nl_msg *msg, void *arg)
288 {
289     return NL_OK;
290 }
291
292 static int internal_valid_message_handler(nl_msg *msg, void *arg)
293 {
294     wifi_handle handle = (wifi_handle)arg;
295     hal_info *info = getHalInfo(handle);
296
297     WifiEvent event(msg);
298     int res = event.parse();
299     if (res < 0) {
300         ALOGE("Failed to parse event: %d", res);
301         return NL_SKIP;
302     }
303
304     int cmd = event.get_cmd();
305     uint32_t vendor_id = 0;
306     int subcmd = 0;
307
308     if (cmd == NL80211_CMD_VENDOR) {
309         vendor_id = event.get_u32(NL80211_ATTR_VENDOR_ID);
310         subcmd = event.get_u32(NL80211_ATTR_VENDOR_SUBCMD);
311         ALOGI("event received %s, vendor_id = 0x%0x, subcmd = 0x%0x",
312                 event.get_cmdString(), vendor_id, subcmd);
313     } else {
314         // ALOGI("event received %s", event.get_cmdString());
315     }
316
317     // ALOGI("event received %s, vendor_id = 0x%0x", event.get_cmdString(), vendor_id);
318     // event.log();
319
320     bool dispatched = false;
321
322     pthread_mutex_lock(&info->cb_lock);
323
324     for (int i = 0; i < info->num_event_cb; i++) {
325         if (cmd == info->event_cb[i].nl_cmd) {
326             if (cmd == NL80211_CMD_VENDOR
327                 && ((vendor_id != info->event_cb[i].vendor_id)
328                 || (subcmd != info->event_cb[i].vendor_subcmd)))
329             {
330                 /* event for a different vendor, ignore it */
331                 continue;
332             }
333
334             cb_info *cbi = &(info->event_cb[i]);
335             nl_recvmsg_msg_cb_t cb_func = cbi->cb_func;
336             void *cb_arg = cbi->cb_arg;
337             WifiCommand *cmd = (WifiCommand *)cbi->cb_arg;
338             if (cmd != NULL) {
339                 cmd->addRef();
340             }
341
342             pthread_mutex_unlock(&info->cb_lock);
343
344             (*cb_func)(msg, cb_arg);
345             if (cmd != NULL) {
346                 cmd->releaseRef();
347             }
348
349             return NL_OK;
350         }
351     }
352
353     pthread_mutex_unlock(&info->cb_lock);
354     return NL_OK;
355 }
356
357 ///////////////////////////////////////////////////////////////////////////////////////
358
359 class GetMulticastIdCommand : public WifiCommand
360 {
361 private:
362     const char *mName;
363     const char *mGroup;
364     int   mId;
365 public:
366     GetMulticastIdCommand(wifi_handle handle, const char *name, const char *group)
367         : WifiCommand(handle, 0)
368     {
369         mName = name;
370         mGroup = group;
371         mId = -1;
372     }
373
374     int getId() {
375         return mId;
376     }
377
378     virtual int create() {
379         int nlctrlFamily = genl_ctrl_resolve(mInfo->cmd_sock, "nlctrl");
380         // ALOGI("ctrl family = %d", nlctrlFamily);
381         int ret = mMsg.create(nlctrlFamily, CTRL_CMD_GETFAMILY, 0, 0);
382         if (ret < 0) {
383             return ret;
384         }
385         ret = mMsg.put_string(CTRL_ATTR_FAMILY_NAME, mName);
386         return ret;
387     }
388
389     virtual int handleResponse(WifiEvent& reply) {
390
391         // ALOGI("handling reponse in %s", __func__);
392
393         struct nlattr **tb = reply.attributes();
394         struct genlmsghdr *gnlh = reply.header();
395         struct nlattr *mcgrp = NULL;
396         int i;
397
398         if (!tb[CTRL_ATTR_MCAST_GROUPS]) {
399             ALOGI("No multicast groups found");
400             return NL_SKIP;
401         } else {
402             // ALOGI("Multicast groups attr size = %d", nla_len(tb[CTRL_ATTR_MCAST_GROUPS]));
403         }
404
405         for_each_attr(mcgrp, tb[CTRL_ATTR_MCAST_GROUPS], i) {
406
407             // ALOGI("Processing group");
408             struct nlattr *tb2[CTRL_ATTR_MCAST_GRP_MAX + 1];
409             nla_parse(tb2, CTRL_ATTR_MCAST_GRP_MAX, (nlattr *)nla_data(mcgrp),
410                 nla_len(mcgrp), NULL);
411             if (!tb2[CTRL_ATTR_MCAST_GRP_NAME] || !tb2[CTRL_ATTR_MCAST_GRP_ID]) {
412                 continue;
413             }
414
415             char *grpName = (char *)nla_data(tb2[CTRL_ATTR_MCAST_GRP_NAME]);
416             int grpNameLen = nla_len(tb2[CTRL_ATTR_MCAST_GRP_NAME]);
417
418             // ALOGI("Found group name %s", grpName);
419
420             if (strncmp(grpName, mGroup, grpNameLen) != 0)
421                 continue;
422
423             mId = nla_get_u32(tb2[CTRL_ATTR_MCAST_GRP_ID]);
424             break;
425         }
426
427         return NL_SKIP;
428     }
429
430 };
431
432 class SetPnoMacAddrOuiCommand : public WifiCommand {
433
434 private:
435     byte *mOui;
436     feature_set *fset;
437     feature_set *feature_matrix;
438     int *fm_size;
439     int set_size_max;
440 public:
441     SetPnoMacAddrOuiCommand(wifi_interface_handle handle, oui scan_oui)
442         : WifiCommand(handle, 0)
443     {
444         mOui = scan_oui;
445     }
446
447     int createRequest(WifiRequest& request, int subcmd, byte *scan_oui) {
448         int result = request.create(GOOGLE_OUI, subcmd);
449         if (result < 0) {
450             return result;
451         }
452
453         nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
454         result = request.put(ANDR_WIFI_ATTRIBUTE_PNO_RANDOM_MAC_OUI, scan_oui, DOT11_OUI_LEN);
455         if (result < 0) {
456             return result;
457         }
458
459         request.attr_end(data);
460         return WIFI_SUCCESS;
461
462     }
463
464     int start() {
465         ALOGD("Sending mac address OUI");
466         WifiRequest request(familyId(), ifaceId());
467         int result = createRequest(request, WIFI_SUBCMD_SET_PNO_RANDOM_MAC_OUI, mOui);
468         if (result != WIFI_SUCCESS) {
469             ALOGE("failed to create request; result = %d", result);
470             return result;
471         }
472
473         result = requestResponse(request);
474         if (result != WIFI_SUCCESS) {
475             ALOGE("failed to set scanning mac OUI; result = %d", result);
476         }
477
478         return result;
479     }
480 protected:
481     virtual int handleResponse(WifiEvent& reply) {
482          ALOGD("Request complete!");
483         /* Nothing to do on response! */
484         return NL_SKIP;
485     }
486
487 };
488
489
490
491 class GetFeatureSetCommand : public WifiCommand {
492
493 private:
494     int feature_type;
495     feature_set *fset;
496     feature_set *feature_matrix;
497     int *fm_size;
498     int set_size_max;
499 public:
500     GetFeatureSetCommand(wifi_interface_handle handle, int feature, feature_set *set,
501          feature_set set_matrix[], int *size, int max_size)
502         : WifiCommand(handle, 0)
503     {
504         feature_type = feature;
505         fset = set;
506         feature_matrix = set_matrix;
507         fm_size = size;
508         set_size_max = max_size;
509     }
510
511     virtual int create() {
512         int ret;
513
514         if(feature_type == FEATURE_SET) {
515             ret = mMsg.create(GOOGLE_OUI, WIFI_SUBCMD_GET_FEATURE_SET);
516         } else if (feature_type == FEATURE_SET_MATRIX){
517             ret = mMsg.create(GOOGLE_OUI, WIFI_SUBCMD_GET_FEATURE_SET_MATRIX);
518         } else {
519             ALOGE("Unknown feature type %d", feature_type);
520             return -1;
521         }
522
523         if (ret < 0) {
524             ALOGE("Can't create message to send to driver - %d", ret);
525         }
526
527         return ret;
528     }
529
530 protected:
531     virtual int handleResponse(WifiEvent& reply) {
532
533         ALOGD("In GetFeatureSetCommand::handleResponse");
534
535         if (reply.get_cmd() != NL80211_CMD_VENDOR) {
536             ALOGD("Ignoring reply with cmd = %d", reply.get_cmd());
537             return NL_SKIP;
538         }
539
540         int id = reply.get_vendor_id();
541         int subcmd = reply.get_vendor_subcmd();
542
543         nlattr *vendor_data = reply.get_attribute(NL80211_ATTR_VENDOR_DATA);
544         int len = reply.get_vendor_data_len();
545
546         ALOGD("Id = %0x, subcmd = %d, len = %d", id, subcmd, len);
547         if (vendor_data == NULL || len == 0) {
548             ALOGE("no vendor data in GetFeatureSetCommand response; ignoring it");
549             return NL_SKIP;
550         }
551         if(feature_type == FEATURE_SET) {
552             void *data = reply.get_vendor_data();
553             if(!fset) {
554                 ALOGE("Buffers pointers not set");
555                 return NL_SKIP;
556             }
557             memcpy(fset, data, min(len, (int) sizeof(*fset)));
558         } else {
559             int num_features_set = 0;
560             int i = 0;
561
562             if(!feature_matrix || !fm_size) {
563                 ALOGE("Buffers pointers not set");
564                 return NL_SKIP;
565             }
566
567             for (nl_iterator it(vendor_data); it.has_next(); it.next()) {
568                 if (it.get_type() == ANDR_WIFI_ATTRIBUTE_NUM_FEATURE_SET) {
569                     num_features_set = it.get_u32();
570                     ALOGI("Got feature list with %d concurrent sets", num_features_set);
571                     if(set_size_max && (num_features_set > set_size_max))
572                         num_features_set = set_size_max;
573                     *fm_size = num_features_set;
574                 } else if ((it.get_type() == ANDR_WIFI_ATTRIBUTE_FEATURE_SET) &&
575                              i < num_features_set) {
576                     feature_matrix[i] = it.get_u32();
577                     i++;
578                 } else {
579                     ALOGW("Ignoring invalid attribute type = %d, size = %d",
580                             it.get_type(), it.get_len());
581                 }
582             }
583
584         }
585         return NL_OK;
586     }
587
588 };
589
590 static int wifi_get_multicast_id(wifi_handle handle, const char *name, const char *group)
591 {
592     GetMulticastIdCommand cmd(handle, name, group);
593     int res = cmd.requestResponse();
594     if (res < 0)
595         return res;
596     else
597         return cmd.getId();
598 }
599
600 /////////////////////////////////////////////////////////////////////////
601
602 static bool is_wifi_interface(const char *name)
603 {
604     if (strncmp(name, "wlan", 4) != 0 && strncmp(name, "p2p", 3) != 0) {
605         /* not a wifi interface; ignore it */
606         return false;
607     } else {
608         return true;
609     }
610 }
611
612 static int get_interface(const char *name, interface_info *info)
613 {
614     strcpy(info->name, name);
615     info->id = if_nametoindex(name);
616     // ALOGI("found an interface : %s, id = %d", name, info->id);
617     return WIFI_SUCCESS;
618 }
619
620 wifi_error wifi_init_interfaces(wifi_handle handle)
621 {
622     hal_info *info = (hal_info *)handle;
623
624     struct dirent *de;
625
626     DIR *d = opendir("/sys/class/net");
627     if (d == 0)
628         return WIFI_ERROR_UNKNOWN;
629
630     int n = 0;
631     while ((de = readdir(d))) {
632         if (de->d_name[0] == '.')
633             continue;
634         if (is_wifi_interface(de->d_name) ) {
635             n++;
636         }
637     }
638
639     closedir(d);
640
641     d = opendir("/sys/class/net");
642     if (d == 0)
643         return WIFI_ERROR_UNKNOWN;
644
645     info->interfaces = (interface_info **)malloc(sizeof(interface_info *) * n);
646
647     int i = 0;
648     while ((de = readdir(d))) {
649         if (de->d_name[0] == '.')
650             continue;
651         if (is_wifi_interface(de->d_name)) {
652             interface_info *ifinfo = (interface_info *)malloc(sizeof(interface_info));
653             if (get_interface(de->d_name, ifinfo) != WIFI_SUCCESS) {
654                 free(ifinfo);
655                 continue;
656             }
657             ifinfo->handle = handle;
658             info->interfaces[i] = ifinfo;
659             i++;
660         }
661     }
662
663     closedir(d);
664
665     info->num_interfaces = n;
666     return WIFI_SUCCESS;
667 }
668
669 wifi_error wifi_get_ifaces(wifi_handle handle, int *num, wifi_interface_handle **interfaces)
670 {
671     hal_info *info = (hal_info *)handle;
672
673     *interfaces = (wifi_interface_handle *)info->interfaces;
674     *num = info->num_interfaces;
675
676     return WIFI_SUCCESS;
677 }
678
679 wifi_error wifi_get_iface_name(wifi_interface_handle handle, char *name, size_t size)
680 {
681     interface_info *info = (interface_info *)handle;
682     strcpy(name, info->name);
683     return WIFI_SUCCESS;
684 }
685
686 wifi_error wifi_get_supported_feature_set(wifi_interface_handle handle, feature_set *set)
687 {
688     GetFeatureSetCommand command(handle, FEATURE_SET, set, NULL, NULL, 1);
689     return (wifi_error) command.requestResponse();
690 }
691
692 wifi_error wifi_get_concurrency_matrix(wifi_interface_handle handle, int set_size_max,
693        feature_set set[], int *set_size)
694 {
695     GetFeatureSetCommand command(handle, FEATURE_SET_MATRIX, NULL, set, set_size, set_size_max);
696     return (wifi_error) command.requestResponse();
697 }
698
699 wifi_error wifi_set_scanning_mac_oui(wifi_interface_handle handle, oui scan_oui)
700 {
701     SetPnoMacAddrOuiCommand command(handle, scan_oui);
702     return (wifi_error)command.start();
703
704 }
705
706 /////////////////////////////////////////////////////////////////////////////
707