|
|
|
/***************************************************************************
|
|
|
|
* Copyright (C) 2005 by Pawel Nawrocki *
|
|
|
|
* pnawrocki@interia.pl *
|
|
|
|
* *
|
|
|
|
* This program is free software; you can redistribute it and/or modify *
|
|
|
|
* it under the terms of the GNU General Public License as published by *
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or *
|
|
|
|
* (at your option) any later version. *
|
|
|
|
* *
|
|
|
|
* 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 "watools.h"
|
|
|
|
|
|
|
|
#include <unistd.h> //provides readlink
|
|
|
|
#include <dirent.h>
|
|
|
|
#include <stdio.h> //to get values from /sys
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/socket.h>
|
|
|
|
#include <arpa/inet.h> //inet_ntoa
|
|
|
|
#include <iostream> //debugging
|
|
|
|
|
|
|
|
char* WATools::ifname = 0;
|
|
|
|
int WATools::iw_socket = -1;
|
|
|
|
int WATools::prev_tx_packets = 0;
|
|
|
|
int WATools::prev_rx_packets = 0;
|
|
|
|
|
|
|
|
//////////////////////
|
|
|
|
///// GENERAL INTERFACE CALLS
|
|
|
|
bool WATools::isUp( const char* _ifname ) ///returns true if specified interface is up. Uses request SIOCGIFFLAGS
|
|
|
|
{
|
|
|
|
if (_ifname==0)
|
|
|
|
_ifname = ifname;
|
|
|
|
|
|
|
|
struct ifreq req;
|
|
|
|
if ( doRequest( SIOCGIFFLAGS, &req, _ifname ) < 0) // get interface flags
|
|
|
|
return 0;
|
|
|
|
// ( req.ifr_flags & IFF_UP ) ? std::cout << "* UP: YES" << std::endl : std::cout << "* UP: NO" << std::endl;
|
|
|
|
return ( req.ifr_flags & IFF_UP );
|
|
|
|
}
|
|
|
|
|
|
|
|
bool WATools::setUp( bool u, const char* _ifname ) /// brings interface up or down. Requests SIOCGIFFLAGS and SIOCSIFFLAGS
|
|
|
|
{
|
|
|
|
if (_ifname==0)
|
|
|
|
_ifname = ifname;
|
|
|
|
|
|
|
|
struct ifreq req;
|
|
|
|
if ( doRequest( SIOCGIFFLAGS, &req, _ifname ) < 0 ) //get current flags, so they're not reset
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if ( u != (req.ifr_flags & IFF_UP) )
|
|
|
|
req.ifr_flags ^= IFF_UP; //change value of IFF_UP flag (XOR)
|
|
|
|
|
|
|
|
return ( doRequest( SIOCSIFFLAGS, &req, _ifname ) > -1 ); //set up/down flag, > -1 if succeeded
|
|
|
|
}
|
|
|
|
|
|
|
|
char* WATools::ip( const char* _ifname ) ///returns current IP. Request SIOCGIFADDR
|
|
|
|
{
|
|
|
|
if (_ifname==0)
|
|
|
|
_ifname = ifname;
|
|
|
|
|
|
|
|
struct ifreq req;
|
|
|
|
static char buffer[16];
|
|
|
|
if ( doRequest( SIOCGIFADDR, &req, _ifname ) < 0 )
|
|
|
|
strcpy( buffer, "0.0.0.0" );
|
|
|
|
else
|
|
|
|
strcpy( buffer, inet_ntoa( ((sockaddr_in*)&req.ifr_addr)->sin_addr ) );
|
|
|
|
// std::cout << "* IP ADDRESS: " << buffer << std::endl;
|
|
|
|
return buffer;
|
|
|
|
}
|
|
|
|
|
|
|
|
int WATools::txpackets( const char* _ifname ) ///returns number of packets send via _iface
|
|
|
|
{
|
|
|
|
if (_ifname==0)
|
|
|
|
_ifname = ifname;
|
|
|
|
|
|
|
|
return getStatistic( "tx_packets", _ifname );
|
|
|
|
}
|
|
|
|
|
|
|
|
int WATools::rxpackets( const char* _ifname ) ///returns number of packets received via _iface
|
|
|
|
{
|
|
|
|
if (_ifname==0)
|
|
|
|
_ifname = ifname;
|
|
|
|
|
|
|
|
return getStatistic( "rx_packets", _ifname );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//////////////////////
|
|
|
|
///// WIRELESS EXTENSIONS CALLS
|
|
|
|
|
|
|
|
bool WATools::isWireless( const char* _ifname ) /// returns TRUE if the specified interface supports Wireless Extensions
|
|
|
|
{
|
|
|
|
static iwreq req;
|
|
|
|
memset( &req, 0, sizeof(req) );
|
|
|
|
return ( doWirelessRequest(SIOCGIWNAME, &req, _ifname ) > -1 );
|
|
|
|
}
|
|
|
|
|
|
|
|
char* WATools::essid( const char* _ifname ) ///returns current ESSID (for the specified interface). Request SIOCGIWESSID
|
|
|
|
{
|
|
|
|
static iwreq req;
|
|
|
|
static char buffer[IW_ESSID_MAX_SIZE + 1];
|
|
|
|
|
|
|
|
memset( buffer, 0, sizeof(buffer) );
|
|
|
|
req.u.essid.pointer = buffer; //set pointer of essid string resulting from request to buffer
|
|
|
|
req.u.essid.length = IW_ESSID_MAX_SIZE;
|
|
|
|
if( doWirelessRequest(SIOCGIWESSID, &req, _ifname) < 0 ) // try to get ap address.
|
|
|
|
return 0; // no ap address
|
|
|
|
return buffer;
|
|
|
|
}
|
|
|
|
|
|
|
|
char* WATools::ap( const char* _ifname ) ///returns current AP (for the specified interface). Request SIOCGIWAP
|
|
|
|
{
|
|
|
|
static iwreq req;
|
|
|
|
if( doWirelessRequest(SIOCGIWAP, &req, _ifname) < 0 ) // try to get ap address.
|
|
|
|
return 0; // no ap address
|
|
|
|
static char buffer[32];
|
|
|
|
iw_ether_ntop( (const struct ether_addr *)req.u.ap_addr.sa_data, buffer );
|
|
|
|
|
|
|
|
// std::cout << "* AP ADDRESS: " << buffer << std::endl;
|
|
|
|
return buffer;
|
|
|
|
}
|
|
|
|
|
|
|
|
int WATools::quality( const char* _ifname ) ///returns active link quality in range 0-100 (for the specified interface)
|
|
|
|
{
|
|
|
|
static iw_statistics stats;
|
|
|
|
if ( doWirelessStatisticsRequest( &stats, _ifname ) < 0 )
|
|
|
|
return 0;
|
|
|
|
unsigned int std_qual = (100*stats.qual.qual)/50; //calculate normalized quality (0-100). 50 is the best noise/signal difference
|
|
|
|
if (std_qual > 100) std_qual = 100;
|
|
|
|
|
|
|
|
// std::cout << "* QUALITY: " << std_qual << std::endl;
|
|
|
|
return std_qual;
|
|
|
|
}
|
|
|
|
|
|
|
|
int WATools::txpower( const char* _ifname ) ///returns current txpower in mW (for the specified interface). Request SIOCGIWTXPOW
|
|
|
|
{
|
|
|
|
static iwreq req;
|
|
|
|
if( doWirelessRequest(SIOCGIWTXPOW, &req, _ifname) < 0 ) // try to get txpower.
|
|
|
|
return 0; // no txpower
|
|
|
|
else {
|
|
|
|
if (req.u.txpower.disabled)
|
|
|
|
return -1;
|
|
|
|
else
|
|
|
|
return req.u.txpower.value;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool WATools::hasKey( const char* _ifname ) ///returns true if WEP key for the specified interface is set. Request SIOCGIWENCODE
|
|
|
|
{
|
|
|
|
static iwreq req;
|
|
|
|
static char buffer[IW_ENCODING_TOKEN_MAX + 1];
|
|
|
|
|
|
|
|
memset( buffer, 0, sizeof(buffer) );
|
|
|
|
req.u.encoding.pointer = buffer; //set pointer of encoding string resulting from request to buffer
|
|
|
|
req.u.encoding.length = IW_ENCODING_TOKEN_MAX;
|
|
|
|
|
|
|
|
if( doWirelessRequest(SIOCGIWENCODE, &req, _ifname) < 0 ) // try to get current key flags.
|
|
|
|
return 0;
|
|
|
|
// ( strlen(buffer)!=0 ) ? std::cout << "* KEY: YES" << std::endl : std::cout << "*KEY: NO" << std::endl;
|
|
|
|
return ( strlen(buffer)!=0 ); // not encoding token empty
|
|
|
|
}
|
|
|
|
|
|
|
|
int WATools::availableNetworks( const char* _ifname ) //returns a list of available networks
|
|
|
|
{
|
|
|
|
static struct wireless_scan_head context;
|
|
|
|
static struct wireless_scan* scan;
|
|
|
|
|
|
|
|
if (_ifname==0)
|
|
|
|
_ifname = ifname;
|
|
|
|
if (iw_socket<0)
|
|
|
|
iw_socket = iw_sockets_open(); //get kernel socket
|
|
|
|
if (iw_socket<0)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
iw_scan( iw_socket, (char*)_ifname, iw_get_kernel_we_version(), &context );
|
|
|
|
scan = context.result;
|
|
|
|
|
|
|
|
int i = 0;
|
|
|
|
if ( scan = context.result ) do {
|
|
|
|
char buffer[32];
|
|
|
|
//iw_ether_ntop( (const struct ether_addr *)scan->ap_addr.sa_data, buffer );
|
|
|
|
//printf( "ESSID: %s, quality: %i\n", scan->b.essid, scan->stats.qual.qual );
|
|
|
|
i++;
|
|
|
|
} while (scan = scan->next);
|
|
|
|
printf( "WATools: Networks found: %i\n", i );
|
|
|
|
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//////////////////////
|
|
|
|
///// MISC FUNCTIONS
|
|
|
|
|
|
|
|
bool WATools::isConnected( const char* _ifname ) ///returns true if interface is properly configured and associated
|
|
|
|
{
|
|
|
|
bool ret;
|
|
|
|
if ( WATools::isUp( _ifname ) && \
|
|
|
|
(strcmp( WATools::ip( _ifname ), "0.0.0.0" ) != 0) && \
|
|
|
|
(strcmp( WATools::ap( _ifname ), "00:00:00:00:00:00" ) != 0) && \
|
|
|
|
(WATools::quality( _ifname ) > 0) ) {
|
|
|
|
int tx = txpackets( _ifname);
|
|
|
|
if ( tx > prev_tx_packets + WA_TX_THRESHOLD ) {
|
|
|
|
prev_tx_packets = tx;
|
|
|
|
int rx = rxpackets( _ifname );
|
|
|
|
if ( rx > prev_rx_packets ) {
|
|
|
|
prev_rx_packets = rx;
|
|
|
|
ret = 1;
|
|
|
|
} else { // no packets received since last change
|
|
|
|
std::cout << "Connection lost (TX threshold exceeded)" << std::endl;
|
|
|
|
ret = 0;
|
|
|
|
}
|
|
|
|
} else ret = 1; // no packets sent since last check
|
|
|
|
} else ret = 0;
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
char* WATools::kernelModule( const char* _ifname ) ///returns KERNEL MODULE name for the given interface
|
|
|
|
{
|
|
|
|
/// DOES SOMEONE KNOW A BETTER WAY TO RETRIEVE IT?
|
|
|
|
char origPath[64], symPath[64];
|
|
|
|
static char module[32];
|
|
|
|
char* p;
|
|
|
|
sprintf( origPath, "/sys/class/net/%s/device/driver", _ifname );
|
|
|
|
memset( &symPath, 0, sizeof(symPath) );
|
|
|
|
readlink( (const char*)origPath, symPath, sizeof(symPath) );
|
|
|
|
p = strtok( symPath, "/" );
|
|
|
|
do {
|
|
|
|
strcpy( module, p );
|
|
|
|
p = strtok( NULL, "/" );
|
|
|
|
} while ( p != NULL ); //last part of the symlinked directory is the module name used for the interface.
|
|
|
|
return module;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//////////////////////
|
|
|
|
///// PRIVATE CONVENIENCE FUNCTIONS
|
|
|
|
|
|
|
|
int WATools::getStatistic( const char* statName, const char* _ifname )
|
|
|
|
{
|
|
|
|
if (_ifname==0)
|
|
|
|
_ifname = ifname;
|
|
|
|
|
|
|
|
char path[64];
|
|
|
|
sprintf( path, "/sys/class/net/%s/statistics/%s", _ifname, statName );
|
|
|
|
|
|
|
|
FILE* f = fopen( path, "r" );
|
|
|
|
void* ptr;
|
|
|
|
static char buffer[16];
|
|
|
|
fgets(buffer, sizeof(buffer), f);
|
|
|
|
fclose(f);
|
|
|
|
return atoi( buffer ); //convert string to integer
|
|
|
|
}
|
|
|
|
|
|
|
|
int WATools::doRequest( int request, struct ifreq* reqStruct, const char* _ifname )
|
|
|
|
{
|
|
|
|
if (_ifname==0)
|
|
|
|
_ifname = ifname;
|
|
|
|
if (iw_socket<0)
|
|
|
|
iw_socket = iw_sockets_open(); //get kernel socket
|
|
|
|
if (iw_socket<0)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
memset( reqStruct, 0, sizeof(reqStruct) );
|
|
|
|
strncpy(reqStruct->ifr_name, _ifname, IFNAMSIZ);
|
|
|
|
return ioctl(iw_socket, request, reqStruct);
|
|
|
|
}
|
|
|
|
|
|
|
|
int WATools::doWirelessRequest( int request, struct iwreq* reqStruct, const char* _ifname )
|
|
|
|
{
|
|
|
|
if (_ifname==0)
|
|
|
|
_ifname = ifname;
|
|
|
|
if (iw_socket<0)
|
|
|
|
iw_socket = iw_sockets_open(); //get kernel socket
|
|
|
|
if (iw_socket<0)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
memset( reqStruct, 0, sizeof(reqStruct) );
|
|
|
|
strncpy(reqStruct->ifr_name, _ifname, IFNAMSIZ);
|
|
|
|
return ioctl(iw_socket, request, reqStruct);
|
|
|
|
}
|
|
|
|
|
|
|
|
int WATools::doWirelessStatisticsRequest( iw_statistics* iwStats, const char* _ifname )
|
|
|
|
{
|
|
|
|
if (_ifname==0)
|
|
|
|
_ifname = ifname;
|
|
|
|
if (iw_socket<0)
|
|
|
|
iw_socket = iw_sockets_open();//get kernel socket
|
|
|
|
if (iw_socket<0)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
unsigned int has_range;
|
|
|
|
iw_range range;
|
|
|
|
|
|
|
|
if ( iw_get_range_info(iw_socket, _ifname, &range) < 0 )
|
|
|
|
has_range = 0;
|
|
|
|
else
|
|
|
|
has_range = 1;
|
|
|
|
return iw_get_stats(iw_socket, _ifname, iwStats, &range, has_range);
|
|
|
|
}
|
|
|
|
|
|
|
|
void WATools::cleanup()
|
|
|
|
{
|
|
|
|
if (!iw_socket<0)
|
|
|
|
iw_sockets_close(iw_socket);
|
|
|
|
}
|