/* KSysGuard, the KDE System Guard Copyright (c) 1999, 2000 Chris Schlaeger Solaris support by Torsten Kasch This program is free software; you can redistribute it and/or modify it under the terms of version 2 of the GNU General Public License as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include #include #include #include #include #include #include "config.h" #ifdef HAVE_KSTAT #include #endif #include "ksysguardd.h" #include "Command.h" #include "NetDev.h" /* * available network interface statistics through kstat(3): * * kstat name value * ---------------------------------------------------------------------- * for the loopback interface(s) we can get * ipackets # packets received * opackets # packets sent * in addition to those, for "real" interfaces: * oerrors # xmit errors * ierrors # recv errors * macxmt_errors # xmit errors reported by hardware? * macrcv_errors # recv errors reported by hardware? * opackets64 same as opackets (64bit) * ipackets64 same as ipackets (64bit) * obytes # bytes sent * rbytes # bytes received * obytes64 same as obytes (64bit) * rbytes64 same as ibytes (64bit) * collisions # collisions * multixmt # multicasts sent? * multircv # multicasts received? * brdcstxmt # broadcasts transmitted * brdcstrcv # broadcasts received * unknowns * blocked * ex_collisions * defer_xmts * align_errors * fcs_errors * oflo # overflow errors * uflo # underflow errors * runt_errors * missed * tx_late_collisions * carrier_errors * noxmtbuf * norcvbuf * xmt_badinterp * rcv_badinterp * intr # interrupts? * xmtretry # xmit retries? * ifspeed interface speed: 10000000 for 10BaseT * duplex "half" or "full" * media e.g. "PHY/MII" * promisc promiscuous mode (e.g. "off") * first_collisions * multi_collisions * sqe_errors * toolong_errors */ typedef struct { char *Name; short flags; unsigned long ipackets; unsigned long OLDipackets; unsigned long opackets; unsigned long OLDopackets; unsigned long ierrors; unsigned long OLDierrors; unsigned long oerrors; unsigned long OLDoerrors; unsigned long collisions; unsigned long OLDcollisions; unsigned long multixmt; unsigned long OLDmultixmt; unsigned long multircv; unsigned long OLDmultircv; unsigned long brdcstxmt; unsigned long OLDbrdcstxmt; unsigned long brdcstrcv; unsigned long OLDbrdcstrcv; } NetDevInfo; #define NBUFFERS 64 #define MAXNETDEVS 64 static NetDevInfo IfInfo[MAXNETDEVS]; static int NetDevCount; /* * insertnetdev() -- insert device name & flags into our list */ int insertnetdev( const char *name, const short flags ) { int i = 0; /* * interface "aliases" don't seem to have * separate kstat statistics, so we skip them */ if( strchr( name, (int) ':' ) != NULL ) return( 0 ); while( (i < NetDevCount) && (strcmp( IfInfo[i].Name, name ) != 0) ) { if( strcmp( IfInfo[i].Name, name ) == 0 ) return( 0 ); i++; } /* * init new slot */ IfInfo[i].Name = strdup( name ); IfInfo[i].flags = flags; IfInfo[i].ipackets = 0L; IfInfo[i].OLDipackets = 0L; IfInfo[i].opackets = 0L; IfInfo[i].OLDopackets = 0L; IfInfo[i].ierrors = 0L; IfInfo[i].OLDierrors = 0L; IfInfo[i].oerrors = 0L; IfInfo[i].OLDoerrors = 0L; IfInfo[i].collisions = 0L; IfInfo[i].OLDcollisions = 0L; IfInfo[i].multixmt = 0L; IfInfo[i].OLDmultixmt = 0L; IfInfo[i].multircv = 0L; IfInfo[i].OLDmultircv = 0L; IfInfo[i].brdcstxmt = 0L; IfInfo[i].OLDbrdcstxmt = 0L; IfInfo[i].brdcstrcv = 0L; IfInfo[i].OLDbrdcstrcv = 0L; NetDevCount = ++i; /* XXX: need sanity checks! */ return( 0 ); } /* * getnetdevlist() -- get a list of all "up" interfaces */ int getnetdevlist( void ) { int fd; int buffsize; int prevsize; int prevCount; struct ifconf ifc; struct ifreq *ifr; if( (fd = socket( PF_INET, SOCK_DGRAM, 0 )) < 0 ) { return( -1 ); } /* * get the interface list via iotl( SIOCGIFCONF ) * the following algorithm based on ideas from W.R. Stevens' * "UNIX Network Programming", Vol. 1: * Since the ioctl may return 0, indicating success, even if the * ifreq buffer was too small, we have to make sure, it didn't * get truncated by comparing our initial size guess with the * actual returned size. */ prevsize = 0; buffsize = NBUFFERS * sizeof( struct ifreq ); while( 1 ) { if( (ifc.ifc_buf = malloc( buffsize )) == NULL ) return( -1 ); ifc.ifc_len = buffsize; if( ioctl( fd, SIOCGIFCONF, &ifc ) < 0 ) { if( errno != EINVAL || prevsize != 0 ) { free( ifc.ifc_buf ); return( -1 ); } } else { if( ifc.ifc_len == prevsize ) /* success */ break; prevsize = ifc.ifc_len; } /* * initial buffer guessed too small, allocate a bigger one */ free( ifc.ifc_buf ); buffsize = (NBUFFERS + 10) * sizeof( struct ifreq ); } /* * get the names for all interfaces which are configured "up" * we're not interested in the ifc data (address), so we reuse the * same structure (with ifc.len set) for the next ioctl() */ prevCount = NetDevCount; for( ifr = (struct ifreq *) ifc.ifc_buf; ifr < (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len); ifr++ ) { if( ioctl( fd, SIOCGIFFLAGS, ifr ) < 0 ) { free( ifc.ifc_buf ); return( -1 ); } if( ifr->ifr_flags & IFF_UP ) insertnetdev( ifr->ifr_name, ifr->ifr_flags ); } free( ifc.ifc_buf ); close( fd ); if( (prevCount > 0) && (prevCount != NetDevCount) ) { print_error( "RECONFIGURE\n" ); prevCount = NetDevCount; } return( NetDevCount ); } void initNetDev( struct SensorModul* sm ) { #ifdef HAVE_KSTAT char mon[128]; int i; getnetdevlist(); for( i = 0; i < NetDevCount; i++ ) { sprintf( mon, "network/%s/ipackets", IfInfo[i].Name ); registerMonitor( mon, "integer", printIPackets, printIPacketsInfo, sm ); sprintf( mon, "network/%s/opackets", IfInfo[i].Name ); registerMonitor( mon, "integer", printOPackets, printOPacketsInfo, sm ); /* * if this isn't a loopback interface, * register additional monitors */ if( ! (IfInfo[i].flags & IFF_LOOPBACK) ) { /* * recv errors */ sprintf( mon, "network/%s/ierrors", IfInfo[i].Name ); registerMonitor( mon, "integer", printIErrors, printIErrorsInfo, sm ); /* * xmit errors */ sprintf( mon, "network/%s/oerrors", IfInfo[i].Name ); registerMonitor( mon, "integer", printOErrors, printOErrorsInfo, sm ); /* * collisions */ sprintf( mon, "network/%s/collisions", IfInfo[i].Name ); registerMonitor( mon, "integer", printCollisions, printCollisionsInfo, sm ); /* * multicast xmits */ sprintf( mon, "network/%s/multixmt", IfInfo[i].Name ); registerMonitor( mon, "integer", printMultiXmits, printMultiXmitsInfo, sm ); /* * multicast recvs */ sprintf( mon, "network/%s/multircv", IfInfo[i].Name ); registerMonitor( mon, "integer", printMultiRecvs, printMultiRecvsInfo, sm ); /* * broadcast xmits */ sprintf( mon, "network/%s/brdcstxmt", IfInfo[i].Name ); registerMonitor( mon, "integer", printBcastXmits, printBcastXmitsInfo, sm ); /* * broadcast recvs */ sprintf( mon, "network/%s/brdcstrcv", IfInfo[i].Name ); registerMonitor( mon, "integer", printBcastRecvs, printBcastRecvsInfo, sm ); } } #endif } void exitNetDev( void ) { } int updateNetDev( void ) { #ifdef HAVE_KSTAT kstat_ctl_t *kctl; kstat_t *ksp; kstat_named_t *kdata; int i; /* * get a kstat handle and update the user's kstat chain */ if( (kctl = kstat_open()) == NULL ) return( 0 ); while( kstat_chain_update( kctl ) != 0 ) ; for( i = 0; i < NetDevCount; i++ ) { char *name; char *ptr; /* * chop off the trailing interface no */ name = strdup( IfInfo[i].Name ); ptr = name + strlen( name ) - 1; while( (ptr > name) && isdigit( (int) *ptr ) ) { *ptr = '\0'; ptr--; } /* * traverse the kstat chain * to find the appropriate statistics */ if( (ksp = kstat_lookup( kctl, name, 0, IfInfo[i].Name )) == NULL ) { free( name ); return( 0 ); } if( kstat_read( kctl, ksp, NULL ) == -1 ) { free( name ); return( 0 ); } free( name ); /* * lookup & store the data */ kdata = (kstat_named_t *) kstat_data_lookup( ksp, "ipackets" ); if( kdata != NULL ) { IfInfo[i].OLDipackets = IfInfo[i].ipackets; IfInfo[i].ipackets = kdata->value.ul; } kdata = (kstat_named_t *) kstat_data_lookup( ksp, "opackets" ); if( kdata != NULL ) { IfInfo[i].OLDopackets = IfInfo[i].opackets; IfInfo[i].opackets = kdata->value.ul; } kdata = (kstat_named_t *) kstat_data_lookup( ksp, "ierrors" ); if( kdata != NULL ) { IfInfo[i].OLDierrors = IfInfo[i].ierrors; IfInfo[i].ierrors = kdata->value.ul; } kdata = (kstat_named_t *) kstat_data_lookup( ksp, "oerrors" ); if( kdata != NULL ) { IfInfo[i].OLDoerrors = IfInfo[i].oerrors; IfInfo[i].oerrors = kdata->value.ul; } kdata = (kstat_named_t *) kstat_data_lookup( ksp, "collisions" ); if( kdata != NULL ) { IfInfo[i].OLDcollisions = IfInfo[i].collisions; IfInfo[i].collisions = kdata->value.ul; } kdata = (kstat_named_t *) kstat_data_lookup( ksp, "multixmt" ); if( kdata != NULL ) { IfInfo[i].OLDmultixmt = IfInfo[i].multixmt; IfInfo[i].multixmt = kdata->value.ul; } kdata = (kstat_named_t *) kstat_data_lookup( ksp, "multircv" ); if( kdata != NULL ) { IfInfo[i].OLDmultircv = IfInfo[i].multircv; IfInfo[i].multircv = kdata->value.ul; } kdata = (kstat_named_t *) kstat_data_lookup( ksp, "brdcstxmt" ); if( kdata != NULL ) { IfInfo[i].OLDbrdcstxmt = IfInfo[i].brdcstxmt; IfInfo[i].brdcstxmt = kdata->value.ul; } kdata = (kstat_named_t *) kstat_data_lookup( ksp, "brdcstrcv" ); if( kdata != NULL ) { IfInfo[i].OLDbrdcstrcv = IfInfo[i].brdcstrcv; IfInfo[i].brdcstrcv = kdata->value.ul; } } kstat_close( kctl ); #endif /* ! HAVE_KSTAT */ return( 0 ); } void printIPacketsInfo( const char *cmd ) { fprintf(CurrentClient, "Received Packets\t0\t0\tPackets\n" ); } void printIPackets( const char *cmd ) { char *cmdcopy = strdup( cmd ); char *name, *ptr; int i; ptr = strchr( cmdcopy, (int) '/' ); name = ++ptr; ptr = strchr( name, (int) '/' ); *ptr = '\0'; for( i = 0; i < NetDevCount; i++ ) { if( (IfInfo[i].OLDipackets > 0) && (strcmp( IfInfo[i].Name, name ) == 0) ) { fprintf(CurrentClient, "%ld\n", IfInfo[i].ipackets - IfInfo[i].OLDipackets); free( cmdcopy ); return; } } free( cmdcopy ); fprintf(CurrentClient, "0\n" ); } void printOPacketsInfo( const char *cmd ) { fprintf(CurrentClient, "Transmitted Packets\t0\t0\tPackets\n" ); } void printOPackets( const char *cmd ) { char *cmdcopy = strdup( cmd ); char *name, *ptr; int i; ptr = strchr( cmdcopy, (int) '/' ); name = ++ptr; ptr = strchr( name, (int) '/' ); *ptr = '\0'; for( i = 0; i < NetDevCount; i++ ) { if( (IfInfo[i].OLDopackets > 0) && (strcmp( IfInfo[i].Name, name ) == 0) ) { fprintf(CurrentClient, "%ld\n", IfInfo[i].opackets - IfInfo[i].OLDopackets ); free( cmdcopy ); return; } } free( cmdcopy ); fprintf(CurrentClient, "0\n" ); } void printIErrorsInfo( const char *cmd ) { fprintf(CurrentClient, "Input Errors\t0\t0\tPackets\n" ); } void printIErrors( const char *cmd ) { char *cmdcopy = strdup( cmd ); char *name, *ptr; int i; ptr = strchr( cmdcopy, (int) '/' ); name = ++ptr; ptr = strchr( name, (int) '/' ); *ptr = '\0'; for( i = 0; i < NetDevCount; i++ ) { if( (IfInfo[i].OLDierrors > 0) && (strcmp( IfInfo[i].Name, name ) == 0) ) { fprintf(CurrentClient, "%ld\n", IfInfo[i].ierrors - IfInfo[i].OLDierrors ); free( cmdcopy ); return; } } free( cmdcopy ); fprintf(CurrentClient, "0\n" ); } void printOErrorsInfo( const char *cmd ) { fprintf(CurrentClient, "Output Errors\t0\t0\tPackets\n" ); } void printOErrors( const char *cmd ) { char *cmdcopy = strdup( cmd ); char *name, *ptr; int i; ptr = strchr( cmdcopy, (int) '/' ); name = ++ptr; ptr = strchr( name, (int) '/' ); *ptr = '\0'; for( i = 0; i < NetDevCount; i++ ) { if( (IfInfo[i].OLDoerrors > 0) && (strcmp( IfInfo[i].Name, name ) == 0) ) { fprintf(CurrentClient, "%ld\n", IfInfo[i].oerrors - IfInfo[i].OLDoerrors ); free( cmdcopy ); return; } } free( cmdcopy ); fprintf(CurrentClient, "0\n" ); } void printCollisionsInfo( const char *cmd ) { fprintf(CurrentClient, "Collisions\t0\t0\tPackets\n" ); } void printCollisions( const char *cmd ) { char *cmdcopy = strdup( cmd ); char *name, *ptr; int i; ptr = strchr( cmdcopy, (int) '/' ); name = ++ptr; ptr = strchr( name, (int) '/' ); *ptr = '\0'; for( i = 0; i < NetDevCount; i++ ) { if( (IfInfo[i].OLDcollisions > 0) && (strcmp( IfInfo[i].Name, name ) == 0) ) { fprintf(CurrentClient, "%ld\n", IfInfo[i].collisions - IfInfo[i].OLDcollisions ); free( cmdcopy ); return; } } free( cmdcopy ); fprintf(CurrentClient, "0\n" ); } void printMultiXmitsInfo( const char *cmd ) { fprintf(CurrentClient, "Multicasts Sent\t0\t0\tPackets\n" ); } void printMultiXmits( const char *cmd ) { char *cmdcopy = strdup( cmd ); char *name, *ptr; int i; ptr = strchr( cmdcopy, (int) '/' ); name = ++ptr; ptr = strchr( name, (int) '/' ); *ptr = '\0'; for( i = 0; i < NetDevCount; i++ ) { if( (IfInfo[i].OLDmultixmt > 0) && (strcmp( IfInfo[i].Name, name ) == 0) ) { fprintf(CurrentClient, "%ld\n", IfInfo[i].multixmt - IfInfo[i].OLDmultixmt ); free( cmdcopy ); return; } } free( cmdcopy ); fprintf(CurrentClient, "0\n" ); } void printMultiRecvsInfo( const char *cmd ) { fprintf(CurrentClient, "Multicasts Received\t0\t0\tPackets\n" ); } void printMultiRecvs( const char *cmd ) { char *cmdcopy = strdup( cmd ); char *name, *ptr; int i; ptr = strchr( cmdcopy, (int) '/' ); name = ++ptr; ptr = strchr( name, (int) '/' ); *ptr = '\0'; for( i = 0; i < NetDevCount; i++ ) { if( (IfInfo[i].OLDmultircv > 0) && (strcmp( IfInfo[i].Name, name ) == 0) ) { fprintf(CurrentClient, "%ld\n", IfInfo[i].multircv - IfInfo[i].OLDmultircv ); free( cmdcopy ); return; } } free( cmdcopy ); fprintf(CurrentClient, "0\n" ); } void printBcastXmitsInfo( const char *cmd ) { fprintf(CurrentClient, "Broadcasts Sent\t0\t0\tPackets\n" ); } void printBcastXmits( const char *cmd ) { char *cmdcopy = strdup( cmd ); char *name, *ptr; int i; ptr = strchr( cmdcopy, (int) '/' ); name = ++ptr; ptr = strchr( name, (int) '/' ); *ptr = '\0'; for( i = 0; i < NetDevCount; i++ ) { if( (IfInfo[i].OLDbrdcstxmt > 0) && (strcmp( IfInfo[i].Name, name ) == 0) ) { fprintf(CurrentClient, "%ld\n", IfInfo[i].brdcstxmt - IfInfo[i].OLDbrdcstxmt ); free( cmdcopy ); return; } } free( cmdcopy ); fprintf(CurrentClient, "0\n" ); } void printBcastRecvsInfo( const char *cmd ) { fprintf(CurrentClient, "Broadcasts Received\t0\t0\tPackets\n" ); } void printBcastRecvs( const char *cmd ) { char *cmdcopy = strdup( cmd ); char *name, *ptr; int i; ptr = strchr( cmdcopy, (int) '/' ); name = ++ptr; ptr = strchr( name, (int) '/' ); *ptr = '\0'; for( i = 0; i < NetDevCount; i++ ) { if( (IfInfo[i].OLDbrdcstrcv > 0) && (strcmp( IfInfo[i].Name, name ) == 0) ) { fprintf(CurrentClient, "%ld\n", IfInfo[i].brdcstrcv - IfInfo[i].OLDbrdcstrcv ); free( cmdcopy ); return; } } free( cmdcopy ); fprintf(CurrentClient, "0\n" ); }