$NetBSD: patch-ac,v 1.4 2002/07/18 12:57:57 seb Exp $

--- drivers.c.orig	Fri May  5 02:34:29 2000
+++ drivers.c	Mon Jul  8 16:50:15 2002
@@ -37,7 +37,15 @@
 int kvm_updateStats(void);
 #endif /* USE_KVM */
 
+/* For Solaris */
+#ifdef USE_KSTAT
+#include <kstat.h>
 
+int kstat_test(void);
+int kstat_updateStats(void);
+#endif /* USE_KSTAT */
+
+
 #ifdef USE_LINUX_PPP
 #include<net/ppp_defs.h>
 
@@ -57,7 +65,7 @@
 #define ACCOUNT_IN_FOUND        1
 #define ACCOUNT_OUT_FOUND       2
 
-extern char buffer[256];
+extern char buffer[2048];
 extern char *in_rule_string, *out_rule_string, *device;
 extern unsigned long totalbytes_in, totalbytes_out, lastbytes_in, lastbytes_out;
 extern unsigned long totalpackets_in, totalpackets_out, lastpackets_in, lastpackets_out;
@@ -104,6 +112,9 @@
 #ifdef USE_KVM
  {"kmem",kvm_updateStats, kvm_test},
 #endif
+#ifdef USE_KSTAT
+ {"kstat", kstat_updateStats, kstat_test},
+#endif
  {NULL, NULL}
 };
 
@@ -445,7 +456,7 @@
   if (((kvmfd = kvm_open(NULL, NULL, NULL, O_RDONLY, buffer)) == NULL) ||
       (kvm_nlist(kvmfd, symbols) < 0) ||
       kvm_read(kvmfd, (unsigned long)symbols[0].n_value, &ifnet_savedaddr, sizeof(unsigned long)) == -1 ) return False;
-  if(device == NULL) device = "ec0";
+  if(device == NULL) device = "ppp0";
   fprintf(stderr, "wmnet: using kmem driver to monitor %s\n", device);
   return True;
 }
@@ -457,7 +468,7 @@
  int flag = 0;
  while (ifnet_addr && flag != (ACCOUNT_IN_FOUND|ACCOUNT_OUT_FOUND)) {
   kvm_read(kvmfd, ifnet_addr, buffer, sizeof(struct ifnet));
-#ifdef __OpenBSD__
+#if defined(__OpenBSD__) || defined(__NetBSD__)
   snprintf(devname, 15, "%s", ifnet->if_xname);
 #else
   kvm_read(kvmfd, (unsigned long)ifnet->if_name, devname, 15);
@@ -487,7 +498,7 @@
         flag = (ACCOUNT_IN_FOUND|ACCOUNT_OUT_FOUND);
 
   } else {
-#ifdef __OpenBSD__
+#if defined(__OpenBSD__) || defined(__NetBSD__)
         ifnet_addr = (unsigned long)ifnet->if_list.tqe_next;
 #else
         ifnet_addr = (unsigned long)ifnet->if_next;
@@ -502,8 +513,119 @@
 }
 
 
-#endif
+#endif /* KVM */
   
 
+#ifdef USE_KSTAT
    
+kstat_ctl_t *kc = NULL;
+kstat_t *if_ksp = NULL;
+
+int kstat_test(void)
+{
+	kstat_t *ksp;
+
+	if (kc == NULL) {
+		if ((kc = kstat_open()) == NULL) {
+			perror("wmnet [kstat]: can't open /dev/kstat\n");
+			return (False);
+		}
+	}
+
+	/*
+	 * If no device given, take the first thing we find of class 'net'
+	 * which exports the four kstats we need.
+	 */
+	if (device == NULL) {
+		for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) {
+			if (strcmp(ksp->ks_class, "net") == 0) {
+				kstat_read(kc, ksp, NULL);
+				if (kstat_data_lookup(ksp, "ipackets") &&
+				    kstat_data_lookup(ksp, "opackets") &&
+				    kstat_data_lookup(ksp, "rbytes") &&
+				    kstat_data_lookup(ksp, "obytes")) {
+					if_ksp = ksp;
+					break;
+				}
+			}
+		}
+		if (if_ksp == NULL) {
+			fprintf(stderr, "wmnet [kstat]: no network interface "
+			    "exporting kstats found\n");
+			return (False);
+		} else {
+			fprintf(stderr, "wmnet [kstat]: monitoring %s\n",
+			    ksp->ks_name);
+		}
+	} else {
+		if ((if_ksp = (kstat_lookup(kc, NULL, -1, device))) == NULL) {
+			fprintf(stderr, "wmnet [kstat]: no network interface "
+			    "%s exporting kstats found\n", device);
+			return (False);
+		}
+	}
+
+	return (True);
+}
+
+int kstat_updateStats(void)
+{
+	kstat_named_t *in_pkt, *in_byte, *out_pkt, *out_byte;
+	tx = rx = False;
+
+	if (kstat_read(kc, if_ksp, NULL) == -1) {
+		(void) fprintf(stderr, "wmnet [kstat]: kstat_read failed\n");
+		exit (1);
+	}
+
+	if ((in_pkt = (kstat_named_t *) kstat_data_lookup(if_ksp, "ipackets"))
+	    == NULL) {
+		(void) fprintf(stderr, "wmnet [kstat]: kstat_data_lookup "
+		    "(ipackets) failed\n");
+		exit (1);
+	}
+
+	totalpackets_in = (in_pkt->value.ui32);
+	if (totalpackets_in != lastpackets_in) {
+		if ((in_byte = (kstat_named_t *) kstat_data_lookup(if_ksp,
+		    "rbytes")) == NULL) {
+			(void) fprintf(stderr, "wmnet [kstat]: "
+			    "kstat_data_lookup (rbytes) failed\n");
+			exit (1);
+		}
+		totalbytes_in = in_byte->value.ui32;
+		diffpackets_in += totalpackets_in - lastpackets_in;
+		diffbytes_in += totalbytes_in - lastbytes_in;
+		lastpackets_in = totalpackets_in;
+                lastbytes_in = totalbytes_in;
+                rx = True;
+	}
+
+	if ((out_pkt = (kstat_named_t *) kstat_data_lookup(if_ksp, "opackets"))
+	    == NULL) {
+		(void) fprintf(stderr, "wmnet [kstat]: kstat_data_lookup "
+		    "(opackets) failed\n");
+		exit (1);
+	}
+
+	totalpackets_out = (out_pkt->value.ui32);
+	if (totalpackets_out != lastpackets_out) {
+		if ((out_byte = (kstat_named_t *) kstat_data_lookup(if_ksp,
+		    "obytes")) == NULL) {
+			(void) fprintf(stderr, "wmnet [kstat]: "
+			    "kstat_data_lookup (obytes) failed\n");
+			exit (1);
+		}
+		totalbytes_out = out_byte->value.ui32;
+		diffpackets_out += totalpackets_out - lastpackets_out;
+		diffbytes_out += totalbytes_out - lastbytes_out;
+		lastpackets_out = totalpackets_out;
+                lastbytes_out = totalbytes_out;
+                tx = True;
+	}
+
+	return ((rx == current_rx) && (tx == current_tx));
+}
+
+#endif /* KSTAT */
   
