madwifi plugin: Plugin for detailed information from the MadWifi driver.
authorOndrej Zajicek <santiago@crfreenet.org>
Tue, 11 Aug 2009 09:44:28 +0000 (11:44 +0200)
committerFlorian Forster <sifnfors@informatik.stud.uni-erlangen.de>
Tue, 11 Aug 2009 09:51:18 +0000 (11:51 +0200)
Hello

After some time i managed to make a new version of Madwifi plugin. The
main change is that it is possible to finely tune the set of monitored
statistics and just the most important statistics are monitored by
default. Also the number of new data types is reduced (by using type
instances).

Signed-off-by: Florian Forster <octo@verplant.org>
configure.in
src/Makefile.am
src/madwifi.c [new file with mode: 0644]
src/madwifi.h [new file with mode: 0644]
src/types.db

index 65e296a..af790d1 100644 (file)
@@ -3434,6 +3434,7 @@ plugin_ipvs="no"
 plugin_irq="no"
 plugin_libvirt="no"
 plugin_load="no"
+plugin_madwifi="no"
 plugin_memory="no"
 plugin_multimeter="no"
 plugin_nfs="no"
@@ -3465,6 +3466,7 @@ then
        plugin_interface="yes"
        plugin_irq="yes"
        plugin_load="yes"
+       plugin_madwifi="yes"
        plugin_memory="yes"
        plugin_nfs="yes"
        plugin_fscache="yes"
@@ -3717,6 +3719,7 @@ AC_PLUGIN([java],        [$with_java],         [Embed the Java Virtual Machine])
 AC_PLUGIN([libvirt],     [$plugin_libvirt],    [Virtual machine statistics])
 AC_PLUGIN([load],        [$plugin_load],       [System load])
 AC_PLUGIN([logfile],     [yes],                [File logging plugin])
+AC_PLUGIN([madwifi],     [$plugin_madwifi],    [Madwifi wireless statistics])
 AC_PLUGIN([match_empty_counter], [yes],        [The empty counter match])
 AC_PLUGIN([match_regex], [yes],                [The regex match])
 AC_PLUGIN([match_timediff], [yes],             [The timediff match])
@@ -4014,6 +4017,7 @@ Configuration:
     libvirt . . . . . . . $enable_libvirt
     load  . . . . . . . . $enable_load
     logfile . . . . . . . $enable_logfile
+    madwifi . . . . . . . $enable_madwifi
     match_empty_counter . $enable_match_empty_counter
     match_regex . . . . . $enable_match_regex
     match_timediff  . . . $enable_match_timediff
index d7d92c4..5e0b028 100644 (file)
@@ -453,6 +453,14 @@ collectd_LDADD += "-dlopen" logfile.la
 collectd_DEPENDENCIES += logfile.la
 endif
 
+if BUILD_PLUGIN_MADWIFI
+pkglib_LTLIBRARIES += madwifi.la
+madwifi_la_SOURCES = madwifi.c
+madwifi_la_LDFLAGS = -module -avoid-version
+collectd_LDADD += "-dlopen" madwifi.la
+collectd_DEPENDENCIES += madwifi.la
+endif
+
 if BUILD_PLUGIN_MATCH_EMPTY_COUNTER
 pkglib_LTLIBRARIES += match_empty_counter.la
 match_empty_counter_la_SOURCES = match_empty_counter.c
diff --git a/src/madwifi.c b/src/madwifi.c
new file mode 100644 (file)
index 0000000..478341e
--- /dev/null
@@ -0,0 +1,851 @@
+/**
+ * collectd - src/madwifi.c
+ * Copyright (C) 2009  Ondrej 'SanTiago' Zajicek
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; only version 2 of the License is applicable.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ *
+ * Author:
+ *   Ondrej 'SanTiago' Zajicek <santiago@crfreenet.org>
+ *
+ *   based on some code from interfaces.c (collectd) and Madwifi driver
+ **/
+
+
+/**
+ * There are several data streams provided by Madwifi plugin, some are 
+ * connected to network interface, some are connected to each node
+ * associated to that interface. Nodes represents other sides in
+ * wireless communication, for example on network interface in AP mode,
+ * there is one node for each associated station. Node data streams
+ * contain MAC address of the node as the last part  of the type_instance
+ * field.
+ *
+ * Inteface data streams:
+ *     ath_nodes       The number of associated nodes
+ *     ath_stat        Device statistic counters
+ *
+ * Node data streams:
+ *     node_octets     RX and TX data count (octets/bytes)
+ *     node_rssi       Received RSSI of the node
+ *     node_tx_rate    Reported TX rate to that node
+ *     node_stat       Node statistic counters
+ *
+ * Both statistic counters have type instances for each counter returned
+ * by Madwifi. See madwifi.h for content of ieee80211_nodestats, 
+ * ieee80211_stats and ath_stats structures. Type instances use the same
+ * name as fields in these structures (like ns_rx_dup). Some fields are
+ * not reported, because they are not counters (like ns_tx_deauth_code
+ * or ast_tx_rssi). Fields ns_rx_bytes and ns_tx_bytes are reported as
+ * node_octets data stream instead of type instance of node_stat.
+ * Statistics are not logged when they are zero.
+ * 
+ * There are two sets of these counters - the first 'WatchList' is a
+ * set of counters that are individually logged. The second 'MiscList'
+ * is a set of counters that are summed together and the sum is logged.
+ * By default, the most important statistics are in the WatchList and 
+ * many error statistics are in MiscList. There are also many statistics
+ * that are not in any of these sets, so they are not monitored by default.
+ * It is possible to alter these lists using configuration options:
+ *
+ *     WatchAdd X      Adds X to WachList
+ *     WatchRemove X   Removes X from WachList
+ *     WatchSet All    Adds all statistics to WatchList
+ *     WatchSet None   Removes all statistics from WachList
+ *
+ * There are also Misc* variants fo these options, they modifies MiscList
+ * instead of WatchList.
+ *
+ * Example:
+ *
+ *     WatchSet None
+ *     WatchAdd node_octets
+ *     WatchAdd node_rssi
+ *     WatchAdd is_rx_acl
+ *     WatchAdd is_scan_active
+ *
+ * That causes that just the four mentioned data streams are logged.
+ *
+ *
+ * By default, madwifi plugin enumerates network interfaces using /sys
+ * filesystem. Configuration option DisableSysfs can change this to use
+ * /proc filesystem (which is useful for example when running on Linux
+ * 2.4). But without /sys filesystem, Madwifi plugin cannot check whether
+ * given interface is madwifi interface and there are private ioctls used,
+ * which may do something completely different on non-madwifi devices.
+ * Therefore, option DisableSysfs should be used together with option
+ * Interface, to limit found interfaces to madwifi interfaces only.
+ **/
+
+
+#include "collectd.h"
+#include "common.h"
+#include "plugin.h"
+#include "configfile.h"
+#include "utils_ignorelist.h"
+
+#include <dirent.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+
+#if !KERNEL_LINUX
+# error "No applicable input method."
+#endif
+
+#include <linux/wireless.h>
+#include "madwifi.h"
+
+
+
+struct stat_spec {
+       uint16_t flags;
+       uint16_t offset;
+       const char *name;
+};
+
+
+#define OFFSETOF(s, i) ((size_t)&((s *)0)->i)
+
+#define FLAG(i)  (((uint32_t) 1) << ((i) % 32))
+
+#define SPC_STAT 0
+#define NOD_STAT 1
+#define IFA_STAT 2
+#define ATH_STAT 3
+#define SRC_MASK 3
+
+/* By default, the item is disabled */
+#define D 0
+
+/* By default, the item is logged */
+#define LOG 4
+
+/* By default, the item is summed with other such items and logged together */
+#define SU 8
+
+#define SS_STAT(flags, name) { flags | SPC_STAT, 0, #name }
+#define NS_STAT(flags, name) { flags | NOD_STAT, OFFSETOF(struct ieee80211_nodestats, name), #name }
+#define IS_STAT(flags, name) { flags | IFA_STAT, OFFSETOF(struct ieee80211_stats, name), #name }
+#define AS_STAT(flags, name) { flags | ATH_STAT, OFFSETOF(struct ath_stats, name), #name }
+
+
+/*
+ * (Module-)Global variables
+ */
+
+/* Indices of special stats in specs array */
+#define STAT_NODE_OCTETS       0
+#define STAT_NODE_RSSI         1
+#define STAT_NODE_TX_RATE      2
+#define STAT_ATH_NODES         3
+#define STAT_NS_RX_BEACONS     4
+#define STAT_AST_ANT_RX                5
+#define STAT_AST_ANT_TX                6
+
+static struct stat_spec specs[] = {
+
+/* Special statistics */
+SS_STAT(LOG, node_octets),             /* rx and tx data count (bytes) */
+SS_STAT(LOG, node_rssi),               /* received RSSI of the node */
+SS_STAT(LOG, node_tx_rate),            /* used tx rate to the node */
+SS_STAT(LOG, ath_nodes),               /* the number of associated nodes */
+SS_STAT(D,   ns_rx_beacons),           /* rx beacon frames */
+SS_STAT(LOG, ast_ant_rx),              /* rx frames with antenna */
+SS_STAT(LOG, ast_ant_tx),              /* tx frames with antenna */
+
+/* Node statistics */
+NS_STAT(LOG, ns_rx_data),              /* rx data frames */
+NS_STAT(LOG, ns_rx_mgmt),              /* rx management frames */
+NS_STAT(LOG, ns_rx_ctrl),              /* rx control frames */
+NS_STAT(D,   ns_rx_ucast),             /* rx unicast frames */
+NS_STAT(D,   ns_rx_mcast),             /* rx multi/broadcast frames */
+NS_STAT(D,   ns_rx_proberesp),         /* rx probe response frames */
+NS_STAT(LOG, ns_rx_dup),               /* rx discard because it's a dup */
+NS_STAT(SU,  ns_rx_noprivacy),         /* rx w/ wep but privacy off */
+NS_STAT(SU,  ns_rx_wepfail),           /* rx wep processing failed */
+NS_STAT(SU,  ns_rx_demicfail),         /* rx demic failed */
+NS_STAT(SU,  ns_rx_decap),             /* rx decapsulation failed */
+NS_STAT(SU,  ns_rx_defrag),            /* rx defragmentation failed */
+NS_STAT(D,   ns_rx_disassoc),          /* rx disassociation */
+NS_STAT(D,   ns_rx_deauth),            /* rx deauthentication */
+NS_STAT(SU,  ns_rx_decryptcrc),                /* rx decrypt failed on crc */
+NS_STAT(SU,  ns_rx_unauth),            /* rx on unauthorized port */
+NS_STAT(SU,  ns_rx_unencrypted),       /* rx unecrypted w/ privacy */
+NS_STAT(LOG, ns_tx_data),              /* tx data frames */
+NS_STAT(LOG, ns_tx_mgmt),              /* tx management frames */
+NS_STAT(D,   ns_tx_ucast),             /* tx unicast frames */
+NS_STAT(D,   ns_tx_mcast),             /* tx multi/broadcast frames */
+NS_STAT(D,   ns_tx_probereq),          /* tx probe request frames */
+NS_STAT(D,   ns_tx_uapsd),             /* tx on uapsd queue */
+NS_STAT(SU,  ns_tx_novlantag),         /* tx discard due to no tag */
+NS_STAT(SU,  ns_tx_vlanmismatch),      /* tx discard due to of bad tag */
+NS_STAT(D,   ns_tx_eosplost),          /* uapsd EOSP retried out */
+NS_STAT(D,   ns_ps_discard),           /* ps discard due to of age */
+NS_STAT(D,   ns_uapsd_triggers),       /* uapsd triggers */
+NS_STAT(LOG, ns_tx_assoc),             /* [re]associations */
+NS_STAT(LOG, ns_tx_auth),              /* [re]authentications */
+NS_STAT(D,   ns_tx_deauth),            /* deauthentications */
+NS_STAT(D,   ns_tx_disassoc),          /* disassociations */
+NS_STAT(D,   ns_psq_drops),            /* power save queue drops */
+
+/* Iface statistics */
+IS_STAT(SU,  is_rx_badversion),                /* rx frame with bad version */
+IS_STAT(SU,  is_rx_tooshort),          /* rx frame too short */
+IS_STAT(LOG, is_rx_wrongbss),          /* rx from wrong bssid */
+IS_STAT(LOG, is_rx_dup),               /* rx discard due to it's a dup */
+IS_STAT(SU,  is_rx_wrongdir),          /* rx w/ wrong direction */
+IS_STAT(D,   is_rx_mcastecho),         /* rx discard due to of mcast echo */
+IS_STAT(SU,  is_rx_notassoc),          /* rx discard due to sta !assoc */
+IS_STAT(SU,  is_rx_noprivacy),         /* rx w/ wep but privacy off */
+IS_STAT(SU,  is_rx_unencrypted),       /* rx w/o wep and privacy on */
+IS_STAT(SU,  is_rx_wepfail),           /* rx wep processing failed */
+IS_STAT(SU,  is_rx_decap),             /* rx decapsulation failed */
+IS_STAT(D,   is_rx_mgtdiscard),                /* rx discard mgt frames */
+IS_STAT(D,   is_rx_ctl),               /* rx discard ctrl frames */
+IS_STAT(D,   is_rx_beacon),            /* rx beacon frames */
+IS_STAT(D,   is_rx_rstoobig),          /* rx rate set truncated */
+IS_STAT(SU,  is_rx_elem_missing),      /* rx required element missing*/
+IS_STAT(SU,  is_rx_elem_toobig),       /* rx element too big */
+IS_STAT(SU,  is_rx_elem_toosmall),     /* rx element too small */
+IS_STAT(LOG, is_rx_elem_unknown),      /* rx element unknown */
+IS_STAT(SU,  is_rx_badchan),           /* rx frame w/ invalid chan */
+IS_STAT(SU,  is_rx_chanmismatch),      /* rx frame chan mismatch */
+IS_STAT(SU,  is_rx_nodealloc),         /* rx frame dropped */
+IS_STAT(LOG, is_rx_ssidmismatch),      /* rx frame ssid mismatch  */
+IS_STAT(SU,  is_rx_auth_unsupported),  /* rx w/ unsupported auth alg */
+IS_STAT(SU,  is_rx_auth_fail),         /* rx sta auth failure */
+IS_STAT(SU,  is_rx_auth_countermeasures),/* rx auth discard due to CM */
+IS_STAT(SU,  is_rx_assoc_bss),         /* rx assoc from wrong bssid */
+IS_STAT(SU,  is_rx_assoc_notauth),     /* rx assoc w/o auth */
+IS_STAT(SU,  is_rx_assoc_capmismatch), /* rx assoc w/ cap mismatch */
+IS_STAT(SU,  is_rx_assoc_norate),      /* rx assoc w/ no rate match */
+IS_STAT(SU,  is_rx_assoc_badwpaie),    /* rx assoc w/ bad WPA IE */
+IS_STAT(LOG, is_rx_deauth),            /* rx deauthentication */
+IS_STAT(LOG, is_rx_disassoc),          /* rx disassociation */
+IS_STAT(SU,  is_rx_badsubtype),                /* rx frame w/ unknown subtype*/
+IS_STAT(SU,  is_rx_nobuf),             /* rx failed for lack of buf */
+IS_STAT(SU,  is_rx_decryptcrc),                /* rx decrypt failed on crc */
+IS_STAT(D,   is_rx_ahdemo_mgt),                /* rx discard ahdemo mgt frame*/
+IS_STAT(SU,  is_rx_bad_auth),          /* rx bad auth request */
+IS_STAT(SU,  is_rx_unauth),            /* rx on unauthorized port */
+IS_STAT(SU,  is_rx_badkeyid),          /* rx w/ incorrect keyid */
+IS_STAT(D,   is_rx_ccmpreplay),                /* rx seq# violation (CCMP), */
+IS_STAT(D,   is_rx_ccmpformat),                /* rx format bad (CCMP), */
+IS_STAT(D,   is_rx_ccmpmic),           /* rx MIC check failed (CCMP), */
+IS_STAT(D,   is_rx_tkipreplay),                /* rx seq# violation (TKIP), */
+IS_STAT(D,   is_rx_tkipformat),                /* rx format bad (TKIP), */
+IS_STAT(D,   is_rx_tkipmic),           /* rx MIC check failed (TKIP), */
+IS_STAT(D,   is_rx_tkipicv),           /* rx ICV check failed (TKIP), */
+IS_STAT(D,   is_rx_badcipher),         /* rx failed due to of key type */
+IS_STAT(D,   is_rx_nocipherctx),       /* rx failed due to key !setup */
+IS_STAT(D,   is_rx_acl),               /* rx discard due to of acl policy */
+IS_STAT(D,   is_rx_ffcnt),             /* rx fast frames */
+IS_STAT(SU,  is_rx_badathtnl),         /* driver key alloc failed */
+IS_STAT(SU,  is_tx_nobuf),             /* tx failed for lack of buf */
+IS_STAT(SU,  is_tx_nonode),            /* tx failed for no node */
+IS_STAT(SU,  is_tx_unknownmgt),                /* tx of unknown mgt frame */
+IS_STAT(SU,  is_tx_badcipher),         /* tx failed due to of key type */
+IS_STAT(SU,  is_tx_nodefkey),          /* tx failed due to no defkey */
+IS_STAT(SU,  is_tx_noheadroom),                /* tx failed due to no space */
+IS_STAT(D,   is_tx_ffokcnt),           /* tx fast frames sent success */
+IS_STAT(D,   is_tx_fferrcnt),          /* tx fast frames sent success */
+IS_STAT(D,   is_scan_active),          /* active scans started */
+IS_STAT(D,   is_scan_passive),         /* passive scans started */
+IS_STAT(D,   is_node_timeout),         /* nodes timed out inactivity */
+IS_STAT(D,   is_crypto_nomem),         /* no memory for crypto ctx */
+IS_STAT(D,   is_crypto_tkip),          /* tkip crypto done in s/w */
+IS_STAT(D,   is_crypto_tkipenmic),     /* tkip en-MIC done in s/w */
+IS_STAT(D,   is_crypto_tkipdemic),     /* tkip de-MIC done in s/w */
+IS_STAT(D,   is_crypto_tkipcm),                /* tkip counter measures */
+IS_STAT(D,   is_crypto_ccmp),          /* ccmp crypto done in s/w */
+IS_STAT(D,   is_crypto_wep),           /* wep crypto done in s/w */
+IS_STAT(D,   is_crypto_setkey_cipher), /* cipher rejected key */
+IS_STAT(D,   is_crypto_setkey_nokey),  /* no key index for setkey */
+IS_STAT(D,   is_crypto_delkey),                /* driver key delete failed */
+IS_STAT(D,   is_crypto_badcipher),     /* unknown cipher */
+IS_STAT(D,   is_crypto_nocipher),      /* cipher not available */
+IS_STAT(D,   is_crypto_attachfail),    /* cipher attach failed */
+IS_STAT(D,   is_crypto_swfallback),    /* cipher fallback to s/w */
+IS_STAT(D,   is_crypto_keyfail),       /* driver key alloc failed */
+IS_STAT(D,   is_crypto_enmicfail),     /* en-MIC failed */
+IS_STAT(SU,  is_ibss_capmismatch),     /* merge failed-cap mismatch */
+IS_STAT(SU,  is_ibss_norate),          /* merge failed-rate mismatch */
+IS_STAT(D,   is_ps_unassoc),           /* ps-poll for unassoc. sta */
+IS_STAT(D,   is_ps_badaid),            /* ps-poll w/ incorrect aid */
+IS_STAT(D,   is_ps_qempty),            /* ps-poll w/ nothing to send */
+
+/* Atheros statistics */
+AS_STAT(D,   ast_watchdog),            /* device reset by watchdog */
+AS_STAT(D,   ast_hardware),            /* fatal hardware error interrupts */
+AS_STAT(D,   ast_bmiss),               /* beacon miss interrupts */
+AS_STAT(D,   ast_rxorn),               /* rx overrun interrupts */
+AS_STAT(D,   ast_rxeol),               /* rx eol interrupts */
+AS_STAT(D,   ast_txurn),               /* tx underrun interrupts */
+AS_STAT(D,   ast_mib),                 /* mib interrupts */
+AS_STAT(D,   ast_tx_packets),          /* packet sent on the interface */
+AS_STAT(D,   ast_tx_mgmt),             /* management frames transmitted */
+AS_STAT(LOG, ast_tx_discard),          /* frames discarded prior to assoc */
+AS_STAT(SU,  ast_tx_invalid),          /* frames discarded due to is device gone */
+AS_STAT(SU,  ast_tx_qstop),            /* tx queue stopped because it's full */
+AS_STAT(SU,  ast_tx_encap),            /* tx encapsulation failed */
+AS_STAT(SU,  ast_tx_nonode),           /* tx failed due to of no node */
+AS_STAT(SU,  ast_tx_nobuf),            /* tx failed due to of no tx buffer (data), */
+AS_STAT(SU,  ast_tx_nobufmgt),         /* tx failed due to of no tx buffer (mgmt),*/
+AS_STAT(LOG, ast_tx_xretries),         /* tx failed due to of too many retries */
+AS_STAT(SU,  ast_tx_fifoerr),          /* tx failed due to of FIFO underrun */
+AS_STAT(SU,  ast_tx_filtered),         /* tx failed due to xmit filtered */
+AS_STAT(LOG, ast_tx_shortretry),       /* tx on-chip retries (short), */
+AS_STAT(LOG, ast_tx_longretry),                /* tx on-chip retries (long), */
+AS_STAT(SU,  ast_tx_badrate),          /* tx failed due to of bogus xmit rate */
+AS_STAT(D,   ast_tx_noack),            /* tx frames with no ack marked */
+AS_STAT(D,   ast_tx_rts),              /* tx frames with rts enabled */
+AS_STAT(D,   ast_tx_cts),              /* tx frames with cts enabled */
+AS_STAT(D,   ast_tx_shortpre),         /* tx frames with short preamble */
+AS_STAT(LOG, ast_tx_altrate),          /* tx frames with alternate rate */
+AS_STAT(D,   ast_tx_protect),          /* tx frames with protection */
+AS_STAT(SU,  ast_rx_orn),              /* rx failed due to of desc overrun */
+AS_STAT(LOG, ast_rx_crcerr),           /* rx failed due to of bad CRC */
+AS_STAT(SU,  ast_rx_fifoerr),          /* rx failed due to of FIFO overrun */
+AS_STAT(SU,  ast_rx_badcrypt),         /* rx failed due to of decryption */
+AS_STAT(SU,  ast_rx_badmic),           /* rx failed due to of MIC failure */
+AS_STAT(LOG, ast_rx_phyerr),           /* rx PHY error summary count */
+AS_STAT(SU,  ast_rx_tooshort),         /* rx discarded due to frame too short */
+AS_STAT(SU,  ast_rx_toobig),           /* rx discarded due to frame too large */
+AS_STAT(SU,  ast_rx_nobuf),            /* rx setup failed due to of no skbuff */
+AS_STAT(D,   ast_rx_packets),          /* packet recv on the interface */
+AS_STAT(D,   ast_rx_mgt),              /* management frames received */
+AS_STAT(D,   ast_rx_ctl),              /* control frames received */
+AS_STAT(D,   ast_be_xmit),             /* beacons transmitted */
+AS_STAT(SU,  ast_be_nobuf),            /* no skbuff available for beacon */
+AS_STAT(D,   ast_per_cal),             /* periodic calibration calls */
+AS_STAT(D,   ast_per_calfail),         /* periodic calibration failed */
+AS_STAT(D,   ast_per_rfgain),          /* periodic calibration rfgain reset */
+AS_STAT(D,   ast_rate_calls),          /* rate control checks */
+AS_STAT(D,   ast_rate_raise),          /* rate control raised xmit rate */
+AS_STAT(D,   ast_rate_drop),           /* rate control dropped xmit rate */
+AS_STAT(D,   ast_ant_defswitch),       /* rx/default antenna switches */
+AS_STAT(D,   ast_ant_txswitch)         /* tx antenna switches */
+};
+
+/* Bounds between SS, NS, IS and AS stats in stats array */
+static int bounds[4];
+
+#define WL_LEN 6
+/* Bitmasks for logged and error items */
+static uint32_t watch_items[WL_LEN];
+static uint32_t misc_items[WL_LEN];
+
+
+static const char *config_keys[] =
+{
+       "Interface",
+       "IgnoreSelected",
+       "DisableSysfs",
+       "WatchAdd",
+       "WatchRemove",
+       "WatchSet",
+       "MiscAdd",
+       "MiscRemove",
+       "MiscSet",
+       NULL
+};
+static int config_keys_num = 9;
+
+static ignorelist_t *ignorelist;
+
+static int use_sysfs = 1;
+static int init_state = 0;
+
+static inline int item_watched(int i)
+{
+       return watch_items[i / 32] & FLAG (i);
+}
+
+static inline int item_summed(int i)
+{
+       return misc_items[i / 32] & FLAG (i);
+}
+
+static inline void watchlist_add (uint32_t *wl, int item)
+{
+       wl[item / 32] |= FLAG (item);
+}
+
+static inline void watchlist_remove (uint32_t *wl, int item)
+{
+       wl[item / 32] &= ~FLAG (item);
+}
+
+static inline void watchlist_set (uint32_t *wl, uint32_t val)
+{
+       int i;
+       for (i = 0; i < WL_LEN; i++)
+               wl[i] = val;
+}
+
+/* This is horribly inefficient, but it is called only during configuration */
+static int watchitem_find (const char *name)
+{
+       int max = sizeof (specs) / sizeof (struct stat_spec);
+       int i;
+
+       for (i = 0; i < max; i++)
+               if (strcasecmp (name, specs[i].name) == 0)
+                       return i;
+
+       return -1;
+}
+
+
+/* Collectd hooks */
+
+/* We need init function called before madwifi_config */
+
+static int madwifi_real_init (void)
+{
+       int max = sizeof (specs) / sizeof (struct stat_spec);
+       int i;
+
+       for (i = 0; i < 4; i++)
+               bounds[i] = 0;
+
+       watchlist_set(watch_items, 0);
+       watchlist_set(misc_items, 0);
+
+       for (i = 0; i < max; i++)
+       {
+               bounds[specs[i].flags & SRC_MASK] = i;
+
+               if (specs[i].flags & LOG)
+                       watch_items[i / 32] |= FLAG (i);
+
+               if (specs[i].flags & SU)
+                       misc_items[i / 32] |= FLAG (i);
+       }
+
+       for (i = 0; i < 4; i++)
+               bounds[i]++;
+
+       return (0);
+}
+
+static int bool_arg (const char *value)
+{
+       return ((strcasecmp (value, "True") == 0)
+               || (strcasecmp (value, "Yes") == 0)
+               || (strcasecmp (value, "On") == 0));
+}
+
+static int madwifi_config (const char *key, const char *value)
+{
+       if (init_state != 1)
+               madwifi_real_init();
+       init_state = 1;
+
+       if (ignorelist == NULL)
+               ignorelist = ignorelist_create (/* invert = */ 1);
+
+       if (strcasecmp (key, "Interface") == 0)
+               ignorelist_add (ignorelist, value);
+
+       else if (strcasecmp (key, "IgnoreSelected") == 0)
+               ignorelist_set_invert (ignorelist, ! bool_arg(value));
+
+       else if (strcasecmp (key, "DisableSysfs") == 0)
+               use_sysfs = ! bool_arg(value);
+
+       else if (strcasecmp (key, "WatchSet") == 0)
+       {
+               if (strcasecmp (value, "All") == 0)
+                       watchlist_set (watch_items, 0xFFFFFFFF);
+               else if (strcasecmp (value, "None") == 0)
+                       watchlist_set (watch_items, 0);
+               else return -1;
+       }
+
+       else if (strcasecmp (key, "WatchAdd") == 0)
+       {
+               int id = watchitem_find (value);
+
+               if (id < 0)
+                       return (-1);
+               else
+                       watchlist_add (watch_items, id);
+       }
+
+       else if (strcasecmp (key, "WatchRemove") == 0)
+       {
+               int id = watchitem_find (value);
+
+               if (id < 0)
+                       return (-1);
+               else
+                       watchlist_remove (watch_items, id);
+       }
+
+       else if (strcasecmp (key, "MiscSet") == 0)
+       {
+               if (strcasecmp (value, "All") == 0)
+                       watchlist_set (misc_items, 0xFFFFFFFF);
+               else if (strcasecmp (value, "None") == 0)
+                       watchlist_set (misc_items, 0);
+               else return -1;
+       }
+
+       else if (strcasecmp (key, "MiscAdd") == 0)
+       {
+               int id = watchitem_find (value);
+
+               if (id < 0)
+                       return (-1);
+               else
+                       watchlist_add (misc_items, id);
+       }
+
+       else if (strcasecmp (key, "MiscRemove") == 0)
+       {
+               int id = watchitem_find (value);
+
+               if (id < 0)
+                       return (-1);
+               else
+                       watchlist_remove (misc_items, id);
+       }
+
+       else
+               return (-1);
+
+       return (0);
+}
+
+
+static void submit (const char *dev, const char *type, const char *ti1,
+                       const char *ti2, value_t *val, int len)
+{
+       value_list_t vl = VALUE_LIST_INIT;
+
+       vl.values = val;
+       vl.values_len = len;
+       sstrncpy (vl.host, hostname_g, sizeof (vl.host));
+       sstrncpy (vl.plugin, "madwifi", sizeof (vl.plugin));
+       sstrncpy (vl.plugin_instance, dev, sizeof (vl.plugin_instance));
+       sstrncpy (vl.type, type, sizeof (vl.type));
+
+       if (ti1 && !ti2)
+               sstrncpy (vl.type_instance, ti1, sizeof (vl.type_instance));
+
+       if (ti1 && ti2)
+               ssnprintf (vl.type_instance, sizeof (vl.type_instance), "%s-%s", ti1, ti2);
+
+       plugin_dispatch_values (&vl);
+}
+
+static void submit_counter (const char *dev, const char *type, const char *ti1,
+                               const char *ti2, counter_t val)
+{
+       value_t item;
+       item.counter = val;
+       submit (dev, type, ti1, ti2, &item, 1);
+}
+
+static void submit_counter2 (const char *dev, const char *type, const char *ti1,
+                               const char *ti2, counter_t val1, counter_t val2)
+{
+       value_t items[2];
+       items[0].counter = val1;
+       items[1].counter = val2;
+       submit (dev, type, ti1, ti2, items, 2);
+}
+
+static void submit_gauge (const char *dev, const char *type, const char *ti1,
+                               const char *ti2, gauge_t val)
+{
+       value_t item;
+       item.gauge = val;
+       submit (dev, type, ti1, ti2, &item, 1);
+}
+
+static void submit_antx (const char *dev, const char *name, u_int32_t *vals)
+{
+       char no[2] = {0, 0};
+       int i;
+
+       for (i = 0; i < 8; i++)
+               if (vals[i])
+               {
+                       no[0] = '0' + i;
+                       submit_counter (dev, "ath_stat", name, no, vals[i]);
+               }
+}
+
+static inline void
+macaddr_to_str (char *buf, size_t bufsize, const uint8_t mac[IEEE80211_ADDR_LEN])
+{
+       snprintf (buf, bufsize, "%02x:%02x:%02x:%02x:%02x:%02x",
+               mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
+}
+
+static void
+process_stat_struct (int which, const void *ptr, const char *dev, const char *mac,
+                        const char *type_name, const char *misc_name)
+{
+       uint32_t misc = 0;
+       int i;
+
+       for (i = bounds[which - 1]; i < bounds[which]; i++)
+       {
+               uint32_t val = *(uint32_t *)(((char *) ptr) + specs[i].offset) ;
+
+               if (item_watched (i) && (val != 0))
+                       submit_counter (dev, type_name, specs[i].name, mac, val);
+
+               if (item_summed (i))
+                       misc += val;
+       }
+       
+       if (misc != 0)
+               submit_counter (dev, type_name, misc_name, mac, misc);
+
+}
+
+static void
+process_athstats (int sk, const char *dev)
+{
+       struct ifreq ifr;
+       struct ath_stats stats;
+
+       strncpy (ifr.ifr_name, dev, sizeof (ifr.ifr_name));
+       ifr.ifr_data = (void *) &stats;
+       if (ioctl (sk, SIOCGATHSTATS, &ifr) < 0)
+               return;
+
+       /* These stats are handled as a special case, because they are
+          eight values each */
+
+       if (item_watched (STAT_AST_ANT_RX))
+               submit_antx (dev, "ast_ant_rx", stats.ast_ant_rx);
+
+       if (item_watched (STAT_AST_ANT_TX))
+               submit_antx (dev, "ast_ant_tx", stats.ast_ant_tx);
+
+       /* All other ath statistics */
+       process_stat_struct (ATH_STAT, &stats, dev, NULL, "ath_stat", "ast_misc");
+}
+
+static void
+process_80211stats (int sk, const char *dev)
+{
+       struct ifreq ifr;
+       struct ieee80211_stats stats;
+       strncpy (ifr.ifr_name, dev, sizeof (ifr.ifr_name));
+       ifr.ifr_data = (void *) &stats;
+       if (ioctl(sk, SIOCG80211STATS, &ifr) < 0)
+               return;
+
+       process_stat_struct (IFA_STAT, &stats, dev, NULL, "ath_stat", "is_misc");
+}
+
+
+static void
+process_station (int sk, const char *dev, struct ieee80211req_sta_info *si)
+{
+       struct iwreq iwr;
+       static char mac[DATA_MAX_NAME_LEN];
+       struct ieee80211req_sta_stats stats;
+       const struct ieee80211_nodestats *ns = &stats.is_stats;
+
+       macaddr_to_str (mac, sizeof (mac), si->isi_macaddr);
+
+       if (item_watched (STAT_NODE_TX_RATE))
+               submit_gauge (dev, "node_tx_rate", mac, NULL,
+                       (si->isi_rates[si->isi_txrate] & IEEE80211_RATE_VAL) / 2);
+
+       if (item_watched (STAT_NODE_RSSI))
+               submit_gauge (dev, "node_rssi", mac, NULL, si->isi_rssi);
+
+       memset (&iwr, 0, sizeof (iwr));
+       strncpy(iwr.ifr_name, dev, sizeof (iwr.ifr_name));
+       iwr.u.data.pointer = (void *) &stats;
+       iwr.u.data.length = sizeof (stats);
+       memcpy(stats.is_u.macaddr, si->isi_macaddr, IEEE80211_ADDR_LEN);
+       if (ioctl(sk, IEEE80211_IOCTL_STA_STATS, &iwr) < 0)
+               return;
+
+       /* These two stats are handled as a special case as they are
+          a pair of 64bit values */
+       if (item_watched (STAT_NODE_OCTETS))
+               submit_counter2 (dev, "node_octets", mac, NULL,
+                       ns->ns_rx_bytes, ns->ns_tx_bytes);
+
+       /* This stat is handled as a special case, because it is stored
+          as uin64_t, but we will ignore upper half */
+       if (item_watched (STAT_NS_RX_BEACONS))
+               submit_counter (dev, "node_stat", "ns_rx_beacons", mac,
+                       (ns->ns_rx_beacons & 0xFFFFFFFF));
+
+       /* All other node statistics */
+       process_stat_struct (NOD_STAT, ns, dev, mac, "node_stat", "ns_misc");
+}
+
+static void
+process_stations (int sk, const char *dev)
+{
+       uint8_t buf[24*1024];
+       struct iwreq iwr;
+       uint8_t *cp;
+       int len, nodes;
+
+       memset (&iwr, 0, sizeof (iwr));
+       strncpy (iwr.ifr_name, dev, sizeof (iwr.ifr_name));
+       iwr.u.data.pointer = (void *) buf;
+       iwr.u.data.length = sizeof (buf);
+       if (ioctl (sk, IEEE80211_IOCTL_STA_INFO, &iwr) < 0)
+               return;
+
+       len = iwr.u.data.length;
+
+       cp = buf;
+       nodes = 0;
+       while (len >= sizeof (struct ieee80211req_sta_info))
+       {
+               struct ieee80211req_sta_info *si = (void *) cp;
+               process_station(sk, dev, si);
+               cp += si->isi_len;
+               len -= si->isi_len;
+               nodes++;
+       }
+
+       if (item_watched (STAT_ATH_NODES))
+               submit_gauge (dev, "ath_nodes", NULL, NULL, nodes);
+}
+
+static void
+process_device (int sk, const char *dev)
+{
+       process_athstats (sk, dev);
+       process_80211stats (sk, dev);
+       process_stations (sk, dev);
+}
+
+static int
+check_devname (const char *dev)
+{
+       char buf[256];
+       char buf2[256];
+       int i;
+
+       if (dev[0] == '.')
+               return 0;
+       
+       ssnprintf (buf, sizeof (buf), "/sys/class/net/%s/device/driver", dev);
+       buf[sizeof (buf) - 1] = 0;
+
+       i = readlink (buf, buf2, sizeof (buf2) - 1);
+       if (i < 0)
+               return 0;
+       buf2[i] = 0;
+
+       return (strstr (buf2, "/drivers/ath_") != NULL);
+}
+
+static int
+sysfs_iterate(int sk)
+{
+       struct dirent *de;
+
+       DIR *nets = opendir ("/sys/class/net/");
+       if (nets == NULL)
+       {
+               WARNING ("madwifi plugin: opening /sys/class/net failed");
+               return (-1);
+       }
+
+       while ((de = readdir (nets)))
+               if (check_devname (de->d_name) &&
+                   (ignorelist_match (ignorelist, de->d_name) == 0))
+                       process_device (sk, de->d_name);
+
+       closedir(nets);
+
+       return 0;
+}
+
+static int
+procfs_iterate(int sk)
+{
+       char buffer[1024];
+       char *device, *dummy;
+       FILE *fh;
+       
+       if ((fh = fopen ("/proc/net/dev", "r")) == NULL)
+       {
+               WARNING ("madwifi plugin: opening /proc/net/dev failed");
+               return (-1);
+       }
+
+       while (fgets (buffer, 1024, fh) != NULL)
+       {
+               if (!(dummy = strchr(buffer, ':')))
+                       continue;
+               dummy[0] = '\0';
+
+               device = buffer;
+               while (device[0] == ' ')
+                       device++;
+
+               if (device[0] == '\0')
+                       continue;
+
+               if (ignorelist_match (ignorelist, device) == 0)
+                       process_device (sk, device);
+       }
+
+       fclose(fh);
+       return 0;
+}
+
+static int madwifi_read (void)
+{
+       if (init_state == 0)
+               madwifi_real_init();
+       init_state = 2;
+
+       int sk = socket(AF_INET, SOCK_DGRAM, 0);
+       if (sk < 0)
+               return (-1);
+
+       int rv;
+
+/* procfs iteration is not safe because it does not check whether given
+   interface is madwifi interface and there are private ioctls used, which
+   may do something completely different on non-madwifi devices.   
+   Therefore, it is not used unless explicitly enabled (and should be used
+   together with ignorelist). */
+
+       if (use_sysfs)
+               rv = sysfs_iterate(sk);
+       else
+               rv = procfs_iterate(sk);
+
+       close(sk);
+
+       return rv;
+}
+
+void module_register (void)
+{
+       plugin_register_config ("madwifi", madwifi_config,
+                       config_keys, config_keys_num);
+
+       plugin_register_read ("madwifi", madwifi_read);
+}
diff --git a/src/madwifi.h b/src/madwifi.h
new file mode 100644 (file)
index 0000000..d6a5e35
--- /dev/null
@@ -0,0 +1,307 @@
+/**
+ * This file is compiled from several Madwifi header files.
+ * Original copyright is:
+ *
+ * Copyright (c) 2001 Atsushi Onoe
+ * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef MADWIFI_H
+#define MADWIFI_H
+
+#define        IEEE80211_ADDR_LEN              6               /* size of 802.11 address */
+#define        IEEE80211_RATE_VAL              0x7f
+#define        IEEE80211_RATE_SIZE             8               /* 802.11 standard */
+#define        IEEE80211_RATE_MAXSIZE          15              /* max rates we'll handle */
+
+
+/*
+ * Per/node (station) statistics available when operating as an AP.
+ */
+struct ieee80211_nodestats {
+       u_int32_t ns_rx_data;           /* rx data frames */
+       u_int32_t ns_rx_mgmt;           /* rx management frames */
+       u_int32_t ns_rx_ctrl;           /* rx control frames */
+       u_int32_t ns_rx_ucast;          /* rx unicast frames */
+       u_int32_t ns_rx_mcast;          /* rx multi/broadcast frames */
+       u_int64_t ns_rx_bytes;          /* rx data count (bytes) */
+       u_int64_t ns_rx_beacons;        /* rx beacon frames */
+       u_int32_t ns_rx_proberesp;      /* rx probe response frames */
+
+       u_int32_t ns_rx_dup;            /* rx discard because it's a dup */
+       u_int32_t ns_rx_noprivacy;      /* rx w/ wep but privacy off */
+       u_int32_t ns_rx_wepfail;        /* rx wep processing failed */
+       u_int32_t ns_rx_demicfail;      /* rx demic failed */
+       u_int32_t ns_rx_decap;          /* rx decapsulation failed */
+       u_int32_t ns_rx_defrag;         /* rx defragmentation failed */
+       u_int32_t ns_rx_disassoc;       /* rx disassociation */
+       u_int32_t ns_rx_deauth;         /* rx deauthentication */
+       u_int32_t ns_rx_decryptcrc;     /* rx decrypt failed on crc */
+       u_int32_t ns_rx_unauth;         /* rx on unauthorized port */
+       u_int32_t ns_rx_unencrypted;    /* rx unecrypted w/ privacy */
+
+       u_int32_t ns_tx_data;           /* tx data frames */
+       u_int32_t ns_tx_mgmt;           /* tx management frames */
+       u_int32_t ns_tx_ucast;          /* tx unicast frames */
+       u_int32_t ns_tx_mcast;          /* tx multi/broadcast frames */
+       u_int64_t ns_tx_bytes;          /* tx data count (bytes) */
+       u_int32_t ns_tx_probereq;       /* tx probe request frames */
+       u_int32_t ns_tx_uapsd;          /* tx on uapsd queue */
+
+       u_int32_t ns_tx_novlantag;      /* tx discard due to no tag */
+       u_int32_t ns_tx_vlanmismatch;   /* tx discard due to of bad tag */
+
+       u_int32_t ns_tx_eosplost;       /* uapsd EOSP retried out */
+
+       u_int32_t ns_ps_discard;        /* ps discard due to of age */
+
+       u_int32_t ns_uapsd_triggers;    /* uapsd triggers */
+
+       /* MIB-related state */
+       u_int32_t ns_tx_assoc;          /* [re]associations */
+       u_int32_t ns_tx_assoc_fail;     /* [re]association failures */
+       u_int32_t ns_tx_auth;           /* [re]authentications */
+       u_int32_t ns_tx_auth_fail;      /* [re]authentication failures*/
+       u_int32_t ns_tx_deauth;         /* deauthentications */
+       u_int32_t ns_tx_deauth_code;    /* last deauth reason */
+       u_int32_t ns_tx_disassoc;       /* disassociations */
+       u_int32_t ns_tx_disassoc_code;  /* last disassociation reason */
+       u_int32_t ns_psq_drops;         /* power save queue drops */
+};
+
+/*
+ * Summary statistics.
+ */
+struct ieee80211_stats {
+       u_int32_t is_rx_badversion;     /* rx frame with bad version */
+       u_int32_t is_rx_tooshort;       /* rx frame too short */
+       u_int32_t is_rx_wrongbss;       /* rx from wrong bssid */
+       u_int32_t is_rx_dup;            /* rx discard due to it's a dup */
+       u_int32_t is_rx_wrongdir;       /* rx w/ wrong direction */
+       u_int32_t is_rx_mcastecho;      /* rx discard due to of mcast echo */
+       u_int32_t is_rx_notassoc;       /* rx discard due to sta !assoc */
+       u_int32_t is_rx_noprivacy;      /* rx w/ wep but privacy off */
+       u_int32_t is_rx_unencrypted;    /* rx w/o wep and privacy on */
+       u_int32_t is_rx_wepfail;        /* rx wep processing failed */
+       u_int32_t is_rx_decap;          /* rx decapsulation failed */
+       u_int32_t is_rx_mgtdiscard;     /* rx discard mgt frames */
+       u_int32_t is_rx_ctl;            /* rx discard ctrl frames */
+       u_int32_t is_rx_beacon;         /* rx beacon frames */
+       u_int32_t is_rx_rstoobig;       /* rx rate set truncated */
+       u_int32_t is_rx_elem_missing;   /* rx required element missing*/
+       u_int32_t is_rx_elem_toobig;    /* rx element too big */
+       u_int32_t is_rx_elem_toosmall;  /* rx element too small */
+       u_int32_t is_rx_elem_unknown;   /* rx element unknown */
+       u_int32_t is_rx_badchan;        /* rx frame w/ invalid chan */
+       u_int32_t is_rx_chanmismatch;   /* rx frame chan mismatch */
+       u_int32_t is_rx_nodealloc;      /* rx frame dropped */
+       u_int32_t is_rx_ssidmismatch;   /* rx frame ssid mismatch  */
+       u_int32_t is_rx_auth_unsupported;/* rx w/ unsupported auth alg */
+       u_int32_t is_rx_auth_fail;      /* rx sta auth failure */
+       u_int32_t is_rx_auth_countermeasures;/* rx auth discard due to CM */
+       u_int32_t is_rx_assoc_bss;      /* rx assoc from wrong bssid */
+       u_int32_t is_rx_assoc_notauth;  /* rx assoc w/o auth */
+       u_int32_t is_rx_assoc_capmismatch;/* rx assoc w/ cap mismatch */
+       u_int32_t is_rx_assoc_norate;   /* rx assoc w/ no rate match */
+       u_int32_t is_rx_assoc_badwpaie; /* rx assoc w/ bad WPA IE */
+       u_int32_t is_rx_deauth;         /* rx deauthentication */
+       u_int32_t is_rx_disassoc;       /* rx disassociation */
+       u_int32_t is_rx_badsubtype;     /* rx frame w/ unknown subtype*/
+       u_int32_t is_rx_nobuf;          /* rx failed for lack of buf */
+       u_int32_t is_rx_decryptcrc;     /* rx decrypt failed on crc */
+       u_int32_t is_rx_ahdemo_mgt;     /* rx discard ahdemo mgt frame*/
+       u_int32_t is_rx_bad_auth;       /* rx bad auth request */
+       u_int32_t is_rx_unauth;         /* rx on unauthorized port */
+       u_int32_t is_rx_badkeyid;       /* rx w/ incorrect keyid */
+       u_int32_t is_rx_ccmpreplay;     /* rx seq# violation (CCMP) */
+       u_int32_t is_rx_ccmpformat;     /* rx format bad (CCMP) */
+       u_int32_t is_rx_ccmpmic;        /* rx MIC check failed (CCMP) */
+       u_int32_t is_rx_tkipreplay;     /* rx seq# violation (TKIP) */
+       u_int32_t is_rx_tkipformat;     /* rx format bad (TKIP) */
+       u_int32_t is_rx_tkipmic;        /* rx MIC check failed (TKIP) */
+       u_int32_t is_rx_tkipicv;        /* rx ICV check failed (TKIP) */
+       u_int32_t is_rx_badcipher;      /* rx failed due to of key type */
+       u_int32_t is_rx_nocipherctx;    /* rx failed due to key !setup */
+       u_int32_t is_rx_acl;            /* rx discard due to of acl policy */
+       u_int32_t is_rx_ffcnt;          /* rx fast frames */
+       u_int32_t is_rx_badathtnl;      /* driver key alloc failed */
+       u_int32_t is_tx_nobuf;          /* tx failed for lack of buf */
+       u_int32_t is_tx_nonode;         /* tx failed for no node */
+       u_int32_t is_tx_unknownmgt;     /* tx of unknown mgt frame */
+       u_int32_t is_tx_badcipher;      /* tx failed due to of key type */
+       u_int32_t is_tx_nodefkey;       /* tx failed due to no defkey */
+       u_int32_t is_tx_noheadroom;     /* tx failed due to no space */
+       u_int32_t is_tx_ffokcnt;        /* tx fast frames sent success */
+       u_int32_t is_tx_fferrcnt;       /* tx fast frames sent success */
+       u_int32_t is_scan_active;       /* active scans started */
+       u_int32_t is_scan_passive;      /* passive scans started */
+       u_int32_t is_node_timeout;      /* nodes timed out inactivity */
+       u_int32_t is_crypto_nomem;      /* no memory for crypto ctx */
+       u_int32_t is_crypto_tkip;       /* tkip crypto done in s/w */
+       u_int32_t is_crypto_tkipenmic;  /* tkip en-MIC done in s/w */
+       u_int32_t is_crypto_tkipdemic;  /* tkip de-MIC done in s/w */
+       u_int32_t is_crypto_tkipcm;     /* tkip counter measures */
+       u_int32_t is_crypto_ccmp;       /* ccmp crypto done in s/w */
+       u_int32_t is_crypto_wep;        /* wep crypto done in s/w */
+       u_int32_t is_crypto_setkey_cipher;/* cipher rejected key */
+       u_int32_t is_crypto_setkey_nokey;/* no key index for setkey */
+       u_int32_t is_crypto_delkey;     /* driver key delete failed */
+       u_int32_t is_crypto_badcipher;  /* unknown cipher */
+       u_int32_t is_crypto_nocipher;   /* cipher not available */
+       u_int32_t is_crypto_attachfail; /* cipher attach failed */
+       u_int32_t is_crypto_swfallback; /* cipher fallback to s/w */
+       u_int32_t is_crypto_keyfail;    /* driver key alloc failed */
+       u_int32_t is_crypto_enmicfail;  /* en-MIC failed */
+       u_int32_t is_ibss_capmismatch;  /* merge failed-cap mismatch */
+       u_int32_t is_ibss_norate;       /* merge failed-rate mismatch */
+       u_int32_t is_ps_unassoc;        /* ps-poll for unassoc. sta */
+       u_int32_t is_ps_badaid;         /* ps-poll w/ incorrect aid */
+       u_int32_t is_ps_qempty;         /* ps-poll w/ nothing to send */
+};
+
+/*
+ * Retrieve per-node statistics.
+ */
+struct ieee80211req_sta_stats {
+       union {
+               /* NB: explicitly force 64-bit alignment */
+               u_int8_t macaddr[IEEE80211_ADDR_LEN];
+               u_int64_t pad;
+       } is_u;
+       struct ieee80211_nodestats is_stats;
+};
+
+/*
+ * Station information block; the mac address is used
+ * to retrieve other data like stats, unicast key, etc.
+ */
+struct ieee80211req_sta_info {
+       u_int16_t isi_len;              /* length (mult of 4) */
+       u_int16_t isi_freq;             /* MHz */
+       u_int16_t isi_flags;            /* channel flags */
+       u_int16_t isi_state;            /* state flags */
+       u_int8_t isi_authmode;          /* authentication algorithm */
+       u_int8_t isi_rssi;
+       u_int16_t isi_capinfo;          /* capabilities */
+       u_int8_t isi_athflags;          /* Atheros capabilities */
+       u_int8_t isi_erp;               /* ERP element */
+       u_int8_t isi_macaddr[IEEE80211_ADDR_LEN];
+       u_int8_t isi_nrates;            /* negotiated rates */
+       u_int8_t isi_rates[IEEE80211_RATE_MAXSIZE];
+       u_int8_t isi_txrate;            /* index to isi_rates[] */
+       u_int16_t isi_ie_len;           /* IE length */
+       u_int16_t isi_associd;          /* assoc response */
+       u_int16_t isi_txpower;          /* current tx power */
+       u_int16_t isi_vlan;             /* vlan tag */
+       u_int16_t isi_txseqs[17];       /* seq to be transmitted */
+       u_int16_t isi_rxseqs[17];       /* seq previous for qos frames*/
+       u_int16_t isi_inact;            /* inactivity timer */
+       u_int8_t isi_uapsd;             /* UAPSD queues */
+       u_int8_t isi_opmode;            /* sta operating mode */
+
+       /* XXX frag state? */
+       /* variable length IE data */
+};
+
+
+struct ath_stats {
+       u_int32_t ast_watchdog;         /* device reset by watchdog */
+       u_int32_t ast_hardware;         /* fatal hardware error interrupts */
+       u_int32_t ast_bmiss;            /* beacon miss interrupts */
+       u_int32_t ast_rxorn;            /* rx overrun interrupts */
+       u_int32_t ast_rxeol;            /* rx eol interrupts */
+       u_int32_t ast_txurn;            /* tx underrun interrupts */
+       u_int32_t ast_mib;              /* mib interrupts */
+       u_int32_t ast_tx_packets;       /* packet sent on the interface */
+       u_int32_t ast_tx_mgmt;          /* management frames transmitted */
+       u_int32_t ast_tx_discard;       /* frames discarded prior to assoc */
+       u_int32_t ast_tx_invalid;       /* frames discarded due to is device gone */
+       u_int32_t ast_tx_qstop;         /* tx queue stopped because it's full */
+       u_int32_t ast_tx_encap;         /* tx encapsulation failed */
+       u_int32_t ast_tx_nonode;        /* tx failed due to of no node */
+       u_int32_t ast_tx_nobuf;         /* tx failed due to of no tx buffer (data) */
+       u_int32_t ast_tx_nobufmgt;      /* tx failed due to of no tx buffer (mgmt)*/
+       u_int32_t ast_tx_xretries;      /* tx failed due to of too many retries */
+       u_int32_t ast_tx_fifoerr;       /* tx failed due to of FIFO underrun */
+       u_int32_t ast_tx_filtered;      /* tx failed due to xmit filtered */
+       u_int32_t ast_tx_shortretry;    /* tx on-chip retries (short) */
+       u_int32_t ast_tx_longretry;     /* tx on-chip retries (long) */
+       u_int32_t ast_tx_badrate;       /* tx failed due to of bogus xmit rate */
+       u_int32_t ast_tx_noack;         /* tx frames with no ack marked */
+       u_int32_t ast_tx_rts;           /* tx frames with rts enabled */
+       u_int32_t ast_tx_cts;           /* tx frames with cts enabled */
+       u_int32_t ast_tx_shortpre;      /* tx frames with short preamble */
+       u_int32_t ast_tx_altrate;       /* tx frames with alternate rate */
+       u_int32_t ast_tx_protect;       /* tx frames with protection */
+       u_int32_t ast_rx_orn;           /* rx failed due to of desc overrun */
+       u_int32_t ast_rx_crcerr;        /* rx failed due to of bad CRC */
+       u_int32_t ast_rx_fifoerr;       /* rx failed due to of FIFO overrun */
+       u_int32_t ast_rx_badcrypt;      /* rx failed due to of decryption */
+       u_int32_t ast_rx_badmic;        /* rx failed due to of MIC failure */
+       u_int32_t ast_rx_phyerr;        /* rx PHY error summary count */
+       u_int32_t ast_rx_phy[32];       /* rx PHY error per-code counts */
+       u_int32_t ast_rx_tooshort;      /* rx discarded due to frame too short */
+       u_int32_t ast_rx_toobig;        /* rx discarded due to frame too large */
+       u_int32_t ast_rx_nobuf;         /* rx setup failed due to of no skbuff */
+       u_int32_t ast_rx_packets;       /* packet recv on the interface */
+       u_int32_t ast_rx_mgt;           /* management frames received */
+       u_int32_t ast_rx_ctl;           /* control frames received */
+       int8_t ast_tx_rssi;             /* tx rssi of last ack */
+       int8_t ast_rx_rssi;             /* rx rssi from histogram */
+       u_int32_t ast_be_xmit;          /* beacons transmitted */
+       u_int32_t ast_be_nobuf;         /* no skbuff available for beacon */
+       u_int32_t ast_per_cal;          /* periodic calibration calls */
+       u_int32_t ast_per_calfail;      /* periodic calibration failed */
+       u_int32_t ast_per_rfgain;       /* periodic calibration rfgain reset */
+       u_int32_t ast_rate_calls;       /* rate control checks */
+       u_int32_t ast_rate_raise;       /* rate control raised xmit rate */
+       u_int32_t ast_rate_drop;        /* rate control dropped xmit rate */
+       u_int32_t ast_ant_defswitch;    /* rx/default antenna switches */
+       u_int32_t ast_ant_txswitch;     /* tx antenna switches */
+       u_int32_t ast_ant_rx[8];        /* rx frames with antenna */
+       u_int32_t ast_ant_tx[8];        /* tx frames with antenna */
+};
+
+#define        SIOCGATHSTATS                   (SIOCDEVPRIVATE+0)
+#define        SIOCGATHDIAG                    (SIOCDEVPRIVATE+1)
+#define        SIOCGATHRADARSIG                (SIOCDEVPRIVATE+2)
+#define        SIOCGATHHALDIAG                 (SIOCDEVPRIVATE+3)
+#define        SIOCG80211STATS                 (SIOCDEVPRIVATE+2)
+/* NB: require in+out parameters so cannot use wireless extensions, yech */
+#define        IEEE80211_IOCTL_GETKEY          (SIOCDEVPRIVATE+3)
+#define        IEEE80211_IOCTL_GETWPAIE        (SIOCDEVPRIVATE+4)
+#define        IEEE80211_IOCTL_STA_STATS       (SIOCDEVPRIVATE+5)
+#define        IEEE80211_IOCTL_STA_INFO        (SIOCDEVPRIVATE+6)
+#define        SIOC80211IFCREATE               (SIOCDEVPRIVATE+7)
+#define        SIOC80211IFDESTROY              (SIOCDEVPRIVATE+8)
+#define        IEEE80211_IOCTL_SCAN_RESULTS    (SIOCDEVPRIVATE+9)
+
+
+#endif
index 1acdaf6..ec92f4b 100644 (file)
@@ -138,3 +138,9 @@ voltage                     value:GAUGE:U:U
 vs_memory              value:GAUGE:0:9223372036854775807
 vs_processes           value:GAUGE:0:65535
 vs_threads             value:GAUGE:0:65535
+ath_nodes              value:GAUGE:0:65535
+ath_stat               value:COUNTER:0:4294967295
+node_octets            rx:COUNTER:0:U, tx:COUNTER:0:U
+node_rssi              value:GAUGE:0:255
+node_tx_rate           value:GAUGE:0:127
+node_stat              value:COUNTER:0:4294967295