ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/i-scream/projects/libstatgrab/src/libstatgrab/network_stats.c
Revision: 1.55
Committed: Tue Mar 9 11:29:46 2004 UTC (20 years, 2 months ago) by ats
Content type: text/plain
Branch: MAIN
Changes since 1.54: +3 -1 lines
Log Message:
Add a FIXME note on the network interface stats code; some Solaris
interfaces have packet counts but not byte counts, so it would be useful
to return those once we have a way of indicating the byte count is
unknown.

File Contents

# User Rev Content
1 tdb 1.22 /*
2 pajs 1.1 * i-scream central monitoring system
3 tdb 1.15 * http://www.i-scream.org
4 tdb 1.22 * Copyright (C) 2000-2004 i-scream
5 pajs 1.1 *
6 tdb 1.22 * This library is free software; you can redistribute it and/or
7     * modify it under the terms of the GNU Lesser General Public
8     * License as published by the Free Software Foundation; either
9     * version 2.1 of the License, or (at your option) any later version.
10 pajs 1.1 *
11 tdb 1.22 * This library is distributed in the hope that it will be useful,
12 pajs 1.1 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 tdb 1.22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14     * Lesser General Public License for more details.
15 pajs 1.1 *
16 tdb 1.22 * You should have received a copy of the GNU Lesser General Public
17     * License along with this library; if not, write to the Free Software
18     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19     * 02111-1307 USA
20 tdb 1.23 *
21 ats 1.55 * $Id: network_stats.c,v 1.54 2004/03/08 13:48:00 tdb Exp $
22 pajs 1.1 */
23    
24     #ifdef HAVE_CONFIG_H
25     #include "config.h"
26     #endif
27    
28 tdb 1.4 #include <stdlib.h>
29 pajs 1.6 #include <string.h>
30 pajs 1.1 #include "statgrab.h"
31 tdb 1.11 #include <time.h>
32 pajs 1.1 #ifdef SOLARIS
33     #include <kstat.h>
34     #include <sys/sysinfo.h>
35 ats 1.44 #include <sys/types.h>
36     #include <sys/socket.h>
37     #include <sys/ioctl.h>
38     #include <net/if.h>
39     #include <netinet/in.h>
40     #include <sys/sockio.h>
41 pajs 1.6 #endif
42     #ifdef LINUX
43     #include <stdio.h>
44     #include <sys/types.h>
45     #include <regex.h>
46 pajs 1.27 #include <sys/ioctl.h>
47     #include <sys/socket.h>
48     #include <net/if.h>
49     #include <ctype.h>
50 pajs 1.6 #include "tools.h"
51 pajs 1.27 /* Stuff which could be defined by defining KERNEL, but
52     * that would be a bad idea, so we'll just declare it here
53     */
54     typedef __uint8_t u8;
55     typedef __uint16_t u16;
56     typedef __uint32_t u32;
57 ats 1.42 typedef __uint64_t u64;
58 pajs 1.27 #include <linux/ethtool.h>
59     #include <linux/sockios.h>
60 ats 1.32 #include <unistd.h>
61 pajs 1.1 #endif
62 ats 1.18 #ifdef ALLBSD
63 pajs 1.14 #include <sys/types.h>
64     #include <sys/socket.h>
65     #include <ifaddrs.h>
66     #include <net/if.h>
67 pajs 1.26 #include <net/if_media.h>
68     #include <sys/ioctl.h>
69 pajs 1.14 #endif
70 pajs 1.1
71 pajs 1.3 static network_stat_t *network_stats=NULL;
72     static int interfaces=0;
73 pajs 1.1
74 pajs 1.3 void network_stat_init(int start, int end, network_stat_t *net_stats){
75    
76     for(net_stats+=start; start<end; start++){
77     net_stats->interface_name=NULL;
78     net_stats->tx=0;
79     net_stats->rx=0;
80 tdb 1.47 net_stats->ipackets=0;
81     net_stats->opackets=0;
82     net_stats->ierrors=0;
83     net_stats->oerrors=0;
84     net_stats->collisions=0;
85 pajs 1.3 net_stats++;
86     }
87     }
88    
89     network_stat_t *network_stat_malloc(int needed_entries, int *cur_entries, network_stat_t *net_stats){
90    
91     if(net_stats==NULL){
92    
93     if((net_stats=malloc(needed_entries * sizeof(network_stat_t)))==NULL){
94 pajs 1.1 return NULL;
95     }
96 pajs 1.3 network_stat_init(0, needed_entries, net_stats);
97     *cur_entries=needed_entries;
98    
99 pajs 1.1 return net_stats;
100     }
101 pajs 1.3
102    
103     if(*cur_entries<needed_entries){
104     net_stats=realloc(net_stats, (sizeof(network_stat_t)*needed_entries));
105     if(net_stats==NULL){
106 pajs 1.1 return NULL;
107     }
108 pajs 1.3 network_stat_init(*cur_entries, needed_entries, net_stats);
109     *cur_entries=needed_entries;
110 pajs 1.1 }
111    
112     return net_stats;
113     }
114    
115 pajs 1.3
116 pajs 1.1 network_stat_t *get_network_stats(int *entries){
117 pajs 1.6
118     static int sizeof_network_stats=0;
119     network_stat_t *network_stat_ptr;
120    
121     #ifdef SOLARIS
122 pajs 1.1 kstat_ctl_t *kc;
123     kstat_t *ksp;
124     kstat_named_t *knp;
125 pajs 1.6 #endif
126 pajs 1.3
127 pajs 1.6 #ifdef LINUX
128     FILE *f;
129 pajs 1.12 /* Horrible big enough, but it should be easily big enough */
130 pajs 1.6 char line[8096];
131     regex_t regex;
132 ats 1.49 regmatch_t line_match[9];
133 pajs 1.14 #endif
134 ats 1.18 #ifdef ALLBSD
135 pajs 1.14 struct ifaddrs *net, *net_ptr;
136     struct if_data *net_data;
137     #endif
138    
139 ats 1.18 #ifdef ALLBSD
140 pajs 1.14 if(getifaddrs(&net) != 0){
141     return NULL;
142     }
143    
144     interfaces=0;
145    
146     for(net_ptr=net;net_ptr!=NULL;net_ptr=net_ptr->ifa_next){
147     if(net_ptr->ifa_addr->sa_family != AF_LINK) continue;
148     network_stats=network_stat_malloc((interfaces+1), &sizeof_network_stats, network_stats);
149     if(network_stats==NULL){
150     return NULL;
151     }
152     network_stat_ptr=network_stats+interfaces;
153    
154     if(network_stat_ptr->interface_name!=NULL) free(network_stat_ptr->interface_name);
155     network_stat_ptr->interface_name=strdup(net_ptr->ifa_name);
156     if(network_stat_ptr->interface_name==NULL) return NULL;
157     net_data=(struct if_data *)net_ptr->ifa_data;
158     network_stat_ptr->rx=net_data->ifi_ibytes;
159 tdb 1.46 network_stat_ptr->tx=net_data->ifi_obytes;
160     network_stat_ptr->ipackets=net_data->ifi_ipackets;
161     network_stat_ptr->opackets=net_data->ifi_opackets;
162     network_stat_ptr->ierrors=net_data->ifi_ierrors;
163     network_stat_ptr->oerrors=net_data->ifi_oerrors;
164     network_stat_ptr->collisions=net_data->ifi_collisions;
165 pajs 1.14 network_stat_ptr->systime=time(NULL);
166     interfaces++;
167     }
168     freeifaddrs(net);
169 pajs 1.6 #endif
170 pajs 1.1
171 pajs 1.6 #ifdef SOLARIS
172 pajs 1.1 if ((kc = kstat_open()) == NULL) {
173     return NULL;
174     }
175    
176 pajs 1.6 interfaces=0;
177 pajs 1.3
178 pajs 1.1 for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) {
179     if (!strcmp(ksp->ks_class, "net")) {
180     kstat_read(kc, ksp, NULL);
181    
182 pajs 1.7 #ifdef SOL7
183 tdb 1.53 #define LRX "rbytes"
184     #define LTX "obytes"
185     #define LIPACKETS "ipackets"
186     #define LOPACKETS "opackets"
187 pajs 1.7 #define VALTYPE value.ui32
188     #else
189 tdb 1.53 #define LRX "rbytes64"
190     #define LTX "obytes64"
191     #define LIPACKETS "ipackets64"
192     #define LOPACKETS "opackets64"
193 pajs 1.7 #define VALTYPE value.ui64
194     #endif
195    
196 tdb 1.53 /* Read rx */
197     if((knp=kstat_data_lookup(ksp, LRX))==NULL){
198 ats 1.44 /* This is a network interface, but it doesn't
199     * have the rbytes/obytes values; for instance,
200     * the loopback devices have this behaviour
201     * (although they do track packets in/out). */
202 ats 1.55 /* FIXME: Show packet counts when byte counts
203     * not available. */
204 pajs 1.1 continue;
205     }
206 pajs 1.3
207 tdb 1.53 /* Create new network_stats */
208 pajs 1.3 network_stats=network_stat_malloc((interfaces+1), &sizeof_network_stats, network_stats);
209 pajs 1.1 if(network_stats==NULL){
210     return NULL;
211     }
212     network_stat_ptr=network_stats+interfaces;
213 tdb 1.53
214     /* Finish reading rx */
215 pajs 1.7 network_stat_ptr->rx=knp->VALTYPE;
216 pajs 1.1
217 tdb 1.53 /* Read tx */
218     if((knp=kstat_data_lookup(ksp, LTX))==NULL){
219 pajs 1.1 continue;
220     }
221 pajs 1.7 network_stat_ptr->tx=knp->VALTYPE;
222 tdb 1.53
223     /* Read ipackets */
224     if((knp=kstat_data_lookup(ksp, LIPACKETS))==NULL){
225     continue;
226     }
227     network_stat_ptr->ipackets=knp->VALTYPE;
228    
229     /* Read opackets */
230     if((knp=kstat_data_lookup(ksp, LOPACKETS))==NULL){
231     continue;
232     }
233     network_stat_ptr->opackets=knp->VALTYPE;
234    
235     /* Read ierrors */
236     if((knp=kstat_data_lookup(ksp, "ierrors"))==NULL){
237     continue;
238     }
239     network_stat_ptr->ierrors=knp->value.ui32;
240    
241     /* Read oerrors */
242     if((knp=kstat_data_lookup(ksp, "oerrors"))==NULL){
243     continue;
244     }
245     network_stat_ptr->oerrors=knp->value.ui32;
246    
247     /* Read collisions */
248     if((knp=kstat_data_lookup(ksp, "collisions"))==NULL){
249     continue;
250     }
251     network_stat_ptr->collisions=knp->value.ui32;
252    
253     /* Read interface name */
254 pajs 1.1 if(network_stat_ptr->interface_name!=NULL){
255     free(network_stat_ptr->interface_name);
256     }
257     network_stat_ptr->interface_name=strdup(ksp->ks_name);
258 pajs 1.3
259 tdb 1.53 /* Store systime */
260 pajs 1.3 network_stat_ptr->systime=time(NULL);
261 tdb 1.53
262 pajs 1.1 interfaces++;
263     }
264     }
265 pajs 1.2
266     kstat_close(kc);
267 pajs 1.6 #endif
268     #ifdef LINUX
269     f=fopen("/proc/net/dev", "r");
270     if(f==NULL){
271     return NULL;
272     }
273     /* read the 2 lines.. Its the title, so we dont care :) */
274     fgets(line, sizeof(line), f);
275     fgets(line, sizeof(line), f);
276    
277    
278 ats 1.50 if((regcomp(&regex, "^ *([^:]+): *([0-9]+) +([0-9]+) +([0-9]+) +[0-9]+ +[0-9]+ +[0-9]+ +[0-9]+ +[0-9]+ +([0-9]+) +([0-9]+) +([0-9]+) +[0-9]+ +[0-9]+ +([0-9]+)", REG_EXTENDED))!=0){
279 pajs 1.6 return NULL;
280     }
281    
282     interfaces=0;
283 pajs 1.1
284 pajs 1.6 while((fgets(line, sizeof(line), f)) != NULL){
285 ats 1.51 if((regexec(&regex, line, 9, line_match, 0))!=0){
286 pajs 1.6 continue;
287     }
288     network_stats=network_stat_malloc((interfaces+1), &sizeof_network_stats, network_stats);
289     if(network_stats==NULL){
290     return NULL;
291     }
292     network_stat_ptr=network_stats+interfaces;
293    
294     if(network_stat_ptr->interface_name!=NULL){
295     free(network_stat_ptr->interface_name);
296     }
297    
298     network_stat_ptr->interface_name=get_string_match(line, &line_match[1]);
299     network_stat_ptr->rx=get_ll_match(line, &line_match[2]);
300 tdb 1.48 network_stat_ptr->tx=get_ll_match(line, &line_match[5]);
301     network_stat_ptr->ipackets=get_ll_match(line, &line_match[3]);
302     network_stat_ptr->opackets=get_ll_match(line, &line_match[6]);
303     network_stat_ptr->ierrors=get_ll_match(line, &line_match[4]);
304     network_stat_ptr->oerrors=get_ll_match(line, &line_match[7]);
305     network_stat_ptr->collisions=get_ll_match(line, &line_match[8]);
306 pajs 1.6 network_stat_ptr->systime=time(NULL);
307    
308     interfaces++;
309     }
310 pajs 1.12 fclose(f);
311 pajs 1.13 regfree(&regex);
312 pajs 1.6
313     #endif
314 ats 1.20
315     #ifdef CYGWIN
316     return NULL;
317     #endif
318    
319 pajs 1.1 *entries=interfaces;
320    
321     return network_stats;
322 pajs 1.3 }
323    
324 pajs 1.8 long long transfer_diff(long long new, long long old){
325 tdb 1.45 #if defined(SOL7) || defined(LINUX) || defined(FREEBSD) || defined(DFBSD)
326 tdb 1.52 #define MAXVAL 0xffffffffLL
327 pajs 1.8 #else
328 tdb 1.52 #define MAXVAL 0xffffffffffffffffLL
329 pajs 1.8 #endif
330     long long result;
331 pajs 1.10 if(new>=old){
332 pajs 1.8 result = (new-old);
333     }else{
334     result = (MAXVAL+(new-old));
335     }
336    
337     return result;
338    
339     }
340    
341 ats 1.24 network_stat_t *get_network_stats_diff(int *entries) {
342     static network_stat_t *diff = NULL;
343     static int diff_count = 0;
344     network_stat_t *src, *dest;
345     int i, j, new_count;
346    
347     if (network_stats == NULL) {
348     /* No previous stats, so we can't calculate a difference. */
349     return get_network_stats(entries);
350 pajs 1.3 }
351    
352 ats 1.24 /* Resize the results array to match the previous stats. */
353     diff = network_stat_malloc(interfaces, &diff_count, diff);
354     if (diff == NULL) {
355 pajs 1.3 return NULL;
356     }
357    
358 ats 1.24 /* Copy the previous stats into the result. */
359     for (i = 0; i < diff_count; i++) {
360     src = &network_stats[i];
361     dest = &diff[i];
362 pajs 1.3
363 ats 1.24 if (dest->interface_name != NULL) {
364     free(dest->interface_name);
365 pajs 1.3 }
366 ats 1.24 dest->interface_name = strdup(src->interface_name);
367     dest->rx = src->rx;
368     dest->tx = src->tx;
369 tdb 1.47 dest->ipackets = src->ipackets;
370     dest->opackets = src->opackets;
371     dest->ierrors = src->ierrors;
372     dest->oerrors = src->oerrors;
373     dest->collisions = src->collisions;
374 ats 1.24 dest->systime = src->systime;
375     }
376 pajs 1.3
377 ats 1.24 /* Get a new set of stats. */
378     if (get_network_stats(&new_count) == NULL) {
379 ats 1.21 return NULL;
380     }
381 pajs 1.3
382 ats 1.24 /* For each previous stat... */
383     for (i = 0; i < diff_count; i++) {
384     dest = &diff[i];
385    
386     /* ... find the corresponding new stat ... */
387     for (j = 0; j < new_count; j++) {
388     /* Try the new stat in the same position first,
389     since that's most likely to be it. */
390     src = &network_stats[(i + j) % new_count];
391     if (strcmp(src->interface_name, dest->interface_name) == 0) {
392     break;
393     }
394     }
395     if (j == new_count) {
396     /* No match found. */
397     continue;
398 pajs 1.3 }
399    
400 ats 1.24 /* ... and subtract the previous stat from it to get the
401     difference. */
402     dest->rx = transfer_diff(src->rx, dest->rx);
403     dest->tx = transfer_diff(src->tx, dest->tx);
404 tdb 1.47 dest->ipackets = transfer_diff(src->ipackets, dest->ipackets);
405     dest->opackets = transfer_diff(src->opackets, dest->opackets);
406     dest->ierrors = transfer_diff(src->ierrors, dest->ierrors);
407     dest->oerrors = transfer_diff(src->oerrors, dest->oerrors);
408     dest->collisions = transfer_diff(src->collisions, dest->collisions);
409 ats 1.24 dest->systime = src->systime - dest->systime;
410 pajs 1.3 }
411    
412 ats 1.24 *entries = diff_count;
413     return diff;
414     }
415 pajs 1.25 /* NETWORK INTERFACE STATS */
416    
417     void network_iface_stat_init(int start, int end, network_iface_stat_t *net_stats){
418    
419     for(net_stats+=start; start<end; start++){
420     net_stats->interface_name=NULL;
421     net_stats->speed=0;
422 ats 1.31 net_stats->dup=UNKNOWN_DUPLEX;
423 pajs 1.25 net_stats++;
424     }
425     }
426    
427     network_iface_stat_t *network_iface_stat_malloc(int needed_entries, int *cur_entries, network_iface_stat_t *net_stats){
428    
429     if(net_stats==NULL){
430    
431     if((net_stats=malloc(needed_entries * sizeof(network_iface_stat_t)))==NULL){
432     return NULL;
433     }
434     network_iface_stat_init(0, needed_entries, net_stats);
435     *cur_entries=needed_entries;
436    
437     return net_stats;
438     }
439    
440    
441     if(*cur_entries<needed_entries){
442     net_stats=realloc(net_stats, (sizeof(network_iface_stat_t)*needed_entries));
443     if(net_stats==NULL){
444     return NULL;
445     }
446     network_iface_stat_init(*cur_entries, needed_entries, net_stats);
447     *cur_entries=needed_entries;
448     }
449    
450     return net_stats;
451     }
452    
453     network_iface_stat_t *get_network_iface_stats(int *entries){
454     static network_iface_stat_t *network_iface_stats;
455     network_iface_stat_t *network_iface_stat_ptr;
456     static int sizeof_network_iface_stats=0;
457 ats 1.43 int ifaces = 0;
458 pajs 1.25
459     #ifdef SOLARIS
460     kstat_ctl_t *kc;
461     kstat_t *ksp;
462     kstat_named_t *knp;
463 ats 1.44 int sock;
464 pajs 1.25 #endif
465 pajs 1.26 #ifdef ALLBSD
466     struct ifaddrs *net, *net_ptr;
467     struct ifmediareq ifmed;
468 pajs 1.36 struct ifreq ifr;
469 ats 1.37 int sock;
470 pajs 1.26 int x;
471     #endif
472 pajs 1.27 #ifdef LINUX
473     FILE *f;
474     /* Horrible big enough, but it should be easily big enough */
475     char line[8096];
476     int sock;
477     #endif
478 ats 1.43
479 pajs 1.26 #ifdef ALLBSD
480     if(getifaddrs(&net) != 0){
481     return NULL;
482     }
483    
484 ats 1.37 if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) == 0) return NULL;
485 pajs 1.26
486     for(net_ptr=net; net_ptr!=NULL; net_ptr=net_ptr->ifa_next){
487     if(net_ptr->ifa_addr->sa_family != AF_LINK) continue;
488     network_iface_stats=network_iface_stat_malloc((ifaces+1), &sizeof_network_iface_stats, network_iface_stats);
489     if(network_iface_stats==NULL){
490     return NULL;
491     }
492     network_iface_stat_ptr = network_iface_stats + ifaces;
493    
494 ats 1.40 memset(&ifr, 0, sizeof(ifr));
495     strncpy(ifr.ifr_name, net_ptr->ifa_name, sizeof(ifr.ifr_name));
496    
497     if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0){
498     continue;
499     }
500     if((ifr.ifr_flags & IFF_UP) != 0){
501     network_iface_stat_ptr->up = 1;
502     }else{
503     network_iface_stat_ptr->up = 0;
504     }
505    
506     if (network_iface_stat_ptr->interface_name != NULL) free(network_iface_stat_ptr->interface_name);
507     network_iface_stat_ptr->interface_name = strdup(net_ptr->ifa_name);
508     if (network_iface_stat_ptr->interface_name == NULL) return NULL;
509    
510     network_iface_stat_ptr->speed = 0;
511     network_iface_stat_ptr->dup = UNKNOWN_DUPLEX;
512     ifaces++;
513    
514 pajs 1.26 memset(&ifmed, 0, sizeof(struct ifmediareq));
515     strlcpy(ifmed.ifm_name, net_ptr->ifa_name, sizeof(ifmed.ifm_name));
516 ats 1.37 if(ioctl(sock, SIOCGIFMEDIA, (caddr_t)&ifmed) == -1){
517 ats 1.40 /* Not all interfaces support the media ioctls. */
518 pajs 1.26 continue;
519     }
520    
521     /* We may need to change this if we start doing wireless devices too */
522     if( (ifmed.ifm_active | IFM_ETHER) != ifmed.ifm_active ){
523     /* Not a ETHER device */
524     continue;
525     }
526    
527     /* Only intrested in the first 4 bits) - Assuming only ETHER devices */
528     x = ifmed.ifm_active & 0x0f;
529     switch(x){
530     /* 10 Mbit connections. Speedy :) */
531     case(IFM_10_T):
532     case(IFM_10_2):
533     case(IFM_10_5):
534     case(IFM_10_STP):
535     case(IFM_10_FL):
536     network_iface_stat_ptr->speed = 10;
537     break;
538     /* 100 Mbit conneections */
539     case(IFM_100_TX):
540     case(IFM_100_FX):
541     case(IFM_100_T4):
542     case(IFM_100_VG):
543     case(IFM_100_T2):
544     network_iface_stat_ptr->speed = 100;
545     break;
546     /* 1000 Mbit connections */
547     case(IFM_1000_SX):
548     case(IFM_1000_LX):
549     case(IFM_1000_CX):
550 tdb 1.54 #if defined(IFM_1000_TX) && !defined(OPENBSD)
551     case(IFM_1000_TX): /* FreeBSD 4 and others (but NOT OpenBSD)? */
552 tdb 1.45 #endif
553     #ifdef IFM_1000_FX
554     case(IFM_1000_FX): /* FreeBSD 4 */
555     #endif
556     #ifdef IFM_1000_T
557     case(IFM_1000_T): /* FreeBSD 5 */
558 tdb 1.28 #endif
559 pajs 1.26 network_iface_stat_ptr->speed = 1000;
560     break;
561     /* We don't know what it is */
562     default:
563     network_iface_stat_ptr->speed = 0;
564     break;
565     }
566    
567     if( (ifmed.ifm_active | IFM_FDX) == ifmed.ifm_active ){
568     network_iface_stat_ptr->dup = FULL_DUPLEX;
569     }else if( (ifmed.ifm_active | IFM_HDX) == ifmed.ifm_active ){
570     network_iface_stat_ptr->dup = HALF_DUPLEX;
571     }else{
572 ats 1.31 network_iface_stat_ptr->dup = UNKNOWN_DUPLEX;
573 pajs 1.26 }
574 pajs 1.36
575 pajs 1.26 }
576     freeifaddrs(net);
577 ats 1.37 close(sock);
578 pajs 1.26 #endif
579 pajs 1.25
580     #ifdef SOLARIS
581 ats 1.44 if ((kc = kstat_open()) == NULL) {
582     return NULL;
583     }
584    
585     if ((sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP)) < 0) {
586     return NULL;
587     }
588 pajs 1.25
589 ats 1.44 for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) {
590     if (!strcmp(ksp->ks_class, "net")) {
591     struct ifreq ifr;
592    
593     kstat_read(kc, ksp, NULL);
594    
595     strncpy(ifr.ifr_name, ksp->ks_name, sizeof ifr.ifr_name);
596     if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0) {
597     /* Not a network interface. */
598 pajs 1.25 continue;
599     }
600 ats 1.44
601     network_iface_stats = network_iface_stat_malloc(ifaces + 1, &sizeof_network_iface_stats, network_iface_stats);
602     if (network_iface_stats == NULL) {
603 pajs 1.25 return NULL;
604     }
605 pajs 1.26 network_iface_stat_ptr = network_iface_stats + ifaces;
606 ats 1.44 ifaces++;
607    
608     if (network_iface_stat_ptr->interface_name != NULL) free(network_iface_stat_ptr->interface_name);
609     network_iface_stat_ptr->interface_name = strdup(ksp->ks_name);
610     if (network_iface_stat_ptr->interface_name == NULL) return NULL;
611 pajs 1.25
612 ats 1.44 if ((ifr.ifr_flags & IFF_UP) != 0) {
613     network_iface_stat_ptr->up = 1;
614     } else {
615     network_iface_stat_ptr->up = 1;
616     }
617 pajs 1.35
618 ats 1.44 if ((knp = kstat_data_lookup(ksp, "ifspeed")) != NULL) {
619     network_iface_stat_ptr->speed = knp->value.ui64 / (1000 * 1000);
620     } else {
621     network_iface_stat_ptr->speed = 0;
622 pajs 1.25 }
623    
624 pajs 1.33 network_iface_stat_ptr->dup = UNKNOWN_DUPLEX;
625 ats 1.44 if ((knp = kstat_data_lookup(ksp, "link_duplex")) != NULL) {
626     switch (knp->value.ui32) {
627     case 1:
628     network_iface_stat_ptr->dup = HALF_DUPLEX;
629     break;
630     case 2:
631     network_iface_stat_ptr->dup = FULL_DUPLEX;
632     break;
633     }
634 pajs 1.33 }
635 pajs 1.25 }
636     }
637 ats 1.44
638     close(sock);
639 pajs 1.25 kstat_close(kc);
640     #endif
641 pajs 1.27 #ifdef LINUX
642     f = fopen("/proc/net/dev", "r");
643     if(f == NULL){
644     return NULL;
645     }
646    
647     /* Setup stuff so we can do the ioctl to get the info */
648     if((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0){
649     return NULL;
650     }
651    
652     /* Ignore first 2 lines.. Just headings */
653 pajs 1.29 if((fgets(line, sizeof(line), f)) == NULL) return NULL;
654     if((fgets(line, sizeof(line), f)) == NULL) return NULL;
655 pajs 1.27
656     while((fgets(line, sizeof(line), f)) != NULL){
657     char *name, *ptr;
658     struct ifreq ifr;
659 ats 1.38 struct ethtool_cmd ethcmd;
660 pajs 1.27 int err;
661    
662     /* Get the interface name */
663     ptr = strchr(line, ':');
664     if (ptr == NULL) continue;
665     *ptr='\0';
666     name = line;
667     while(isspace(*(name))){
668     name++;
669     }
670    
671 ats 1.38 memset(&ifr, 0, sizeof ifr);
672     strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name);
673 pajs 1.27
674 ats 1.38 if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0) {
675     continue;
676     }
677 pajs 1.27
678     /* We have a good interface to add */
679     network_iface_stats=network_iface_stat_malloc((ifaces+1), &sizeof_network_iface_stats, network_iface_stats);
680     if(network_iface_stats==NULL){
681     return NULL;
682     }
683     network_iface_stat_ptr = network_iface_stats + ifaces;
684     network_iface_stat_ptr->interface_name = strdup(name);
685 ats 1.38 if ((ifr.ifr_flags & IFF_UP) != 0) {
686 pajs 1.35 network_iface_stat_ptr->up = 1;
687 ats 1.38 } else {
688 pajs 1.35 network_iface_stat_ptr->up = 0;
689     }
690    
691 ats 1.38 memset(&ethcmd, 0, sizeof ethcmd);
692     ethcmd.cmd = ETHTOOL_GSET;
693     ifr.ifr_data = (caddr_t) &ethcmd;
694    
695     err = ioctl(sock, SIOCETHTOOL, &ifr);
696     if (err == 0) {
697     network_iface_stat_ptr->speed = ethcmd.speed;
698    
699     switch (ethcmd.duplex) {
700     case 0x00:
701     network_iface_stat_ptr->dup = FULL_DUPLEX;
702     break;
703     case 0x01:
704     network_iface_stat_ptr->dup = HALF_DUPLEX;
705     break;
706     default:
707     network_iface_stat_ptr->dup = UNKNOWN_DUPLEX;
708     }
709     } else {
710     /* Not all interfaces support the ethtool ioctl. */
711 ats 1.39 network_iface_stat_ptr->speed = 0;
712 ats 1.38 network_iface_stat_ptr->dup = UNKNOWN_DUPLEX;
713 pajs 1.27 }
714 ats 1.38
715 pajs 1.27 ifaces++;
716     }
717 pajs 1.30 close(sock);
718 ats 1.38 fclose(f);
719 pajs 1.27 #endif
720 pajs 1.26 *entries = ifaces;
721 pajs 1.25 return network_iface_stats;
722     }
723