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 totalbytes_in
, totalbytes_out
, lastbytes_in
, lastbytes_out
;
63 extern unsigned long totalpackets_in
, totalpackets_out
, lastpackets_in
, lastpackets_out
;
64 extern unsigned int diffpackets_in
, diffpackets_out
, 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 diffpackets_in
+= totalpackets_in
- lastpackets_in
;
203 diffbytes_in
+= totalbytes_in
- lastbytes_in
;
204 lastpackets_in
= totalpackets_in
;
205 lastbytes_in
= totalbytes_in
;
208 case ACCOUNT_OUT_FOUND
:
210 flag
|= ACCOUNT_OUT_FOUND
;
211 while(buffer
[offset
++] != ' ');
213 totalpackets_out
= strtoul(&buffer
[offset
], &ptr
, 10);
214 if (totalpackets_out
== lastpackets_out
) break;
215 totalbytes_out
= strtoul(ptr
, NULL
, 10);
216 diffpackets_out
+= totalpackets_out
- lastpackets_out
;
217 diffbytes_out
+= totalbytes_out
- lastbytes_out
;
218 lastpackets_out
= totalpackets_out
;
219 lastbytes_out
= totalbytes_out
;
227 if(flag
!= (ACCOUNT_IN_FOUND
|ACCOUNT_OUT_FOUND
)) {
228 fprintf(stderr
,"wmnet: couldn't find %s accounting rule to monitor in /proc/net/ip_acct\n",
229 (flag
== ACCOUNT_IN_FOUND
) ? "the TX" : ((flag
== ACCOUNT_OUT_FOUND
) ? "the RX" : "a single"));
234 /* return True if no change to tx/rx
235 * return False if display will need to be updated
237 return((rx
== current_rx
) && (tx
== current_tx
));
240 #endif /* USE_IPFWADM */
243 int ipchains_test(void) {
244 if (open("/proc/net/ip_fwchains",O_RDONLY
) == -1) return False
;
245 if (in_rule_string
== NULL
) in_rule_string
= "acctin";
246 if (out_rule_string
== NULL
) out_rule_string
= "acctout";
247 fprintf(stderr
, "wmnet: using ipchains driver to monitor chains %s and %s\n", in_rule_string
, out_rule_string
);
251 /* ipchains parser mostly from Bjoern Kriews <bkr@cut.de> */
252 int updateStats_ipchains(void) {
254 unsigned int flag
= 0;
255 static char name
[32];
256 unsigned long pack
, bytes
;
261 if ((ip_acct
= fopen("/proc/net/ip_fwchains", "r")) == NULL
) {
262 fprintf(stderr
, "/proc/net/ip_fwchains does not exist?\n"
263 "Do you have IP accounting in your kernel?\n");
267 /* IP Chain Rules for Linux kernel 2_1.x */
268 while(flag
!= (ACCOUNT_IN_FOUND
|ACCOUNT_OUT_FOUND
) && fgets(buffer
, 256, ip_acct
)) {
271 sscanf(buffer
, "%30s %*s - %*d %*d %*d %*d %lu %*d %lu",
272 name
, &pack
, &bytes
);
275 if(strcmp(name
, in_rule_string
) == 0) {
276 flag
|= ACCOUNT_IN_FOUND
;
278 totalpackets_in
= pack
;
279 if (totalpackets_in
!= lastpackets_in
) {
280 totalbytes_in
= bytes
;
281 diffpackets_in
+= totalpackets_in
- lastpackets_in
;
282 diffbytes_in
+= totalbytes_in
- lastbytes_in
;
283 lastpackets_in
= totalpackets_in
;
284 lastbytes_in
= totalbytes_in
;
288 } else if (strcmp(name
, out_rule_string
) == 0) {
289 flag
|= ACCOUNT_OUT_FOUND
;
291 totalpackets_out
= pack
;
292 if (totalpackets_out
!= lastpackets_out
) {
293 totalbytes_out
= bytes
;
294 diffpackets_out
+= totalpackets_out
- lastpackets_out
;
295 diffbytes_out
+= totalbytes_out
- lastbytes_out
;
296 lastpackets_out
= totalpackets_out
;
297 lastbytes_out
= totalbytes_out
;
303 if(flag
!= (ACCOUNT_IN_FOUND
|ACCOUNT_OUT_FOUND
)) {
304 fprintf(stderr
,"I couldn't find %s IP chain to monitor in /proc/net/ip_fwchains.\n",
305 (flag
== ACCOUNT_IN_FOUND
) ? "the TX" : ((flag
== ACCOUNT_OUT_FOUND
) ? "the RX" : "a single"));
310 /* return True if no change to tx/rx
311 * return False if display will need to be updated
313 return((rx
== current_rx
) && (tx
== current_tx
));
316 #endif /* USE_IPCHAINS */
321 int updateStats_dev(void) {
324 unsigned int flag
= 0;
330 if ((dev
= fopen("/proc/net/dev", "r")) == NULL
) {
331 fprintf(stderr
, "/proc/net/dev does not exist?\n"
332 "Perhaps we are not running Linux?\n");
335 /* the first two lines we can skip */
336 fgets(buffer
, 256, dev
);
337 fgets(buffer
, 256, dev
);
339 /* IP Chain Rules for Linux kernel 2_1.x */
340 while(flag
!= (ACCOUNT_IN_FOUND
|ACCOUNT_OUT_FOUND
) && fgets(buffer
, 256, dev
)) {
342 while(*ptr
== ' ') ptr
++;
344 while(*ptr
!= ':') ptr
++;
347 if (!strcmp(name
, device
)) {
349 flag
= (ACCOUNT_IN_FOUND
|ACCOUNT_OUT_FOUND
);
351 totalpackets_in
= strtoul(&buffer
[15], NULL
, 10);
352 if (totalpackets_in
!= lastpackets_in
) {
353 totalbytes_in
= strtoul(&buffer
[7], NULL
, 10);
354 diffpackets_in
+= totalpackets_in
- lastpackets_in
;
355 diffbytes_in
+= totalbytes_in
- lastbytes_in
;
356 lastpackets_in
= totalpackets_in
;
357 lastbytes_in
= totalbytes_in
;
362 totalpackets_out
= strtoul(&buffer
[74], NULL
, 10);
363 if (totalpackets_out
!= lastpackets_out
) {
364 totalbytes_out
= strtoul(&buffer
[66], NULL
, 10);
365 diffpackets_out
+= totalpackets_out
- lastpackets_out
;
366 diffbytes_out
+= totalbytes_out
- lastbytes_out
;
367 lastpackets_out
= totalpackets_out
;
368 lastbytes_out
= totalbytes_out
;
376 /* return True if no change to tx/rx
377 * return False if display will need to be updated
379 return((rx
== current_rx
) && (tx
== current_tx
));
384 if((devfd
= open("/proc/net/dev", O_RDONLY
)) == -1) return False
;
385 read(devfd
, buffer
, 36);
386 if(buffer
[35] == '|') return False
;
387 if(device
== NULL
) device
= "eth0";
388 fprintf(stderr
, "wmnet: using devstats driver to monitor %s\n", device
);
392 #endif /* USE_2_1_DEV */
396 pppfd
= socket(AF_INET
, SOCK_DGRAM
, 0);
397 if(device
== NULL
) device
= "ppp0";
398 strncpy(ppp_stats_req
.ifr__name
, device
, 15);
399 ppp_stats_req
.stats_ptr
=(caddr_t
) &ppp_stats_req
.stats
;
400 fprintf(stderr
, "wmnet: using pppstats driver to monitor %s\n", device
);
405 int updateStats_ppp(void) {
406 if(ioctl(pppfd
, SIOCGPPPSTATS
, &ppp_stats_req
) != 0) {
409 totalpackets_in
= ppp_stats_req
.stats
.p
.ppp_ipackets
;
410 if (totalpackets_in
!= lastpackets_in
) {
411 totalbytes_in
= ppp_stats_req
.stats
.p
.ppp_ibytes
;
412 diffpackets_in
+= totalpackets_in
- lastpackets_in
;
413 diffbytes_in
+= totalbytes_in
- lastbytes_in
;
414 lastpackets_in
= totalpackets_in
;
415 lastbytes_in
= totalbytes_in
;
420 totalpackets_out
= ppp_stats_req
.stats
.p
.ppp_opackets
;
421 if (totalpackets_out
!= lastpackets_out
) {
422 totalbytes_out
=ppp_stats_req
.stats
.p
.ppp_obytes
;
423 diffpackets_out
+= totalpackets_out
- lastpackets_out
;
424 diffbytes_out
+= totalbytes_out
- lastbytes_out
;
425 lastpackets_out
= totalpackets_out
;
426 lastbytes_out
= totalbytes_out
;
430 /* return True if no change to tx/rx
431 * return False if display will need to be updated
433 return((rx
== current_rx
) && (tx
== current_tx
));
438 #endif /* USE_LINUX_PPP */
445 if (((kvmfd
= kvm_open(NULL
, NULL
, NULL
, O_RDONLY
, buffer
)) == NULL
) ||
446 (kvm_nlist(kvmfd
, symbols
) < 0) ||
447 kvm_read(kvmfd
, (unsigned long)symbols
[0].n_value
, &ifnet_savedaddr
, sizeof(unsigned long)) == -1 ) return False
;
448 if(device
== NULL
) device
= "ec0";
449 fprintf(stderr
, "wmnet: using kmem driver to monitor %s\n", device
);
453 int kvm_updateStats(void) {
454 struct ifnet
* ifnet
= (struct ifnet
*)buffer
;
455 unsigned long ifnet_addr
= ifnet_savedaddr
;
458 while (ifnet_addr
&& flag
!= (ACCOUNT_IN_FOUND
|ACCOUNT_OUT_FOUND
)) {
459 kvm_read(kvmfd
, ifnet_addr
, buffer
, sizeof(struct ifnet
));
461 snprintf(devname
, 15, "%s", ifnet
->if_xname
);
463 kvm_read(kvmfd
, (unsigned long)ifnet
->if_name
, devname
, 15);
464 snprintf(devname
, 15, "%s%d", devname
, ifnet
->if_unit
);
466 if(!strncmp(devname
, device
, strlen(device
))) { /* we found our struct */
467 totalpackets_in
=ifnet
->if_ipackets
;
468 if (totalpackets_in
!= lastpackets_in
) {
469 totalbytes_in
= ifnet
->if_ibytes
;
470 diffpackets_in
+= totalpackets_in
- lastpackets_in
;
471 diffbytes_in
+= totalbytes_in
- lastbytes_in
;
472 lastpackets_in
= totalpackets_in
;
473 lastbytes_in
= totalbytes_in
;
478 totalpackets_out
= ifnet
->if_opackets
;
479 if (totalpackets_out
!= lastpackets_out
) {
480 totalbytes_out
=ifnet
->if_obytes
;
481 diffpackets_out
+= totalpackets_out
- lastpackets_out
;
482 diffbytes_out
+= totalbytes_out
- lastbytes_out
;
483 lastpackets_out
= totalpackets_out
;
484 lastbytes_out
= totalbytes_out
;
487 flag
= (ACCOUNT_IN_FOUND
|ACCOUNT_OUT_FOUND
);
491 ifnet_addr
= (unsigned long)ifnet
->if_list
.tqe_next
;
493 ifnet_addr
= (unsigned long)ifnet
->if_next
;
498 /* return True if no change to tx/rx
499 * return False if display will need to be updated
501 return((rx
== current_rx
) && (tx
== current_tx
));