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/handlers.h>
     18 
     19 #include "sync.h"
     20 
     21 #define LOG_TAG  "WifiHAL"
     22 
     23 #include <utils/Log.h>
     24 
     25 #include "wifi_hal.h"
     26 #include "common.h"
     27 #include "cpp_bindings.h"
     28 
     29 /* Internal radio statistics structure in the driver */
     30 typedef struct {
     31 	wifi_radio radio;
     32 	uint32_t on_time;
     33 	uint32_t tx_time;
     34 	uint32_t rx_time;
     35 	uint32_t on_time_scan;
     36 	uint32_t on_time_nbd;
     37 	uint32_t on_time_gscan;
     38 	uint32_t on_time_roam_scan;
     39 	uint32_t on_time_pno_scan;
     40 	uint32_t on_time_hs20;
     41 	uint32_t num_channels;
     42 	wifi_channel_stat channels[];
     43 } wifi_radio_stat_internal;
     44 
     45 enum {
     46     LSTATS_SUBCMD_GET_INFO = ANDROID_NL80211_SUBCMD_LSTATS_RANGE_START,
     47 };
     48 
     49 class GetLinkStatsCommand : public WifiCommand
     50 {
     51     wifi_stats_result_handler mHandler;
     52 public:
     53     GetLinkStatsCommand(wifi_interface_handle iface, wifi_stats_result_handler handler)
     54         : WifiCommand("GetLinkStatsCommand", iface, 0), mHandler(handler)
     55     { }
     56 
     57     virtual int create() {
     58         // ALOGI("Creating message to get link statistics; iface = %d", mIfaceInfo->id);
     59 
     60         int ret = mMsg.create(GOOGLE_OUI, LSTATS_SUBCMD_GET_INFO);
     61         if (ret < 0) {
     62             ALOGE("Failed to create %x - %d", LSTATS_SUBCMD_GET_INFO, ret);
     63             return ret;
     64         }
     65 
     66         return ret;
     67     }
     68 
     69 protected:
     70     virtual int handleResponse(WifiEvent& reply) {
     71 
     72         // ALOGI("In GetLinkStatsCommand::handleResponse");
     73 
     74         if (reply.get_cmd() != NL80211_CMD_VENDOR) {
     75             ALOGD("Ignoring reply with cmd = %d", reply.get_cmd());
     76             return NL_SKIP;
     77         }
     78 
     79         int id = reply.get_vendor_id();
     80         int subcmd = reply.get_vendor_subcmd();
     81 
     82         // ALOGI("Id = %0x, subcmd = %d", id, subcmd);
     83 
     84         void *data = reply.get_vendor_data();
     85         int len = reply.get_vendor_data_len();
     86         wifi_radio_stat *radio_stat =
     87             convertToExternalRadioStatStructure((wifi_radio_stat_internal *)data);
     88         if (!radio_stat) {
     89             ALOGE("Invalid stats pointer received");
     90             return NL_SKIP;
     91         }
     92         if (radio_stat->num_channels > 11) {
     93             ALOGE("Incorrect number of channels = %d", radio_stat->num_channels);
     94             // dump data before num_channels
     95             ALOGE("radio: = %d", radio_stat->radio);
     96             ALOGE("on_time: = %d", radio_stat->on_time);
     97             ALOGE("tx_time: = %d", radio_stat->tx_time);
     98             ALOGE("rx_time: = %d", radio_stat->rx_time);
     99             ALOGE("on_time_scan: = %d", radio_stat->on_time_scan);
    100             ALOGE("on_time_nbd: = %d", radio_stat->on_time_nbd);
    101             ALOGE("on_time_gscan: = %d", radio_stat->on_time_gscan);
    102             ALOGE("on_time_pno_scan: = %d", radio_stat->on_time_pno_scan);
    103             ALOGE("on_time_hs20: = %d", radio_stat->on_time_hs20);
    104             free(radio_stat);
    105             return NL_SKIP;
    106         }
    107         wifi_iface_stat *iface_stat =
    108             (wifi_iface_stat *)((char *)&((wifi_radio_stat_internal *)data)->channels
    109                 + radio_stat->num_channels * sizeof(wifi_channel_stat));
    110         (*mHandler.on_link_stats_results)(id, iface_stat, 1, radio_stat);
    111         free(radio_stat);
    112         return NL_OK;
    113     }
    114 
    115 private:
    116     wifi_radio_stat *convertToExternalRadioStatStructure(wifi_radio_stat_internal *internal_stat_ptr) {
    117         wifi_radio_stat *external_stat_ptr = NULL;
    118         if (internal_stat_ptr) {
    119             uint32_t channel_size = internal_stat_ptr->num_channels * sizeof(wifi_channel_stat);
    120             uint32_t total_size = sizeof(wifi_radio_stat) + channel_size;
    121             external_stat_ptr = (wifi_radio_stat *)malloc(total_size);
    122             if (external_stat_ptr) {
    123                 external_stat_ptr->radio = internal_stat_ptr->radio;
    124                 external_stat_ptr->on_time = internal_stat_ptr->on_time;
    125                 external_stat_ptr->tx_time = internal_stat_ptr->tx_time;
    126                 external_stat_ptr->rx_time = internal_stat_ptr->rx_time;
    127                 external_stat_ptr->tx_time_per_levels = NULL;
    128                 external_stat_ptr->num_tx_levels = 0;
    129                 external_stat_ptr->on_time_scan = internal_stat_ptr->on_time_scan;
    130                 external_stat_ptr->on_time_nbd = internal_stat_ptr->on_time_nbd;
    131                 external_stat_ptr->on_time_gscan = internal_stat_ptr->on_time_gscan;
    132                 external_stat_ptr->on_time_roam_scan = internal_stat_ptr->on_time_roam_scan;
    133                 external_stat_ptr->on_time_pno_scan = internal_stat_ptr->on_time_pno_scan;
    134                 external_stat_ptr->on_time_hs20 = internal_stat_ptr->on_time_hs20;
    135                 external_stat_ptr->num_channels = internal_stat_ptr->num_channels;
    136                 if (internal_stat_ptr->num_channels) {
    137                     memcpy(&(external_stat_ptr->channels), &(internal_stat_ptr->channels),
    138                         channel_size);
    139                 }
    140             }
    141         }
    142         return external_stat_ptr;
    143     }
    144 };
    145 
    146 wifi_error wifi_get_link_stats(wifi_request_id id,
    147         wifi_interface_handle iface, wifi_stats_result_handler handler)
    148 {
    149     GetLinkStatsCommand command(iface, handler);
    150     return (wifi_error) command.requestResponse();
    151 }
    152 
    153