Home | History | Annotate | Download | only in wifi_hal
      1 #include <stdint.h>
      2 #include <fcntl.h>
      3 #include <sys/socket.h>
      4 #include <netlink/genl/genl.h>
      5 #include <netlink/genl/family.h>
      6 #include <netlink/genl/ctrl.h>
      7 #include <linux/rtnetlink.h>
      8 #include <netpacket/packet.h>
      9 #include <linux/filter.h>
     10 #include <linux/errqueue.h>
     11 
     12 #include <linux/pkt_sched.h>
     13 #include <netlink/object-api.h>
     14 #include <netlink/netlink.h>
     15 #include <netlink/socket.h>
     16 #include <netlink/handlers.h>
     17 
     18 #include "wifi_hal.h"
     19 #include "common.h"
     20 #include "cpp_bindings.h"
     21 
     22 interface_info *getIfaceInfo(wifi_interface_handle handle)
     23 {
     24     return (interface_info *)handle;
     25 }
     26 
     27 wifi_handle getWifiHandle(wifi_interface_handle handle)
     28 {
     29     return getIfaceInfo(handle)->handle;
     30 }
     31 
     32 hal_info *getHalInfo(wifi_handle handle)
     33 {
     34     return (hal_info *)handle;
     35 }
     36 
     37 hal_info *getHalInfo(wifi_interface_handle handle)
     38 {
     39     return getHalInfo(getWifiHandle(handle));
     40 }
     41 
     42 wifi_handle getWifiHandle(hal_info *info)
     43 {
     44     return (wifi_handle)info;
     45 }
     46 
     47 wifi_interface_handle getIfaceHandle(interface_info *info)
     48 {
     49     return (wifi_interface_handle)info;
     50 }
     51 
     52 wifi_error wifi_register_handler(wifi_handle handle, int cmd, nl_recvmsg_msg_cb_t func, void *arg)
     53 {
     54     hal_info *info = (hal_info *)handle;
     55 
     56     /* TODO: check for multiple handlers? */
     57     pthread_mutex_lock(&info->cb_lock);
     58 
     59     wifi_error result = WIFI_ERROR_OUT_OF_MEMORY;
     60 
     61     if (info->num_event_cb < info->alloc_event_cb) {
     62         info->event_cb[info->num_event_cb].nl_cmd  = cmd;
     63         info->event_cb[info->num_event_cb].vendor_id  = 0;
     64         info->event_cb[info->num_event_cb].vendor_subcmd  = 0;
     65         info->event_cb[info->num_event_cb].cb_func = func;
     66         info->event_cb[info->num_event_cb].cb_arg  = arg;
     67         ALOGV("Successfully added event handler %p:%p for command %d at %d",
     68                 arg, func, cmd, info->num_event_cb);
     69         info->num_event_cb++;
     70         result = WIFI_SUCCESS;
     71     }
     72 
     73     pthread_mutex_unlock(&info->cb_lock);
     74     return result;
     75 }
     76 
     77 wifi_error wifi_register_vendor_handler(wifi_handle handle,
     78         uint32_t id, int subcmd, nl_recvmsg_msg_cb_t func, void *arg)
     79 {
     80     hal_info *info = (hal_info *)handle;
     81 
     82     /* TODO: check for multiple handlers? */
     83     pthread_mutex_lock(&info->cb_lock);
     84 
     85     wifi_error result = WIFI_ERROR_OUT_OF_MEMORY;
     86 
     87     if (info->num_event_cb < info->alloc_event_cb) {
     88         info->event_cb[info->num_event_cb].nl_cmd  = NL80211_CMD_VENDOR;
     89         info->event_cb[info->num_event_cb].vendor_id  = id;
     90         info->event_cb[info->num_event_cb].vendor_subcmd  = subcmd;
     91         info->event_cb[info->num_event_cb].cb_func = func;
     92         info->event_cb[info->num_event_cb].cb_arg  = arg;
     93         ALOGV("Added event handler %p:%p for vendor 0x%0x and subcmd 0x%0x at %d",
     94                 arg, func, id, subcmd, info->num_event_cb);
     95         info->num_event_cb++;
     96         result = WIFI_SUCCESS;
     97     }
     98 
     99     pthread_mutex_unlock(&info->cb_lock);
    100     return result;
    101 }
    102 
    103 void wifi_unregister_handler(wifi_handle handle, int cmd)
    104 {
    105     hal_info *info = (hal_info *)handle;
    106 
    107     if (cmd == NL80211_CMD_VENDOR) {
    108         ALOGE("Must use wifi_unregister_vendor_handler to remove vendor handlers");
    109         return;
    110     }
    111 
    112     pthread_mutex_lock(&info->cb_lock);
    113 
    114     for (int i = 0; i < info->num_event_cb; i++) {
    115         if (info->event_cb[i].nl_cmd == cmd) {
    116             ALOGV("Successfully removed event handler %p:%p for cmd = 0x%0x from %d",
    117                     info->event_cb[i].cb_arg, info->event_cb[i].cb_func, cmd, i);
    118 
    119             memmove(&info->event_cb[i], &info->event_cb[i+1],
    120                 (info->num_event_cb - i - 1) * sizeof(cb_info));
    121             info->num_event_cb--;
    122             break;
    123         }
    124     }
    125 
    126     pthread_mutex_unlock(&info->cb_lock);
    127 }
    128 
    129 void wifi_unregister_vendor_handler(wifi_handle handle, uint32_t id, int subcmd)
    130 {
    131     hal_info *info = (hal_info *)handle;
    132 
    133     pthread_mutex_lock(&info->cb_lock);
    134 
    135     for (int i = 0; i < info->num_event_cb; i++) {
    136 
    137         if (info->event_cb[i].nl_cmd == NL80211_CMD_VENDOR
    138                 && info->event_cb[i].vendor_id == id
    139                 && info->event_cb[i].vendor_subcmd == subcmd) {
    140             ALOGV("Successfully removed event handler %p:%p for vendor 0x%0x, subcmd 0x%0x from %d",
    141                     info->event_cb[i].cb_arg, info->event_cb[i].cb_func, id, subcmd, i);
    142             memmove(&info->event_cb[i], &info->event_cb[i+1],
    143                 (info->num_event_cb - i - 1) * sizeof(cb_info));
    144             info->num_event_cb--;
    145             break;
    146         }
    147     }
    148 
    149     pthread_mutex_unlock(&info->cb_lock);
    150 }
    151 
    152 
    153 wifi_error wifi_register_cmd(wifi_handle handle, int id, WifiCommand *cmd)
    154 {
    155     hal_info *info = (hal_info *)handle;
    156 
    157     ALOGV("registering command %d", id);
    158 
    159     wifi_error result = WIFI_ERROR_OUT_OF_MEMORY;
    160 
    161     if (info->num_cmd < info->alloc_cmd) {
    162         info->cmd[info->num_cmd].id   = id;
    163         info->cmd[info->num_cmd].cmd  = cmd;
    164         ALOGV("Successfully added command %d: %p at %d", id, cmd, info->num_cmd);
    165         info->num_cmd++;
    166         result = WIFI_SUCCESS;
    167     } else {
    168         ALOGE("Failed to add command %d: %p at %d, reached max limit %d",
    169                 id, cmd, info->num_cmd, info->alloc_cmd);
    170     }
    171 
    172     return result;
    173 }
    174 
    175 WifiCommand *wifi_unregister_cmd(wifi_handle handle, int id)
    176 {
    177     hal_info *info = (hal_info *)handle;
    178 
    179     ALOGV("un-registering command %d", id);
    180 
    181     WifiCommand *cmd = NULL;
    182 
    183     for (int i = 0; i < info->num_cmd; i++) {
    184         if (info->cmd[i].id == id) {
    185             cmd = info->cmd[i].cmd;
    186             memmove(&info->cmd[i], &info->cmd[i+1], (info->num_cmd - i - 1) * sizeof(cmd_info));
    187             info->num_cmd--;
    188             ALOGV("Successfully removed command %d: %p from %d", id, cmd, i);
    189             break;
    190         }
    191     }
    192 
    193     if (!cmd) {
    194         ALOGI("Failed to remove command %d: %p", id, cmd);
    195     }
    196 
    197     return cmd;
    198 }
    199 
    200 WifiCommand *wifi_get_cmd(wifi_handle handle, int id)
    201 {
    202     hal_info *info = (hal_info *)handle;
    203 
    204     WifiCommand *cmd = NULL;
    205 
    206     for (int i = 0; i < info->num_cmd; i++) {
    207         if (info->cmd[i].id == id) {
    208             cmd = info->cmd[i].cmd;
    209             break;
    210         }
    211     }
    212 
    213     return cmd;
    214 }
    215 
    216 void wifi_unregister_cmd(wifi_handle handle, WifiCommand *cmd)
    217 {
    218     hal_info *info = (hal_info *)handle;
    219 
    220     for (int i = 0; i < info->num_cmd; i++) {
    221         if (info->cmd[i].cmd == cmd) {
    222             int id = info->cmd[i].id;
    223             memmove(&info->cmd[i], &info->cmd[i+1], (info->num_cmd - i - 1) * sizeof(cmd_info));
    224             info->num_cmd--;
    225             ALOGV("Successfully removed command %d: %p from %d", id, cmd, i);
    226             break;
    227         }
    228     }
    229 }
    230 
    231 wifi_error wifi_cancel_cmd(wifi_request_id id, wifi_interface_handle iface)
    232 {
    233     wifi_handle handle = getWifiHandle(iface);
    234 
    235     WifiCommand *cmd = wifi_unregister_cmd(handle, id);
    236     ALOGV("Cancel WifiCommand = %p", cmd);
    237     if (cmd) {
    238         cmd->cancel();
    239         cmd->releaseRef();
    240         return WIFI_SUCCESS;
    241     }
    242 
    243     return WIFI_ERROR_INVALID_ARGS;
    244 }
    245 
    246