diff --git a/configure.in b/configure.in index d29d82edb5..148c5f2e06 100644 --- a/configure.in +++ b/configure.in @@ -790,6 +790,9 @@ if test "x$enable_ip6" = xyes; then EXTRA_DRIVER_OBJS="ip6address.o ip6flowid.o ip6table.o $EXTRA_DRIVER_OBJS" EXTRA_TOOL_OBJS="ip6address.o $EXTRA_TOOL_OBJS" fi +if test "x$enable_wifi" = xyes; then + EXTRA_DRIVER_OBJS="radiotap.o $EXTRA_DRIVER_OBJS" +fi AC_SUBST(EXTRA_DRIVER_OBJS) AC_SUBST(EXTRA_TOOL_OBJS) diff --git a/elements/userlevel/fromdevice.cc b/elements/userlevel/fromdevice.cc index 212fafe257..b11a5ef766 100644 --- a/elements/userlevel/fromdevice.cc +++ b/elements/userlevel/fromdevice.cc @@ -51,6 +51,7 @@ # include # include # include +# include #endif CLICK_DECLS diff --git a/elements/userlevel/rawsocket.cc b/elements/userlevel/rawsocket.cc index 40e9ce25eb..07bc8e8cb7 100644 --- a/elements/userlevel/rawsocket.cc +++ b/elements/userlevel/rawsocket.cc @@ -21,6 +21,7 @@ */ #include +#include #include "rawsocket.hh" #include #include @@ -43,6 +44,15 @@ #include "fakepcap.hh" +#if FROMDEVICE_ALLOW_LINUX +# include +# include +# include +# include +# include +# include +#endif + CLICK_DECLS RawSocket::RawSocket() diff --git a/elements/userlevel/rawsocket.hh b/elements/userlevel/rawsocket.hh index 1ae7cab335..de85647537 100644 --- a/elements/userlevel/rawsocket.hh +++ b/elements/userlevel/rawsocket.hh @@ -5,6 +5,11 @@ #include #include #include + +#ifdef __linux__ +# define FROMDEVICE_ALLOW_LINUX 1 +#endif + CLICK_DECLS /* diff --git a/elements/wifi/athdescdecap.cc b/elements/wifi/athdescdecap.cc index 53275574bc..5a4b9846f7 100644 --- a/elements/wifi/athdescdecap.cc +++ b/elements/wifi/athdescdecap.cc @@ -66,7 +66,7 @@ AthdescDecap::simple_action(Packet *p) eh->power = desc->xmit_power; eh->rssi = desc->ack_sig_strength; eh->rate = ratecode_to_dot11(desc->xmit_rate0); - eh->retries = desc->data_fail_count; + eh->max_tries = desc->data_fail_count; if (desc->excessive_retries) eh->flags |= WIFI_EXTRA_TX_FAIL; } diff --git a/elements/wifi/autoratefallback.cc b/elements/wifi/autoratefallback.cc index c6bb122a38..a462634520 100644 --- a/elements/wifi/autoratefallback.cc +++ b/elements/wifi/autoratefallback.cc @@ -104,7 +104,7 @@ AutoRateFallback::process_feedback(Packet *p_in) if (used_alt_rate || !success) { /* step down 1 or 2 rates */ - int down = eh->retries / 2; + int down = eh->max_tries / 2; if (down > 0) { down--; } @@ -137,7 +137,7 @@ AutoRateFallback::process_feedback(Packet *p_in) } nfo->_wentup = false; - if (eh->retries == 0) { + if (eh->max_tries == 0) { nfo->_successes++; } else { nfo->_successes = 0; diff --git a/elements/wifi/bitrate.cc b/elements/wifi/bitrate.cc index de412445f8..f38f16ff9b 100644 --- a/elements/wifi/bitrate.cc +++ b/elements/wifi/bitrate.cc @@ -2,28 +2,34 @@ #include "bitrate.hh" #include +// MCS data rates (kbps) +static const uint32_t mcs_rate_lookup[16] = +{ +6500, 13000, 19500, 26000, 39000, 52000, 58500, 65000, +13000, 26000, 39000, 52000, 78000, 104000, 117000, 130000 +}; unsigned calc_transmit_time(int rate, int length) { - unsigned t_plcp_header = 96; - if (rate == 2) { - t_plcp_header = 192; - } else if (!is_b_rate(rate)) { - t_plcp_header = 20; - } - return (2 * (t_plcp_header + ((length * 8))))/ rate; + unsigned t_plcp_header = 0; + if (is_b_rate(rate)) { + t_plcp_header = (rate == 2) ? WIFI_PLCP_HEADER_LONG_B : WIFI_PLCP_HEADER_SHORT_B; + } else { + t_plcp_header = WIFI_PLCP_HEADER_A; + } + return (2 * length * 8) / rate + t_plcp_header; } unsigned calc_backoff(int rate, int t) { int t_slot = is_b_rate(rate) ? WIFI_SLOT_B : WIFI_SLOT_A; - int cw = WIFI_CW_MIN; - + int cw = is_b_rate(rate) ? WIFI_CW_MIN_B : WIFI_CW_MIN; + int cw_max = is_b_rate(rate) ? WIFI_CW_MAX_B : WIFI_CW_MAX; /* there is backoff, even for the first packet */ for (int x = 0; x < t; x++) { - cw = WIFI_MIN(WIFI_CW_MAX, (cw + 1) * 2); + cw = WIFI_MIN(cw_max, (cw + 1) * 2); } return t_slot * cw / 2; } @@ -34,22 +40,12 @@ calc_usecs_wifi_packet_tries(int length, int rate, int try0, int tryN) if (!rate || !length || try0 > tryN) { return 99999; } - - /* pg 205 ieee.802.11.pdf */ - unsigned t_slot = 20; - unsigned t_ack = 304; // 192 + 14*8/1 - unsigned t_difs = 50; - unsigned t_sifs = 10; - - - if (!is_b_rate(rate)) { - /* with 802.11g, things are at 6 mbit/s */ - t_slot = 9; - t_sifs = 9; - t_difs = 28; - t_ack = 30; + unsigned t_ack = WIFI_ACK_A; + unsigned t_sifs = WIFI_SIFS_A; + if (is_b_rate(rate)) { + t_ack = WIFI_ACK_B; + t_sifs = WIFI_SIFS_B; } - int tt = 0; for (int x = try0; x <= tryN; x++) { tt += calc_backoff(rate, x) + calc_transmit_time(rate, length) + @@ -64,4 +60,41 @@ calc_usecs_wifi_packet(int length, int rate, int retries) return calc_usecs_wifi_packet_tries(length, rate, 0, retries); } +unsigned +calc_transmit_time_ht(int rate, int length) +{ + return (1000 * length * 8) / mcs_rate_lookup[rate] + WIFI_PLCP_HEADER_N; +} + +unsigned +calc_backoff_ht(int, int t) +{ + int cw = WIFI_CW_MIN; + /* there is backoff, even for the first packet */ + for (int x = 0; x < t; x++) { + cw = WIFI_MIN(WIFI_CW_MAX, (cw + 1) * 2); + } + return WIFI_SLOT_N * cw / 2; +} + +unsigned +calc_usecs_wifi_packet_tries_ht(int length, int rate, int try0, int tryN) +{ + if (rate < 0 || !length || try0 > tryN) { + return 99999; + } + int tt = 0; + for (int x = try0; x <= tryN; x++) { + tt += calc_backoff_ht(rate, x) + calc_transmit_time_ht(rate, length) + + WIFI_SIFS_N + WIFI_ACK_N; + } + return tt; +} + +unsigned +calc_usecs_wifi_packet_ht(int length, int rate, int retries) +{ + return calc_usecs_wifi_packet_tries_ht(length, rate, 0, retries); +} + ELEMENT_PROVIDES(bitrate) diff --git a/elements/wifi/bitrate.hh b/elements/wifi/bitrate.hh index a365442060..b2af541e1f 100644 --- a/elements/wifi/bitrate.hh +++ b/elements/wifi/bitrate.hh @@ -14,4 +14,16 @@ extern unsigned calc_usecs_wifi_packet(int length, extern unsigned calc_transmit_time(int rate, int length); +extern unsigned calc_usecs_wifi_packet_tries_ht(int length, + int rate, + int try0, int tryN); + +extern unsigned calc_backoff_ht(int rate, int t); + +extern unsigned calc_usecs_wifi_packet_ht(int length, + int rate, int retries); + + +extern unsigned calc_transmit_time_ht(int rate, int length); + #endif /* _BITRATE_H_ */ diff --git a/elements/wifi/madwifirate.cc b/elements/wifi/madwifirate.cc index aff33031e2..0ab1f7634b 100644 --- a/elements/wifi/madwifirate.cc +++ b/elements/wifi/madwifirate.cc @@ -192,7 +192,7 @@ MadwifiRate::process_feedback(Packet *p_in) if (success && (!_alt_rate || !used_alt_rate)) { nfo->_successes++; - nfo->_retries += ceh->retries; + nfo->_retries += (ceh->max_tries - 1); } else { nfo->_failures++; nfo->_retries += 4; diff --git a/elements/wifi/printtxfeedback.cc b/elements/wifi/printtxfeedback.cc index ec2df67619..1708a6039d 100644 --- a/elements/wifi/printtxfeedback.cc +++ b/elements/wifi/printtxfeedback.cc @@ -72,15 +72,16 @@ PrintTXFeedback::simple_action(Packet *p) sa << " " << dst; sa << " flags " << (int) ceh->flags; sa << " rate " << (int) ceh->rate; - sa << " max_retries " << (int) ceh->max_tries; - sa << " alt_rate " << (int) ceh->rate1; - sa << " alt_retries " << (int) ceh->max_tries1; - sa << " retries " << (int) ceh->retries; - sa << " virt_col " << (int) ceh->virt_col; + sa << " tries " << (int) ceh->max_tries; + sa << " rate1 " << (int) ceh->rate1; + sa << " tries1 " << (int) ceh->max_tries1; + sa << " rate2 " << (int) ceh->rate2; + sa << " tries2 " << (int) ceh->max_tries2; + sa << " rate3 " << (int) ceh->rate3; + sa << " tries3 " << (int) ceh->max_tries3; click_chatter("%s\n", sa.c_str()); - return p; } diff --git a/elements/wifi/printwifi.cc b/elements/wifi/printwifi.cc index f780c9a7be..8cc78c1db0 100644 --- a/elements/wifi/printwifi.cc +++ b/elements/wifi/printwifi.cc @@ -327,22 +327,29 @@ PrintWifi::simple_action(Packet *p) len = sprintf(sa.reserve(9), "%4d | ", p->length()); sa.adjust_length(len); - if (ceh->rate == 11) { - sa << " 5.5"; + if (ceh->flags & WIFI_EXTRA_MCS) { + len = sprintf(sa.reserve(2), "%2d", ceh->rate); + sa.adjust_length(len); + sa << "HT "; } else { - len = sprintf(sa.reserve(2), "%2d", ceh->rate/2); - sa.adjust_length(len); + if (ceh->rate == 11) { + sa << " 5.5"; + } else { + len = sprintf(sa.reserve(2), "%2d", ceh->rate/2); + sa.adjust_length(len); + } + sa << "Mb "; } - sa << "Mb "; - len = sprintf(sa.reserve(9), "+%2d/", ceh->rssi); - sa.adjust_length(len); + int8_t rssi; + memcpy(&rssi, &ceh->rssi, 1); - len = sprintf(sa.reserve(9), "%2d | ", ceh->silence); + len = sprintf(sa.reserve(9), "%2ddB ", rssi); sa.adjust_length(len); + switch (wh->i_fc[1] & WIFI_FC1_DIR_MASK) { case WIFI_FC1_DIR_NODS: dst = EtherAddress(wh->i_addr1); @@ -540,7 +547,7 @@ PrintWifi::simple_action(Packet *p) sa << " ] "; if (ceh->flags & WIFI_EXTRA_TX) { - sa << " retries " << (int) ceh->retries; + sa << " tries " << (int) ceh->max_tries; } done: diff --git a/elements/wifi/probetxrate.cc b/elements/wifi/probetxrate.cc index 4e1d63b75f..3173db1925 100644 --- a/elements/wifi/probetxrate.cc +++ b/elements/wifi/probetxrate.cc @@ -146,7 +146,7 @@ ProbeTXRate::process_feedback(Packet *p_in) { EtherAddress dst = EtherAddress(dst_ptr); struct click_wifi_extra *ceh = WIFI_EXTRA_ANNO(p_in); bool success = !(ceh->flags & WIFI_EXTRA_TX_FAIL); - int retries = ceh->retries; + int retries = ceh->max_tries; Timestamp now = Timestamp::now(); diff --git a/elements/wifi/radiotapdecap.cc b/elements/wifi/radiotapdecap.cc index 5fc26ea557..d906ea5403 100644 --- a/elements/wifi/radiotapdecap.cc +++ b/elements/wifi/radiotapdecap.cc @@ -18,89 +18,18 @@ #include #include "radiotapdecap.hh" #include -#include #include #include +#include #include #include -#include #include -CLICK_DECLS - -#define NUM_RADIOTAP_ELEMENTS 22 - -static const int radiotap_elem_to_bytes[NUM_RADIOTAP_ELEMENTS] = - {8, /* IEEE80211_RADIOTAP_TSFT */ - 1, /* IEEE80211_RADIOTAP_FLAGS */ - 1, /* IEEE80211_RADIOTAP_RATE */ - 4, /* IEEE80211_RADIOTAP_CHANNEL */ - 2, /* IEEE80211_RADIOTAP_FHSS */ - 1, /* IEEE80211_RADIOTAP_DBM_ANTSIGNAL */ - 1, /* IEEE80211_RADIOTAP_DBM_ANTNOISE */ - 2, /* IEEE80211_RADIOTAP_LOCK_QUALITY */ - 2, /* IEEE80211_RADIOTAP_TX_ATTENUATION */ - 2, /* IEEE80211_RADIOTAP_DB_TX_ATTENUATION */ - 1, /* IEEE80211_RADIOTAP_DBM_TX_POWER */ - 1, /* IEEE80211_RADIOTAP_ANTENNA */ - 1, /* IEEE80211_RADIOTAP_DB_ANTSIGNAL */ - 1, /* IEEE80211_RADIOTAP_DB_ANTNOISE */ - 2, /* IEEE80211_RADIOTAP_RX_FLAGS */ - 2, /* IEEE80211_RADIOTAP_TX_FLAGS */ - 1, /* IEEE80211_RADIOTAP_RTS_RETRIES */ - 1, /* IEEE80211_RADIOTAP_DATA_RETRIES */ - 8, /* IEEE80211_RADIOTAP_XCHANNEL */ - 3, /* IEEE80211_RADIOTAP_MCS */ - 8, /* IEEE80211_RADIOTAP_A_MPDU_STATUS */ - 12, /* IEEE80211_RADIOTAP_VHT */ - }; - -static int rt_el_present(struct ieee80211_radiotap_header *th, u_int32_t element) -{ - if (element > NUM_RADIOTAP_ELEMENTS) - return 0; - return le32_to_cpu(th->it_present) & (1 << element); -} - -static int rt_check_header(struct ieee80211_radiotap_header *th, int len, u_int8_t *offsets[], u_int8_t additional_it_present_flags) -{ - int bytes = additional_it_present_flags * sizeof(u_int32_t); - bytes += bytes % 8; - int x = 0; - u_int8_t *ptr = (u_int8_t *)(th + 1); - - if (th->it_version != 0) { - return 0; - } - - if (le16_to_cpu(th->it_len) < sizeof(struct ieee80211_radiotap_header)) { - return 0; - } - - for (x = 0; x < NUM_RADIOTAP_ELEMENTS; x++) { - if (rt_el_present(th, x)) { - int radiotap_padding_size = radiotap_elem_to_bytes[x]; - if(x==IEEE80211_RADIOTAP_CHANNEL) radiotap_padding_size = 2; - int pad = bytes % radiotap_padding_size; - - if (pad) - bytes += radiotap_padding_size - pad; - offsets[x] = ptr + bytes; - bytes += radiotap_elem_to_bytes[x]; - } - } - - if (le16_to_cpu(th->it_len) < sizeof(struct ieee80211_radiotap_header) + bytes) { - return 0; - } - - if (le16_to_cpu(th->it_len) > len) { - return 0; - } - - return 1; +extern "C" { + #include } +CLICK_DECLS -RadiotapDecap::RadiotapDecap() +RadiotapDecap::RadiotapDecap() : _debug(false) { } @@ -108,119 +37,93 @@ RadiotapDecap::~RadiotapDecap() { } -int -RadiotapDecap::configure(Vector &conf, ErrorHandler *errh) -{ - _debug = false; - return Args(conf, this, errh).read("DEBUG", _debug).complete(); -} - Packet * -RadiotapDecap::simple_action(Packet *p) -{ - u_int8_t *offsets[NUM_RADIOTAP_ELEMENTS]; +RadiotapDecap::simple_action(Packet *p) { + struct ieee80211_radiotap_header *th = (struct ieee80211_radiotap_header *) p->data(); + struct ieee80211_radiotap_iterator iter; + struct click_wifi_extra *ceh = WIFI_EXTRA_ANNO(p); - u_int8_t additional_it_present_flags = 0; - u_int32_t *itpp = (u_int32_t*) &th->it_present; + int err = ieee80211_radiotap_iterator_init(&iter, th, p->length(), 0); - while(le32_to_cpu(*itpp) & (1 << IEEE80211_RADIOTAP_EXT)){ - additional_it_present_flags++; - itpp += 1; + if (err) { + click_chatter("%{element} :: %s :: malformed radiotap header (init returns %d)", this, __func__, err); + goto drop; } - struct click_wifi_extra *ceh = WIFI_EXTRA_ANNO(p); - if (rt_check_header(th, p->length(), offsets, additional_it_present_flags)) { - memset((void*)ceh, 0, sizeof(struct click_wifi_extra)); - ceh->magic = WIFI_EXTRA_MAGIC; - - if (rt_el_present(th, IEEE80211_RADIOTAP_FLAGS)) { - u_int8_t flags = *offsets[IEEE80211_RADIOTAP_FLAGS]; + memset((void*)ceh, 0, sizeof(struct click_wifi_extra)); + ceh->magic = WIFI_EXTRA_MAGIC; + + while (!(err = ieee80211_radiotap_iterator_next(&iter))) { + u_int16_t flags; + switch (iter.this_arg_index) { + case IEEE80211_RADIOTAP_TSFT: + ceh->tsft = *((uint64_t *)iter.this_arg); + break; + case IEEE80211_RADIOTAP_FLAGS: + flags = le16_to_cpu(*(uint16_t *)iter.this_arg); if (flags & IEEE80211_RADIOTAP_F_DATAPAD) { ceh->pad = 1; } if (flags & IEEE80211_RADIOTAP_F_FCS) { p->take(4); } - } - - if (rt_el_present(th, IEEE80211_RADIOTAP_RATE)) { - ceh->rate = *offsets[IEEE80211_RADIOTAP_RATE]; - } - - if (rt_el_present(th, IEEE80211_RADIOTAP_DBM_ANTSIGNAL)) - ceh->rssi = *offsets[IEEE80211_RADIOTAP_DBM_ANTSIGNAL]; - - if (rt_el_present(th, IEEE80211_RADIOTAP_DBM_ANTNOISE)) - ceh->silence = *offsets[IEEE80211_RADIOTAP_DBM_ANTNOISE]; - - if (rt_el_present(th, IEEE80211_RADIOTAP_DB_ANTSIGNAL)) - ceh->rssi = *offsets[IEEE80211_RADIOTAP_DB_ANTSIGNAL]; - - if (rt_el_present(th, IEEE80211_RADIOTAP_DB_ANTNOISE)) - ceh->silence = *offsets[IEEE80211_RADIOTAP_DB_ANTNOISE]; - - if (rt_el_present(th, IEEE80211_RADIOTAP_RX_FLAGS)) { - u_int16_t flags = le16_to_cpu(*((u_int16_t *) offsets[IEEE80211_RADIOTAP_RX_FLAGS])); - if (flags & IEEE80211_RADIOTAP_F_RX_BADFCS) + break; + case IEEE80211_RADIOTAP_MCS: + ceh->rate = *((uint8_t *)iter.this_arg+2); + ceh->flags |= WIFI_EXTRA_MCS; + break; + case IEEE80211_RADIOTAP_RATE: + ceh->rate = *iter.this_arg; + break; + case IEEE80211_RADIOTAP_DATA_RETRIES: + ceh->max_tries = *iter.this_arg + 1; + break; + case IEEE80211_RADIOTAP_CHANNEL: + ceh->channel = le16_to_cpu(*(uint16_t *)iter.this_arg); + break; + case IEEE80211_RADIOTAP_DBM_ANTSIGNAL: + ceh->rssi = *iter.this_arg; + break; + case IEEE80211_RADIOTAP_DBM_ANTNOISE: + ceh->silence = *iter.this_arg; + break; + case IEEE80211_RADIOTAP_DB_ANTSIGNAL: + ceh->rssi = *iter.this_arg; + break; + case IEEE80211_RADIOTAP_DB_ANTNOISE: + ceh->silence = *iter.this_arg; + break; + case IEEE80211_RADIOTAP_RX_FLAGS: + flags = le16_to_cpu(*(uint16_t *)iter.this_arg); + if (flags & IEEE80211_RADIOTAP_F_BADFCS) ceh->flags |= WIFI_EXTRA_RX_ERR; - } - - if (rt_el_present(th, IEEE80211_RADIOTAP_TX_FLAGS)) { - u_int16_t flags = le16_to_cpu(*((u_int16_t *) offsets[IEEE80211_RADIOTAP_TX_FLAGS])); + break; + case IEEE80211_RADIOTAP_TX_FLAGS: + flags = le16_to_cpu(*(uint16_t *)iter.this_arg); ceh->flags |= WIFI_EXTRA_TX; if (flags & IEEE80211_RADIOTAP_F_TX_FAIL) ceh->flags |= WIFI_EXTRA_TX_FAIL; + break; } - - if (rt_el_present(th, IEEE80211_RADIOTAP_DATA_RETRIES)) - ceh->retries = *offsets[IEEE80211_RADIOTAP_DATA_RETRIES]; - - p->pull(le16_to_cpu(th->it_len)); - p->set_mac_header(p->data()); // reset mac-header pointer } - return p; -} + if (err != -ENOENT) { + click_chatter("%{element} :: %s :: malformed radiotap data", this, __func__); + goto drop; + } + p->pull(le16_to_cpu(th->it_len)); + p->set_mac_header(p->data()); // reset mac-header pointer -enum {H_DEBUG}; + return p; -static String -RadiotapDecap_read_param(Element *e, void *thunk) -{ - RadiotapDecap *td = (RadiotapDecap *)e; - switch ((uintptr_t) thunk) { - case H_DEBUG: - return String(td->_debug) + "\n"; - default: - return String(); - } -} -static int -RadiotapDecap_write_param(const String &in_s, Element *e, void *vparam, - ErrorHandler *errh) -{ - RadiotapDecap *f = (RadiotapDecap *)e; - String s = cp_uncomment(in_s); - switch((intptr_t)vparam) { - case H_DEBUG: { //debug - bool debug; - if (!BoolArg().parse(s, debug)) - return errh->error("debug parameter must be boolean"); - f->_debug = debug; - break; - } - } - return 0; -} + drop: -void -RadiotapDecap::add_handlers() -{ - add_read_handler("debug", RadiotapDecap_read_param, H_DEBUG); + p->kill(); + return 0; - add_write_handler("debug", RadiotapDecap_write_param, H_DEBUG); } + CLICK_ENDDECLS EXPORT_ELEMENT(RadiotapDecap) diff --git a/elements/wifi/radiotapdecap.hh b/elements/wifi/radiotapdecap.hh index 3a9a680c26..e2cd0d7f31 100644 --- a/elements/wifi/radiotapdecap.hh +++ b/elements/wifi/radiotapdecap.hh @@ -28,17 +28,10 @@ class RadiotapDecap : public Element { public: const char *port_count() const { return PORTS_1_1; } const char *processing() const { return AGNOSTIC; } - int configure(Vector &, ErrorHandler *) CLICK_COLD; bool can_live_reconfigure() const { return true; } Packet *simple_action(Packet *); - - - void add_handlers() CLICK_COLD; - - bool _debug; - private: }; diff --git a/elements/wifi/radiotapencap.cc b/elements/wifi/radiotapencap.cc index d8dfe8e095..71160489ea 100644 --- a/elements/wifi/radiotapencap.cc +++ b/elements/wifi/radiotapencap.cc @@ -1,6 +1,6 @@ /* * radiotapencap.{cc,hh} -- encapsultates 802.11 packets - * John Bicket + * John Bicket, Roberto Riggio * * Copyright (c) 2004 Massachusetts Institute of Technology * @@ -18,7 +18,6 @@ #include #include "radiotapencap.hh" #include -#include #include #include #include @@ -27,118 +26,251 @@ #include CLICK_DECLS +#define CLICK_RADIOTAP_PRESENT ( \ + (1 << IEEE80211_RADIOTAP_RATE) | \ + (1 << IEEE80211_RADIOTAP_TX_FLAGS) | \ + (1 << IEEE80211_RADIOTAP_DATA_RETRIES) | \ + (1 << IEEE80211_RADIOTAP_RADIOTAP_NAMESPACE) | \ + (1 << IEEE80211_RADIOTAP_EXT) | \ + 0) - -#define CLICK_RADIOTAP_PRESENT ( \ - (1 << IEEE80211_RADIOTAP_RATE) | \ - (1 << IEEE80211_RADIOTAP_DBM_TX_POWER) | \ - (1 << IEEE80211_RADIOTAP_TX_FLAGS) | \ - (1 << IEEE80211_RADIOTAP_DATA_RETRIES) | \ +#define CLICK_RADIOTAP_PRESENT_HT ( \ + (1 << IEEE80211_RADIOTAP_TX_FLAGS) | \ + (1 << IEEE80211_RADIOTAP_DATA_RETRIES) | \ + (1 << IEEE80211_RADIOTAP_MCS) | \ + (1 << IEEE80211_RADIOTAP_RADIOTAP_NAMESPACE) | \ + (1 << IEEE80211_RADIOTAP_EXT) | \ 0) struct click_radiotap_header { struct ieee80211_radiotap_header wt_ihdr; + u_int32_t it_present1; + u_int32_t it_present2; + u_int32_t it_present3; + u_int8_t wt_rate; - u_int8_t wt_txpower; + u_int8_t wt_pad; u_int16_t wt_tx_flags; - u_int8_t wt_data_retries; -}; + u_int8_t wt_data_retries; + u_int8_t wt_rate1; + u_int8_t wt_data_retries1; + u_int8_t wt_rate2; + u_int8_t wt_data_retries2; + u_int8_t wt_rate3; + u_int8_t wt_data_retries3; +} __attribute__((__packed__)); +struct click_radiotap_header_ht { + struct ieee80211_radiotap_header wt_ihdr; + u_int32_t it_present1; + u_int32_t it_present2; + u_int32_t it_present3; -RadiotapEncap::RadiotapEncap() -{ -} + u_int16_t wt_tx_flags; + u_int8_t wt_data_retries; + u_int8_t wt_known; + u_int8_t wt_flags; + u_int8_t wt_mcs; -RadiotapEncap::~RadiotapEncap() -{ + u_int8_t wt_data_retries1; + u_int8_t wt_known1; + u_int8_t wt_flags1; + u_int8_t wt_mcs1; + + u_int8_t wt_data_retries2; + u_int8_t wt_known2; + u_int8_t wt_flags2; + u_int8_t wt_mcs2; + + u_int8_t wt_data_retries3; + u_int8_t wt_known3; + u_int8_t wt_flags3; + u_int8_t wt_mcs3; +} __attribute__((__packed__)); + +RadiotapEncap::RadiotapEncap() : _debug(false) { } -int -RadiotapEncap::configure(Vector &conf, ErrorHandler *errh) -{ - _debug = false; - return Args(conf, this, errh).read("DEBUG", _debug).complete(); +RadiotapEncap::~RadiotapEncap() { } Packet * -RadiotapEncap::simple_action(Packet *p) -{ - - WritablePacket *p_out = p->uniqueify(); - if (!p_out) { - p->kill(); - return 0; - } - - p_out = p_out->push(sizeof(struct click_radiotap_header)); - - if (p_out) { - struct click_radiotap_header *crh = (struct click_radiotap_header *) p_out->data(); - click_wifi_extra *ceh = WIFI_EXTRA_ANNO(p); - - memset(crh, 0, sizeof(struct click_radiotap_header)); - - crh->wt_ihdr.it_version = 0; - crh->wt_ihdr.it_len = cpu_to_le16(sizeof(struct click_radiotap_header)); - crh->wt_ihdr.it_present = cpu_to_le32(CLICK_RADIOTAP_PRESENT); - - crh->wt_rate = ceh->rate; - crh->wt_txpower = ceh->power; - if (ceh->flags & WIFI_EXTRA_TX_NOACK) { - crh->wt_tx_flags |= IEEE80211_RADIOTAP_F_TX_NOACK; - } - if (ceh->max_tries > 0) { - crh->wt_data_retries = ceh->max_tries - 1; - } else { - crh->wt_data_retries = WIFI_MAX_RETRIES + 1; - } - } - - return p_out; +RadiotapEncap::simple_action(Packet *p) { + click_wifi_extra *ceh = WIFI_EXTRA_ANNO(p); + if (ceh->flags & WIFI_EXTRA_MCS) + return encap_ht(p); + return encap(p); } +Packet * +RadiotapEncap::encap_ht(Packet *p) { -enum {H_DEBUG}; + click_wifi_extra *ceh = WIFI_EXTRA_ANNO(p); + WritablePacket *p_out = p->uniqueify(); + + if (!p_out) { + p->kill(); + return 0; + } + + p_out = p_out->push(sizeof(struct click_radiotap_header_ht)); + + if (!p_out) { + p->kill(); + return 0; + } + + struct click_radiotap_header_ht *crh = (struct click_radiotap_header_ht *) p_out->data(); + + memset(crh, 0, sizeof(struct click_radiotap_header_ht)); + + crh->wt_ihdr.it_version = 0; + crh->wt_ihdr.it_len = cpu_to_le16(sizeof(struct click_radiotap_header_ht)); + + crh->wt_ihdr.it_present = cpu_to_le32(CLICK_RADIOTAP_PRESENT_HT); + + crh->wt_known |= IEEE80211_RADIOTAP_MCS_HAVE_BW | + IEEE80211_RADIOTAP_MCS_HAVE_MCS | + IEEE80211_RADIOTAP_MCS_HAVE_GI; + + if (ceh->flags & WIFI_EXTRA_MCS_SGI) { + crh->wt_flags |= IEEE80211_RADIOTAP_MCS_SGI; + } + + if (ceh->flags & WIFI_EXTRA_MCS_BW_40) { + crh->wt_flags |= IEEE80211_RADIOTAP_MCS_BW_40; + } + + crh->wt_mcs = ceh->rate; + crh->wt_data_retries = (ceh->max_tries > 0) ? ceh->max_tries - 1 : WIFI_MAX_RETRIES; + + if (ceh->flags & WIFI_EXTRA_TX_NOACK) { + crh->wt_tx_flags |= IEEE80211_RADIOTAP_F_TX_NOACK; + } + + crh->it_present1 |= cpu_to_le32(1 << IEEE80211_RADIOTAP_RADIOTAP_NAMESPACE); + crh->it_present1 |= cpu_to_le32(1 << IEEE80211_RADIOTAP_EXT); + crh->it_present2 |= cpu_to_le32(1 << IEEE80211_RADIOTAP_RADIOTAP_NAMESPACE); + crh->it_present2 |= cpu_to_le32(1 << IEEE80211_RADIOTAP_EXT); + + if (ceh->rate1 != -1) { + crh->it_present1 |= cpu_to_le32(1 << IEEE80211_RADIOTAP_MCS); + crh->it_present1 |= cpu_to_le32(1 << IEEE80211_RADIOTAP_DATA_RETRIES); + crh->wt_mcs1 = ceh->rate1; + crh->wt_data_retries1 = (ceh->max_tries1 > 0) ? ceh->max_tries1 - 1 : WIFI_MAX_RETRIES; + crh->wt_known1 |= IEEE80211_RADIOTAP_MCS_HAVE_BW | + IEEE80211_RADIOTAP_MCS_HAVE_MCS | + IEEE80211_RADIOTAP_MCS_HAVE_GI; + if (ceh->flags & WIFI_EXTRA_MCS_SGI) { + crh->wt_flags1 |= IEEE80211_RADIOTAP_MCS_SGI; + } + + if (ceh->flags & WIFI_EXTRA_MCS_BW_40) { + crh->wt_flags1 |= IEEE80211_RADIOTAP_MCS_BW_40; + } + if (ceh->rate2 != -1) { + crh->it_present2 |= cpu_to_le32(1 << IEEE80211_RADIOTAP_MCS); + crh->it_present2 |= cpu_to_le32(1 << IEEE80211_RADIOTAP_DATA_RETRIES); + crh->wt_mcs2 = ceh->rate2; + crh->wt_data_retries2 = (ceh->max_tries2 > 0) ? ceh->max_tries2 - 1 : WIFI_MAX_RETRIES; + crh->wt_known2 |= IEEE80211_RADIOTAP_MCS_HAVE_BW | + IEEE80211_RADIOTAP_MCS_HAVE_MCS | + IEEE80211_RADIOTAP_MCS_HAVE_GI; + if (ceh->flags & WIFI_EXTRA_MCS_SGI) { + crh->wt_flags2 |= IEEE80211_RADIOTAP_MCS_SGI; + } + + if (ceh->flags & WIFI_EXTRA_MCS_BW_40) { + crh->wt_flags2 |= IEEE80211_RADIOTAP_MCS_BW_40; + } + if (ceh->rate3 != -1) { + crh->it_present3 |= cpu_to_le32(1 << IEEE80211_RADIOTAP_MCS); + crh->it_present3 |= cpu_to_le32(1 << IEEE80211_RADIOTAP_DATA_RETRIES); + crh->wt_mcs3 = ceh->rate3; + crh->wt_data_retries3 = (ceh->max_tries3 > 0) ? ceh->max_tries3 - 1 : WIFI_MAX_RETRIES; + crh->wt_known3 |= IEEE80211_RADIOTAP_MCS_HAVE_BW | + IEEE80211_RADIOTAP_MCS_HAVE_MCS | + IEEE80211_RADIOTAP_MCS_HAVE_GI; + if (ceh->flags & WIFI_EXTRA_MCS_SGI) { + crh->wt_flags3 |= IEEE80211_RADIOTAP_MCS_SGI; + } + + if (ceh->flags & WIFI_EXTRA_MCS_BW_40) { + crh->wt_flags3 |= IEEE80211_RADIOTAP_MCS_BW_40; + } + } + } + } + + return p_out; -static String -RadiotapEncap_read_param(Element *e, void *thunk) -{ - RadiotapEncap *td = (RadiotapEncap *)e; - switch ((uintptr_t) thunk) { - case H_DEBUG: - return String(td->_debug) + "\n"; - default: - return String(); - } -} -static int -RadiotapEncap_write_param(const String &in_s, Element *e, void *vparam, - ErrorHandler *errh) -{ - RadiotapEncap *f = (RadiotapEncap *)e; - String s = cp_uncomment(in_s); - switch((intptr_t)vparam) { - case H_DEBUG: { //debug - bool debug; - if (!BoolArg().parse(s, debug)) - return errh->error("debug parameter must be boolean"); - f->_debug = debug; - break; - } - } - return 0; } -void -RadiotapEncap::add_handlers() -{ - add_read_handler("debug", RadiotapEncap_read_param, H_DEBUG); +Packet * +RadiotapEncap::encap(Packet *p) { + + click_wifi_extra *ceh = WIFI_EXTRA_ANNO(p); + WritablePacket *p_out = p->uniqueify(); + + if (!p_out) { + p->kill(); + return 0; + } + + p_out = p_out->push(sizeof(struct click_radiotap_header)); + + if (!p_out) { + p->kill(); + return 0; + } + + struct click_radiotap_header *crh = (struct click_radiotap_header *) p_out->data(); + + memset(crh, 0, sizeof(struct click_radiotap_header)); + + crh->wt_ihdr.it_version = 0; + crh->wt_ihdr.it_len = cpu_to_le16(sizeof(struct click_radiotap_header)); + + crh->wt_ihdr.it_present = cpu_to_le32(CLICK_RADIOTAP_PRESENT); + + crh->wt_rate = ceh->rate; + crh->wt_data_retries = (ceh->max_tries > 0) ? ceh->max_tries - 1 : WIFI_MAX_RETRIES; + + if (ceh->flags & WIFI_EXTRA_TX_NOACK) { + crh->wt_tx_flags |= IEEE80211_RADIOTAP_F_TX_NOACK; + } + + crh->it_present1 |= cpu_to_le32(1 << IEEE80211_RADIOTAP_RADIOTAP_NAMESPACE); + crh->it_present1 |= cpu_to_le32(1 << IEEE80211_RADIOTAP_EXT); + crh->it_present2 |= cpu_to_le32(1 << IEEE80211_RADIOTAP_RADIOTAP_NAMESPACE); + crh->it_present2 |= cpu_to_le32(1 << IEEE80211_RADIOTAP_EXT); + + if (ceh->rate1 != -1) { + crh->it_present1 |= cpu_to_le32(1 << IEEE80211_RADIOTAP_RATE); + crh->it_present1 |= cpu_to_le32(1 << IEEE80211_RADIOTAP_DATA_RETRIES); + crh->wt_rate1 = ceh->rate1; + crh->wt_data_retries1 = (ceh->max_tries1 > 0) ? ceh->max_tries1 - 1 : WIFI_MAX_RETRIES; + if (ceh->rate2 != -1) { + crh->it_present2 |= cpu_to_le32(1 << IEEE80211_RADIOTAP_RATE); + crh->it_present2 |= cpu_to_le32(1 << IEEE80211_RADIOTAP_DATA_RETRIES); + crh->wt_rate2 = ceh->rate2; + crh->wt_data_retries2 = (ceh->max_tries2 > 0) ? ceh->max_tries2 - 1 : WIFI_MAX_RETRIES; + if (ceh->rate3 != -1) { + crh->it_present3 |= cpu_to_le32(1 << IEEE80211_RADIOTAP_RATE); + crh->it_present3 |= cpu_to_le32(1 << IEEE80211_RADIOTAP_DATA_RETRIES); + crh->wt_rate3 = ceh->rate3; + crh->wt_data_retries3 = (ceh->max_tries3 > 0) ? ceh->max_tries3 - 1 : WIFI_MAX_RETRIES; + } + } + } + + return p_out; - add_write_handler("debug", RadiotapEncap_write_param, H_DEBUG); } + CLICK_ENDDECLS EXPORT_ELEMENT(RadiotapEncap) diff --git a/elements/wifi/radiotapencap.hh b/elements/wifi/radiotapencap.hh index e70c2e95ed..f237c17d59 100644 --- a/elements/wifi/radiotapencap.hh +++ b/elements/wifi/radiotapencap.hh @@ -29,17 +29,13 @@ class RadiotapEncap : public Element { public: const char *port_count() const { return PORTS_1_1; } const char *processing() const { return AGNOSTIC; } - int configure(Vector &, ErrorHandler *) CLICK_COLD; bool can_live_reconfigure() const { return true; } Packet *simple_action(Packet *); - - - void add_handlers() CLICK_COLD; - + Packet *encap(Packet *); + Packet *encap_ht(Packet *); bool _debug; - private: }; diff --git a/elements/wifi/settxrate.cc b/elements/wifi/settxrate.cc index ca70365922..be89cb78b1 100644 --- a/elements/wifi/settxrate.cc +++ b/elements/wifi/settxrate.cc @@ -1,6 +1,6 @@ /* * settxrate.{cc,hh} -- sets wifi txrate annotation on a packet - * John Bicket + * John Bicket, Roberto Riggio * * Copyright (c) 2003 Massachusetts Institute of Technology * @@ -26,107 +26,104 @@ #include CLICK_DECLS -SetTXRate::SetTXRate() -{ +SetTXRate::SetTXRate() : _rate(-1), _rate1(-1), _rate2(-1), _rate3(-1), + _max_tries(0), _max_tries1(0), _max_tries2(0), + _max_tries3(0), _et(0), _offset(0) { } -SetTXRate::~SetTXRate() -{ +SetTXRate::~SetTXRate() { } -int -SetTXRate::configure(Vector &conf, ErrorHandler *errh) -{ - _rate = 0; - _et = 0; - _offset = 0; - _tries = WIFI_MAX_RETRIES+1; - if (Args(conf, this, errh) - .read_p("RATE", _rate) - .read("TRIES", _tries) - .read("ETHTYPE", _et) - .read("OFFSET", _offset) - .complete() < 0) { - return -1; - } - - if (_rate < 0) { - return errh->error("RATE must be >= 0"); - } - - if (_tries < 1) { - return errh->error("TRIES must be >= 0"); - } - - - return 0; +int SetTXRate::configure(Vector &conf, ErrorHandler *errh) { + return Args(conf, this, errh) + .read_p("RATE", _rate) + .read("TRIES", _max_tries) + .read("RATE1", _rate1) + .read("TRIES1", _max_tries1) + .read("RATE2", _rate2) + .read("TRIES2", _max_tries2) + .read("RATE3", _rate3) + .read("TRIES3", _max_tries3) + .read("ETHTYPE", _et) + .read("OFFSET", _offset) + .complete(); } Packet * -SetTXRate::simple_action(Packet *p_in) -{ - uint8_t *dst_ptr = (uint8_t *) p_in->data() + _offset; - click_ether *eh = (click_ether *) dst_ptr; +SetTXRate::simple_action(Packet *p_in) { - if (_et && eh->ether_type != htons(_et)) { - return p_in; - } + uint8_t *dst_ptr = (uint8_t *) p_in->data() + _offset; + click_ether *eh = (click_ether *) dst_ptr; - struct click_wifi_extra *ceh = WIFI_EXTRA_ANNO(p_in); - ceh->magic = WIFI_EXTRA_MAGIC; - ceh->rate = _rate ? _rate : 2; - ceh->max_tries = _tries; + if (_et && eh->ether_type != htons(_et)) { + return p_in; + } + + struct click_wifi_extra *ceh = WIFI_EXTRA_ANNO(p_in); + + ceh->magic = WIFI_EXTRA_MAGIC; + + ceh->rate = _rate ? _rate : 2; + ceh->max_tries = _max_tries; + + ceh->rate1 = _rate1; + ceh->max_tries1 = _max_tries1; + + ceh->rate2 = _rate2; + ceh->max_tries2 = _max_tries2; + + ceh->rate3 = _rate3; + ceh->max_tries3 = _max_tries3; + + return p_in; - return p_in; } -enum {H_RATE, H_TRIES}; - -String -SetTXRate::read_handler(Element *e, void *thunk) -{ - SetTXRate *foo = (SetTXRate *)e; - switch((uintptr_t) thunk) { - case H_RATE: return String(foo->_rate) + "\n"; - case H_TRIES: return String(foo->_tries) + "\n"; - default: return "\n"; - } +enum { + H_RATE, H_TRIES +}; + +String SetTXRate::read_handler(Element *e, void *thunk) { + SetTXRate *foo = (SetTXRate *) e; + switch ((uintptr_t) thunk) { + case H_RATE: + return String(foo->_rate) + "\n"; + case H_TRIES: + return String(foo->_max_tries) + "\n"; + default: + return "\n"; + } } -int -SetTXRate::write_handler(const String &arg, Element *e, - void *vparam, ErrorHandler *errh) -{ - SetTXRate *f = (SetTXRate *) e; - String s = cp_uncomment(arg); - switch((intptr_t)vparam) { - case H_RATE: { - unsigned m; - if (!IntArg().parse(s, m)) - return errh->error("rate parameter must be unsigned"); - f->_rate = m; - break; - } - case H_TRIES: { - unsigned m; - if (!IntArg().parse(s, m)) - return errh->error("tries parameter must be unsigned"); - f->_tries = m; - break; - } - } - return 0; +int SetTXRate::write_handler(const String &arg, Element *e, void *vparam, + ErrorHandler *errh) { + SetTXRate *f = (SetTXRate *) e; + String s = cp_uncomment(arg); + switch ((intptr_t) vparam) { + case H_RATE: { + unsigned m; + if (!IntArg().parse(s, m)) + return errh->error("rate parameter must be unsigned"); + f->_rate = m; + break; + } + case H_TRIES: { + unsigned m; + if (!IntArg().parse(s, m)) + return errh->error("tries parameter must be unsigned"); + f->_max_tries = m; + break; + } + } + return 0; } -void -SetTXRate::add_handlers() -{ - add_read_handler("rate", read_handler, H_RATE); - add_read_handler("tries", read_handler, H_TRIES); - add_write_handler("rate", write_handler, H_RATE); - add_write_handler("tries", write_handler, H_TRIES); +void SetTXRate::add_handlers() { + add_read_handler("rate", read_handler, H_RATE); + add_read_handler("tries", read_handler, H_TRIES); + add_write_handler("rate", write_handler, H_RATE); + add_write_handler("tries", write_handler, H_TRIES); } CLICK_ENDDECLS EXPORT_ELEMENT(SetTXRate) - diff --git a/elements/wifi/settxrate.hh b/elements/wifi/settxrate.hh index ca356ce1d3..87f3828b2e 100644 --- a/elements/wifi/settxrate.hh +++ b/elements/wifi/settxrate.hh @@ -31,30 +31,41 @@ Same as RATE Argument =a AutoRateFallback, MadwifiRate, ProbeRate, ExtraEncap */ -class SetTXRate : public Element { public: +class SetTXRate: public Element { +public: - SetTXRate() CLICK_COLD; - ~SetTXRate() CLICK_COLD; + SetTXRate() CLICK_COLD; + ~SetTXRate() CLICK_COLD; - const char *class_name() const { return "SetTXRate"; } - const char *port_count() const { return PORTS_1_1; } - const char *processing() const { return AGNOSTIC; } + const char *class_name() const { return "SetTXRate"; } + const char *port_count() const { return PORTS_1_1; } + const char *processing() const { return AGNOSTIC; } - int configure(Vector &, ErrorHandler *) CLICK_COLD; - bool can_live_reconfigure() const { return true; } + int configure(Vector &, ErrorHandler *) CLICK_COLD; + bool can_live_reconfigure() const { return true; } - Packet *simple_action(Packet *); + Packet *simple_action(Packet *); + + void add_handlers() CLICK_COLD; + + static String read_handler(Element *e, void *) CLICK_COLD; + static int write_handler(const String &, Element *, void *, ErrorHandler *); - void add_handlers() CLICK_COLD; - static String read_handler(Element *e, void *) CLICK_COLD; - static int write_handler(const String &arg, Element *e, - void *, ErrorHandler *errh); private: - int _rate; - int _tries; - uint16_t _et; // This protocol's ethertype - unsigned _offset; + int _rate; + int _rate1; + int _rate2; + int _rate3; + + unsigned _max_tries; + unsigned _max_tries1; + unsigned _max_tries2; + unsigned _max_tries3; + + uint16_t _et; + unsigned _offset; + }; CLICK_ENDDECLS diff --git a/elements/wifi/settxrateht.cc b/elements/wifi/settxrateht.cc new file mode 100644 index 0000000000..05b0437483 --- /dev/null +++ b/elements/wifi/settxrateht.cc @@ -0,0 +1,140 @@ +/* + * settxrateht.{cc,hh} -- sets wifi txrate annotation on a packet + * John Bicket, Roberto Riggio + * + * Copyright (c) 2003 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 +#include +#include +#include +#include +#include "settxrateht.hh" +#include +#include +#include +CLICK_DECLS + +SetTXRateHT::SetTXRateHT() : _mcs(-1), _mcs1(-1), _mcs2(-1), _mcs3(-1), + _max_tries(0), _max_tries1(0), _max_tries2(0), + _max_tries3(0), _et(0), _offset(0), _sgi(false), + _bw_40(false) { +} + +SetTXRateHT::~SetTXRateHT() { +} + +int SetTXRateHT::configure(Vector &conf, ErrorHandler *errh) { + return Args(conf, this, errh) + .read_p("MCS", _mcs) + .read("TRIES", _max_tries) + .read("MCS1", _mcs1) + .read("TRIES1", _max_tries1) + .read("MCS2", _mcs2) + .read("TRIES2", _max_tries2) + .read("MCS3", _mcs3) + .read("TRIES3", _max_tries3) + .read("ETHTYPE", _et) + .read("OFFSET", _offset) + .read("SGI", _sgi) + .read("BW_40", _bw_40) + .complete(); +} + +Packet * +SetTXRateHT::simple_action(Packet *p_in) { + + uint8_t *dst_ptr = (uint8_t *) p_in->data() + _offset; + click_ether *eh = (click_ether *) dst_ptr; + + if (_et && eh->ether_type != htons(_et)) { + return p_in; + } + + struct click_wifi_extra *ceh = WIFI_EXTRA_ANNO(p_in); + + ceh->magic = WIFI_EXTRA_MAGIC; + + ceh->rate = _mcs; + ceh->max_tries = _max_tries; + + ceh->rate1 = _mcs1; + ceh->max_tries1 = _max_tries1; + + ceh->rate2 = _mcs2; + ceh->max_tries2 = _max_tries2; + + ceh->rate3 = _mcs3; + ceh->max_tries3 = _max_tries3; + + ceh->flags |= WIFI_EXTRA_MCS; + + if (_sgi) + ceh->flags |= WIFI_EXTRA_MCS_SGI; + + if (_bw_40) + ceh->flags |= WIFI_EXTRA_MCS_BW_40; + + return p_in; + +} + +enum { + H_MCS, H_TRIES +}; + +String SetTXRateHT::read_handler(Element *e, void *thunk) { + SetTXRateHT *foo = (SetTXRateHT *) e; + switch ((uintptr_t) thunk) { + case H_MCS: + return String(foo->_mcs) + "\n"; + case H_TRIES: + return String(foo->_max_tries) + "\n"; + default: + return "\n"; + } +} + +int SetTXRateHT::write_handler(const String &arg, Element *e, void *vparam, + ErrorHandler *errh) { + SetTXRateHT *f = (SetTXRateHT *) e; + String s = cp_uncomment(arg); + switch ((intptr_t) vparam) { + case H_MCS: { + unsigned m; + if (!IntArg().parse(s, m)) + return errh->error("rate parameter must be unsigned"); + f->_mcs = m; + break; + } + case H_TRIES: { + unsigned m; + if (!IntArg().parse(s, m)) + return errh->error("tries parameter must be unsigned"); + f->_max_tries = m; + break; + } + } + return 0; +} + +void SetTXRateHT::add_handlers() { + add_read_handler("rate", read_handler, H_MCS); + add_read_handler("tries", read_handler, H_TRIES); + add_write_handler("rate", write_handler, H_MCS); + add_write_handler("tries", write_handler, H_TRIES); +} + +CLICK_ENDDECLS +EXPORT_ELEMENT(SetTXRateHT) diff --git a/elements/wifi/settxrateht.hh b/elements/wifi/settxrateht.hh new file mode 100644 index 0000000000..368ac7d50a --- /dev/null +++ b/elements/wifi/settxrateht.hh @@ -0,0 +1,73 @@ +#ifndef CLICK_SETTXRATEHT_HH +#define CLICK_SETTXRATEHT_HH +#include +#include +CLICK_DECLS + +/* +=c +SetTXRateHT([I]) + +=s Wifi + +Sets the bit-rate for a packet. + +=d + +Sets the Wifi TXRate Annotation on a packet. + +Regular Arguments: +=over 8 + +=item MCS +Unsigned integer. MCS index. + +=back 8 + +=h rate read/write +Same as RATE Argument + +=a AutoRateFallback, MadwifiRate, ProbeRate, ExtraEncap +*/ + +class SetTXRateHT: public Element { +public: + + SetTXRateHT() CLICK_COLD; + ~SetTXRateHT() CLICK_COLD; + + const char *class_name() const { return "SetTXRateHT"; } + const char *port_count() const { return PORTS_1_1; } + const char *processing() const { return AGNOSTIC; } + + int configure(Vector &, ErrorHandler *) CLICK_COLD; + bool can_live_reconfigure() const { return true; } + + Packet *simple_action(Packet *); + + void add_handlers() CLICK_COLD; + + static String read_handler(Element *e, void *) CLICK_COLD; + static int write_handler(const String &, Element *, void *, ErrorHandler *); + +private: + + int _mcs; + int _mcs1; + int _mcs2; + int _mcs3; + + unsigned _max_tries; + unsigned _max_tries1; + unsigned _max_tries2; + unsigned _max_tries3; + + uint16_t _et; + unsigned _offset; + bool _sgi; + bool _bw_40; + +}; + +CLICK_ENDDECLS +#endif diff --git a/include/click/packet_anno.hh b/include/click/packet_anno.hh index 80b7ee658d..60ba4aabda 100644 --- a/include/click/packet_anno.hh +++ b/include/click/packet_anno.hh @@ -13,7 +13,7 @@ // bytes 16-31 #define WIFI_EXTRA_ANNO_OFFSET 16 -#define WIFI_EXTRA_ANNO_SIZE 24 +#define WIFI_EXTRA_ANNO_SIZE 28 #define WIFI_EXTRA_ANNO(p) ((click_wifi_extra *) ((p)->anno_u8() + WIFI_EXTRA_ANNO_OFFSET)) // byte 16 diff --git a/include/click/platform.h b/include/click/platform.h new file mode 100644 index 0000000000..00de1c93f4 --- /dev/null +++ b/include/click/platform.h @@ -0,0 +1,25 @@ +#include +#include +#ifndef _BSD_SOURCE +#define _BSD_SOURCE +#endif +#include + +#if !defined(le32toh) || !defined(le16toh) +# include +# define le32toh(x) bswap_32(x) +# define le16toh(x) bswap_16(x) +#endif + +#define le16_to_cpu le16toh +#define le32_to_cpu le32toh +#define get_unaligned(p) \ +({ \ + struct packed_dummy_struct { \ + typeof(*(p)) __val; \ + } __attribute__((packed)) *__ptr = (void *) (p); \ + \ + __ptr->__val; \ +}) +#define get_unaligned_le16(p) le16_to_cpu(get_unaligned((uint16_t *)(p))) +#define get_unaligned_le32(p) le32_to_cpu(get_unaligned((uint32_t *)(p))) diff --git a/include/click/radiotap_iter.h b/include/click/radiotap_iter.h new file mode 100644 index 0000000000..0f8eb4c17b --- /dev/null +++ b/include/click/radiotap_iter.h @@ -0,0 +1,94 @@ +#ifndef CLICK_RADIOTAP_ITER_H +#define CLICK_RADIOTAP_ITER_H + +#include +#include + +/* Radiotap header iteration + * implemented in radiotap.c + */ + +struct radiotap_override { + uint8_t field; + uint8_t align:4, size:4; +}; + +struct radiotap_align_size { + uint8_t align:4, size:4; +}; + +struct ieee80211_radiotap_namespace { + const struct radiotap_align_size *align_size; + int n_bits; + uint32_t oui; + uint8_t subns; +}; + +struct ieee80211_radiotap_vendor_namespaces { + const struct ieee80211_radiotap_namespace *ns; + int n_ns; +}; + +/** + * struct ieee80211_radiotap_iterator - tracks walk thru present radiotap args + * @this_arg_index: index of current arg, valid after each successful call + * to ieee80211_radiotap_iterator_next() + * @this_arg: pointer to current radiotap arg; it is valid after each + * call to ieee80211_radiotap_iterator_next() but also after + * ieee80211_radiotap_iterator_init() where it will point to + * the beginning of the actual data portion + * @this_arg_size: length of the current arg, for convenience + * @current_namespace: pointer to the current namespace definition + * (or internally %NULL if the current namespace is unknown) + * @is_radiotap_ns: indicates whether the current namespace is the default + * radiotap namespace or not + * + * @overrides: override standard radiotap fields + * @n_overrides: number of overrides + * + * @_rtheader: pointer to the radiotap header we are walking through + * @_max_length: length of radiotap header in cpu byte ordering + * @_arg_index: next argument index + * @_arg: next argument pointer + * @_next_bitmap: internal pointer to next present u32 + * @_bitmap_shifter: internal shifter for curr u32 bitmap, b0 set == arg present + * @_vns: vendor namespace definitions + * @_next_ns_data: beginning of the next namespace's data + * @_reset_on_ext: internal; reset the arg index to 0 when going to the + * next bitmap word + * + * Describes the radiotap parser state. Fields prefixed with an underscore + * must not be used by users of the parser, only by the parser internally. + */ + +struct ieee80211_radiotap_iterator { + struct ieee80211_radiotap_header *_rtheader; + const struct ieee80211_radiotap_vendor_namespaces *_vns; + const struct ieee80211_radiotap_namespace *current_namespace; + + unsigned char *_arg, *_next_ns_data; + uint32_t *_next_bitmap; + + unsigned char *this_arg; + const struct radiotap_override *overrides; /* Only for RADIOTAP_SUPPORT_OVERRIDES */ + int n_overrides; /* Only for RADIOTAP_SUPPORT_OVERRIDES */ + int this_arg_index; + int this_arg_size; + + int is_radiotap_ns; + + int _max_length; + int _arg_index; + uint32_t _bitmap_shifter; + int _reset_on_ext; +}; + +extern int ieee80211_radiotap_iterator_init( + struct ieee80211_radiotap_iterator *iterator, + struct ieee80211_radiotap_header *radiotap_header, + int max_length, const struct ieee80211_radiotap_vendor_namespaces *vns); + +extern int ieee80211_radiotap_iterator_next( + struct ieee80211_radiotap_iterator *iterator); + +#endif /* CLICK_RADIOTAP_ITER_H */ diff --git a/include/clicknet/radiotap.h b/include/clicknet/radiotap.h index 49207a1c63..71c17c35b4 100644 --- a/include/clicknet/radiotap.h +++ b/include/clicknet/radiotap.h @@ -1,6 +1,3 @@ -/* $FreeBSD: src/sys/net80211/ieee80211_radiotap.h,v 1.5 2005/01/22 20:12:05 sam Exp $ */ -/* $NetBSD: ieee80211_radiotap.h,v 1.10 2005/01/04 00:34:58 dyoung Exp $ */ - /*- * Copyright (c) 2003, 2004 David Young. All rights reserved. * @@ -29,8 +26,19 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. */ -#ifndef _NET_IF_IEEE80211RADIOTAP_H_ -#define _NET_IF_IEEE80211RADIOTAP_H_ + +/* + * Modifications to fit into the linux IEEE 802.11 stack, + * Mike Kershaw (dragorn@kismetwireless.net) + */ + +#ifndef IEEE80211RADIOTAP_H +#define IEEE80211RADIOTAP_H + +#include + +/* Base version of the radiotap packet header data */ +#define PKTHDR_RADIOTAP_VERSION 0 /* A generic radio capture format is desirable. There is one for * Linux, but it is neither rigidly defined (there were not even @@ -46,135 +54,135 @@ * function of...") that I cannot set false expectations for lawyerly * readers. */ -#if defined(__KERNEL__) || defined(_KERNEL) -#ifndef DLT_IEEE802_11_RADIO -#define DLT_IEEE802_11_RADIO 127 /* 802.11 plus WLAN header */ -#endif -#endif /* defined(__KERNEL__) || defined(_KERNEL) */ - -/* XXX tcpdump/libpcap do not tolerate variable-length headers, - * yet, so we pad every radiotap header to 64 bytes. Ugh. - */ -#define IEEE80211_RADIOTAP_HDRLEN 64 -/* The radio capture header precedes the 802.11 header. */ +/* The radio capture header precedes the 802.11 header. + * All data in the header is little endian on all platforms. + */ struct ieee80211_radiotap_header { - u_int8_t it_version; /* Version 0. Only increases - * for drastic changes, - * introduction of compatible - * new fields does not count. - */ - u_int8_t it_pad; - u_int16_t it_len; /* length of the whole - * header in bytes, including - * it_version, it_pad, - * it_len, and data fields. - */ - u_int32_t it_present; /* A bitmap telling which - * fields are present. Set bit 31 - * (0x80000000) to extend the - * bitmap by another 32 bits. - * Additional extensions are made - * by setting bit 31. - */ + uint8_t it_version; /* Version 0. Only increases + * for drastic changes, + * introduction of compatible + * new fields does not count. + */ + uint8_t it_pad; + uint16_t it_len; /* length of the whole + * header in bytes, including + * it_version, it_pad, + * it_len, and data fields. + */ + uint32_t it_present; /* A bitmap telling which + * fields are present. Set bit 31 + * (0x80000000) to extend the + * bitmap by another 32 bits. + * Additional extensions are made + * by setting bit 31. + */ } __attribute__((__packed__)); -/* Name Data type Units - * ---- --------- ----- +/* Name Data type Units + * ---- --------- ----- * - * IEEE80211_RADIOTAP_TSFT u_int64_t microseconds + * IEEE80211_RADIOTAP_TSFT __le64 microseconds * * Value in microseconds of the MAC's 64-bit 802.11 Time * Synchronization Function timer when the first bit of the * MPDU arrived at the MAC. For received frames, only. * - * IEEE80211_RADIOTAP_CHANNEL 2 x u_int16_t MHz, bitmap + * IEEE80211_RADIOTAP_CHANNEL 2 x uint16_t MHz, bitmap * * Tx/Rx frequency in MHz, followed by flags (see below). * - * IEEE80211_RADIOTAP_FHSS u_int16_t see below + * IEEE80211_RADIOTAP_FHSS uint16_t see below * * For frequency-hopping radios, the hop set (first byte) * and pattern (second byte). * - * IEEE80211_RADIOTAP_RATE u_int8_t 500kb/s + * IEEE80211_RADIOTAP_RATE u8 500kb/s * * Tx/Rx data rate * - * IEEE80211_RADIOTAP_DBM_ANTSIGNAL int8_t decibels from - * one milliwatt (dBm) + * IEEE80211_RADIOTAP_DBM_ANTSIGNAL s8 decibels from + * one milliwatt (dBm) * * RF signal power at the antenna, decibel difference from * one milliwatt. * - * IEEE80211_RADIOTAP_DBM_ANTNOISE int8_t decibels from - * one milliwatt (dBm) + * IEEE80211_RADIOTAP_DBM_ANTNOISE s8 decibels from + * one milliwatt (dBm) * * RF noise power at the antenna, decibel difference from one * milliwatt. * - * IEEE80211_RADIOTAP_DB_ANTSIGNAL u_int8_t decibel (dB) + * IEEE80211_RADIOTAP_DB_ANTSIGNAL u8 decibel (dB) * * RF signal power at the antenna, decibel difference from an * arbitrary, fixed reference. * - * IEEE80211_RADIOTAP_DB_ANTNOISE u_int8_t decibel (dB) + * IEEE80211_RADIOTAP_DB_ANTNOISE u8 decibel (dB) * * RF noise power at the antenna, decibel difference from an * arbitrary, fixed reference point. * - * IEEE80211_RADIOTAP_LOCK_QUALITY u_int16_t unitless + * IEEE80211_RADIOTAP_LOCK_QUALITY uint16_t unitless * * Quality of Barker code lock. Unitless. Monotonically * nondecreasing with "better" lock strength. Called "Signal * Quality" in datasheets. (Is there a standard way to measure * this?) * - * IEEE80211_RADIOTAP_TX_ATTENUATION u_int16_t unitless + * IEEE80211_RADIOTAP_TX_ATTENUATION uint16_t unitless * * Transmit power expressed as unitless distance from max * power set at factory calibration. 0 is max power. * Monotonically nondecreasing with lower power levels. * - * IEEE80211_RADIOTAP_DB_TX_ATTENUATION u_int16_t decibels (dB) + * IEEE80211_RADIOTAP_DB_TX_ATTENUATION uint16_t decibels (dB) * * Transmit power expressed as decibel distance from max power * set at factory calibration. 0 is max power. Monotonically * nondecreasing with lower power levels. * - * IEEE80211_RADIOTAP_DBM_TX_POWER int8_t decibels from - * one milliwatt (dBm) + * IEEE80211_RADIOTAP_DBM_TX_POWER s8 decibels from + * one milliwatt (dBm) * * Transmit power expressed as dBm (decibels from a 1 milliwatt * reference). This is the absolute power level measured at * the antenna port. * - * IEEE80211_RADIOTAP_FLAGS u_int8_t bitmap + * IEEE80211_RADIOTAP_FLAGS u8 bitmap * * Properties of transmitted and received frames. See flags * defined below. * - * IEEE80211_RADIOTAP_ANTENNA u_int8_t antenna index + * IEEE80211_RADIOTAP_ANTENNA u8 antenna index * * Unitless indication of the Rx/Tx antenna for this packet. * The first antenna is antenna 0. * - * IEEE80211_RADIOTAP_RX_FLAGS u_int16_t bitmap + * IEEE80211_RADIOTAP_RX_FLAGS uint16_t bitmap + * + * Properties of received frames. See flags defined below. * - * Properties of received frames. See flags defined below. + * IEEE80211_RADIOTAP_TX_FLAGS uint16_t bitmap * - * IEEE80211_RADIOTAP_TX_FLAGS u_int16_t bitmap + * Properties of transmitted frames. See flags defined below. * - * Properties of transmitted frames. See flags defined below. + * IEEE80211_RADIOTAP_RTS_RETRIES u8 data * - * IEEE80211_RADIOTAP_RTS_RETRIES u_int8_t data + * Number of rts retries a transmitted frame used. * - * Number of rts retries a transmitted frame used. - * - * IEEE80211_RADIOTAP_DATA_RETRIES u_int8_t data + * IEEE80211_RADIOTAP_DATA_RETRIES u8 data * - * Number of unicast retries a transmitted frame used. - * + * Number of unicast retries a transmitted frame used. + * + * IEEE80211_RADIOTAP_MCS u8, u8, u8 unitless + * + * Contains a bitmap of known fields/flags, the flags, and + * the MCS index. + * + * IEEE80211_RADIOTAP_AMPDU_STATUS u32, u16, u8, u8 unitlesss + * + * Contains the AMPDU information for the subframe. */ enum ieee80211_radiotap_type { IEEE80211_RADIOTAP_TSFT = 0, @@ -195,24 +203,25 @@ enum ieee80211_radiotap_type { IEEE80211_RADIOTAP_TX_FLAGS = 15, IEEE80211_RADIOTAP_RTS_RETRIES = 16, IEEE80211_RADIOTAP_DATA_RETRIES = 17, - IEEE80211_RADIOTAP_XCHANNEL = 18, + IEEE80211_RADIOTAP_MCS = 19, - IEEE80211_RADIOTAP_A_MPDU_STATUS = 20, - IEEE80211_RADIOTAP_VHT = 21, + IEEE80211_RADIOTAP_AMPDU_STATUS = 20, + + /* valid in every it_present bitmap, even vendor namespaces */ + IEEE80211_RADIOTAP_RADIOTAP_NAMESPACE = 29, + IEEE80211_RADIOTAP_VENDOR_NAMESPACE = 30, IEEE80211_RADIOTAP_EXT = 31 }; -#if !defined(__KERNEL__) && !defined(_KERNEL) /* Channel flags. */ -#define IEEE80211_CHAN_TURBO 0x0010 /* Turbo channel */ -#define IEEE80211_CHAN_CCK 0x0020 /* CCK channel */ -#define IEEE80211_CHAN_OFDM 0x0040 /* OFDM channel */ -#define IEEE80211_CHAN_2GHZ 0x0080 /* 2 GHz spectrum channel. */ -#define IEEE80211_CHAN_5GHZ 0x0100 /* 5 GHz spectrum channel */ -#define IEEE80211_CHAN_PASSIVE 0x0200 /* Only passive scan allowed */ +#define IEEE80211_CHAN_TURBO 0x0010 /* Turbo channel */ +#define IEEE80211_CHAN_CCK 0x0020 /* CCK channel */ +#define IEEE80211_CHAN_OFDM 0x0040 /* OFDM channel */ +#define IEEE80211_CHAN_2GHZ 0x0080 /* 2 GHz spectrum channel. */ +#define IEEE80211_CHAN_5GHZ 0x0100 /* 5 GHz spectrum channel */ +#define IEEE80211_CHAN_PASSIVE 0x0200 /* Only passive scan allowed */ #define IEEE80211_CHAN_DYN 0x0400 /* Dynamic CCK-OFDM channel */ #define IEEE80211_CHAN_GFSK 0x0800 /* GFSK channel (FHSS PHY) */ -#endif /* !defined(__KERNEL__) && !defined(_KERNEL) */ /* For IEEE80211_RADIOTAP_FLAGS */ #define IEEE80211_RADIOTAP_F_CFP 0x01 /* sent/received @@ -233,17 +242,50 @@ enum ieee80211_radiotap_type { * 802.11 header and payload * (to 32-bit boundary) */ +#define IEEE80211_RADIOTAP_F_BADFCS 0x40 /* frame failed FCS check */ + /* For IEEE80211_RADIOTAP_RX_FLAGS */ -#define IEEE80211_RADIOTAP_F_RX_BADFCS 0x0001 /* frame failed crc check */ +#define IEEE80211_RADIOTAP_F_RX_BADPLCP 0x0002 /* bad PLCP */ /* For IEEE80211_RADIOTAP_TX_FLAGS */ -#define IEEE80211_RADIOTAP_F_TX_FAIL 0x0001 /* failed due to excessive +#define IEEE80211_RADIOTAP_F_TX_FAIL 0x0001 /* failed due to excessive * retries */ -#define IEEE80211_RADIOTAP_F_TX_CTS 0x0002 /* used cts 'protection' */ -#define IEEE80211_RADIOTAP_F_TX_RTS 0x0004 /* used rts/cts handshake */ +#define IEEE80211_RADIOTAP_F_TX_CTS 0x0002 /* used cts 'protection' */ +#define IEEE80211_RADIOTAP_F_TX_RTS 0x0004 /* used rts/cts handshake */ +#define IEEE80211_RADIOTAP_F_TX_NOACK 0x0008 /* receiver will not ack */ + +/* For IEEE80211_RADIOTAP_AMPDU_STATUS */ +#define IEEE80211_RADIOTAP_AMPDU_REPORT_ZEROLEN 0x0001 +#define IEEE80211_RADIOTAP_AMPDU_IS_ZEROLEN 0x0002 +#define IEEE80211_RADIOTAP_AMPDU_LAST_KNOWN 0x0004 +#define IEEE80211_RADIOTAP_AMPDU_IS_LAST 0x0008 +#define IEEE80211_RADIOTAP_AMPDU_DELIM_CRC_ERR 0x0010 +#define IEEE80211_RADIOTAP_AMPDU_DELIM_CRC_KNOWN 0x0020 -#define IEEE80211_RADIOTAP_F_TX_NOACK 0x0008 /* Receiver will not ack */ +/* For IEEE80211_RADIOTAP_MCS */ +#define IEEE80211_RADIOTAP_MCS_HAVE_BW 0x01 +#define IEEE80211_RADIOTAP_MCS_HAVE_MCS 0x02 +#define IEEE80211_RADIOTAP_MCS_HAVE_GI 0x04 +#define IEEE80211_RADIOTAP_MCS_HAVE_FMT 0x08 +#define IEEE80211_RADIOTAP_MCS_HAVE_FEC 0x10 +#define IEEE80211_RADIOTAP_MCS_HAVE_STBC 0x20 +#define IEEE80211_RADIOTAP_MCS_HAVE_NESS 0x40 +#define IEEE80211_RADIOTAP_MCS_NESS_BIT1 0x80 +#define IEEE80211_RADIOTAP_MCS_BW_MASK 0x03 +#define IEEE80211_RADIOTAP_MCS_BW_20 0 +#define IEEE80211_RADIOTAP_MCS_BW_40 1 +#define IEEE80211_RADIOTAP_MCS_BW_20L 2 +#define IEEE80211_RADIOTAP_MCS_BW_20U 3 +#define IEEE80211_RADIOTAP_MCS_SGI 0x04 +#define IEEE80211_RADIOTAP_MCS_FMT_GF 0x08 +#define IEEE80211_RADIOTAP_MCS_FEC_LDPC 0x10 +#define IEEE80211_RADIOTAP_MCS_STBC_MASK 0x60 +#define IEEE80211_RADIOTAP_MCS_STBC_SHIFT 5 +#define IEEE80211_RADIOTAP_MCS_STBC_1 1 +#define IEEE80211_RADIOTAP_MCS_STBC_2 2 +#define IEEE80211_RADIOTAP_MCS_STBC_3 3 +#define IEEE80211_RADIOTAP_MCS_NESS_BIT0 0x80 -#endif /* _NET_IF_IEEE80211RADIOTAP_H_ */ +#endif /* IEEE80211_RADIOTAP_H */ diff --git a/include/clicknet/wifi.h b/include/clicknet/wifi.h index c6ca3136e9..87f6b05527 100644 --- a/include/clicknet/wifi.h +++ b/include/clicknet/wifi.h @@ -10,49 +10,49 @@ #ifndef _CLICKNET_WIFI_H_ #define _CLICKNET_WIFI_H_ - #define WIFI_EXTRA_MAGIC 0x7492001 enum { - WIFI_EXTRA_TX = (1<<0), /* packet transmission */ - WIFI_EXTRA_TX_FAIL = (1<<1), /* transmission failed */ + WIFI_EXTRA_TX = (1<<0), /* packet transmission */ + WIFI_EXTRA_TX_FAIL = (1<<1), /* transmission failed */ WIFI_EXTRA_TX_USED_ALT_RATE = (1<<2), /* used alternate bitrate */ - WIFI_EXTRA_RX_ERR = (1<<3), /* failed crc check */ - WIFI_EXTRA_RX_MORE = (1<<4), /* first part of a fragmented skb */ - WIFI_EXTRA_NO_SEQ = (1<<5), - WIFI_EXTRA_NO_TXF = (1<<6), - WIFI_EXTRA_DO_RTS_CTS = (1<<7), - WIFI_EXTRA_DO_CTS = (1<<8), - WIFI_EXTRA_TX_NOACK = (1<<9) + WIFI_EXTRA_RX_ERR = (1<<3), /* failed crc check */ + WIFI_EXTRA_RX_MORE = (1<<4), /* first part of a fragmented skb */ + WIFI_EXTRA_NO_SEQ = (1<<5), + WIFI_EXTRA_NO_TXF = (1<<6), + WIFI_EXTRA_DO_RTS_CTS = (1<<7), + WIFI_EXTRA_DO_CTS = (1<<8), + WIFI_EXTRA_MCS = (1<<9), + WIFI_EXTRA_MCS_SGI = (1<<10), + WIFI_EXTRA_MCS_BW_40 = (1<<11), + WIFI_EXTRA_TX_NOACK = (1<<12) }; - - struct click_wifi_extra { uint32_t magic; - uint32_t flags; + + uint64_t tsft; + + uint16_t flags; + uint16_t channel; uint8_t rssi; uint8_t silence; uint8_t power; uint8_t pad; - uint8_t rate; /* bitrate in Mbps*2 */ - uint8_t rate1; /* bitrate in Mbps*2 */ - uint8_t rate2; /* bitrate in Mbps*2 */ - uint8_t rate3; /* bitrate in Mbps*2 */ + int8_t rate; /* bitrate in Mbps*2 or MCS index */ + int8_t rate1; /* bitrate in Mbps*2 or MCS index */ + int8_t rate2; /* bitrate in Mbps*2 or MCS index */ + int8_t rate3; /* bitrate in Mbps*2 or MCS index */ uint8_t max_tries; uint8_t max_tries1; uint8_t max_tries2; uint8_t max_tries3; - uint8_t virt_col; - uint8_t retries; - uint16_t len; } CLICK_SIZE_PACKED_ATTRIBUTE; - /* * generic definitions for IEEE 802.11 frames */ @@ -67,7 +67,22 @@ struct click_wifi { uint16_t i_seq; } CLICK_SIZE_PACKED_ATTRIBUTE; -#define WIFI_FC0_VERSION_MASK 0x03 +struct click_qos_control { + uint16_t qos_control; +} CLICK_SIZE_PACKED_ATTRIBUTE; + +#define WIFI_QOS_CONTROL_QOS_TID_MASK 0x000F +#define WIFI_QOS_CONTROL_QOS_TID_SHIFT 0 +#define WIFI_QOS_CONTROL_QOS_EOSP_MASK 0x0010 +#define WIFI_QOS_CONTROL_QOS_EOSP_SHIFT 4 +#define WIFI_QOS_CONTROL_ACK_POLICY_MASK 0x0060 +#define WIFI_QOS_CONTROL_ACK_POLICY_SHIFT 5 +#define WIFI_QOS_CONTROL_QOS_AMSDU_PRESENT_MASK 0x0080 +#define WIFI_QOS_CONTROL_QOS_AMSDU_PRESENT_SHIFT 7 +#define WIFI_QOS_CONTROL_QOS_STUFF_MASK 0xFF00 +#define WIFI_QOS_CONTROL_QOS_STUFF_SHIFT 8 + +#define WIFI_FC0_VERSION_MASK 0x03 #define WIFI_FC0_VERSION_0 0x00 #define WIFI_FC0_TYPE_MASK 0x0c #define WIFI_FC0_TYPE_MGT 0x00 @@ -87,6 +102,7 @@ struct click_wifi { #define WIFI_FC0_SUBTYPE_DISASSOC 0xa0 #define WIFI_FC0_SUBTYPE_AUTH 0xb0 #define WIFI_FC0_SUBTYPE_DEAUTH 0xc0 +#define WIFI_FC0_SUBTYPE_ACTION 0xd0 /* for TYPE_CTL */ #define WIFI_FC0_SUBTYPE_PS_POLL 0xa0 #define WIFI_FC0_SUBTYPE_RTS 0xb0 @@ -106,7 +122,6 @@ struct click_wifi { #define WIFI_FC0_SUBTYPE_QOS 0x80 #define WIFI_FC0_SUBTYPE_QOS_NULL 0xc0 - #define WIFI_FC1_DIR_MASK 0x03 #define WIFI_FC1_DIR_NODS 0x00 /* STA->STA */ #define WIFI_FC1_DIR_TODS 0x01 /* STA->AP */ @@ -146,8 +161,6 @@ typedef uint8_t * wifi_mgt_beacon_t; #define WIFI_CAPINFO_CF_POLLREQ 0x08 #define WIFI_CAPINFO_PRIVACY 0x10 - - #define WIFI_MAX_RETRIES 11 #define WIFI_QOS_HAS_SEQ(wh) \ @@ -155,7 +168,6 @@ typedef uint8_t * wifi_mgt_beacon_t; (WIFI_FC0_TYPE_MASK | WIFI_FC0_SUBTYPE_QOS)) == \ (WIFI_FC0_TYPE_DATA | WIFI_FC0_SUBTYPE_QOS)) - /* * Management information elements */ @@ -194,20 +206,168 @@ struct wifi_information { } challenge; }; +/* + * HT Capabilities Element + */ + +#define WIFI_HT_CAPS_TYPE 45 +#define WIFI_HT_CAPS_SIZE 26 + +#define WIFI_HT_CI_LDPC 0x01 +#define WIFI_HT_CI_CHANNEL_WIDTH_SET 0x02 + +#define WIFI_HT_CI_SM_PS_MASK 0x0C +#define WIFI_HT_CI_SM_PS_SHIFT 2 +#define WIFI_HT_CI_SM_PS_STATIC 0x00 +#define WIFI_HT_CI_SM_PS_DYNAMIC 0x01 +#define WIFI_HT_CI_SM_PS_DISABLED 0x03 + +#define WIFI_HT_CI_HT_GF 0x10 +#define WIFI_HT_CI_SGI_20 0x20 +#define WIFI_HT_CI_SGI_40 0x40 + +#define WIFI_HT_CI_TX_STBC 0x80 + +#define WIFI_HT_CI_RX_STBC_MASK 0x300 +#define WIFI_HT_CI_RX_STBC_SHIFT 8 +#define WIFI_HT_CI_RX_STBC_NO 0x00 +#define WIFI_HT_CI_RX_STBC_1SS 0x01 +#define WIFI_HT_CI_RX_STBC_2SS 0x02 +#define WIFI_HT_CI_RX_STBC_3SS 0x03 + +#define WIFI_HT_CI_HT_DBACK 0x400 +#define WIFI_HT_CI_HT_MAX_AMSDU 0x800 +#define WIFI_HT_CI_HT_DSSS_CCK 0x1000 +#define WIFI_HT_CI_HT_PSMP 0x2000 +#define WIFI_HT_CI_HT_INTOLLERANT 0x4000 +#define WIFI_HT_CI_HT_LSIG_TXOP 0x8000 + +#define WIFI_HT_CI_AMDU_PARAMS_MAX_AMPDU_LENGTH_MASK 0x03 +#define WIFI_HT_CI_AMDU_PARAMS_MAX_AMPDU_LENGTH_SHIFT 0 + +#define WIFI_HT_CI_AMDU_PARAMS_MPDU_DENSITY_MASK 0x1C +#define WIFI_HT_CI_AMDU_PARAMS_MPDU_DENSITY_SHIFT 2 + +#define WIFI_HT_CI_SM12_TX_MCS_SET_DEFINED 0x1 +#define WIFI_HT_CI_SM12_TX_RX_MCS_SET_NOT_EQUAL 0x2 +#define WIFI_HT_CI_SM12_TX_MAX_SS_MASK 0x10 +#define WIFI_HT_CI_SM12_TX_MAX_SS_SHIFT 2 +#define WIFI_HT_CI_SM12_TX_UEQM 0x016 + +struct click_wifi_ht_caps { + uint8_t type; + uint8_t len; + uint16_t ht_caps_info; + uint8_t ampdu_params; + uint8_t rx_supported_mcs[16]; + uint16_t ht_extended_caps; + uint32_t transmit_beam_forming; + uint8_t antenna_selection; +} CLICK_SIZE_PACKED_ATTRIBUTE; + +/* + * HT Info Element + */ + +#define WIFI_HT_INFO_TYPE 61 +#define WIFI_HT_INFO_SIZE 22 + +struct click_wifi_ht_info { + uint8_t type; + uint8_t len; + uint8_t primary_channel; + uint8_t ht_info_1_3; + uint16_t ht_info_2_3; + uint16_t ht_info_3_3; + uint8_t rx_supported_mcs[16]; +} CLICK_SIZE_PACKED_ATTRIBUTE; + + +/* + * WMM/WME Information Element + */ + +/* WMM/WME Elements */ +#define WIFI_WME_LEN 24 +#define WIFI_WME_OUI "\x00\x50\xf2" +#define WIFI_WME_OUI_LEN 3 +#define WIFI_WME_TYPE 0x02 +#define WIFI_WME_SUBTYPE 1 +#define WIFI_WME_VERSION 1 + +/* EDCA categories */ +#define AC_BE 0 +#define AC_BK 1 +#define AC_VI 2 +#define AC_VO 3 +#define AC_COUNT 4 + +/* EDCA Values */ +#define WIFI_WME_AC_BE_ACI 0x03 +#define WIFI_WME_AC_BE_ECW 0xA4 +#define WIFI_WME_AC_BE_TXOP 0x0000 + +#define WIFI_WME_AC_BK_ACI 0x27 +#define WIFI_WME_AC_BK_ECW 0xA4 +#define WIFI_WME_AC_BK_TXOP 0x0000 + +#define WIFI_WME_AC_VI_ACI 0x42 +#define WIFI_WME_AC_VI_ECW 0x43 +#define WIFI_WME_AC_VI_TXOP 0x005E + +#define WIFI_WME_AC_VO_ACI 0x62 +#define WIFI_WME_AC_VO_ECW 0x32 +#define WIFI_WME_AC_VO_TXOP 0x002F + +/* WME QoS Info */ +#define WIFI_WME_APSD_MASK 0x80 +#define WIFI_WME_APSD_SHIFT 7 + +struct edca_ac_param { + uint8_t aci; + uint8_t ecw; + uint16_t txop; +} CLICK_SIZE_PACKED_ATTRIBUTE; + +/* WMM/WME Parameter Element */ +struct click_wifi_wmm { + uint8_t tag_type; + uint8_t len; + char oui[WIFI_WME_OUI_LEN]; + uint8_t type; + uint8_t subtype; + uint8_t version; + uint8_t qosinfo; + uint8_t reserved; + edca_ac_param acparam[AC_COUNT]; +} CLICK_SIZE_PACKED_ATTRIBUTE; + +/* + * AMSDU subframe header + */ +struct click_wifi_amsdu_subframe_header { + uint8_t da[6]; /* 0-5 Ethernet destination address */ + uint8_t sa[6]; /* 6-11 Ethernet source address */ + uint16_t len; /* A-MSDU Length without including header and padding */ +} CLICK_SIZE_PACKED_ATTRIBUTE; + #define WIFI_RATES_MAXSIZE 15 #define WIFI_NWID_MAXSIZE 32 enum { - WIFI_ELEMID_SSID = 0, - WIFI_ELEMID_RATES = 1, + WIFI_ELEMID_SSID = 0, + WIFI_ELEMID_RATES = 1, WIFI_ELEMID_FHPARMS = 2, WIFI_ELEMID_DSPARMS = 3, WIFI_ELEMID_CFPARMS = 4, - WIFI_ELEMID_TIM = 5, + WIFI_ELEMID_TIM = 5, WIFI_ELEMID_IBSSPARMS = 6, WIFI_ELEMID_CHALLENGE = 16, - WIFI_ELEMID_ERP = 42, + WIFI_ELEMID_CSA = 37, + WIFI_ELEMID_ERP = 42, + WIFI_ELEMID_HTCAPS = 45, WIFI_ELEMID_XRATES = 50, + WIFI_ELEMID_HTINFO = 61, WIFI_ELEMID_VENDOR = 221 }; /* @@ -274,7 +434,6 @@ typedef uint8_t * wifi_mgt_auth_t; #define WIFI_STATUS_RATES 23 #define WIFI_STATUS_SHORTSLOT_REQUIRED 25 - #define WIFI_WEP_KEYLEN 5 /* 40bit */ #define WIFI_WEP_IVLEN 3 /* 24bit */ #define WIFI_WEP_KIDLEN 1 /* 1 octet */ @@ -283,7 +442,6 @@ typedef uint8_t * wifi_mgt_auth_t; #define WIFI_WEP_HEADERSIZE (WIFI_WEP_IVLEN + WIFI_WEP_KIDLEN) - #define WIFI_WEP_NOSUP -1 #define WIFI_WEP_OFF 0 #define WIFI_WEP_ON 1 @@ -310,7 +468,6 @@ typedef uint8_t * wifi_mgt_auth_t; #define WIFI_SEQ_SEQ_MASK 0xfff0 #define WIFI_SEQ_SEQ_SHIFT 4 - /* * 802.11 protocol crypto-related definitions. */ @@ -325,11 +482,6 @@ typedef uint8_t * wifi_mgt_auth_t; #define WIFI_MIN(a, b) ((a) < (b) ? (a) : (b)) #endif - - -/* ARPHRD_IEEE80211_PRISM uses a bloated version of Prism2 RX frame header - * (from linux-wlan-ng) */ - /* * For packet capture, define the same physical layer packet header * structure as used in the wlan-ng driver @@ -354,7 +506,6 @@ enum { P80211ENUM_truth_false = 0x00 }; - typedef struct { uint32_t did; uint16_t status; @@ -379,27 +530,34 @@ typedef struct { p80211item_uint32_t frmlen; } wlan_ng_prism2_header; - #define LWNG_CAP_DID_BASE (4 | (1 << 6)) /* section 4, group 1 */ #define LWNG_CAPHDR_VERSION 0x80211001 #define WIFI_SLOT_B 20 #define WIFI_DIFS_B 50 #define WIFI_SIFS_B 10 -#define WIFI_ACK_B 304 +#define WIFI_ACK_B 304 // 192 + (14 * 8) / 1 #define WIFI_PLCP_HEADER_LONG_B 192 -#define WIFI_PLCP_HEADER_SHORT_B 192 +#define WIFI_PLCP_HEADER_SHORT_B 96 #define WIFI_SLOT_A 9 -#define WIFI_DIFS_A 28 -#define WIFI_SIFS_A 9 -#define WIFI_ACK_A 30 -#define WIFI_PLCP_HEADER_A 20 +#define WIFI_DIFS_A 34 +#define WIFI_SIFS_A 16 +#define WIFI_ACK_A 44 // 25 + (14 * 8) / 6 +#define WIFI_PLCP_HEADER_A 25 +#define WIFI_SLOT_N 9 +#define WIFI_DIFS_N 28 +#define WIFI_SIFS_N 10 +#define WIFI_ACK_N 50 // 33 + (14 * 8) / 6.5 +#define WIFI_PLCP_HEADER_N 33 #define is_b_rate(b) ((b == 2) || (b == 4) || (b == 11) || (b == 22)) -#define WIFI_CW_MIN 31 +#define WIFI_CW_MIN_B 31 +#define WIFI_CW_MAX_B 1023 + +#define WIFI_CW_MIN 15 #define WIFI_CW_MAX 1023 // 6-byte LLC header (last byte is terminating NUL) diff --git a/lib/radiotap.c b/lib/radiotap.c new file mode 100644 index 0000000000..092d941043 --- /dev/null +++ b/lib/radiotap.c @@ -0,0 +1,394 @@ +/* + * Radiotap parser + * + * Copyright 2007 Andy Green + * Copyright 2009 Johannes Berg + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See COPYING for more details. + */ +#include +#include +#include + +/* function prototypes and related defs are in radiotap_iter.h */ + +static const struct radiotap_align_size rtap_namespace_sizes[] = { + [IEEE80211_RADIOTAP_TSFT] = { .align = 8, .size = 8, }, + [IEEE80211_RADIOTAP_FLAGS] = { .align = 1, .size = 1, }, + [IEEE80211_RADIOTAP_RATE] = { .align = 1, .size = 1, }, + [IEEE80211_RADIOTAP_CHANNEL] = { .align = 2, .size = 4, }, + [IEEE80211_RADIOTAP_FHSS] = { .align = 2, .size = 2, }, + [IEEE80211_RADIOTAP_DBM_ANTSIGNAL] = { .align = 1, .size = 1, }, + [IEEE80211_RADIOTAP_DBM_ANTNOISE] = { .align = 1, .size = 1, }, + [IEEE80211_RADIOTAP_LOCK_QUALITY] = { .align = 2, .size = 2, }, + [IEEE80211_RADIOTAP_TX_ATTENUATION] = { .align = 2, .size = 2, }, + [IEEE80211_RADIOTAP_DB_TX_ATTENUATION] = { .align = 2, .size = 2, }, + [IEEE80211_RADIOTAP_DBM_TX_POWER] = { .align = 1, .size = 1, }, + [IEEE80211_RADIOTAP_ANTENNA] = { .align = 1, .size = 1, }, + [IEEE80211_RADIOTAP_DB_ANTSIGNAL] = { .align = 1, .size = 1, }, + [IEEE80211_RADIOTAP_DB_ANTNOISE] = { .align = 1, .size = 1, }, + [IEEE80211_RADIOTAP_RX_FLAGS] = { .align = 2, .size = 2, }, + [IEEE80211_RADIOTAP_TX_FLAGS] = { .align = 2, .size = 2, }, + [IEEE80211_RADIOTAP_RTS_RETRIES] = { .align = 1, .size = 1, }, + [IEEE80211_RADIOTAP_DATA_RETRIES] = { .align = 1, .size = 1, }, + [IEEE80211_RADIOTAP_MCS] = { .align = 1, .size = 3, }, + [IEEE80211_RADIOTAP_AMPDU_STATUS] = { .align = 4, .size = 8, }, + /* + * add more here as they are defined in radiotap.h + */ +}; + +static const struct ieee80211_radiotap_namespace radiotap_ns = { + .n_bits = sizeof(rtap_namespace_sizes) / sizeof(rtap_namespace_sizes[0]), + .align_size = rtap_namespace_sizes, +}; + +/** + * ieee80211_radiotap_iterator_init - radiotap parser iterator initialization + * @iterator: radiotap_iterator to initialize + * @radiotap_header: radiotap header to parse + * @max_length: total length we can parse into (eg, whole packet length) + * + * Returns: 0 or a negative error code if there is a problem. + * + * This function initializes an opaque iterator struct which can then + * be passed to ieee80211_radiotap_iterator_next() to visit every radiotap + * argument which is present in the header. It knows about extended + * present headers and handles them. + * + * How to use: + * call __ieee80211_radiotap_iterator_init() to init a semi-opaque iterator + * struct ieee80211_radiotap_iterator (no need to init the struct beforehand) + * checking for a good 0 return code. Then loop calling + * __ieee80211_radiotap_iterator_next()... it returns either 0, + * -ENOENT if there are no more args to parse, or -EINVAL if there is a problem. + * The iterator's @this_arg member points to the start of the argument + * associated with the current argument index that is present, which can be + * found in the iterator's @this_arg_index member. This arg index corresponds + * to the IEEE80211_RADIOTAP_... defines. + * + * Radiotap header length: + * You can find the CPU-endian total radiotap header length in + * iterator->max_length after executing ieee80211_radiotap_iterator_init() + * successfully. + * + * Alignment Gotcha: + * You must take care when dereferencing iterator.this_arg + * for multibyte types... the pointer is not aligned. Use + * get_unaligned((type *)iterator.this_arg) to dereference + * iterator.this_arg for type "type" safely on all arches. + * + * Example code: parse.c + */ + +int ieee80211_radiotap_iterator_init( + struct ieee80211_radiotap_iterator *iterator, + struct ieee80211_radiotap_header *radiotap_header, + int max_length, const struct ieee80211_radiotap_vendor_namespaces *vns) +{ + /* must at least have the radiotap header */ + if (max_length < (int)sizeof(struct ieee80211_radiotap_header)) + return -EINVAL; + + /* Linux only supports version 0 radiotap format */ + if (radiotap_header->it_version) + return -EINVAL; + + /* sanity check for allowed length and radiotap length field */ + if (max_length < get_unaligned_le16(&radiotap_header->it_len)) + return -EINVAL; + + iterator->_rtheader = radiotap_header; + iterator->_max_length = get_unaligned_le16(&radiotap_header->it_len); + iterator->_arg_index = 0; + iterator->_bitmap_shifter = get_unaligned_le32(&radiotap_header->it_present); + iterator->_arg = (uint8_t *)radiotap_header + sizeof(*radiotap_header); + iterator->_reset_on_ext = 0; + iterator->_next_bitmap = &radiotap_header->it_present; + iterator->_next_bitmap++; + iterator->_vns = vns; + iterator->current_namespace = &radiotap_ns; + iterator->is_radiotap_ns = 1; +#ifdef RADIOTAP_SUPPORT_OVERRIDES + iterator->n_overrides = 0; + iterator->overrides = NULL; +#endif + + /* find payload start allowing for extended bitmap(s) */ + + if (iterator->_bitmap_shifter & (1<_arg - + (unsigned long)iterator->_rtheader + sizeof(uint32_t) > + (unsigned long)iterator->_max_length) + return -EINVAL; + while (get_unaligned_le32(iterator->_arg) & + (1 << IEEE80211_RADIOTAP_EXT)) { + iterator->_arg += sizeof(uint32_t); + + /* + * check for insanity where the present bitmaps + * keep claiming to extend up to or even beyond the + * stated radiotap header length + */ + + if ((unsigned long)iterator->_arg - + (unsigned long)iterator->_rtheader + + sizeof(uint32_t) > + (unsigned long)iterator->_max_length) + return -EINVAL; + } + + iterator->_arg += sizeof(uint32_t); + + /* + * no need to check again for blowing past stated radiotap + * header length, because ieee80211_radiotap_iterator_next + * checks it before it is dereferenced + */ + } + + iterator->this_arg = iterator->_arg; + + /* we are all initialized happily */ + + return 0; +} + +static void find_ns(struct ieee80211_radiotap_iterator *iterator, + uint32_t oui, uint8_t subns) +{ + int i; + + iterator->current_namespace = NULL; + + if (!iterator->_vns) + return; + + for (i = 0; i < iterator->_vns->n_ns; i++) { + if (iterator->_vns->ns[i].oui != oui) + continue; + if (iterator->_vns->ns[i].subns != subns) + continue; + + iterator->current_namespace = &iterator->_vns->ns[i]; + break; + } +} + +#ifdef RADIOTAP_SUPPORT_OVERRIDES +static int find_override(struct ieee80211_radiotap_iterator *iterator, + int *align, int *size) +{ + int i; + + if (!iterator->overrides) + return 0; + + for (i = 0; i < iterator->n_overrides; i++) { + if (iterator->_arg_index == iterator->overrides[i].field) { + *align = iterator->overrides[i].align; + *size = iterator->overrides[i].size; + if (!*align) /* erroneous override */ + return 0; + return 1; + } + } + + return 0; +} +#endif + + +/** + * ieee80211_radiotap_iterator_next - return next radiotap parser iterator arg + * @iterator: radiotap_iterator to move to next arg (if any) + * + * Returns: 0 if there is an argument to handle, + * -ENOENT if there are no more args or -EINVAL + * if there is something else wrong. + * + * This function provides the next radiotap arg index (IEEE80211_RADIOTAP_*) + * in @this_arg_index and sets @this_arg to point to the + * payload for the field. It takes care of alignment handling and extended + * present fields. @this_arg can be changed by the caller (eg, + * incremented to move inside a compound argument like + * IEEE80211_RADIOTAP_CHANNEL). The args pointed to are in + * little-endian format whatever the endianess of your CPU. + * + * Alignment Gotcha: + * You must take care when dereferencing iterator.this_arg + * for multibyte types... the pointer is not aligned. Use + * get_unaligned((type *)iterator.this_arg) to dereference + * iterator.this_arg for type "type" safely on all arches. + */ + +int ieee80211_radiotap_iterator_next( + struct ieee80211_radiotap_iterator *iterator) +{ + while (1) { + int hit = 0; + int pad, align, size, subns; + uint32_t oui; + + /* if no more EXT bits, that's it */ + if ((iterator->_arg_index % 32) == IEEE80211_RADIOTAP_EXT && + !(iterator->_bitmap_shifter & 1)) + return -ENOENT; + + if (!(iterator->_bitmap_shifter & 1)) + goto next_entry; /* arg not present */ + + /* get alignment/size of data */ + switch (iterator->_arg_index % 32) { + case IEEE80211_RADIOTAP_RADIOTAP_NAMESPACE: + case IEEE80211_RADIOTAP_EXT: + align = 1; + size = 0; + break; + case IEEE80211_RADIOTAP_VENDOR_NAMESPACE: + align = 2; + size = 6; + break; + default: +#ifdef RADIOTAP_SUPPORT_OVERRIDES + if (find_override(iterator, &align, &size)) { + /* all set */ + } else +#endif + if (!iterator->current_namespace || + iterator->_arg_index >= iterator->current_namespace->n_bits) { + if (iterator->current_namespace == &radiotap_ns) + return -ENOENT; + align = 0; + } else { + align = iterator->current_namespace->align_size[iterator->_arg_index].align; + size = iterator->current_namespace->align_size[iterator->_arg_index].size; + } + if (!align) { + /* skip all subsequent data */ + iterator->_arg = iterator->_next_ns_data; + /* give up on this namespace */ + iterator->current_namespace = NULL; + goto next_entry; + } + break; + } + + /* + * arg is present, account for alignment padding + * + * Note that these alignments are relative to the start + * of the radiotap header. There is no guarantee + * that the radiotap header itself is aligned on any + * kind of boundary. + * + * The above is why get_unaligned() is used to dereference + * multibyte elements from the radiotap area. + */ + + pad = ((unsigned long)iterator->_arg - + (unsigned long)iterator->_rtheader) & (align - 1); + + if (pad) + iterator->_arg += align - pad; + + if (iterator->_arg_index % 32 == IEEE80211_RADIOTAP_VENDOR_NAMESPACE) { + int vnslen; + + if ((unsigned long)iterator->_arg + size - + (unsigned long)iterator->_rtheader > + (unsigned long)iterator->_max_length) + return -EINVAL; + + oui = (*iterator->_arg << 16) | + (*(iterator->_arg + 1) << 8) | + *(iterator->_arg + 2); + subns = *(iterator->_arg + 3); + + find_ns(iterator, oui, subns); + + vnslen = get_unaligned_le16(iterator->_arg + 4); + iterator->_next_ns_data = iterator->_arg + size + vnslen; + if (!iterator->current_namespace) + size += vnslen; + } + + /* + * this is what we will return to user, but we need to + * move on first so next call has something fresh to test + */ + iterator->this_arg_index = iterator->_arg_index; + iterator->this_arg = iterator->_arg; + iterator->this_arg_size = size; + + /* internally move on the size of this arg */ + iterator->_arg += size; + + /* + * check for insanity where we are given a bitmap that + * claims to have more arg content than the length of the + * radiotap section. We will normally end up equalling this + * max_length on the last arg, never exceeding it. + */ + + if ((unsigned long)iterator->_arg - + (unsigned long)iterator->_rtheader > + (unsigned long)iterator->_max_length) + return -EINVAL; + + /* these special ones are valid in each bitmap word */ + switch (iterator->_arg_index % 32) { + case IEEE80211_RADIOTAP_VENDOR_NAMESPACE: + iterator->_reset_on_ext = 1; + + iterator->is_radiotap_ns = 0; + /* + * If parser didn't register this vendor + * namespace with us, allow it to show it + * as 'raw. Do do that, set argument index + * to vendor namespace. + */ + iterator->this_arg_index = + IEEE80211_RADIOTAP_VENDOR_NAMESPACE; + if (!iterator->current_namespace) + hit = 1; + goto next_entry; + case IEEE80211_RADIOTAP_RADIOTAP_NAMESPACE: + iterator->_reset_on_ext = 1; + iterator->current_namespace = &radiotap_ns; + iterator->is_radiotap_ns = 1; + goto next_entry; + case IEEE80211_RADIOTAP_EXT: + /* + * bit 31 was set, there is more + * -- move to next u32 bitmap + */ + iterator->_bitmap_shifter = + get_unaligned_le32(iterator->_next_bitmap); + iterator->_next_bitmap++; + if (iterator->_reset_on_ext) + iterator->_arg_index = 0; + else + iterator->_arg_index++; + iterator->_reset_on_ext = 0; + break; + default: + /* we've got a hit! */ + hit = 1; + next_entry: + iterator->_bitmap_shifter >>= 1; + iterator->_arg_index++; + } + + /* if we found a valid arg earlier, return it now */ + if (hit) + return 0; + } +}