ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/i-scream/projects/libstatgrab/src/libstatgrab/network_stats.c
Revision: 1.72
Committed: Thu Feb 24 18:35:11 2005 UTC (19 years, 2 months ago) by tdb
Content type: text/plain
Branch: MAIN
CVS Tags: LIBSTATGRAB_0_11_1
Changes since 1.71: +3 -3 lines
Log Message:
The labels in this case statement were the wrong way round, so the duplex
settings were being reported incorrectly on linux. Use the defines instead
of the values so we can be sure they're right.

Spotted by Pete.

File Contents

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