diff options
Diffstat (limited to 'src/watools.cpp')
| -rw-r--r-- | src/watools.cpp | 312 |
1 files changed, 312 insertions, 0 deletions
diff --git a/src/watools.cpp b/src/watools.cpp new file mode 100644 index 0000000..5814274 --- /dev/null +++ b/src/watools.cpp @@ -0,0 +1,312 @@ +/*************************************************************************** + * 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 ); +} + + +////////////////////// +///// 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); +} |
