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