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) {
322 dev
= fopen("/proc/net/dev", "r");
324 fprintf(stderr
, "/proc/net/dev does not exist\n");
328 /* the first two lines we can skip */
329 fgets(buffer
, 256, dev
);
330 fgets(buffer
, 256, dev
);
332 while(fgets(buffer
, 256, dev
)) {
334 if (strcmp(buffer
, device
) > 0){
336 sscanf(buffer
, "%*s %llu %llu %*d %*d %*d %*d %*d %*d %llu %llu %*d %*d %*d %*d %*d %*d",
337 &totalbytes_in
, &totalpackets_in
, &totalbytes_out
, &totalpackets_out
);
339 if (totalpackets_in
!= lastpackets_in
) {
340 diffbytes_in
+= totalbytes_in
- lastbytes_in
;
341 lastpackets_in
= totalpackets_in
;
342 lastbytes_in
= totalbytes_in
;
346 if (totalpackets_out
!= lastpackets_out
) {
347 diffbytes_out
+= totalbytes_out
- lastbytes_out
;
348 lastpackets_out
= totalpackets_out
;
349 lastbytes_out
= totalbytes_out
;
359 /* return True if no change to tx/rx
360 * return False if display will need to be updated
362 return((rx
== current_rx
) && (tx
== current_tx
));
367 if((devfd
= open("/proc/net/dev", O_RDONLY
)) == -1) return False
;
368 read(devfd
, buffer
, 36);
369 if(buffer
[35] == '|') return False
;
370 if(device
== NULL
) device
= "eth0";
371 fprintf(stderr
, "wmnet: using devstats driver to monitor %s\n", device
);
375 #endif /* USE_2_1_DEV */
379 pppfd
= socket(AF_INET
, SOCK_DGRAM
, 0);
380 if(device
== NULL
) device
= "ppp0";
381 strncpy(ppp_stats_req
.ifr__name
, device
, 15);
382 ppp_stats_req
.stats_ptr
=(caddr_t
) &ppp_stats_req
.stats
;
383 fprintf(stderr
, "wmnet: using pppstats driver to monitor %s\n", device
);
388 int updateStats_ppp(void) {
389 if(ioctl(pppfd
, SIOCGPPPSTATS
, &ppp_stats_req
) != 0) {
392 totalpackets_in
= ppp_stats_req
.stats
.p
.ppp_ipackets
;
393 if (totalpackets_in
!= lastpackets_in
) {
394 totalbytes_in
= ppp_stats_req
.stats
.p
.ppp_ibytes
;
395 diffbytes_in
+= totalbytes_in
- lastbytes_in
;
396 lastpackets_in
= totalpackets_in
;
397 lastbytes_in
= totalbytes_in
;
402 totalpackets_out
= ppp_stats_req
.stats
.p
.ppp_opackets
;
403 if (totalpackets_out
!= lastpackets_out
) {
404 totalbytes_out
=ppp_stats_req
.stats
.p
.ppp_obytes
;
405 diffbytes_out
+= totalbytes_out
- lastbytes_out
;
406 lastpackets_out
= totalpackets_out
;
407 lastbytes_out
= totalbytes_out
;
411 /* return True if no change to tx/rx
412 * return False if display will need to be updated
414 return((rx
== current_rx
) && (tx
== current_tx
));
419 #endif /* USE_LINUX_PPP */
426 if (((kvmfd
= kvm_open(NULL
, NULL
, NULL
, O_RDONLY
, buffer
)) == NULL
) ||
427 (kvm_nlist(kvmfd
, symbols
) < 0) ||
428 kvm_read(kvmfd
, (unsigned long)symbols
[0].n_value
, &ifnet_savedaddr
, sizeof(unsigned long)) == -1 ) return False
;
429 if(device
== NULL
) device
= "ec0";
430 fprintf(stderr
, "wmnet: using kmem driver to monitor %s\n", device
);
434 int kvm_updateStats(void) {
435 struct ifnet
* ifnet
= (struct ifnet
*)buffer
;
436 unsigned long ifnet_addr
= ifnet_savedaddr
;
439 while (ifnet_addr
&& flag
!= (ACCOUNT_IN_FOUND
|ACCOUNT_OUT_FOUND
)) {
440 kvm_read(kvmfd
, ifnet_addr
, buffer
, sizeof(struct ifnet
));
442 snprintf(devname
, 15, "%s", ifnet
->if_xname
);
444 kvm_read(kvmfd
, (unsigned long)ifnet
->if_name
, devname
, 15);
445 snprintf(devname
, 15, "%s%d", devname
, ifnet
->if_unit
);
447 if(!strncmp(devname
, device
, strlen(device
))) { /* we found our struct */
448 totalpackets_in
=ifnet
->if_ipackets
;
449 if (totalpackets_in
!= lastpackets_in
) {
450 totalbytes_in
= ifnet
->if_ibytes
;
451 diffpackets_in
+= totalpackets_in
- lastpackets_in
;
452 diffbytes_in
+= totalbytes_in
- lastbytes_in
;
453 lastpackets_in
= totalpackets_in
;
454 lastbytes_in
= totalbytes_in
;
459 totalpackets_out
= ifnet
->if_opackets
;
460 if (totalpackets_out
!= lastpackets_out
) {
461 totalbytes_out
=ifnet
->if_obytes
;
462 diffpackets_out
+= totalpackets_out
- lastpackets_out
;
463 diffbytes_out
+= totalbytes_out
- lastbytes_out
;
464 lastpackets_out
= totalpackets_out
;
465 lastbytes_out
= totalbytes_out
;
468 flag
= (ACCOUNT_IN_FOUND
|ACCOUNT_OUT_FOUND
);
472 ifnet_addr
= (unsigned long)ifnet
->if_list
.tqe_next
;
474 ifnet_addr
= (unsigned long)ifnet
->if_next
;
479 /* return True if no change to tx/rx
480 * return False if display will need to be updated
482 return((rx
== current_rx
) && (tx
== current_tx
));