From 5b4e80afa7d9d15ba5e7d8e357a261c18fad02a6 Mon Sep 17 00:00:00 2001
From: Mats Erik Andersson <gnu@gisladisker.se>
Date: Fri, 7 Aug 2015 22:51:43 +0200
Subject: [PATCH 10/60] ifconfig: Statistics for BSD systems.

---
 ChangeLog             | 24 +++++++++++++
 ifconfig/system/bsd.c | 82 +++++++++++++++++++++++++++++++++++++++++++
 ifconfig/system/bsd.h | 35 +++++++++++++++++-
 3 files changed, 140 insertions(+), 1 deletion(-)

diff --git a/ChangeLog b/ChangeLog
index 6c592b72..73b281b9 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,27 @@
+2015-08-07  Mats Erik Andersson  <gnu@gisladisker.se>
+
+	ifconfig: Statistics for BSD systems.
+
+	* ifconfig/system/bsd.c (system_fh_ifstat_query)
+	(get_if_data_by_name, system_fh_missing_stat): New functions.
+	(_IU_DECLARE2): New macro.
+	(system_fh_rx_bytes, system_fh_rx_dropped, system_fh_rx_errors)
+	(system_fh_rx_packets, system_fh_tx_bytes, system_fh_tx_errors)
+	(system_fh_tx_packets, system_fh_collisions): New functions
+	defined using _IU_DECLARE2.
+	(system_fh_tx_dropped): New function.
+	* ifconfig/system/bsd.h (_IU_CAT2, _IU_DCL, _IU_EXTRN): New
+	macros identical to those in `ifconfig/system/linux.h'.
+	(SYSTEM_FORMAT_HANDLER) <ifstat?, collisions, rxbytes>
+	<rxdropped, rxerrors, rxfifoerr, rxframeerr, rxpackets>
+	<txbytes, txcarrier, txdropped, txerrors, txfifoerr, txpackets>:
+	New handler hooks.
+	(system_fh_ifstat_query, system_fh_missing_stat): New prototypes.
+	(system_fh_rx_bytes, system_fh_tx_bytes, system_fh_rx_dropped)
+	(system_fh_tx_dropped, system_fh_rx_errors, system_fh_tx_errors)
+	(system_fh_rx_packets, system_fh_tx_packets, system_fh_collisions):
+	New prototypes generated by _IU_EXTERN.
+
 2015-08-02  Mats Erik Andersson  <gnu@gisladisker.se>
 
 	ifconfig: Verbose report on changed flags.
diff --git a/ifconfig/system/bsd.c b/ifconfig/system/bsd.c
index 1db525ba..ec47ce62 100644
--- a/ifconfig/system/bsd.c
+++ b/ifconfig/system/bsd.c
@@ -198,6 +198,19 @@ struct ifmediareq ifm;
   if (!ifp) \
     getifaddrs (&ifp);
 
+void
+system_fh_ifstat_query (format_data_t form, int argc, char *argv[])
+{
+  /* Flush an existing interface list, thus renewing statistics.  */
+  if (ifp)
+    {
+      freeifaddrs (ifp);
+      ifp = NULL;
+    }
+
+  select_arg (form, argc, argv, getifaddrs (&ifp) ? 1 : 0);
+}
+
 struct if_nameindex* (*system_if_nameindex) (void) = if_nameindex;
 
 static void
@@ -728,3 +741,72 @@ system_fh_tunsrc (format_data_t form, int argc, char *argv[])
     put_string (form, "(no physrc)");
 #endif /* SIOCGIFPSRCADDR */
 }
+
+static struct if_data *
+get_if_data_by_name (format_data_t form)
+{
+  struct ifaddrs *fp;
+  struct if_data *data = NULL;
+
+  ESTABLISH_IFADDRS
+  if (!ifp)
+    return NULL;
+
+  for (fp = ifp; fp; fp = fp->ifa_next)
+    {
+      /* The choice of AF_LINK is the only portable alternative.
+       * Then IP, ARP etcera are included in all counters.
+       */
+      if (fp->ifa_addr->sa_family != AF_LINK ||
+	  strcmp (fp->ifa_name, form->ifr->ifr_name))
+	continue;
+
+      data = (struct if_data *) fp->ifa_data;
+      break;
+    }
+
+  return data;
+}
+
+void
+system_fh_missing_stat (format_data_t form, int argc, char *argv[])
+{
+  /* FIXME: Would a dash be a better answer?  */
+  put_ulong (form, argc, argv, 0);
+}
+
+#define _IU_DECLARE2(fld, udata)	\
+void					\
+_IU_CAT2 (system_fh_, fld) (format_data_t form, int argc, char *argv[])	\
+{				\
+  struct if_data *data = get_if_data_by_name (form);	\
+  if (data)			\
+    put_ulong (form, argc, argv, data->_IU_CAT2(ifi_, udata));	\
+  else				\
+    put_string (form, "(" #fld " unknown)");		\
+}
+
+_IU_DECLARE2 (rx_bytes, ibytes)
+_IU_DECLARE2 (rx_dropped, iqdrops)
+_IU_DECLARE2 (rx_errors, ierrors)
+_IU_DECLARE2 (rx_packets, ipackets)
+_IU_DECLARE2 (tx_bytes, obytes)
+_IU_DECLARE2 (tx_errors, oerrors)
+_IU_DECLARE2 (tx_packets, opackets)
+_IU_DECLARE2 (collisions, collisions)
+
+void
+system_fh_tx_dropped (format_data_t form, int argc, char *argv[])
+{
+#ifdef _IFI_OQDROPS
+  struct if_data *data = get_if_data_by_name (form);
+
+  if (data)
+    put_ulong (form, argc, argv, data->ifi_oqdrops);
+  else
+    put_string (form, "(txerrors unknown)");
+#else /* !_IFI_OQDROPS */
+  /* FIXME: Would a dash be a better answer?  */
+  put_ulong (form, argc, argv, 0);
+#endif
+}
diff --git a/ifconfig/system/bsd.h b/ifconfig/system/bsd.h
index 918c1f2c..3398df65 100644
--- a/ifconfig/system/bsd.h
+++ b/ifconfig/system/bsd.h
@@ -57,6 +57,12 @@ struct system_ifconfig
 
 /* Output format support.  */
 
+# define _IU_CAT2(a, b) a ## b
+# define _IU_DCL(name, fld)				\
+  {#name, _IU_CAT2(system_fh_, fld) }
+# define _IU_EXTRN(fld)				\
+  extern void _IU_CAT2(system_fh_, fld) (format_data_t, int, char *[]);	\
+
 # define SYSTEM_FORMAT_HANDLER	\
   {"bsd", fh_nothing},		\
   {IU_BSD_TYPE, fh_nothing},	\
@@ -74,7 +80,21 @@ struct system_ifconfig
   {"status", system_fh_status}, \
   {"tunnel?", system_fh_tunnel_query}, \
   {"tundst", system_fh_tundst}, \
-  {"tunsrc", system_fh_tunsrc},
+  {"tunsrc", system_fh_tunsrc}, \
+  {"ifstat?", system_fh_ifstat_query}, \
+  _IU_DCL (collisions, collisions), \
+  _IU_DCL (rxbytes, rx_bytes), \
+  _IU_DCL (rxdropped, rx_dropped), \
+  _IU_DCL (rxerrors, rx_errors), \
+  {"rxfifoerr", system_fh_missing_stat}, \
+  {"rxframeerr", system_fh_missing_stat}, \
+  _IU_DCL (rxpackets, rx_packets), \
+  _IU_DCL (txbytes, tx_bytes), \
+  {"txcarrier", system_fh_missing_stat}, \
+  _IU_DCL (txdropped, tx_dropped), \
+  _IU_DCL (txerrors, tx_errors), \
+  {"txfifoerr", system_fh_missing_stat}, \
+  _IU_DCL (txpackets, tx_packets),
 
 void system_fh_brdaddr_query (format_data_t form, int argc, char *argv[]);
 void system_fh_brdaddr (format_data_t form, int argc, char *argv[]);
@@ -92,4 +112,17 @@ void system_fh_tunnel_query (format_data_t form, int argc, char *argv[]);
 void system_fh_tundst (format_data_t form, int argc, char *argv[]);
 void system_fh_tunsrc (format_data_t form, int argc, char *argv[]);
 
+void system_fh_ifstat_query (format_data_t form, int argc, char *argv[]);
+void system_fh_missing_stat (format_data_t form, int argc, char *argv[]);
+
+_IU_EXTRN (rx_bytes)
+_IU_EXTRN (tx_bytes)
+_IU_EXTRN (rx_dropped)
+_IU_EXTRN (tx_dropped)
+_IU_EXTRN (rx_errors)
+_IU_EXTRN (tx_errors)
+_IU_EXTRN (rx_packets)
+_IU_EXTRN (tx_packets)
+_IU_EXTRN (collisions)
+
 #endif /* IFCONFIG_SYSTEM_BSD_H */
-- 
2.26.0.292.g33ef6b2f38

