📄 airoinfo.cc
字号:
/* * airoinfo.{cc,hh} -- Access Aironet statistics * Douglas S. J. De Couto * * Copyright (c) 2001 Massachusetts Institute of Technology * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, subject to the conditions * listed in the Click LICENSE file. These conditions include: you must * preserve this copyright notice, and you cannot mention the copyright * holders in advertising related to the Software without their permission. * The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This * notice is a summary of the Click LICENSE file; the license in that file is * legally binding. */#include <click/config.h>#include <stddef.h>#include "airoinfo.hh"#include <click/confparse.hh>#include <click/error.hh>#include <click/router.hh>#include <clicknet/ether.h>#include <click/glue.hh>#include <click/etheraddress.hh>#include "grid.hh"#include <math.h>#include <sys/ioctl.h>#include <unistd.h>#define ANLLFAIL#define ANCACHE#ifdef __OpenBSD__#define FUCKED#ifdef FUCKED#include "/usr/src/sys/dev/ic/anvar.h"#else#include <dev/ic/anvar.h>#endif#endif#ifdef __linux__#include <linux/wireless.h>#ifdef IW_MAX_SPY#undef IW_MAX_SPY#define IW_MAX_SPY 40 /* more fuckation -- this constant must be the same across all the drivers as well */#endif/* bullshit problem: dealing with different headers between the application cross-compile environment and the kernel cross-compile environment */#endifCLICK_DECLSAiroInfo::AiroInfo() : Element(0, 0), _fd(-1){}AiroInfo::~AiroInfo(){ if (_fd > -1) close(_fd);}intAiroInfo::configure(Vector<String> &conf, ErrorHandler *errh){ int res = cp_va_parse(conf, this, errh, cpString, "device name", &_ifname, cpEnd); return res;}intAiroInfo::initialize(ErrorHandler *errh){ memset(&_ifr, 0, sizeof(_ifr)); strncpy(_ifr.ifr_name, _ifname.cc(), sizeof(_ifr.ifr_name)); _ifr.ifr_name[sizeof(_ifr.ifr_name) - 1] = 0;#ifdef __linux__ memset(&_ifr2, 0, sizeof(_ifr2)); strncpy(_ifr2.ifr_name, _ifname.cc(), sizeof(_ifr2.ifr_name)); _ifr2.ifr_name[sizeof(_ifr2.ifr_name) - 1] = 0;#endif _fd = socket(AF_INET, SOCK_DGRAM, 0); if (_fd < 0) return errh->error("Unable to open socket to %s device", _ifr.ifr_name); return 0;}#ifdef __OpenBSD__boolAiroInfo::get_signal_info(const EtherAddress &e, int &dbm, int &quality){ struct an_req areq; memset(&areq, 0, sizeof(areq)); areq.an_len = AN_MAX_DATALEN; areq.an_type = AN_RID_READ_CACHE; /* due to AN_MAX_DATALEN = 512 16-bit vals, we could only ever get ~56 entries from the card's cache. however, since the current driver mod has only 30 entries, that's cool... but this could be a problem in big (e.g. > 30 nodes) networks... */ _ifr.ifr_data = (char *) &areq; int res = ioctl(_fd, SIOCGAIRONET, &_ifr); if (res == -1) { click_chatter("AiroInfo: ioctl(SIOCGAIRONET) error when reading signal cache: %s\n", strerror(errno)); return false; } int *num_entries = (int *) &areq.an_val; char *p = (char *) &areq.an_val; p += sizeof(int); struct an_sigcache *entries = (struct an_sigcache *) p; for (int i = 0; i < *num_entries; i++) { if (e == EtherAddress((unsigned char *) entries[i].macsrc)) { dbm = entries[i].signal; quality = entries[i].quality; return true; } } return false;}boolAiroInfo::get_tx_stats(const EtherAddress &e, int &num_successful, int &num_failed){ struct an_req areq; memset(&areq, 0, sizeof(areq)); areq.an_len = AN_MAX_DATALEN; areq.an_type = AN_RID_READ_LLFAIL; _ifr.ifr_data = (char *) &areq; int res = ioctl(_fd, SIOCGAIRONET, &_ifr); if (res == -1) { click_chatter("AiroInfo: ioctl(SIOCGAIRONET) error when reading tx stats cache: %s\n", strerror(errno)); return false; } int *num_entries = (int *) &areq.an_val; char *p = (char *) &areq.an_val; p += sizeof(int); struct an_llfailcache *entries = (struct an_llfailcache *) p; for (int i = 0; i < *num_entries; i++) { if (e == EtherAddress((unsigned char *) entries[i].macdst)) { num_failed = entries[i].num_fail; num_successful = entries[i].num_succeed; return true; } } return false;}boolAiroInfo::get_noise(int &max_over_sec, int &avg_over_minute, int &max_over_minute){ struct an_req areq; memset(&areq, 0, sizeof(areq)); areq.an_len = AN_MAX_DATALEN; areq.an_type = AN_RID_STATUS; _ifr.ifr_data = (char *) &areq; int res = ioctl(_fd, SIOCGAIRONET, &_ifr); if (res == -1) { click_chatter("AiroInfo: ioctl(SIOCGAIRONET) error when reading noise from status struct: %s\n", strerror(errno)); return false; } // noise info from Marco Molteni (molter@tin.it) // u_int8_t an_noise_prev_sec_pc; /* 0x7A */ // u_int8_t an_noise_prev_sec_db; /* 0x7B */ // u_int8_t an_avg_noise_prev_min_pc; /* 0x7C */ // u_int8_t an_avg_noise_prev_min_db; /* 0x7D */ // u_int8_t an_max_noise_prev_min_pc; /* 0x7E */ // u_int8_t an_max_noise_prev_min_db; /* 0x7F */ u_int8_t *base = (u_int8_t *) _ifr.ifr_data; u_int8_t *u8 = base + 0x7B; max_over_sec = *u8; u8 = base + 0x7D; avg_over_minute = *u8; u8 = base + 0x7F; max_over_minute = *u8; return true;}#endif // __OpenBSD__#ifdef __linux__boolAiroInfo::get_signal_info(const EtherAddress &e, int &dbm, int &quality){ char buf[(sizeof(struct iw_quality) + sizeof(struct sockaddr)) * IW_MAX_SPY]; _ifr.u.data.pointer = buf; _ifr.u.data.length = 0; _ifr.u.data.flags = 0; int res = ioctl(_fd, SIOCGIWSPY, &_ifr); if (res == -1) { click_chatter("AiroInfo: ioctl(SIOCGIWSPY) error when reading signal info: %s\n", strerror(errno)); return false; } int n = _ifr.u.data.length; for (int i = 0; i < n; i++) { struct sockaddr *sa = (struct sockaddr *) (buf + i * sizeof(struct sockaddr)); if (e == EtherAddress((unsigned char *) &sa->sa_data)) { struct iw_quality *q = (struct iw_quality *) (buf + n*sizeof(struct sockaddr) + i*sizeof(struct iw_quality)); dbm = ((int) q->level) - 256; quality = q->qual; return true; } } return false;}boolAiroInfo::get_tx_stats(const EtherAddress &, int &, int &){ return false;}#define AIROIOCTL SIOCDEVPRIVATE#define AIROGSTAT 8struct aironet_ioctl_t { unsigned short command; // What to do unsigned short len; // Len of data unsigned char *data; // d-data};boolAiroInfo::get_noise(int &max_over_sec, int &avg_over_minute, int &max_over_minute){ u_int8_t buf[0x80]; memset(buf, 69, sizeof(buf)); aironet_ioctl_t airo_cmd; airo_cmd.command = AIROGSTAT; airo_cmd.data = buf; airo_cmd.len = sizeof(buf); _ifr2.ifr_data = (char *) &airo_cmd; int res = ioctl(_fd, AIROIOCTL, &_ifr2); if (res == -1) { click_chatter("AiroInfo: ioctl(AIROIOCTL) error when reading noise info: %s\n", strerror(errno)); return false; } max_over_sec = -buf[0x7B]; avg_over_minute = -buf[0x7D]; max_over_minute = -buf[0x7F]; return true;}#endif // __linux__#if !defined(__linux__) && !defined(__OpenBSD__)boolAiroInfo::get_signal_info(const EtherAddress &, int &, int &){ return false;}boolAiroInfo::get_tx_stats(const EtherAddress &, int &, int &){ return false;}boolAiroInfo::get_noise(int &, int &, int &){ return false;}#endif /* !__linux__ && !__OpenBSD__ */voidAiroInfo::clear_tx_stats(){#ifdef __OpenBSD__ struct an_req areq; memset(&areq, 0, sizeof(areq)); areq.an_len = 0; areq.an_type = AN_RID_ZERO_LLFAIL; _ifr.ifr_data = (char *) &areq; int res = ioctl(_fd, SIOCGAIRONET, &_ifr); if (res == -1) { click_chatter("AiroInfo: ioctl(SIOCGAIRONET) error when resetting tx stats cache: %s\n", strerror(errno)); }#endif}CLICK_ENDDECLSELEMENT_REQUIRES(userlevel)EXPORT_ELEMENT(AiroInfo)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -