ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/i-scream/projects/libstatgrab/src/libstatgrab/network_stats.c
Revision: 1.43
Committed: Sat Feb 14 15:48:42 2004 UTC (20 years, 3 months ago) by ats
Content type: text/plain
Branch: MAIN
Changes since 1.42: +3 -3 lines
Log Message:
ifaces doesn't need to be static.

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