ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/i-scream/projects/libstatgrab/src/libstatgrab/network_stats.c
Revision: 1.59
Committed: Sun Apr 4 22:52:16 2004 UTC (20 years, 1 month ago) by ats
Content type: text/plain
Branch: MAIN
Changes since 1.58: +40 -95 lines
Log Message:
Make network_stats use vectors.

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