Merge branch 'ff/genericjmx'
authorFlorian Forster <octo@huhu.verplant.org>
Thu, 13 Aug 2009 06:14:24 +0000 (08:14 +0200)
committerFlorian Forster <octo@huhu.verplant.org>
Thu, 13 Aug 2009 06:14:24 +0000 (08:14 +0200)
12 files changed:
AUTHORS
bindings/java/org/collectd/java/JMXMemory.java
configure.in
src/Makefile.am
src/collectd.conf.in
src/common.h
src/madwifi.c [new file with mode: 0644]
src/madwifi.h [new file with mode: 0644]
src/network.c
src/types.db
src/utils_cache.c
src/utils_cache.h

diff --git a/AUTHORS b/AUTHORS
index 8b35c64..be3a838 100644 (file)
--- a/AUTHORS
+++ b/AUTHORS
@@ -103,6 +103,9 @@ Oleg King <king2 at kaluga.ru>
    + the disk plugin, and
    + the users plugin.
 
+Ondrej Zajicek <santiago at crfreenet.org>
+ - madwifi plugin.
+
 Paul Sadauskas <psadauskas at gmail.com>
  - tokyotyrant plugin.
  - `ReportByDevice' option of the df plugin.
index d1666c0..6e6a2fb 100644 (file)
@@ -47,7 +47,7 @@ import org.collectd.api.CollectdShutdownInterface;
 import org.collectd.api.OConfigValue;
 import org.collectd.api.OConfigItem;
 
-public class JMXMemory implements CollectdConfigInterface, /* {{{ */
+public class JMXMemory implements CollectdConfigInterface,
        CollectdInitInterface,
        CollectdReadInterface,
        CollectdShutdownInterface
@@ -227,6 +227,6 @@ public class JMXMemory implements CollectdConfigInterface, /* {{{ */
     _mbean = null;
     return (0);
   } /* }}} int shutdown */
-} /* }}} class JMXMemory */
+} /* class JMXMemory */
 
 /* vim: set sw=2 sts=2 et fdm=marker : */
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
index b4e0f33..1ed9da6 100644 (file)
@@ -338,7 +338,7 @@ FQDNLookup   true
 
 #<Plugin "java">
 #      JVMArg "-verbose:jni"
-#      JVMArg "-Djava.class.path=@prefix@/share/collectd/bindings/java"
+#      JVMArg "-Djava.class.path=@prefix@/share/collectd/java"
 #
 #      LoadPlugin "org.collectd.java.Foobar"
 #      <Plugin "org.collectd.java.Foobar">
index e424f5d..6682e1c 100644 (file)
@@ -253,9 +253,9 @@ int format_name (char *ret, int ret_len,
                const char *hostname,
                const char *plugin, const char *plugin_instance,
                const char *type, const char *type_instance);
-#define FORMAT_VL(ret, ret_len, vl, ds) \
+#define FORMAT_VL(ret, ret_len, vl) \
        format_name (ret, ret_len, (vl)->host, (vl)->plugin, (vl)->plugin_instance, \
-                       (ds)->type, (vl)->type_instance)
+                       (vl)->type, (vl)->type_instance)
 
 int parse_identifier (char *str, char **ret_host,
                char **ret_plugin, char **ret_plugin_instance,
diff --git a/src/madwifi.c b/src/madwifi.c
new file mode 100644 (file)
index 0000000..9d973ec
--- /dev/null
@@ -0,0 +1,885 @@
+/**
+ * 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 `Source' 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, the /proc filesystem should always 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",
+       "Source",
+       "WatchAdd",
+       "WatchRemove",
+       "WatchSet",
+       "MiscAdd",
+       "MiscRemove",
+       "MiscSet"
+};
+static int config_keys_num = STATIC_ARRAY_SIZE (config_keys);
+
+static ignorelist_t *ignorelist = NULL;
+
+static int use_sysfs = 1;
+static int init_state = 0;
+
+static inline int item_watched(int i)
+{
+       assert (i >= 0);
+       assert (i < ((STATIC_ARRAY_SIZE (watch_items) + 1) * 32));
+       return watch_items[i / 32] & FLAG (i);
+}
+
+static inline int item_summed(int i)
+{
+       assert (i >= 0);
+       assert (i < ((STATIC_ARRAY_SIZE (misc_items) + 1) * 32));
+       return misc_items[i / 32] & FLAG (i);
+}
+
+static inline void watchlist_add (uint32_t *wl, int item)
+{
+       assert (item >= 0);
+       assert (item < ((WL_LEN + 1) * 32));
+       wl[item / 32] |= FLAG (item);
+}
+
+static inline void watchlist_remove (uint32_t *wl, int item)
+{
+       assert (item >= 0);
+       assert (item < ((WL_LEN + 1) * 32));
+       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 = STATIC_ARRAY_SIZE (specs);
+       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 = STATIC_ARRAY_SIZE (specs);
+       int i;
+
+       for (i = 0; i < STATIC_ARRAY_SIZE (bounds); 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 < STATIC_ARRAY_SIZE (bounds); i++)
+               bounds[i]++;
+
+       return (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, IS_TRUE (value) ? 0 : 1);
+
+       else if (strcasecmp (key, "Source") == 0)
+       {
+               if (strcasecmp (value, "ProcFS") == 0)
+                       use_sysfs = 0;
+               else if (strcasecmp (value, "SysFS") == 0)
+                       use_sysfs = 1;
+               else
+               {
+                       ERROR ("madwifi plugin: The argument of the `Source' "
+                                       "option must either be `SysFS' or "
+                                       "`ProcFS'.");
+                       return -1;
+               }
+       }
+
+       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 != NULL) && (ti2 != NULL))
+               ssnprintf (vl.type_instance, sizeof (vl.type_instance), "%s-%s", ti1, ti2);
+       else if ((ti1 != NULL) && (ti2 == NULL))
+               sstrncpy (vl.type_instance, ti1, sizeof (vl.type_instance));
+
+       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, int vals_num)
+{
+       char ti2[16];
+       int i;
+
+       for (i = 0; i < vals_num; i++)
+       {
+               if (vals[i] == 0)
+                       continue;
+
+               ssnprintf (ti2, sizeof (ti2), "antenna%i", i);
+               submit_counter (dev, "ath_stat", name, ti2,
+                               (counter_t) vals[i]);
+       }
+}
+
+static inline void
+macaddr_to_str (char *buf, size_t bufsize, const uint8_t mac[IEEE80211_ADDR_LEN])
+{
+       ssnprintf (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;
+
+       assert (which >= 1);
+       assert (which < STATIC_ARRAY_SIZE (bounds));
+
+       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;
+
+       sstrncpy (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,
+                               STATIC_ARRAY_SIZE (stats.ast_ant_rx));
+
+       if (item_watched (STAT_AST_ANT_TX))
+               submit_antx (dev, "ast_ant_tx", stats.ast_ant_tx,
+                               STATIC_ARRAY_SIZE (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;
+       sstrncpy (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));
+       sstrncpy(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;
+       int status;
+
+       memset (&iwr, 0, sizeof (iwr));
+       sstrncpy (iwr.ifr_name, dev, sizeof (iwr.ifr_name));
+       iwr.u.data.pointer = (void *) buf;
+       iwr.u.data.length = sizeof (buf);
+
+       status = ioctl (sk, IEEE80211_IOCTL_STA_INFO, &iwr);
+       if (status < 0)
+       {
+               ERROR ("madwifi plugin: Sending IO-control "
+                               "IEEE80211_IOCTL_STA_INFO to device %s "
+                               "failed with status %i.",
+                               dev, status);
+               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[sizeof (buf2) - 1] = 0;
+
+       if (strstr (buf2, "/drivers/ath_") == NULL)
+               return 0;
+       return 1;
+}
+
+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, sizeof (buffer), fh) != NULL)
+       {
+               dummy = strchr(buffer, ':');
+               if (dummy == NULL)
+                       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)
+{
+       int rv;
+       int sk;
+
+       if (init_state == 0)
+               madwifi_real_init();
+       init_state = 2;
+
+       sk = socket(AF_INET, SOCK_DGRAM, 0);
+       if (sk < 0)
+               return (-1);
+
+
+/* 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 75f52df..0e416bd 100644 (file)
@@ -27,6 +27,7 @@
 #include "configfile.h"
 #include "utils_fbhash.h"
 #include "utils_avltree.h"
+#include "utils_cache.h"
 
 #include "network.h"
 
@@ -283,127 +284,98 @@ static int              send_buffer_fill;
 static value_list_t     send_buffer_vl = VALUE_LIST_STATIC;
 static pthread_mutex_t  send_buffer_lock = PTHREAD_MUTEX_INITIALIZER;
 
-/* In this cache we store all the values we received, so we can send out only
- * those values which were *not* received via the network plugin, too. This is
- * used for the `Forward false' option. */
-static c_avl_tree_t    *cache_tree = NULL;
-static pthread_mutex_t  cache_lock = PTHREAD_MUTEX_INITIALIZER;
-static time_t           cache_flush_last = 0;
-static int              cache_flush_interval = 1800;
-
 /*
  * Private functions
  */
-static int cache_flush (void)
+static _Bool check_receive_okay (const value_list_t *vl) /* {{{ */
 {
-       char **keys = NULL;
-       int    keys_num = 0;
+  uint64_t time_sent = 0;
+  int status;
 
-       char **tmp;
-       int    i;
+  status = uc_meta_data_get_unsigned_int (vl,
+      "network:time_sent", &time_sent);
 
-       char   *key;
-       time_t *value;
-       c_avl_iterator_t *iter;
+  /* This is a value we already sent. Don't allow it to be received again in
+   * order to avoid looping. */
+  if ((status == 0) && (time_sent >= ((uint64_t) vl->time)))
+    return (false);
 
-       time_t curtime = time (NULL);
+  return (true);
+} /* }}} _Bool check_receive_okay */
 
-       iter = c_avl_get_iterator (cache_tree);
-       while (c_avl_iterator_next (iter, (void *) &key, (void *) &value) == 0)
-       {
-               if ((curtime - *value) <= cache_flush_interval)
-                       continue;
-               tmp = (char **) realloc (keys,
-                               (keys_num + 1) * sizeof (char *));
-               if (tmp == NULL)
-               {
-                       sfree (keys);
-                       c_avl_iterator_destroy (iter);
-                       ERROR ("network plugin: cache_flush: realloc"
-                                       " failed.");
-                       return (-1);
-               }
-               keys = tmp;
-               keys[keys_num] = key;
-               keys_num++;
-       } /* while (c_avl_iterator_next) */
-       c_avl_iterator_destroy (iter);
+static _Bool check_send_okay (const value_list_t *vl) /* {{{ */
+{
+  _Bool received = false;
+  int status;
 
-       for (i = 0; i < keys_num; i++)
-       {
-               if (c_avl_remove (cache_tree, keys[i], (void *) &key,
-                                       (void *) &value) != 0)
-               {
-                       WARNING ("network plugin: cache_flush: c_avl_remove"
-                                       " (%s) failed.", keys[i]);
-                       continue;
-               }
+  if (network_config_forward != 0)
+    return (true);
 
-               sfree (key);
-               sfree (value);
-       }
+  if (vl->meta == NULL)
+    return (true);
 
-       sfree (keys);
+  status = meta_data_get_boolean (vl->meta, "network:received", &received);
+  if (status == -ENOENT)
+    return (true);
+  else if (status != 0)
+  {
+    ERROR ("network plugin: check_send_okay: meta_data_get_boolean failed "
+       "with status %i.", status);
+    return (true);
+  }
 
-       DEBUG ("network plugin: cache_flush: Removed %i %s",
-                       keys_num, (keys_num == 1) ? "entry" : "entries");
-       cache_flush_last = curtime;
-       return (0);
-} /* int cache_flush */
+  /* By default, only *send* value lists that were not *received* by the
+   * network plugin. */
+  return (!received);
+} /* }}} _Bool check_send_okay */
 
-static int cache_check (const value_list_t *vl)
+static int network_dispatch_values (value_list_t *vl) /* {{{ */
 {
-       char key[1024];
-       time_t *value = NULL;
-       int retval = -1;
+  int status;
 
-       if (cache_tree == NULL)
-               return (-1);
+  if ((vl->time <= 0)
+      || (strlen (vl->host) <= 0)
+      || (strlen (vl->plugin) <= 0)
+      || (strlen (vl->type) <= 0))
+    return (-EINVAL);
 
-       if (format_name (key, sizeof (key), vl->host, vl->plugin,
-                               vl->plugin_instance, vl->type, vl->type_instance))
-               return (-1);
+  if (!check_receive_okay (vl))
+  {
+#if COLLECT_DEBUG
+         char name[6*DATA_MAX_NAME_LEN];
+         FORMAT_VL (name, sizeof (name), vl);
+         name[sizeof (name) - 1] = 0;
+         DEBUG ("network plugin: network_dispatch_values: "
+             "NOT dispatching %s.", name);
+#endif
+    return (0);
+  }
 
-       pthread_mutex_lock (&cache_lock);
+  assert (vl->meta == NULL);
 
-       if (c_avl_get (cache_tree, key, (void *) &value) == 0)
-       {
-               if (*value < vl->time)
-               {
-                       *value = vl->time;
-                       retval = 0;
-               }
-               else
-               {
-                       DEBUG ("network plugin: cache_check: *value = %i >= vl->time = %i",
-                                       (int) *value, (int) vl->time);
-                       retval = 1;
-               }
-       }
-       else
-       {
-               char *key_copy = strdup (key);
-               value = malloc (sizeof (time_t));
-               if ((key_copy != NULL) && (value != NULL))
-               {
-                       *value = vl->time;
-                       c_avl_insert (cache_tree, key_copy, value);
-                       retval = 0;
-               }
-               else
-               {
-                       sfree (key_copy);
-                       sfree (value);
-               }
-       }
+  vl->meta = meta_data_create ();
+  if (vl->meta == NULL)
+  {
+    ERROR ("network plugin: meta_data_create failed.");
+    return (-ENOMEM);
+  }
 
-       if ((time (NULL) - cache_flush_last) > cache_flush_interval)
-               cache_flush ();
+  status = meta_data_add_boolean (vl->meta, "network:received", true);
+  if (status != 0)
+  {
+    ERROR ("network plugin: meta_data_add_boolean failed.");
+    meta_data_destroy (vl->meta);
+    vl->meta = NULL;
+    return (status);
+  }
 
-       pthread_mutex_unlock (&cache_lock);
+  plugin_dispatch_values (vl);
 
-       return (retval);
-} /* int cache_check */
+  meta_data_destroy (vl->meta);
+  vl->meta = NULL;
+
+  return (0);
+} /* }}} int network_dispatch_values */
 
 #if HAVE_LIBGCRYPT
 static gcry_cipher_hd_t network_get_aes256_cypher (sockent_t *se, /* {{{ */
@@ -1341,23 +1313,10 @@ static int parse_packet (sockent_t *se, /* {{{ */
                {
                        status = parse_part_values (&buffer, &buffer_size,
                                        &vl.values, &vl.values_len);
-
                        if (status != 0)
                                break;
 
-                       if ((vl.time > 0)
-                                       && (strlen (vl.host) > 0)
-                                       && (strlen (vl.plugin) > 0)
-                                       && (strlen (vl.type) > 0)
-                                       && (cache_check (&vl) == 0))
-                       {
-                               plugin_dispatch_values (&vl);
-                       }
-                       else
-                       {
-                               DEBUG ("network plugin: parse_packet:"
-                                               " NOT dispatching values");
-                       }
+                       network_dispatch_values (&vl);
 
                        sfree (vl.values);
                }
@@ -2473,13 +2432,20 @@ static int network_write (const data_set_t *ds, const value_list_t *vl,
 {
        int status;
 
-       /* If the value is already in the cache, we have received it via the
-        * network. We write it again if forwarding is activated. It's then in
-        * the cache and should we receive it again we will ignore it. */
-       status = cache_check (vl);
-       if ((network_config_forward == 0)
-                       && (status != 0))
-               return (0);
+       if (!check_send_okay (vl))
+       {
+#if COLLECT_DEBUG
+         char name[6*DATA_MAX_NAME_LEN];
+         FORMAT_VL (name, sizeof (name), vl);
+         name[sizeof (name) - 1] = 0;
+         DEBUG ("network plugin: network_write: "
+             "NOT sending %s.", name);
+#endif
+         return (0);
+       }
+
+       uc_meta_data_add_unsigned_int (vl,
+           "network:time_sent", (uint64_t) vl->time);
 
        pthread_mutex_lock (&send_buffer_lock);
 
@@ -2794,24 +2760,6 @@ static int network_config_add_server (const oconfig_item_t *ci) /* {{{ */
   return (0);
 } /* }}} int network_config_add_server */
 
-static int network_config_set_cache_flush (const oconfig_item_t *ci) /* {{{ */
-{
-  int tmp;
-  if ((ci->values_num != 1)
-      || (ci->values[0].type != OCONFIG_TYPE_NUMBER))
-  {
-    WARNING ("network plugin: The `CacheFlush' config option needs exactly "
-        "one numeric argument.");
-    return (-1);
-  }
-
-  tmp = (int) ci->values[0].value.number;
-  if (tmp > 0)
-    network_config_ttl = tmp;
-
-  return (0);
-} /* }}} int network_config_set_cache_flush */
-
 static int network_config (oconfig_item_t *ci) /* {{{ */
 {
   int i;
@@ -2829,7 +2777,7 @@ static int network_config (oconfig_item_t *ci) /* {{{ */
     else if (strcasecmp ("Forward", child->key) == 0)
       network_config_set_boolean (child, &network_config_forward);
     else if (strcasecmp ("CacheFlush", child->key) == 0)
-      network_config_set_cache_flush (child);
+      /* no op for backwards compatibility only */;
     else
     {
       WARNING ("network plugin: Option `%s' is not allowed here.",
@@ -2942,20 +2890,6 @@ static int network_shutdown (void)
        if (send_buffer_fill > 0)
                flush_buffer ();
 
-       if (cache_tree != NULL)
-       {
-               void *key;
-               void *value;
-
-               while (c_avl_pick (cache_tree, &key, &value) == 0)
-               {
-                       sfree (key);
-                       sfree (value);
-               }
-               c_avl_destroy (cache_tree);
-               cache_tree = NULL;
-       }
-
        /* TODO: Close `sending_sockets' */
 
        plugin_unregister_config ("network");
@@ -2963,26 +2897,23 @@ static int network_shutdown (void)
        plugin_unregister_write ("network");
        plugin_unregister_shutdown ("network");
 
-       /* Let the init function do it's move again ;) */
-       cache_flush_last = 0;
-
        return (0);
 } /* int network_shutdown */
 
 static int network_init (void)
 {
+       static _Bool have_init = false;
+
        /* Check if we were already initialized. If so, just return - there's
         * nothing more to do (for now, that is). */
-       if (cache_flush_last != 0)
+       if (have_init)
                return (0);
+       have_init = true;
 
        plugin_register_shutdown ("network", network_shutdown);
 
        network_init_buffer ();
 
-       cache_tree = c_avl_create ((int (*) (const void *, const void *)) strcmp);
-       cache_flush_last = time (NULL);
-
        /* setup socket(s) and so on */
        if (sending_sockets != NULL)
        {
@@ -3054,11 +2985,8 @@ static int network_flush (int timeout,
 {
        pthread_mutex_lock (&send_buffer_lock);
 
-       if (((time (NULL) - cache_flush_last) >= timeout)
-                       && (send_buffer_fill > 0))
-       {
-               flush_buffer ();
-       }
+       if (send_buffer_fill > 0)
+         flush_buffer ();
 
        pthread_mutex_unlock (&send_buffer_lock);
 
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
index 39a1468..2505b55 100644 (file)
@@ -25,6 +25,7 @@
 #include "utils_avltree.h"
 #include "utils_cache.h"
 #include "utils_threshold.h"
+#include "meta_data.h"
 
 #include <assert.h>
 #include <pthread.h>
@@ -58,6 +59,8 @@ typedef struct cache_entry_s
        gauge_t *history;
        size_t   history_index; /* points to the next position to write to. */
        size_t   history_length;
+
+       meta_data_t *meta;
 } cache_entry_t;
 
 static c_avl_tree_t   *cache_tree = NULL;
@@ -95,6 +98,7 @@ static cache_entry_t *cache_alloc (int values_num)
 
   ce->history = NULL;
   ce->history_length = 0;
+  ce->meta = NULL;
 
   return (ce);
 } /* cache_entry_t *cache_alloc */
@@ -107,6 +111,11 @@ static void cache_free (cache_entry_t *ce)
   sfree (ce->values_gauge);
   sfree (ce->values_raw);
   sfree (ce->history);
+  if (ce->meta != NULL)
+  {
+    meta_data_destroy (ce->meta);
+    ce->meta = NULL;
+  }
   sfree (ce);
 } /* void cache_free */
 
@@ -441,7 +450,7 @@ int uc_update (const data_set_t *ds, const value_list_t *vl)
   int status;
   int i;
 
-  if (FORMAT_VL (name, sizeof (name), vl, ds) != 0)
+  if (FORMAT_VL (name, sizeof (name), vl) != 0)
   {
     ERROR ("uc_update: FORMAT_VL failed.");
     return (-1);
@@ -638,7 +647,7 @@ gauge_t *uc_get_rate (const data_set_t *ds, const value_list_t *vl)
   size_t ret_num = 0;
   int status;
 
-  if (FORMAT_VL (name, sizeof (name), vl, ds) != 0)
+  if (FORMAT_VL (name, sizeof (name), vl) != 0)
   {
     ERROR ("utils_cache: uc_get_rate: FORMAT_VL failed.");
     return (NULL);
@@ -744,7 +753,7 @@ int uc_get_state (const data_set_t *ds, const value_list_t *vl)
   cache_entry_t *ce = NULL;
   int ret = STATE_ERROR;
 
-  if (FORMAT_VL (name, sizeof (name), vl, ds) != 0)
+  if (FORMAT_VL (name, sizeof (name), vl) != 0)
   {
     ERROR ("uc_get_state: FORMAT_VL failed.");
     return (STATE_ERROR);
@@ -769,7 +778,7 @@ int uc_set_state (const data_set_t *ds, const value_list_t *vl, int state)
   cache_entry_t *ce = NULL;
   int ret = -1;
 
-  if (FORMAT_VL (name, sizeof (name), vl, ds) != 0)
+  if (FORMAT_VL (name, sizeof (name), vl) != 0)
   {
     ERROR ("uc_get_state: FORMAT_VL failed.");
     return (STATE_ERROR);
@@ -863,7 +872,7 @@ int uc_get_history (const data_set_t *ds, const value_list_t *vl,
 {
   char name[6 * DATA_MAX_NAME_LEN];
 
-  if (FORMAT_VL (name, sizeof (name), vl, ds) != 0)
+  if (FORMAT_VL (name, sizeof (name), vl) != 0)
   {
     ERROR ("utils_cache: uc_get_history: FORMAT_VL failed.");
     return (-1);
@@ -872,4 +881,109 @@ int uc_get_history (const data_set_t *ds, const value_list_t *vl,
   return (uc_get_history_by_name (name, ret_history, num_steps, num_ds));
 } /* int uc_get_history */
 
+/*
+ * Meta data interface
+ */
+/* XXX: This function will acquire `cache_lock' but will not free it! */
+static meta_data_t *uc_get_meta (const value_list_t *vl) /* {{{ */
+{
+  char name[6 * DATA_MAX_NAME_LEN];
+  cache_entry_t *ce = NULL;
+  int status;
+
+  status = FORMAT_VL (name, sizeof (name), vl);
+  if (status != 0)
+  {
+    ERROR ("utils_cache: uc_get_meta: FORMAT_VL failed.");
+    return (NULL);
+  }
+
+  pthread_mutex_lock (&cache_lock);
+
+  status = c_avl_get (cache_tree, name, (void *) &ce);
+  if (status != 0)
+  {
+    pthread_mutex_unlock (&cache_lock);
+    return (NULL);
+  }
+  assert (ce != NULL);
+
+  if (ce->meta == NULL)
+    ce->meta = meta_data_create ();
+
+  return (ce->meta);
+} /* }}} meta_data_t *uc_get_meta */
+
+/* Sorry about this preprocessor magic, but it really makes this file much
+ * shorter.. */
+#define UC_WRAP(wrap_function) { \
+  meta_data_t *meta; \
+  int status; \
+  meta = uc_get_meta (vl); \
+  if (meta == NULL) return (-1); \
+  status = wrap_function (meta, key); \
+  pthread_mutex_unlock (&cache_lock); \
+  return (status); \
+}
+int uc_meta_data_exists (const value_list_t *vl, const char *key)
+  UC_WRAP (meta_data_exists)
+
+int uc_meta_data_delete (const value_list_t *vl, const char *key)
+  UC_WRAP (meta_data_delete)
+#undef UC_WRAP
+
+/* We need a new version of this macro because the following functions take
+ * two argumetns. */
+#define UC_WRAP(wrap_function) { \
+  meta_data_t *meta; \
+  int status; \
+  meta = uc_get_meta (vl); \
+  if (meta == NULL) return (-1); \
+  status = wrap_function (meta, key, value); \
+  pthread_mutex_unlock (&cache_lock); \
+  return (status); \
+}
+int uc_meta_data_add_string (const value_list_t *vl,
+    const char *key,
+    const char *value)
+  UC_WRAP(meta_data_add_string)
+int uc_meta_data_add_signed_int (const value_list_t *vl,
+    const char *key,
+    int64_t value)
+  UC_WRAP(meta_data_add_signed_int)
+int uc_meta_data_add_unsigned_int (const value_list_t *vl,
+    const char *key,
+    uint64_t value)
+  UC_WRAP(meta_data_add_unsigned_int)
+int uc_meta_data_add_double (const value_list_t *vl,
+    const char *key,
+    double value)
+  UC_WRAP(meta_data_add_double)
+int uc_meta_data_add_boolean (const value_list_t *vl,
+    const char *key,
+    _Bool value)
+  UC_WRAP(meta_data_add_boolean)
+
+int uc_meta_data_get_string (const value_list_t *vl,
+    const char *key,
+    char **value)
+  UC_WRAP(meta_data_get_string)
+int uc_meta_data_get_signed_int (const value_list_t *vl,
+    const char *key,
+    int64_t *value)
+  UC_WRAP(meta_data_get_signed_int)
+int uc_meta_data_get_unsigned_int (const value_list_t *vl,
+    const char *key,
+    uint64_t *value)
+  UC_WRAP(meta_data_get_unsigned_int)
+int uc_meta_data_get_double (const value_list_t *vl,
+    const char *key,
+    double *value)
+  UC_WRAP(meta_data_get_double)
+int uc_meta_data_get_boolean (const value_list_t *vl,
+    const char *key,
+    _Bool *value)
+  UC_WRAP(meta_data_get_boolean)
+#undef UC_WRAP
+
 /* vim: set sw=2 ts=8 sts=2 tw=78 : */
index d754a32..91a6a6d 100644 (file)
@@ -45,5 +45,43 @@ int uc_get_history (const data_set_t *ds, const value_list_t *vl,
 int uc_get_history_by_name (const char *name,
     gauge_t *ret_history, size_t num_steps, size_t num_ds);
 
+/*
+ * Meta data interface
+ */
+int uc_meta_data_exists (const value_list_t *vl, const char *key);
+int uc_meta_data_delete (const value_list_t *vl, const char *key);
+
+int uc_meta_data_add_string (const value_list_t *vl,
+    const char *key,
+    const char *value);
+int uc_meta_data_add_signed_int (const value_list_t *vl,
+    const char *key,
+    int64_t value);
+int uc_meta_data_add_unsigned_int (const value_list_t *vl,
+    const char *key,
+    uint64_t value);
+int uc_meta_data_add_double (const value_list_t *vl,
+    const char *key,
+    double value);
+int uc_meta_data_add_boolean (const value_list_t *vl,
+    const char *key,
+    _Bool value);
+
+int uc_meta_data_get_string (const value_list_t *vl,
+    const char *key,
+    char **value);
+int uc_meta_data_get_signed_int (const value_list_t *vl,
+    const char *key,
+    int64_t *value);
+int uc_meta_data_get_unsigned_int (const value_list_t *vl,
+    const char *key,
+    uint64_t *value);
+int uc_meta_data_get_double (const value_list_t *vl,
+    const char *key,
+    double *value);
+int uc_meta_data_get_boolean (const value_list_t *vl,
+    const char *key,
+    _Bool *value);
+
 /* vim: set shiftwidth=2 softtabstop=2 tabstop=8 : */
 #endif /* !UTILS_CACHE_H */