You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
483 lines
15 KiB
483 lines
15 KiB
/*
|
|
KSysGuard, the KDE System Guard
|
|
|
|
Copyright (c) 1999 - 2001 Chris Schlaeger <cs@kde.org>
|
|
|
|
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 <config.h>
|
|
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/time.h>
|
|
#include <fcntl.h>
|
|
#include <unistd.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
|
|
#include "Command.h"
|
|
#include "ksysguardd.h"
|
|
|
|
#include "netdev.h"
|
|
|
|
#define MON_SIZE 128
|
|
|
|
#define CALC( a, b, c, d, e, f ) \
|
|
{ \
|
|
if (f){ \
|
|
NetDevs[ i ].a = a - NetDevs[ i ].Old##a; \
|
|
NetDevs[ i ].Old##a = a; \
|
|
} \
|
|
else{ \
|
|
NetDevs[ i ].a = a; \
|
|
} \
|
|
}
|
|
|
|
#define REGISTERSENSOR( a, b, c, d, e, f ) \
|
|
{ \
|
|
snprintf( mon, MON_SIZE, "network/interfaces/%s/%s", tag, b ); \
|
|
registerMonitor( mon, "integer", printNetDev##a, printNetDev##a##Info, NetDevSM ); \
|
|
}
|
|
|
|
#define UNREGISTERSENSOR( a, b, c, d, e, f ) \
|
|
{ \
|
|
snprintf( mon, MON_SIZE, "network/interfaces/%s/%s", NetDevs[ i ].name, b ); \
|
|
removeMonitor( mon ); \
|
|
}
|
|
|
|
#define DEFMEMBERS( a, b, c, d, e, f ) \
|
|
signed long long Old##a; \
|
|
signed long long a; \
|
|
signed long a##Scale;
|
|
|
|
#define DEFVARS( a, b, c, d, e, f ) \
|
|
signed long long a;
|
|
|
|
|
|
/*The sixth variable is 1 if the quantity variation must be provided, 0 if the absolute value must be provided */
|
|
#define FORALL( a ) \
|
|
a( recBytes, "receiver/data", "Received Data", "kBytes/s", 1024, 1) \
|
|
a( recPacks, "receiver/packets", "Received Packets", "1/s", 1, 1 ) \
|
|
a( recErrs, "receiver/errors", "Receiver Errors", "1/s", 1, 1 ) \
|
|
a( recDrop, "receiver/drops", "Receiver Drops", "1/s", 1, 1 ) \
|
|
a( recFifo, "receiver/fifo", "Receiver FIFO Overruns", "1/s", 1, 1 ) \
|
|
a( recFrame, "receiver/frame", "Receiver Frame Errors", "1/s", 1, 1 ) \
|
|
a( recCompressed, "receiver/compressed", "Received Compressed Packets", "1/s", 1, 1 ) \
|
|
a( recMulticast, "receiver/multicast", "Received Multicast Packets", "1/s", 1, 1 ) \
|
|
a( sentBytes, "transmitter/data", "Sent Data", "kBytes/s", 1024, 1 ) \
|
|
a( sentPacks, "transmitter/packets", "Sent Packets", "1/s", 1, 1 ) \
|
|
a( sentErrs, "transmitter/errors", "Transmitter Errors", "1/s", 1, 1 ) \
|
|
a( sentDrop, "transmitter/drops", "Transmitter Drops", "1/s", 1, 1 ) \
|
|
a( sentFifo, "transmitter/fifo", "Transmitter FIFO overruns", "1/s", 1, 1 ) \
|
|
a( sentColls, "transmitter/collisions", "Transmitter Collisions", "1/s", 1, 1 ) \
|
|
a( sentCarrier, "transmitter/carrier", "Transmitter Carrier losses", "1/s", 1, 1 ) \
|
|
a( sentCompressed, "transmitter/compressed", "Transmitter Compressed Packets", "1/s", 1, 1 )
|
|
|
|
#define FORALLWIFI( a ) \
|
|
a( linkQuality, "wifi/quality", "Link Quality", "", 1, 0) \
|
|
a( signalLevel, "wifi/signal", "Signal Level", "dBm", 1, 0) \
|
|
a( noiseLevel, "wifi/noise", "Noise Level", "dBm", 1, 0) \
|
|
a( nwid, "wifi/nwid", "Rx Invalid Nwid Packets", "1/s", 1, 1) \
|
|
a( RxCrypt, "wifi/crypt", "Rx Invalid Crypt Packets", "1/s", 1, 1) \
|
|
a( frag, "wifi/frag", "Rx Invalid Frag Packets", "1/s", 1, 1) \
|
|
a( retry, "wifi/retry", "Tx Excessive Retries Packets", "1/s", 1, 1) \
|
|
a( misc, "wifi/misc", "Invalid Misc Packets", "1/s", 1, 1) \
|
|
a( beacon, "wifi/beacon", "Missed Beacon", "1/s", 1, 1)
|
|
|
|
#define SETZERO( a, b, c, d, e, f ) \
|
|
a = 0;
|
|
|
|
#define SETMEMBERZERO( a, b, c, d, e, f ) \
|
|
NetDevs[ i ].a = 0; \
|
|
NetDevs[ i ].a##Scale = e;
|
|
|
|
#define DECLAREFUNC( a, b, c, d, e, f ) \
|
|
void printNetDev##a( const char* cmd ); \
|
|
void printNetDev##a##Info( const char* cmd );
|
|
|
|
typedef struct
|
|
{
|
|
FORALL( DEFMEMBERS )
|
|
FORALLWIFI( DEFMEMBERS )
|
|
char name[ 32 ];
|
|
int wifi;
|
|
} NetDevInfo;
|
|
|
|
/* We have observed deviations of up to 5% in the accuracy of the timer
|
|
* interrupts. So we try to measure the interrupt interval and use this
|
|
* value to calculate timing dependant values. */
|
|
static float timeInterval = 0;
|
|
static struct timeval lastSampling;
|
|
static struct timeval currSampling;
|
|
static struct SensorModul* NetDevSM;
|
|
|
|
#define NETDEVBUFSIZE 4096
|
|
static char NetDevBuf[ NETDEVBUFSIZE ];
|
|
static char NetDevWifiBuf[ NETDEVBUFSIZE ];
|
|
static int NetDevCnt = 0;
|
|
static int Dirty = 0;
|
|
static int NetDevOk = 0;
|
|
static long OldHash = 0;
|
|
|
|
#define MAXNETDEVS 64
|
|
static NetDevInfo NetDevs[ MAXNETDEVS ];
|
|
|
|
void processNetDev( void );
|
|
|
|
FORALL( DECLAREFUNC )
|
|
FORALLWIFI( DECLAREFUNC )
|
|
|
|
static int processNetDev_( void )
|
|
{
|
|
int i,j;
|
|
char format[ 32 ];
|
|
char devFormat[ 16 ];
|
|
char buf[ 1024 ];
|
|
char tag[ 64 ];
|
|
char* netDevBufP = NetDevBuf;
|
|
char* netDevWifiBufP = NetDevWifiBuf;
|
|
|
|
sprintf( format, "%%%d[^\n]\n", (int)sizeof( buf ) - 1 );
|
|
sprintf( devFormat, "%%%ds", (int)sizeof( tag ) - 1 );
|
|
|
|
/* skip 2 first lines */
|
|
for ( i = 0; i < 2; i++ ) {
|
|
sscanf( netDevBufP, format, buf );
|
|
buf[ sizeof( buf ) - 1 ] = '\0';
|
|
netDevBufP += strlen( buf ) + 1; /* move netDevBufP to next line */
|
|
}
|
|
|
|
for ( i = 0; sscanf( netDevBufP, format, buf ) == 1; ++i ) {
|
|
buf[ sizeof( buf ) - 1 ] = '\0';
|
|
netDevBufP += strlen( buf ) + 1; /* move netDevBufP to next line */
|
|
|
|
if ( sscanf( buf, devFormat, tag ) ) {
|
|
char* pos = strchr( tag, ':' );
|
|
if ( pos ) {
|
|
FORALL( DEFVARS );
|
|
*pos = '\0';
|
|
FORALL( SETZERO );
|
|
sscanf( buf + 7, "%lli %lli %lli %lli %lli %lli %lli %lli "
|
|
"%lli %lli %lli %lli %lli %lli %lli %lli",
|
|
&recBytes, &recPacks, &recErrs, &recDrop, &recFifo,
|
|
&recFrame, &recCompressed, &recMulticast,
|
|
&sentBytes, &sentPacks, &sentErrs, &sentDrop,
|
|
&sentFifo, &sentColls, &sentCarrier, &sentCompressed );
|
|
|
|
if ( i >= NetDevCnt || strcmp( NetDevs[ i ].name, tag ) != 0 ) {
|
|
/* The network device configuration has changed. We
|
|
* need to reconfigure the netdev module. */
|
|
return -1;
|
|
} else {
|
|
FORALL( CALC );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( i != NetDevCnt )
|
|
return -1;
|
|
|
|
/*Update the values for the wifi interfaces*/
|
|
if ( *netDevWifiBufP=='\0') /*there is no /proc/net/wireless file*/
|
|
return 0;
|
|
|
|
/* skip 2 first lines */
|
|
for ( i = 0; i < 2; i++ ) {
|
|
sscanf( netDevWifiBufP, format, buf );
|
|
buf[ sizeof( buf ) - 1 ] = '\0';
|
|
netDevWifiBufP += strlen( buf ) + 1; /* move netDevWifiBufP to next line */
|
|
}
|
|
|
|
for ( j = 0; sscanf( netDevWifiBufP, format, buf ) == 1; ++j ) {
|
|
buf[ sizeof( buf ) - 1 ] = '\0';
|
|
netDevWifiBufP += strlen( buf ) + 1; /* move netDevWifiBufP to next line */
|
|
|
|
if ( sscanf( buf, devFormat, tag ) ) {
|
|
char* pos = strchr( tag, ':' );
|
|
if ( pos ) {
|
|
FORALLWIFI( DEFVARS );
|
|
*pos = '\0';
|
|
|
|
for (i = 0 ; i < NetDevCnt ; ++i){ /*find the corresponding interface*/
|
|
if ( strcmp(tag,NetDevs[ i ].name)==0){
|
|
break;
|
|
}
|
|
}
|
|
sscanf( buf + 12, " %lli. %lli. %lli. %lli %lli %lli %lli %lli %lli",
|
|
&linkQuality, &signalLevel, &noiseLevel, &nwid,
|
|
&RxCrypt, &frag, &retry, &misc, &beacon );
|
|
signalLevel -= 256; /*the units are dBm*/
|
|
noiseLevel -= 256;
|
|
FORALLWIFI( CALC );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/* save exact time inverval between this and the last read of
|
|
* /proc/net/dev */
|
|
timeInterval = currSampling.tv_sec - lastSampling.tv_sec +
|
|
( currSampling.tv_usec - lastSampling.tv_usec ) / 1000000.0;
|
|
lastSampling = currSampling;
|
|
Dirty = 0;
|
|
|
|
return 0;
|
|
}
|
|
|
|
void processNetDev( void )
|
|
{
|
|
int i;
|
|
|
|
if ( NetDevCnt == 0 )
|
|
return;
|
|
|
|
for ( i = 0; i < 5 && processNetDev_() < 0; ++i )
|
|
checkNetDev();
|
|
|
|
/* If 5 reconfiguration attemts failed, something is very wrong and
|
|
* we close the netdev module for further use. */
|
|
if ( i == 5 )
|
|
exitNetDev();
|
|
}
|
|
|
|
/*
|
|
================================ public part =================================
|
|
*/
|
|
|
|
void initNetDev( struct SensorModul* sm )
|
|
{
|
|
int i,j;
|
|
char format[ 32 ];
|
|
char devFormat[ 16 ];
|
|
char buf[ 1024 ];
|
|
char tag[ 64 ];
|
|
char* netDevBufP = NetDevBuf;
|
|
char* netDevWifiBufP = NetDevWifiBuf;
|
|
|
|
NetDevSM = sm;
|
|
|
|
if ( updateNetDev() < 0 )
|
|
return;
|
|
|
|
sprintf( format, "%%%d[^\n]\n", (int)sizeof( buf ) - 1 );
|
|
sprintf( devFormat, "%%%ds", (int)sizeof( tag ) - 1 );
|
|
|
|
/* skip 2 first lines */
|
|
for ( i = 0; i < 2; i++ ) {
|
|
sscanf( netDevBufP, format, buf );
|
|
buf[ sizeof( buf ) - 1 ] = '\0';
|
|
netDevBufP += strlen( buf ) + 1; /* move netDevBufP to next line */
|
|
}
|
|
|
|
for ( i = 0; sscanf( netDevBufP, format, buf ) == 1; ++i ) {
|
|
buf[ sizeof( buf ) - 1 ] = '\0';
|
|
netDevBufP += strlen( buf ) + 1; /* move netDevBufP to next line */
|
|
|
|
if ( sscanf( buf, devFormat, tag ) ) {
|
|
char* pos = strchr( tag, ':' );
|
|
if ( pos ) {
|
|
char mon[ MON_SIZE ];
|
|
*pos = '\0';
|
|
strlcpy( NetDevs[ i ].name, tag, sizeof( NetDevs[ i ].name ) );
|
|
FORALL( REGISTERSENSOR );
|
|
sscanf( pos + 1, "%lli %lli %lli %lli %lli %lli %lli %lli"
|
|
"%lli %lli %lli %lli %lli %lli %lli %lli",
|
|
&NetDevs[ i ].recBytes, &NetDevs[ i ].recPacks,
|
|
&NetDevs[ i ].recErrs, &NetDevs[ i ].recDrop,
|
|
&NetDevs[ i ].recFifo, &NetDevs[ i ].recFrame,
|
|
&NetDevs[ i ].recCompressed, &NetDevs[ i ].recMulticast,
|
|
&NetDevs[ i ].sentBytes, &NetDevs[ i ].sentPacks,
|
|
&NetDevs[ i ].sentErrs, &NetDevs[ i ].sentDrop,
|
|
&NetDevs[ i ].sentFifo, &NetDevs[ i ].sentColls,
|
|
&NetDevs[ i ].sentCarrier, &NetDevs[ i ].sentCompressed );
|
|
NetDevCnt++;
|
|
}
|
|
FORALL( SETMEMBERZERO );
|
|
}
|
|
|
|
}
|
|
|
|
/* detect the wifi interfaces*/
|
|
/* skip 2 first lines */
|
|
for ( i = 0; i < 2; i++ ) {
|
|
sscanf( netDevWifiBufP, format, buf );
|
|
buf[ sizeof( buf ) - 1 ] = '\0';
|
|
netDevWifiBufP += strlen( buf ) + 1; /* move netDevWifiBufP to next line */
|
|
}
|
|
|
|
for ( j = 0; sscanf( netDevWifiBufP, format, buf ) == 1; ++j ) {
|
|
buf[ sizeof( buf ) - 1 ] = '\0';
|
|
netDevWifiBufP += strlen( buf ) + 1; /* move netDevWifiBufP to next line */
|
|
|
|
if ( sscanf( buf, devFormat, tag ) ) {
|
|
char * pos = strchr( tag, ':' );
|
|
if ( pos ) {
|
|
char mon[ MON_SIZE ];
|
|
*pos = '\0';
|
|
/*find and tag the corresponding NetDev as wifi enabled.
|
|
At the end of the loop, i is the index of the device.
|
|
This variable i is used in some macro */
|
|
for (i = 0 ; i < NetDevCnt ; ++i){
|
|
if ( strcmp(tag,NetDevs[ i ].name)==0){
|
|
NetDevs[ i ].wifi = 1;
|
|
break;
|
|
}
|
|
}
|
|
FORALLWIFI( REGISTERSENSOR );
|
|
}
|
|
FORALLWIFI( SETMEMBERZERO ); /* the variable i must point to the corrrect NetDevs[i]*/
|
|
}
|
|
}
|
|
|
|
/* Call processNetDev to elimitate initial peek values. */
|
|
processNetDev();
|
|
}
|
|
|
|
void exitNetDev( void )
|
|
{
|
|
int i;
|
|
|
|
for ( i = 0; i < NetDevCnt; ++i ) {
|
|
char mon[ MON_SIZE ];
|
|
FORALL( UNREGISTERSENSOR );
|
|
if (NetDevs[ i ].wifi)
|
|
FORALLWIFI( UNREGISTERSENSOR );
|
|
}
|
|
NetDevCnt = 0;
|
|
}
|
|
|
|
int updateNetDev( void )
|
|
{
|
|
/* We read the information about the network interfaces from
|
|
/proc/net/dev. The file should look like this:
|
|
|
|
Inter-| Receive | Transmit
|
|
face | bytes packets errs drop fifo frame compressed multicast| bytes packets errs drop fifo colls carrier compressed
|
|
lo:275135772 1437448 0 0 0 0 0 0 275135772 1437448 0 0 0 0 0 0
|
|
eth0:123648812 655251 0 0 0 0 0 0 246847871 889636 0 0 0 0 0 0 Inter-| Receive | Transmit
|
|
face | bytes packets errs drop fifo frame compressed multicast|bytes packets errs drop fifo colls carrier compressed
|
|
lo:275135772 1437448 0 0 0 0 0 0 275135772 1437448 0 0 0 0 0 0
|
|
eth0:123648812 655251 0 0 0 0 0 0 246847871 889636 0 0 0 0 0 0
|
|
*/
|
|
|
|
size_t n;
|
|
int fd;
|
|
long hash;
|
|
char* p;
|
|
|
|
if ( NetDevOk < 0 )
|
|
return 0;
|
|
|
|
if ( ( fd = open( "/proc/net/dev", O_RDONLY ) ) < 0 ) {
|
|
/* /proc/net/dev may not exist on some machines. */
|
|
NetDevOk = -1;
|
|
return 0;
|
|
}
|
|
|
|
if ( ( n = read( fd, NetDevBuf, NETDEVBUFSIZE - 1 ) ) == NETDEVBUFSIZE - 1 ) {
|
|
log_error( "Internal buffer too small to read \'/proc/net/dev\'" );
|
|
NetDevOk = -1;
|
|
|
|
close( fd );
|
|
return -1;
|
|
}
|
|
|
|
gettimeofday( &currSampling, 0 );
|
|
close( fd );
|
|
NetDevOk = 1;
|
|
NetDevBuf[ n ] = '\0';
|
|
|
|
/* Calculate hash over the first 7 characters of each line starting
|
|
* after the first newline. */
|
|
for ( p = NetDevBuf, hash = 0; *p; ++p )
|
|
if ( *p == '\n' )
|
|
for ( ++p; *p && *p != ':' && *p != '|'; ++p )
|
|
hash = ( ( hash << 6 ) + *p ) % 390389;
|
|
|
|
if ( OldHash != 0 && OldHash != hash ) {
|
|
print_error( "RECONFIGURE\n" );
|
|
CheckSetupFlag = 1;
|
|
}
|
|
OldHash = hash;
|
|
|
|
Dirty = 1;
|
|
|
|
/* We read the informations about the wifi from /proc/net/wireless and store it into NetDevWifiBuf */
|
|
if ( ( fd = open( "/proc/net/wireless", O_RDONLY ) ) < 0 ) {
|
|
/* /proc/net/wireless may not exist on some machines. */
|
|
NetDevWifiBuf[0]='\0';
|
|
}
|
|
|
|
if ( ( n = read( fd, NetDevWifiBuf, NETDEVBUFSIZE - 1 ) ) == NETDEVBUFSIZE - 1 ) {
|
|
log_error( "Internal buffer too small to read \'/proc/net/wireless\'" );
|
|
close( fd );
|
|
return -1;
|
|
}
|
|
close( fd );
|
|
NetDevWifiBuf[ n ] = '\0';
|
|
|
|
return 0;
|
|
}
|
|
|
|
void checkNetDev( void )
|
|
{
|
|
/* Values for other network devices are lost, but it is still better
|
|
* than not detecting any new devices. TODO: Fix after 2.1 is out. */
|
|
exitNetDev();
|
|
initNetDev( NetDevSM );
|
|
}
|
|
|
|
#define PRINTFUNC( a, b, c, d, e, f ) \
|
|
void printNetDev##a( const char* cmd ) \
|
|
{ \
|
|
int i; \
|
|
char* beg; \
|
|
char* end; \
|
|
char dev[ 64 ]; \
|
|
\
|
|
beg = strchr( cmd, '/' ); \
|
|
beg = strchr( beg + 1, '/' ); \
|
|
end = strchr( beg + 1, '/' ); \
|
|
strncpy( dev, beg + 1, end - beg - 1 ); \
|
|
dev[ end - beg - 1 ] = '\0'; \
|
|
\
|
|
if ( Dirty ) \
|
|
processNetDev(); \
|
|
\
|
|
for ( i = 0; i < MAXNETDEVS; ++i ) \
|
|
if ( strcmp( NetDevs[ i ].name, dev ) == 0) { \
|
|
if (f) \
|
|
fprintf( CurrentClient, "%li\n", (long) \
|
|
( NetDevs[ i ].a / ( NetDevs[ i ].a##Scale * timeInterval ) ) ); \
|
|
else \
|
|
fprintf( CurrentClient, "%li\n", (long) NetDevs[ i ].a ); \
|
|
return; \
|
|
} \
|
|
\
|
|
fprintf( CurrentClient, "0\n" ); \
|
|
} \
|
|
\
|
|
void printNetDev##a##Info( const char* cmd ) \
|
|
{ \
|
|
(void)cmd; \
|
|
fprintf( CurrentClient, "%s\t0\t0\t%s\n", c, d ); \
|
|
}
|
|
|
|
FORALL( PRINTFUNC )
|
|
FORALLWIFI( PRINTFUNC )
|