Page MenuHomec4science

measurementswifi.cc
No OneTemporary

File Metadata

Created
Sat, Jul 5, 08:00

measurementswifi.cc

#include <click/config.h>
#include "measurementswifi.hh"
#ifdef CLICK_LINUXMODULE
#include <click/cxxprotect.h>
CLICK_CXX_PROTECT
#include <linux/netdevice.h>
#include <net/mac80211.h>
//#include <mac80211/ieee80211_i.h>
#include <net/cfg80211.h>
CLICK_CXX_UNPROTECT
#include <click/cxxunprotect.h>
#endif
#define DEBUG_CHATTER(arg, ...) do { if (_debug) { click_chatter(arg, ## __VA_ARGS__);} } while (0)
#define VERB_DEBUG_CHATTER(arg, ...) do { if (_verb_debug) { click_chatter(arg, ## __VA_ARGS__);} } while (0)
CLICK_DECLS
MeasurementsWifi::MeasurementsWifi() : _get_airtime_timer(this), _empty_channel_timer(this)
{
}
MeasurementsWifi::~MeasurementsWifi()
{
}
void *
MeasurementsWifi::cast(const char *name) {
if (strcmp(name, "MeasurementsWifi") == 0)
return (MeasurementsWifi *) this;
else if (strcmp(name, "Measurements") == 0)
return (Measurements *) this;
else
return Measurements::cast(name);
}
int MeasurementsWifi::configure(Vector<String> &conf, ErrorHandler *errh){
nb_all = 0;
nb_data = 0;
nb_acks = 0;
nb_retry = 0;
nb_rts = 0;
nb_cts = 0;
_save_mcs = false;
_count_str_mcs = 0;
_string_mcs = "";
_count_mcs = 0;
_max_count_mcs = 0;
_ifIndex = -1;
_expectedId = -1;
_cb = NULL;
_sk = NULL;
_begin.assign_now();
_debug = false;
_verb_debug = false;
String td_name;
if(Args(this, errh).bind(conf)
.read("ADDR", _addr)
.read("DEBUG", _debug)
.read("VERB_DEBUG", _verb_debug)
.read("SAVE_MCS", _max_count_mcs)
#ifdef CLICK_LINUXMODULE
.read("TODEVICE", td_name)
#endif
.complete() < 0)
return -1;
_save_mcs = (_max_count_mcs > 0);
if(_save_mcs && _addr == EtherAddress())
return errh->error("If saving MCS, should have the local ethernet address");
#ifdef CLICK_LINUXMODULE
_td = 0;
if(td_name != "") {
_td = (ToDevice *)router()->find(td_name, "", errh);
if(_td != 0 && _td->cast("ToDevice") == 0) {
return errh->error("%s exists but is not a ToDevice.", td_name.c_str());
}
}
if(_td==0)
return errh->error("Could not get ToDevice.");
#endif
click_chatter("MeasurementsWifi run with save_mcs=%d", _save_mcs);
set_mcs_to_rate();
_get_airtime_timer.initialize(this);
_empty_channel_timer.initialize(this);
set_backoff_times();
return 0;
}
int
MeasurementsWifi::initialize(ErrorHandler *errh) {
#ifdef CLICK_LINUXMODULE
/*
_ops = 0;
net_device *dev = _td->device();
struct wiphy *wp = 0;
struct ieee80211_hw *hw = 0;
struct ieee80211_local *local = 0;
if(dev!=0)
wp = dev->ieee80211_ptr->wiphy;
if(wp!=0)
hw = wiphy_to_ieee80211_hw(wp);
if(hw!=0)
local = hw_to_local(hw);
if(local!=0)
_ops = local->ops;
if(_ops == 0)
return errh->error("Could not get ieee80211_ops (dev=%p, wiphy=%p, hw=%p, local=%p)",
dev, wp, hw, local);
*/
#endif
return 0;
}
void
MeasurementsWifi::push(int port, Packet *p_in) {
uint8_t type;
uint8_t subtype;
uint8_t dir;
uint8_t retry;
EtherAddress src, dst, bssid;
struct click_wifi *w = (struct click_wifi *)p_in->data();
struct click_wifi_extra *cwe = WIFI_EXTRA_ANNO(p_in); //radiotap header
type = w->i_fc[0] & WIFI_FC0_TYPE_MASK; /* And recover the fields */
subtype = w->i_fc[0] & WIFI_FC0_SUBTYPE_MASK;
dir = w->i_fc[1] & WIFI_FC1_DIR_MASK;
retry = w->i_fc[1] & WIFI_FC1_RETRY; // >0 if this is a retry
//click_ether *eth_hdr = (click_ether *) (p_in->data());
acne_header *acne_hdr = (acne_header *) (p_in->data()+34); // 34 is offset observed (click_wifi is 24)
switch (dir) {
case WIFI_FC1_DIR_NODS:
dst = EtherAddress(w->i_addr1);
src = EtherAddress(w->i_addr2);
bssid = EtherAddress(w->i_addr3);
/* Most likely ARP requests in ad-hoc mode, ignore and skip */
break;
case WIFI_FC1_DIR_TODS:
bssid = EtherAddress(w->i_addr1);
src = EtherAddress(w->i_addr2);
dst = EtherAddress(w->i_addr3);
break;
case WIFI_FC1_DIR_FROMDS:
dst = EtherAddress(w->i_addr1);
bssid = EtherAddress(w->i_addr2);
src = EtherAddress(w->i_addr3);
break;
case WIFI_FC1_DIR_DSTODS:
/* We should never arrive here */
//assert(false);
break;
default:
/* We should never arrive here */
//assert(false);
break;
}
//if (is_good_address(src) || is_good_address(dst)) { // all stations have same first 5 bytes; check one of them
nb_all++;
bool is_good_address_src = is_good_address(src);
bool is_good_address_dst = is_good_address(dst);
if (_debug) {
if (is_good_address_src) {
from_all[src]++;
}
if (is_good_address_dst) {
to_all[dst]++;
}
}
if (type == WIFI_FC0_TYPE_DATA || type == WIFI_FC0_TYPE_CTL) { // only consider data or control packets
if (retry > 0) {
nb_retry++;
if (_debug) {
if (is_good_address_src) {
from_retry[src]++;
}
if (is_good_address_dst) {
to_retry[dst]++;
}
}
}
if (type == WIFI_FC0_TYPE_DATA) {
if (subtype == WIFI_FC0_SUBTYPE_DATA
|| subtype == WIFI_FC0_SUBTYPE_NODATA
|| subtype == WIFI_FC0_SUBTYPE_QOS
|| subtype == WIFI_FC0_SUBTYPE_QOS_NULL) {
// data packet (regular or qos)
uint8_t known_field = cwe->rate1;
uint32_t rateD = 0;
if(known_field & (1 << 1) && known_field & 1 && known_field & (1 << 2)){
uint8_t bandwidth = cwe->rate2 & 3;
uint8_t GI = cwe->rate2 & (1 << 2);
uint8_t mcs_index = cwe->rate3;
if(mcs_index < NR_MCS){ //check that we don't try to fetch too large a MCS
if(bandwidth == 0 && GI == 0){
rateD = _mcs_to_rate_20_LG[mcs_index];
}
if(bandwidth == 0 && GI > 0){
rateD = _mcs_to_rate_20_SG[mcs_index];
}
if(bandwidth == 1 && GI == 0){
rateD = _mcs_to_rate_40_LG[mcs_index];
}
else if(bandwidth == 1 && GI > 0){
rateD = _mcs_to_rate_40_SG[mcs_index];
}
}
}
_count_links_all[WifiLink(src, dst)]++;
// count only when rate > 0 for src or when AMPDU ref number > 0 for others (else, in aggregated frame)
if ((src == _addr && rateD > 0) || (src != _addr && *((uint32_t *) &cwe->max_tries) > 0)) {
nb_data++;
_nb_frames_empty_channel++;
if (is_good_address_src) {
if (_printed_sta[src] == 0) {
DEBUG_CHATTER("[MeasurementsWifi %s] Received packet of length %d from %s (route %s). Sizes: click_wifi=%d, acne=%d", Timestamp::now().unparse().c_str(),
p_in->length(), src.unparse().c_str(), acne_hdr->_route.unparse().c_str(), sizeof(click_wifi), sizeof(acne_header));
_printed_sta.set(src,1);
}
from_data[src]++;
_count_links[WifiLink(src, dst)]++;
}
else
DEBUG_CHATTER("[MeasurementsWifi] Wrong address %s", src.unparse().c_str());
if (_debug) {
if (is_good_address_dst) {
to_data[dst]++;
}
}
if( _save_mcs && src == _addr && !(dst.is_broadcast() || dst.is_group())) {
_count_mcs++;
if(_count_mcs >= _max_count_mcs) {
_count_mcs = 0;
_now.assign_now();
String str = "MCS "+(_now-_begin).unparse()+" "+print_last_byte(src)+" "+print_last_byte(dst)+" "+String(rateD)+" retry "+String((int)retry)+" \n";
_string_mcs += str;
_count_str_mcs++;
if(_count_str_mcs >= 50) {
click_chatter(_string_mcs.c_str());
_count_str_mcs = 0;
_string_mcs = "";
}
}
}
}
}
}
else if (type == WIFI_FC0_TYPE_CTL) {
if (subtype == WIFI_FC0_SUBTYPE_ACK) {
nb_acks++;
if (_debug) {
if (is_good_address_src) {
from_acks[src]++;
}
if (is_good_address_dst) {
to_acks[dst]++;
}
}
}
else if (subtype == WIFI_FC0_SUBTYPE_RTS) {
nb_rts++;
if (_debug) {
if (is_good_address_src) {
from_rts[src]++;
}
if (is_good_address_dst) {
to_rts[dst]++;
}
}
}
else if (subtype == WIFI_FC0_SUBTYPE_CTS) {
nb_cts++;
if (_debug) {
if (is_good_address_src) {
from_cts[src]++;
}
if (is_good_address_dst) {
to_cts[dst]++;
}
}
}
}
//}
}
if (noutputs()==1)
output(0).push(p_in);
else
p_in->kill();
}
void MeasurementsWifi::run_timer(Timer *timer){
VERB_DEBUG_CHATTER("[MeasurementsWifi %s] Run timer %p", Timestamp::now().unparse().c_str(), timer);
if (timer==&_get_airtime_timer) {
compute_airtime(0);
}
if (timer==&_empty_channel_timer) {
_now.assign_now();
if(_nb_frames_empty_channel == 0) {
DEBUG_CHATTER("[MeasurementsWifi %s] Channel empty during last %d ms", _now.unparse().c_str(), _freq_empty_channel);
_src_to_notify->notification_empty_channel_wifi();
}
else {
DEBUG_CHATTER("[MeasurementsWifi %s] Received %d packets in %d ms", _now.unparse().c_str(), _nb_frames_empty_channel, _freq_empty_channel);
}
_nb_frames_empty_channel = 0;
if(_freq_empty_channel>0)
_empty_channel_timer.schedule_after_msec(_freq_empty_channel);
}
}
gamma_type
MeasurementsWifi::get_airtime(int token) {
return _airtime[token];
}
gamma_type
MeasurementsWifi::get_busytime_us(int token) {
return _busy[token];
}
void
MeasurementsWifi::init_airtime(int interval, int token) {
//_airtime = -1;
//_busy = -1;
if(interval > 0) //interval > 0 not compatible with several tokens
token = 0;
_now.assign_now();
_error_survey = "";
_now.assign_now();
// check that tokens have not timeouted (2 seconds)
Vector<int> token_timeout;
for(HashTable<int,Timestamp>::iterator it=_active_tokens.begin();it.live();it++) {
if((_now-it.value()).sec() >= 2) {
DEBUG_CHATTER("[MeasurementsWifi %s] Token %d has expired", _now.unparse().c_str(), it.key());
token_timeout.push_back(it.key());
}
}
for(int i=0;i<token_timeout.size();i++)
clear_counters(token_timeout[i]);
if(_active_tokens.size() == 0)
reinitialize_counters();
reinitialize_counters(token);
//_iw_survey_begin = exec("iw dev wlan0 survey dump|grep \"in use\" -A 5");
#ifdef __linux
netlink_main();
#endif
if (interval > 0) // if interval == 0, compute_airtime() must be triggered
_get_airtime_timer.schedule_after_msec(interval);
_active_tokens.set(token,_now);
_active_begin.set(token, _active_loc);
_busy_begin.set(token, _busy_loc);
DEBUG_CHATTER("[MeasurementsWifi %s] Initialization of airtime for token %d (%d tokens active): new active %lld, new busy %lld. Timer will fire in %d ms...",
_active_tokens[token].unparse().c_str(), token, _active_tokens.size(), _active_loc, _busy_loc, interval);
}
void
MeasurementsWifi::compute_airtime(int token) {
Timestamp begin_ts;
begin_ts.assign_now();
#ifdef __linux__
netlink_main();
#endif
Timestamp time_after_nl = Timestamp::now();
DEBUG_CHATTER("Time for netlink is %s", (time_after_nl-begin_ts).unparse().c_str());
_active_end.set(token, _active_loc);
_busy_end.set(token, _busy_loc);
// String iw_survey_end = exec("iw dev wlan0 survey dump|grep \"in use\" -A 5");
// uint64_t active_begin;
// uint64_t busy_begin;
// uint64_t active_end;
// uint64_t busy_end;
// if(!parse_airtime_string(_iw_survey_begin, active_begin, busy_begin, _error_survey)) {
// _airtime = -1;
// _busy = -1;
// return;
// }
// if(!parse_airtime_string(iw_survey_end, active_end, busy_end, _error_survey)) {
// _airtime = -1;
// _busy = -1;
// return;
// }
gamma_type busy = (gamma_type) _busy_end[token] - (gamma_type) _busy_begin[token];
// add Inter-Frame Spaces
// IFS for data packets
busy += int_divide((nb_data - nb_data_init[token])*16,1000); //SIFS of 16 us
busy += int_divide((nb_data - nb_data_init[token])*34,1000); //DIFS of 34 us
// IFS for RTS/CTS
busy += int_divide(2*(nb_cts - nb_cts_init[token])*16,1000); // RTS CTS
busy += int_divide(mymax(0,(int) ((nb_rts - nb_rts_init[token])-(nb_cts - nb_cts_init[token])))*34,1000); // RTS w/o CTS
// if retry, add DIFS (retry indicates at least one unsuccessful transmission, we add for exactly one)
busy += int_divide((nb_retry - nb_retry_init[token])*34,1000);
// add an estimation of backoff: - first suppose unsaturated traffic (avg backoff is (CW-1)/2 = 7.5)
// - if above threshold, use Bianchi's model for avg backoff when saturated
gamma_type backoff_coeff;
//gamma_type backoff_time;
//backoff_time = int_divide((nb_data - nb_data_init[token])*array_backoff_times_bianchi_wifi[0]*9,100*1000); // slot time of 9us; divided by 100 for backoff scaling
//backoff_time = 0;
/*
if (((GAMMA_SCALE*(busy+backoff_time)) / (active_end - active_begin)) < SATURATED_THRES) {
busy += backoff_time;
_now.assign_now();
String str = "[MeasurementsWifi "+_now.unparse()+"] Compute airtime (done in "+(_now-begin_ts).unparse()+"s) with unsaturated conditions, "+String(nb_data)+" packets: busy "+String(busy)+
" ms (backoff "+String(backoff_time)+"ms), active "+String(active_end - active_begin)+" ms";
DEBUG_CHATTER(str.c_str());
}
else { // saturated traffic
*/
int nb_STAs = -1;
_now.assign_now();
Timestamp interval = (_now - _active_tokens[token]);
for (HashTable<EtherAddress, uint64_t>::iterator it=from_data.begin();it != from_data.end();++it) {
if(it.value() > int_divide(MIN_NB_PACKET_PERSEC*interval.msecval(),1000)) {
//DEBUG_CHATTER("[MeasurementsWifi %s] Station %s contending (%s packets received)",
// _now.unparse().c_str(), it.key().unparse().c_str(), String(it.value()).c_str());
nb_STAs++;
}
//else
// DEBUG_CHATTER("[MeasurementsWifi %s] For packets from %s, only %s packets",
// _now.unparse().c_str(), it.key().unparse().c_str(), String(it.value()).c_str());
}
if (nb_STAs >= MAX_NB_NGHBRS_BIANCHI)
nb_STAs = MAX_NB_NGHBRS_BIANCHI-1;
backoff_coeff = array_backoff_times_bianchi_wifi[nb_STAs];
#ifdef CLICK_USERLEVEL
busy += ((nb_data - nb_data_init[token])*backoff_coeff*9)/(100*1000);
#else
busy += int_divide((nb_data - nb_data_init[token])*backoff_coeff*9,100u*1000u); // slot time of 9us; divided by 100 for backoff scaling
#endif
//}
int active = (int) _active_end[token] - (int) _active_begin[token]; // in ms
if(active > MIN_AIRTIME_COMPUTATION_TIME_MS) { // do not consider measurements too short
_busy[token] = (gamma_type) GAMMA_SCALE*busy*1000; // busy in ms, _busy in us
#ifdef CLICK_USERLEVEL
_airtime[token] = mymin((gamma_type) GAMMA_SCALE,(gamma_type) (GAMMA_SCALE*busy)/active);
#else
_airtime[token] = mymin((gamma_type) GAMMA_SCALE,(gamma_type) int_divide(GAMMA_SCALE*busy, active));
#endif
}
String link_stats;
if(_debug) {
link_stats+="\n\t\tLinks used ";
for (HashTable<WifiLink, int>::iterator it=_count_links.begin();it != _count_links.end();++it) {
int value = it.value() - _count_links_init[token][it.key()];
int value_all = _count_links_all[it.key()] - _count_links_all_init[token][it.key()];
if(value > 0)
link_stats+=(it.key()._src.unparse()+"->"+it.key()._dst.unparse()+":"+String(value)+" ("+String(value_all)+"); ");
}
StringAccum packets_str;
packets_str << String((nb_data - nb_data_init[token])) << " packets (" << String((nb_rts - nb_rts_init[token])) << " RTS, ";
packets_str << String((nb_cts - nb_cts_init[token])) << " CTS, " << String((nb_retry - nb_retry_init[token])) << " retries)";
String str = "Airtime for token "+String(token)+" is "+String(_airtime[token])+" (done in "+(_now-begin_ts).unparse()+"s, "+String(_active_tokens.size()-1)+
" tokens still active) with "+String(nb_STAs+1)+" stations contending, backoff is "+String(backoff_coeff)+"), "
+packets_str.take_string()+": busy "+String(busy)+" ms ("+String(_busy_end[token] - _busy_begin[token])+" from iw), active "+String(active)+" ms.";
click_chatter("[MeasurementsWifi %s] %s%s", _now.unparse().c_str(), str.c_str(), link_stats.c_str());
}
clear_counters(token);
}
bool
MeasurementsWifi::parse_airtime_string(String survey, uint64_t &active, uint64_t &busy, String &error) {
// keep only information concerning channel in use
int ind_in_use = survey.find_left("in use");
survey = survey.substring(ind_in_use);
int ind_MHz = survey.find_left("MHz");
survey = survey.substring(0,ind_MHz);
// we have information for the good channel: parse times (order: active, busy, receive, transmit)
bool ret_glob = true;
error = "";
for(int i=0;i<2;i++) {
int ind_ms = survey.find_left(" ms");
String sub_survey = survey.substring(0, ind_ms);
sub_survey = sub_survey.substring(sub_survey.find_right('\t')+1); // sub_survey contains the time as a string
int ret;
String val_str;
switch(i) {
case 0:
ret = cp_integer(sub_survey, &active);
val_str = "active";
break;
case 1:
ret = cp_integer(sub_survey, &busy);
val_str = "busy";
break;
}
survey = survey.substring(ind_ms+3);
if (!ret) {
ret_glob = false;
error = val_str+" (arg "+sub_survey+")";
break;
}
}
return ret_glob;
}
void
MeasurementsWifi::set_active_busy(uint64_t active, uint64_t busy) {
// if(_active_begin == -1) { // call on init_airtime
// _active_begin = (int64_t) active;
// _busy_begin = (int64_t) busy;
// }
// else { // call on compute airtime
// _active_end = (int64_t) active;
// _busy_end = (int64_t) busy;
// }
_active_loc = (int64_t) active;
_busy_loc = (int64_t) busy;
}
#ifdef CLICK_USERLEVEL
#ifdef __linux__
// Netlink functions
static int error_handler(struct sockaddr_nl *, struct nlmsgerr *err, void *arg)
{
int *ret = (int *) arg;
*ret = err->error;
return NL_SKIP;
}
static int finish_handler(struct nl_msg *, void *arg)
{
int *ret = (int *) arg;
*ret = 0;
return NL_SKIP;
}
static int ack_handler(struct nl_msg *, void *arg)
{
int *err = (int *) arg;
*err = 0;
return NL_STOP;
}
static int print_survey_handler(struct nl_msg *msg, void *arg)
{
MeasurementsWifi *meas = (MeasurementsWifi *) arg;
struct nlattr *tb[NL80211_ATTR_MAX + 1];
struct genlmsghdr *gnlh = (genlmsghdr *) nlmsg_data(nlmsg_hdr(msg));
struct nlattr *sinfo[NL80211_SURVEY_INFO_MAX + 1];
char dev[20];
static struct nla_policy survey_policy[NL80211_SURVEY_INFO_MAX + 1];
survey_policy[NL80211_SURVEY_INFO_FREQUENCY].type = NLA_U32;
survey_policy[NL80211_SURVEY_INFO_NOISE].type = NLA_U8;
nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
genlmsg_attrlen(gnlh, 0), NULL);
if (!tb[NL80211_ATTR_SURVEY_INFO]) {
click_chatter("WARNING: survey data missing!");
return NL_SKIP;
}
if (nla_parse_nested(sinfo, NL80211_SURVEY_INFO_MAX,
tb[NL80211_ATTR_SURVEY_INFO],
survey_policy)) {
click_chatter("WARNING: failed to parse nested attributes!");
return NL_SKIP;
}
if(sinfo[NL80211_SURVEY_INFO_IN_USE]) {
if_indextoname(nla_get_u32(tb[NL80211_ATTR_IFINDEX]), dev);
uint64_t active = (uint64_t) nla_get_u64(sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME]);
uint64_t busy = (uint64_t) nla_get_u64(sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME_BUSY]);
if(meas->get_debug())
click_chatter("[MeasurementsWifi:%s] Survey data from %s, active=%llu, busy=%llu", Timestamp::now().unparse().c_str(), dev, active, busy);
meas->set_active_busy(active, busy);
}
return NL_SKIP;
}
struct nl_msg* MeasurementsWifi::nl80211_cmd_common(uint8_t cmd, int expectedId)
{
//const char* ssid = "amitssid";
struct nl_msg *msg;
int flags = 0;
//struct nl_msg *ssids;
//struct nl_msg *freqs;
msg = nlmsg_alloc();
if (!msg)
return NULL;
// setup the message
if(NULL==genlmsg_put(msg, 0, 0, expectedId, 0, flags, cmd, 0))
{
click_chatter("WARNING: Error return genlMsg_put");
}
if(_ifIndex == -1)
_ifIndex = if_nametoindex("wlan0");
if(nla_put_u32(msg, NL80211_ATTR_IFINDEX, _ifIndex) < 0)
{
goto fail;
}
return msg;
nla_put_failure:
click_chatter("WARNING: nla_put_failure");
nlmsg_free(msg);
return NULL;
fail:
nlmsg_free(msg);
return NULL;
}
int MeasurementsWifi::netlink_main()
{
struct nl_msg *msg= NULL;
int err = -ENOMEM;
int returnvalue,getret;
int callbackret=-1;
if(_sk == NULL) {
_sk = nl_socket_alloc();
if(_sk == NULL)
{
click_chatter("WARNING: memory error");
return -1;
}
if(genl_connect(_sk))
{
click_chatter("WARNING: Connected failed");
return -1;
}
}
if(_cb == NULL) {
_cb = nl_cb_alloc(NL_CB_CUSTOM);
if(_cb == NULL) {
click_chatter("WARNING: failed to allocate netlink callback");
return -1;
}
}
if(_expectedId < 0) {
//find the nl80211 driverID
_expectedId = genl_ctrl_resolve(_sk, "nl80211");
if(_expectedId < 0)
{
click_chatter("WARNING: negative error code returned");
return -1;
}
}
msg = nl80211_cmd_common(NL80211_CMD_GET_SURVEY, _expectedId);
if (!msg)
{
click_chatter("WARNING: error in cmd_common");
return -1;
}
err = nl_send_auto_complete(_sk, msg);
if (err < 0)
goto out;
err = 1;
nl_cb_err(_cb,NL_CB_CUSTOM,error_handler,&err);
nl_cb_set(_cb,NL_CB_FINISH,NL_CB_CUSTOM,finish_handler,&err);
nl_cb_set(_cb,NL_CB_ACK,NL_CB_CUSTOM,ack_handler,&err);
callbackret = nl_cb_set(_cb,NL_CB_VALID,NL_CB_CUSTOM,print_survey_handler,(void *) this);
if(callbackret < 0)
{
if(_debug)
click_chatter("WARNING: CallbackRet failed: %d",callbackret);
}
returnvalue=nl_recvmsgs(_sk,_cb);
nlmsg_free(msg);
msg = NULL;
msg = nlmsg_alloc();
if (!msg)
return -1;
if(NULL==genlmsg_put(msg, 0, 0, _expectedId, 0, NLM_F_DUMP, NL80211_CMD_GET_SURVEY, 0))
{
if(_debug)
click_chatter("WARNING: Error return genlMsg_put");
}
if(_ifIndex == -1)
_ifIndex = if_nametoindex("wlan0");
nla_put_u32(msg,NL80211_ATTR_IFINDEX,_ifIndex);
err = nl_send_auto_complete(_sk,msg);
if(err < 0) goto out;
err = 1;
getret= nl_recvmsgs(_sk,_cb);
out:
nlmsg_free(msg);
return err;
nla_put_failure:
click_chatter("WARNING: nla_put_failure");
nlmsg_free(msg);
return err;
}
#endif
#endif
void
MeasurementsWifi::reinitialize_counters() {
nb_all = 0;
nb_data = 0;
nb_acks = 0;
nb_retry = 0;
nb_rts = 0;
nb_cts = 0;
nb_all_init.clear();
nb_data_init.clear();
nb_acks_init.clear();
nb_retry_init.clear();
nb_rts_init.clear();
nb_cts_init.clear();
from_all.clear();
from_data.clear();
from_acks.clear();
from_retry.clear();
from_rts.clear();
from_cts.clear();
to_all.clear();
to_data.clear();
to_acks.clear();
to_retry.clear();
to_rts.clear();
to_cts.clear();
_airtime.clear();
_busy.clear();
_active_begin.clear();
_active_end.clear();
_busy_begin.clear();
_busy_end.clear();
_count_links.clear();
_count_links_all.clear();
_count_links_init.clear();
_count_links_all_init.clear();
_printed_sta.clear();
DEBUG_CHATTER("[MeasurementsWifi] Clearing all counters.");
}
void
MeasurementsWifi::reinitialize_counters(int token) {
nb_all_init[token] = nb_all;
nb_data_init[token] = nb_data;
nb_acks_init[token] = nb_acks;
nb_retry_init[token] = nb_retry;
nb_rts_init[token] = nb_rts;
nb_cts_init[token] = nb_cts;
_count_links_init[token] = HashTable<WifiLink, int>(_count_links);
_count_links_all_init[token] = HashTable<WifiLink, int>(_count_links_all);
_airtime.set(token,-1);
_busy.set(token,-1);
_active_begin.set(token,-1);
_active_end.set(token,-1);
_busy_begin.set(token,-1);
_busy_end.set(token,-1);
_printed_sta.clear();
}
void MeasurementsWifi::clear_counters(int token) {
_active_tokens.erase(token);
}
bool
MeasurementsWifi::is_good_address(EtherAddress addr) {
return true;
//return is_wifi_addr(addr);
}
// Handlers
uint64_t
MeasurementsWifi::get_count(int arg) {
if (arg==0)
return nb_all;
else if (arg==1)
return nb_data;
else if (arg==2)
return nb_acks;
else if (arg==3)
return nb_retry;
else if (arg==4)
return nb_rts;
else if (arg==5)
return nb_cts;
}
String
MeasurementsWifi::print_from_to() {
StringAccum str;
if (_debug) {
if (nb_all > 0) {
str << "\nall:\n";
if(from_all.size() > 0) {
for(HashTable<EtherAddress, uint64_t>::iterator it = from_all.begin();it;++it) {
str << "from " << it.key().unparse() << ": " << it.value() << "\n";
}
}
if(to_all.size() > 0) {
for(HashTable<EtherAddress, uint64_t>::iterator it = to_all.begin();it;++it) {
str << "to " << it.key().unparse() << ": " << it.value() << "\n";
}
}
}
if (nb_data > 0) {
str << "\ndata:\n";
if(from_data.size() > 0) {
for(HashTable<EtherAddress, uint64_t>::iterator it = from_data.begin();it;++it) {
str << "from " << it.key().unparse() << ": " << it.value() << "\n";
}
}
if(to_data.size() > 0) {
for(HashTable<EtherAddress, uint64_t>::iterator it = to_data.begin();it;++it) {
str << "to " << it.key().unparse() << ": " << it.value() << "\n";
}
}
}
if (nb_acks > 0) {
str << "\nacks:\n";
if(from_acks.size() > 0) {
for(HashTable<EtherAddress, uint64_t>::iterator it = from_acks.begin();it;++it) {
str << "from " << it.key().unparse() << ": " << it.value() << "\n";
}
}
if(to_acks.size() > 0) {
for(HashTable<EtherAddress, uint64_t>::iterator it = to_acks.begin();it;++it) {
str << "to " << it.key().unparse() << ": " << it.value() << "\n";
}
}
}
if (nb_retry > 0) {
str << "\nretry:\n";
if(from_retry.size() > 0) {
for(HashTable<EtherAddress, uint64_t>::iterator it = from_retry.begin();it;++it) {
str << "from " << it.key().unparse() << ": " << it.value() << "\n";
}
}
if(to_retry.size() > 0) {
for(HashTable<EtherAddress, uint64_t>::iterator it = to_retry.begin();it;++it) {
str << "to " << it.key().unparse() << ": " << it.value() << "\n";
}
}
}
if (nb_rts > 0) {
str << "\nrts:\n";
if(from_rts.size() > 0) {
for(HashTable<EtherAddress, uint64_t>::iterator it = from_rts.begin();it;++it) {
str << "from " << it.key().unparse() << ": " << it.value() << "\n";
}
}
if(to_rts.size() > 0) {
for(HashTable<EtherAddress, uint64_t>::iterator it = to_rts.begin();it;++it) {
str << "to " << it.key().unparse() << ": " << it.value() << "\n";
}
}
}
if (nb_cts > 0) {
str << "\ncts:\n";
if(from_cts.size() > 0) {
for(HashTable<EtherAddress, uint64_t>::iterator it = from_cts.begin();it;++it) {
str << "from " << it.key().unparse() << ": " << it.value() << "\n";
}
}
if(to_cts.size() > 0) {
for(HashTable<EtherAddress, uint64_t>::iterator it = to_cts.begin();it;++it) {
str << "to " << it.key().unparse() << ": " << it.value() << "\n";
}
}
}
}
return str.take_string();
}
String
MeasurementsWifi::get_error() {
StringAccum s;
if(_airtime[0]==-1) {
if (_error_survey=="")
s << "Interval has not elapsed, airtime not ready\n";
else
s << "Error during parsing of " << _error_survey << "\n";
}
return s.take_string();
}
static String
get_handler(Element *e, void *arg) {
MeasurementsWifi *elmt = (MeasurementsWifi *)e;
return String(elmt->get_count((intptr_t)arg));
}
static String
print_handler(Element *e, void *) {
MeasurementsWifi *elmt = (MeasurementsWifi *)e;
StringAccum str;
str << "all=" << elmt->get_count(0) << " data=" << elmt->get_count(1);
str << " acks=" << elmt->get_count(2) << " retry=" << elmt->get_count(3);
str << " rts=" << elmt->get_count(4) << " cts=" << elmt->get_count(5) << " \n";
str << elmt->print_from_to();
return str.take_string();
}
static String
airtime_handler_read(Element *e, void *) {
MeasurementsWifi *elmt = (MeasurementsWifi *)e;
StringAccum str;
gamma_type airtime = elmt->get_airtime(0);
if (airtime == -1)
str << elmt->get_error();
else
str << airtime;
return str.take_string();
}
int
MeasurementsWifi::reset_handler(const String &, Element *e, void *, ErrorHandler *) {
MeasurementsWifi *elmt = (MeasurementsWifi *)e;
elmt->reinitialize_counters();
return 0;
}
int
MeasurementsWifi::debug_handler(const String &s, Element *e, void *,
ErrorHandler *errh) {
MeasurementsWifi *elmt = (MeasurementsWifi *)e;
int debug;
if(!cp_integer(s, &debug))
return errh->error("Debug must be 0 or 1");
if (!(debug == 0 || debug == 1))
return errh->error("Debug must be 0 or 1");
elmt->set_debug(debug==1);
return 0;
}
int
MeasurementsWifi::airtime_handler_write(const String &s, Element *e, void *arg,
ErrorHandler *errh) {
MeasurementsWifi *elmt = (MeasurementsWifi *)e;
if((intptr_t)arg == 0) {
int interval;
if(!cp_integer(s, &interval))
return errh->error("Interval must be an integer (interval in ms)");
elmt->init_airtime(interval, 0);
}
else if ((intptr_t)arg == 1) {
elmt->compute_airtime(0);
}
return 0;
}
void MeasurementsWifi::add_handlers() {
add_read_handler("all", get_handler,0);
add_read_handler("data", get_handler,1);
add_read_handler("acks", get_handler,2);
add_read_handler("retry", get_handler,3);
add_read_handler("rts", get_handler,4);
add_read_handler("cts", get_handler,5);
add_read_handler("print_stats", print_handler,0);
add_read_handler("get_airtime", airtime_handler_read,0);
add_write_handler("reset", reset_handler, 0);
add_write_handler("debug", debug_handler, 0);
add_write_handler("init_airtime", airtime_handler_write, 0);
add_write_handler("compute_airtime", airtime_handler_write, 1);
}
EXPORT_ELEMENT(MeasurementsWifi)
CLICK_ENDDECLS
ELEMENT_MT_SAFE(MeasurementsWifi)
ELEMENT_LIBS((-L/opt/aziala/openWrt_bb_mptcp/openwrt/staging_dir/target-i386_i486_eglibc-2.19/usr/lib/ -lnl-genl-3 -lnl-3))

Event Timeline