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