1 /* wmnet -- X IP accounting monitor
2 * Copyright 1998 Jesse B. Off <joff@iastate.edu>
4 * $Id: drivers.c,v 1.1 1998/10/07 03:42:21 joff Exp joff $
6 * This software is released under the GNU Public License agreement.
7 * No warranties, whatever.... you know the usuals.... this is free
8 * software. if you use it, great... if you wanna make a change to it,
9 * great, but please send me the diff.
19 #include<sys/socket.h>
31 struct nlist symbols
[] = {
35 unsigned long ifnet_savedaddr
;
37 int kvm_updateStats(void);
42 #include<net/ppp_defs.h>
45 # include<linux/if_ppp.h>
47 # include<net/if_ppp.h>
53 int updateStats_ppp(void);
54 static struct ifpppstatsreq ppp_stats_req
;
57 #define ACCOUNT_IN_FOUND 1
58 #define ACCOUNT_OUT_FOUND 2
60 extern char buffer
[256];
61 extern char *in_rule_string
, *out_rule_string
, *device
;
62 extern unsigned long long int totalbytes_in
, totalbytes_out
, lastbytes_in
, lastbytes_out
;
63 extern unsigned long long int totalpackets_in
, totalpackets_out
, lastpackets_in
, lastpackets_out
;
64 extern unsigned int diffbytes_in
, diffbytes_out
;
65 extern unsigned int out_rule
, in_rule
; /* number of rule in /proc/net/ip_acct to use */
66 extern Bool current_tx
, current_rx
, rx
, tx
;
70 char *available_drivers(void);
73 int updateStats_ipfwadm(void);
74 int ipfwadm_test(void);
77 int updateStats_ipchains(void);
78 int ipchains_test(void);
81 int updateStats_dev(void);
86 typedef int (*parser_func
)(void);
87 static struct drivers_struct
{
93 {"devstats", updateStats_dev
, dev_test
},
96 {"ipfwadm", updateStats_ipfwadm
, ipfwadm_test
},
99 {"ipchains", updateStats_ipchains
, ipchains_test
},
102 {"pppstats",updateStats_ppp
, ppp_test
},
105 {"kmem",kvm_updateStats
, kvm_test
},
110 char* available_drivers(void) {
114 while(drivers
[ind
].name
!= NULL
) {
115 len
+= strlen(drivers
[ind
].name
) + 1;
118 ptr
= string
= (char *)malloc(len
);
121 while(drivers
[ind
].name
!= NULL
) {
122 strcpy(string
, drivers
[ind
].name
);
123 string
+= strlen(drivers
[ind
].name
);
133 parser_func
find_driver(void) {
135 while(drivers
[ind
].name
!= NULL
) {
136 if(drivers
[ind
].test()) {
137 return drivers
[ind
].function
;
141 fprintf(stderr
, "wmnet: no appropriate stat driver found\n");
146 parser_func
setup_driver(char * parser_name
) {
148 if (parser_name
== NULL
) return find_driver();
149 while(drivers
[ind
].name
!= NULL
) {
150 if(!strcmp(parser_name
, drivers
[ind
].name
)) {
151 if (drivers
[ind
].test()) return drivers
[ind
].function
;
152 fprintf(stderr
, "wmnet: driver %s not appropriate for this machine\n", parser_name
);
157 fprintf(stderr
, "wmnet: no driver %s\n", parser_name
);
165 /* All the data gathering is done in here.
166 * Return True if no change to tx/rx.
167 * Return False if display will need to be updated.
170 int ipfwadm_test(void) {
171 if(open("/proc/net/ip_acct", O_RDONLY
) == -1) return False
;
172 fprintf(stderr
, "wmnet: using ipfwadm driver to monitor accounting rules %d and %d\n", in_rule
, out_rule
);
176 int updateStats_ipfwadm(void) {
178 unsigned int flag
= 0, lineno
= 0;
179 unsigned int offset
= 37;
185 if ((ip_acct
= fopen("/proc/net/ip_acct", "r")) == NULL
) {
186 fprintf(stderr
, "wmnet: /proc/net/ip_acct unavailable\n"
187 "You either don't have IP accounting compiled in, or this isn't a 2.0 linux kernel.\n");
191 /* IP Accounting Rules for 2.0.x linux kernels*/
192 while(flag
!= (ACCOUNT_IN_FOUND
|ACCOUNT_OUT_FOUND
) && fgets(buffer
, 256, ip_acct
)) {
193 switch(lineno
== out_rule
? ACCOUNT_OUT_FOUND
: ( lineno
== in_rule
? ACCOUNT_IN_FOUND
: -1 ) ) {
194 case ACCOUNT_IN_FOUND
:
196 flag
|= ACCOUNT_IN_FOUND
;
197 while(buffer
[offset
++] != ' ');
199 totalpackets_in
= strtoul(&buffer
[offset
], &ptr
, 10);
200 if (totalpackets_in
== lastpackets_in
) break;
201 totalbytes_in
= strtoul(ptr
, NULL
, 10);
202 diffbytes_in
+= totalbytes_in
- lastbytes_in
;
203 lastpackets_in
= totalpackets_in
;
204 lastbytes_in
= totalbytes_in
;
207 case ACCOUNT_OUT_FOUND
:
209 flag
|= ACCOUNT_OUT_FOUND
;
210 while(buffer
[offset
++] != ' ');
212 totalpackets_out
= strtoul(&buffer
[offset
], &ptr
, 10);
213 if (totalpackets_out
== lastpackets_out
) break;
214 totalbytes_out
= strtoul(ptr
, NULL
, 10);
215 diffbytes_out
+= totalbytes_out
- lastbytes_out
;
216 lastpackets_out
= totalpackets_out
;
217 lastbytes_out
= totalbytes_out
;
225 if(flag
!= (ACCOUNT_IN_FOUND
|ACCOUNT_OUT_FOUND
)) {
226 fprintf(stderr
,"wmnet: couldn't find %s accounting rule to monitor in /proc/net/ip_acct\n",
227 (flag
== ACCOUNT_IN_FOUND
) ? "the TX" : ((flag
== ACCOUNT_OUT_FOUND
) ? "the RX" : "a single"));
232 /* return True if no change to tx/rx
233 * return False if display will need to be updated
235 return((rx
== current_rx
) && (tx
== current_tx
));
238 #endif /* USE_IPFWADM */
241 int ipchains_test(void) {
242 if (open("/proc/net/ip_fwchains",O_RDONLY
) == -1) return False
;
243 if (in_rule_string
== NULL
) in_rule_string
= "acctin";
244 if (out_rule_string
== NULL
) out_rule_string
= "acctout";
245 fprintf(stderr
, "wmnet: using ipchains driver to monitor chains %s and %s\n", in_rule_string
, out_rule_string
);
249 /* ipchains parser mostly from Bjoern Kriews <bkr@cut.de> */
250 int updateStats_ipchains(void) {
252 unsigned int flag
= 0;
253 static char name
[32];
254 unsigned long pack
, bytes
;
259 if ((ip_acct
= fopen("/proc/net/ip_fwchains", "r")) == NULL
) {
260 fprintf(stderr
, "/proc/net/ip_fwchains does not exist?\n"
261 "Do you have IP accounting in your kernel?\n");
265 /* IP Chain Rules for Linux kernel 2_1.x */
266 while(flag
!= (ACCOUNT_IN_FOUND
|ACCOUNT_OUT_FOUND
) && fgets(buffer
, 256, ip_acct
)) {
269 sscanf(buffer
, "%30s %*s - %*d %*d %*d %*d %lu %*d %lu",
270 name
, &pack
, &bytes
);
273 if(strcmp(name
, in_rule_string
) == 0) {
274 flag
|= ACCOUNT_IN_FOUND
;
276 totalpackets_in
= pack
;
277 if (totalpackets_in
!= lastpackets_in
) {
278 totalbytes_in
= bytes
;
279 diffbytes_in
+= totalbytes_in
- lastbytes_in
;
280 lastpackets_in
= totalpackets_in
;
281 lastbytes_in
= totalbytes_in
;
285 } else if (strcmp(name
, out_rule_string
) == 0) {
286 flag
|= ACCOUNT_OUT_FOUND
;
288 totalpackets_out
= pack
;
289 if (totalpackets_out
!= lastpackets_out
) {
290 totalbytes_out
= bytes
;
291 diffbytes_out
+= totalbytes_out
- lastbytes_out
;
292 lastpackets_out
= totalpackets_out
;
293 lastbytes_out
= totalbytes_out
;
299 if(flag
!= (ACCOUNT_IN_FOUND
|ACCOUNT_OUT_FOUND
)) {
300 fprintf(stderr
,"I couldn't find %s IP chain to monitor in /proc/net/ip_fwchains.\n",
301 (flag
== ACCOUNT_IN_FOUND
) ? "the TX" : ((flag
== ACCOUNT_OUT_FOUND
) ? "the RX" : "a single"));
306 /* return True if no change to tx/rx
307 * return False if display will need to be updated
309 return((rx
== current_rx
) && (tx
== current_tx
));
312 #endif /* USE_IPCHAINS */
317 int updateStats_dev(void) {
320 unsigned int flag
= 0;
321 static char interface
[16];
326 if ((dev
= fopen("/proc/net/dev", "r")) == NULL
) {
327 fprintf(stderr
, "/proc/net/dev does not exist?\n"
328 "Perhaps we are not running Linux?\n");
331 /* the first two lines we can skip */
332 fgets(buffer
, 256, dev
);
333 fgets(buffer
, 256, dev
);
335 /* IP Chain Rules for Linux kernel 2_1.x */
336 while(flag
!= (ACCOUNT_IN_FOUND
|ACCOUNT_OUT_FOUND
) && fgets(buffer
, 256, dev
)) {
338 sscanf(buffer
, "%16s %llu %llu %*d %*d %*d %*d %*d %*d %llu %llu %*d %*d %*d %*d %*d %*d",
339 interface
, &totalbytes_in
, &totalpackets_in
, &totalbytes_out
, &totalpackets_out
);
341 /* strip trailing colon */
343 while(*ptr
!= ':') ptr
++;
346 if (!strcmp(interface
, device
)) {
348 flag
= (ACCOUNT_IN_FOUND
|ACCOUNT_OUT_FOUND
);
350 if (totalpackets_in
!= lastpackets_in
) {
351 diffbytes_in
+= totalbytes_in
- lastbytes_in
;
352 lastpackets_in
= totalpackets_in
;
353 lastbytes_in
= totalbytes_in
;
357 if (totalpackets_out
!= lastpackets_out
) {
358 diffbytes_out
+= totalbytes_out
- lastbytes_out
;
359 lastpackets_out
= totalpackets_out
;
360 lastbytes_out
= totalbytes_out
;
368 /* return True if no change to tx/rx
369 * return False if display will need to be updated
371 return((rx
== current_rx
) && (tx
== current_tx
));
376 if((devfd
= open("/proc/net/dev", O_RDONLY
)) == -1) return False
;
377 read(devfd
, buffer
, 36);
378 if(buffer
[35] == '|') return False
;
379 if(device
== NULL
) device
= "eth0";
380 fprintf(stderr
, "wmnet: using devstats driver to monitor %s\n", device
);
384 #endif /* USE_2_1_DEV */
388 pppfd
= socket(AF_INET
, SOCK_DGRAM
, 0);
389 if(device
== NULL
) device
= "ppp0";
390 strncpy(ppp_stats_req
.ifr__name
, device
, 15);
391 ppp_stats_req
.stats_ptr
=(caddr_t
) &ppp_stats_req
.stats
;
392 fprintf(stderr
, "wmnet: using pppstats driver to monitor %s\n", device
);
397 int updateStats_ppp(void) {
398 if(ioctl(pppfd
, SIOCGPPPSTATS
, &ppp_stats_req
) != 0) {
401 totalpackets_in
= ppp_stats_req
.stats
.p
.ppp_ipackets
;
402 if (totalpackets_in
!= lastpackets_in
) {
403 totalbytes_in
= ppp_stats_req
.stats
.p
.ppp_ibytes
;
404 diffbytes_in
+= totalbytes_in
- lastbytes_in
;
405 lastpackets_in
= totalpackets_in
;
406 lastbytes_in
= totalbytes_in
;
411 totalpackets_out
= ppp_stats_req
.stats
.p
.ppp_opackets
;
412 if (totalpackets_out
!= lastpackets_out
) {
413 totalbytes_out
=ppp_stats_req
.stats
.p
.ppp_obytes
;
414 diffbytes_out
+= totalbytes_out
- lastbytes_out
;
415 lastpackets_out
= totalpackets_out
;
416 lastbytes_out
= totalbytes_out
;
420 /* return True if no change to tx/rx
421 * return False if display will need to be updated
423 return((rx
== current_rx
) && (tx
== current_tx
));
428 #endif /* USE_LINUX_PPP */
435 if (((kvmfd
= kvm_open(NULL
, NULL
, NULL
, O_RDONLY
, buffer
)) == NULL
) ||
436 (kvm_nlist(kvmfd
, symbols
) < 0) ||
437 kvm_read(kvmfd
, (unsigned long)symbols
[0].n_value
, &ifnet_savedaddr
, sizeof(unsigned long)) == -1 ) return False
;
438 if(device
== NULL
) device
= "ec0";
439 fprintf(stderr
, "wmnet: using kmem driver to monitor %s\n", device
);
443 int kvm_updateStats(void) {
444 struct ifnet
* ifnet
= (struct ifnet
*)buffer
;
445 unsigned long ifnet_addr
= ifnet_savedaddr
;
448 while (ifnet_addr
&& flag
!= (ACCOUNT_IN_FOUND
|ACCOUNT_OUT_FOUND
)) {
449 kvm_read(kvmfd
, ifnet_addr
, buffer
, sizeof(struct ifnet
));
451 snprintf(devname
, 15, "%s", ifnet
->if_xname
);
453 kvm_read(kvmfd
, (unsigned long)ifnet
->if_name
, devname
, 15);
454 snprintf(devname
, 15, "%s%d", devname
, ifnet
->if_unit
);
456 if(!strncmp(devname
, device
, strlen(device
))) { /* we found our struct */
457 totalpackets_in
=ifnet
->if_ipackets
;
458 if (totalpackets_in
!= lastpackets_in
) {
459 totalbytes_in
= ifnet
->if_ibytes
;
460 diffpackets_in
+= totalpackets_in
- lastpackets_in
;
461 diffbytes_in
+= totalbytes_in
- lastbytes_in
;
462 lastpackets_in
= totalpackets_in
;
463 lastbytes_in
= totalbytes_in
;
468 totalpackets_out
= ifnet
->if_opackets
;
469 if (totalpackets_out
!= lastpackets_out
) {
470 totalbytes_out
=ifnet
->if_obytes
;
471 diffpackets_out
+= totalpackets_out
- lastpackets_out
;
472 diffbytes_out
+= totalbytes_out
- lastbytes_out
;
473 lastpackets_out
= totalpackets_out
;
474 lastbytes_out
= totalbytes_out
;
477 flag
= (ACCOUNT_IN_FOUND
|ACCOUNT_OUT_FOUND
);
481 ifnet_addr
= (unsigned long)ifnet
->if_list
.tqe_next
;
483 ifnet_addr
= (unsigned long)ifnet
->if_next
;
488 /* return True if no change to tx/rx
489 * return False if display will need to be updated
491 return((rx
== current_rx
) && (tx
== current_tx
));