main.c revision 240184
1/*- 2 * Copyright (c) 2012, Adrian Chadd. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer, 10 * without modification. 11 * 2. Redistributions in binary form must reproduce at minimum a disclaimer 12 * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any 13 * redistribution must be conditioned upon including a substantially 14 * similar Disclaimer requirement for further binary redistribution. 15 * 16 * NO WARRANTY 17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY 20 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 21 * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, 22 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 25 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 27 * THE POSSIBILITY OF SUCH DAMAGES. 28 * 29 * $FreeBSD: head/tools/tools/ath/athratestats/main.c 240184 2012-09-07 06:02:40Z adrian $ 30 */ 31 32#include "opt_ah.h" 33 34#include <sys/types.h> 35#include <sys/file.h> 36#include <sys/sockio.h> 37#include <sys/socket.h> 38#include <net/ethernet.h> 39#include <net/if.h> 40#include <net/if_media.h> 41#include <net/if_var.h> 42 43#include <stdio.h> 44#include <stdlib.h> 45#include <stdint.h> 46#include <signal.h> 47#include <string.h> 48#include <unistd.h> 49#include <err.h> 50 51#include "ah.h" 52#include "ah_desc.h" 53#include "net80211/ieee80211_ioctl.h" 54#include "net80211/ieee80211_radiotap.h" 55#include "if_athioctl.h" 56#include "if_athrate.h" 57 58#include "ath_rate/sample/sample.h" 59 60/* 61 * This needs to be big enough to fit the two TLVs, the rate table 62 * and the rate statistics table for a single node. 63 */ 64#define STATS_BUF_SIZE 8192 65 66struct ath_ratestats { 67 int s; 68 struct ath_rateioctl re; 69}; 70 71static inline int 72dot11rate(struct ath_rateioctl_rt *rt, int rix) 73{ 74 75 if (rt->ratecode[rix] & IEEE80211_RATE_MCS) 76 return rt->ratecode[rix] & ~(IEEE80211_RATE_MCS); 77 else 78 return (rt->ratecode[rix] / 2); 79} 80 81static const char * 82dot11str(struct ath_rateioctl_rt *rt, int rix) 83{ 84 if (rix == -1) 85 return ""; 86 else if (rt->ratecode[rix] & IEEE80211_RATE_MCS) 87 return "MCS"; 88 else 89 return " Mb"; 90} 91 92static void 93ath_sample_stats(struct ath_ratestats *r, struct ath_rateioctl_rt *rt, 94 struct sample_node *sn) 95{ 96 uint32_t mask; 97 int rix, y; 98 99 printf("static_rix (%d) ratemask 0x%x\n", 100 sn->static_rix, 101 sn->ratemask); 102 103 for (y = 0; y < NUM_PACKET_SIZE_BINS; y++) { 104 printf("[%4u] cur rate %d %s since switch: " 105 "packets %d ticks %u\n", 106 bin_to_size(y), 107 dot11rate(rt, sn->current_rix[y]), 108 dot11str(rt, sn->current_rix[y]), 109 sn->packets_since_switch[y], 110 sn->ticks_since_switch[y]); 111 112 printf("[%4u] last sample (%d %s) cur sample (%d %s) " 113 "packets sent %d\n", 114 bin_to_size(y), 115 dot11rate(rt, sn->last_sample_rix[y]), 116 dot11str(rt, sn->last_sample_rix[y]), 117 dot11rate(rt, sn->current_sample_rix[y]), 118 dot11str(rt, sn->current_sample_rix[y]), 119 sn->packets_sent[y]); 120 121 printf("[%4u] packets since sample %d sample tt %u\n", 122 bin_to_size(y), 123 sn->packets_since_sample[y], 124 sn->sample_tt[y]); 125 } 126 printf(" TX Rate TXTOTAL:TXOK EWMA T/ F" 127 " avg last xmit\n"); 128 for (mask = sn->ratemask, rix = 0; mask != 0; mask >>= 1, rix++) { 129 if ((mask & 1) == 0) 130 continue; 131 for (y = 0; y < NUM_PACKET_SIZE_BINS; y++) { 132 if (sn->stats[y][rix].total_packets == 0) 133 continue; 134 printf("[%2u %s:%4u] %8ju:%-8ju " 135 "(%3d.%1d%%) %8ju/%4d %5ums %u\n", 136 dot11rate(rt, rix), 137 dot11str(rt, rix), 138 bin_to_size(y), 139 (uintmax_t) sn->stats[y][rix].total_packets, 140 (uintmax_t) sn->stats[y][rix].packets_acked, 141 sn->stats[y][rix].ewma_pct / 10, 142 sn->stats[y][rix].ewma_pct % 10, 143 (uintmax_t) sn->stats[y][rix].tries, 144 sn->stats[y][rix].successive_failures, 145 sn->stats[y][rix].average_tx_time, 146 sn->stats[y][rix].last_tx); 147 } 148 } 149} 150 151static void 152ath_setifname(struct ath_ratestats *r, const char *ifname) 153{ 154 155 strncpy(r->re.if_name, ifname, sizeof (r->re.if_name)); 156} 157 158static void 159ath_setsta(struct ath_ratestats *r, const char *mac) 160{ 161 162 memcpy(&r->re.is_u.macaddr, mac, sizeof(r->re.is_u.macaddr)); 163} 164 165static void 166ath_rate_ioctl(struct ath_ratestats *r) 167{ 168 169 if (ioctl(r->s, SIOCGATHNODERATESTATS, &r->re) < 0) 170 err(1, "ioctl"); 171} 172 173static int 174rate_node_stats(struct ath_ratestats *r, struct ether_addr *e) 175{ 176 struct ath_rateioctl_tlv *av; 177 struct sample_node *sn = NULL; 178 struct ath_rateioctl_rt *rt = NULL; 179 int error = 0; 180 uint8_t *buf = r->re.buf; 181 182 /* 183 * For now, hard-code the TLV order and contents. Ew! 184 */ 185 av = (struct ath_rateioctl_tlv *) buf; 186 if (av->tlv_id != ATH_RATE_TLV_RATETABLE) { 187 fprintf(stderr, "unexpected rate control TLV (got 0x%x, " 188 "expected 0x%x\n", 189 av->tlv_id, 190 ATH_RATE_TLV_RATETABLE); 191 exit(127); 192 } 193 if (av->tlv_len != sizeof(struct ath_rateioctl_rt)) { 194 fprintf(stderr, "unexpected TLV len (got %d bytes, " 195 "expected %d bytes\n", 196 av->tlv_len, 197 sizeof(struct ath_rateioctl_rt)); 198 exit(127); 199 } 200 rt = (void *) (buf + sizeof(struct ath_rateioctl_tlv)); 201 202 /* Next */ 203 av = (void *) (buf + sizeof(struct ath_rateioctl_tlv) + 204 sizeof(struct ath_rateioctl_rt)); 205 if (av->tlv_id != ATH_RATE_TLV_SAMPLENODE) { 206 fprintf(stderr, "unexpected rate control TLV (got 0x%x, " 207 "expected 0x%x\n", 208 av->tlv_id, 209 ATH_RATE_TLV_SAMPLENODE); 210 exit(127); 211 } 212 if (av->tlv_len != sizeof(struct sample_node)) { 213 fprintf(stderr, "unexpected TLV len (got %d bytes, " 214 "expected %d bytes\n", 215 av->tlv_len, 216 sizeof(struct sample_node)); 217 exit(127); 218 } 219 sn = (void *) (buf + sizeof(struct ath_rateioctl_tlv) + 220 sizeof(struct ath_rateioctl_rt) + 221 sizeof(struct ath_rateioctl_tlv)); 222 223 ath_sample_stats(r, rt, sn); 224} 225 226 227int 228main(int argc, char *argv[]) 229{ 230 char const *ifname = NULL, *macaddr = NULL; 231 int c; 232 int do_all = 0; 233 struct ether_addr *e; 234 struct ath_ratestats r; 235 uint8_t *buf; 236 237 ifname = getenv("ATH"); 238 if (ifname == NULL) 239 ifname = "ath0"; 240 241 while ((c = getopt(argc, argv, "ahi:m:")) != -1) { 242 switch (c) { 243 case 'a': 244 do_all = 1; 245 break; 246 case 'i': 247 ifname = optarg; 248 break; 249 case 'm': 250 macaddr = optarg; 251 break; 252 253 default: 254 errx(1, 255 "usage: %s [-h] [-i ifname] [-a] [-m macaddr]\n", 256 argv[0]); 257 /* NOTREACHED */ 258 } 259 } 260 261 if (macaddr == NULL) { 262 errx(1, "%s: macaddress wasn't supplied and no -a given\n", 263 argv[0]); 264 /* NOTREACHED */ 265 } 266 e = ether_aton(macaddr); 267 if (e == NULL) 268 err(1, "ether_aton"); 269 270 bzero(&r, sizeof(r)); 271 272 /* 273 * Persistent buffer for each lookup 274 */ 275 buf = malloc(STATS_BUF_SIZE); 276 if (buf == NULL) 277 err(1, "calloc"); 278 279 r.re.buf = buf; 280 r.re.len = STATS_BUF_SIZE; 281 282 r.s = socket(AF_INET, SOCK_DGRAM, 0); 283 if (r.s < 0) { 284 err(1, "socket"); 285 } 286 /* XXX error check */ 287 ath_setifname(&r, ifname); 288 289 /* Zero the buffer before it's passed in */ 290 memset(buf, '\0', STATS_BUF_SIZE); 291 292 /* 293 * Set the station address for this lookup. 294 */ 295 ath_setsta(&r, e->octet); 296 297 /* 298 * Fetch the data from the driver. 299 */ 300 ath_rate_ioctl(&r); 301 302 /* 303 * Decode and parse statistics. 304 */ 305 rate_node_stats(&r, e); 306} 307