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