summaryrefslogtreecommitdiff
path: root/libopie2/opienet/onetwork.cpp
Side-by-side diff
Diffstat (limited to 'libopie2/opienet/onetwork.cpp') (more/less context) (ignore whitespace changes)
-rw-r--r--libopie2/opienet/onetwork.cpp43
1 files changed, 16 insertions, 27 deletions
diff --git a/libopie2/opienet/onetwork.cpp b/libopie2/opienet/onetwork.cpp
index 1deb051..0649ca2 100644
--- a/libopie2/opienet/onetwork.cpp
+++ b/libopie2/opienet/onetwork.cpp
@@ -1,678 +1,667 @@
/*
                This file is part of the Opie Project
-              Copyright (C) 2003-2005 by Michael 'Mickey' Lauer <mickey@Vanille.de>
- =.
+ =. Copyright (C) 2003-2005 by Michael 'Mickey' Lauer <mickey@Vanille.de>
.=l.
           .>+-=
 _;:,     .>    :=|. This program is free software; you can
.> <`_,   >  .   <= redistribute it and/or modify it under
:`=1 )Y*s>-.--   : the terms of the GNU Library General Public
.="- .-=="i,     .._ License as published by the Free Software
 - .   .-<_>     .<> Foundation; version 2 of the License.
     ._= =}       :
    .%`+i>       _;_.
    .i_,=:_.      -<s. 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
..}^=.=       =       ; Library General Public License for more
++=   -.     .`     .: details.
 :     =  ...= . :.=-
 -.   .:....=;==+<; You should have received a copy of the GNU
  -_. . .   )=.  = Library General Public License along with
    --        :-=` this library; see the file COPYING.LIB.
If not, write to the Free Software Foundation,
Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.
*/
/* OPIE */
#include <opie2/onetwork.h>
#include <opie2/ostation.h>
#include <opie2/odebug.h>
using namespace Opie::Core;
/* QT */
#include <qfile.h>
#include <qtextstream.h>
#include <qapplication.h>
/* STD */
#include <assert.h>
#include <arpa/inet.h>
#include <errno.h>
#include <stdarg.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <unistd.h>
#include <net/if_arp.h>
#include <net/ethernet.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <linux/types.h>
#include <linux/sockios.h>
#define u64 __u64
#define u32 __u32
#define u16 __u16
#define u8 __u8
#include <linux/ethtool.h>
#ifndef NODEBUG
#include <opie2/odebugmapper.h>
using namespace Opie::Net::Internal;
DebugMapper* debugmapper = new DebugMapper();
#endif
/*======================================================================================
* ONetwork
*======================================================================================*/
namespace Opie {
namespace Net {
ONetwork* ONetwork::_instance = 0;
ONetwork::ONetwork()
{
odebug << "ONetwork::ONetwork()" << oendl;
odebug << "ONetwork: This code has been compiled against Wireless Extensions V" << WIRELESS_EXT << oendl;
synchronize();
}
void ONetwork::synchronize()
{
// gather available interfaces by inspecting /proc/net/dev
- //FIXME: we could use SIOCGIFCONF here, but we aren't interested in virtual (e.g. eth0:0) devices
- //FIXME: Use SIOCGIFCONF anway, because we can disable listing of aliased devices
- //FIXME: Best is use SIOCGIFCONF and if this doesn't work (result=-1), then fallback to parsing /proc/net/dev
-
_interfaces.clear();
QString str;
QFile f( "/proc/net/dev" );
bool hasFile = f.open( IO_ReadOnly );
if ( !hasFile )
{
odebug << "ONetwork: /proc/net/dev not existing. No network devices available" << oendl;
return;
}
QTextStream s( &f );
s.readLine();
s.readLine();
while ( !s.atEnd() )
{
s >> str;
str.truncate( str.find( ':' ) );
odebug << "ONetwork: found interface '" << str << "'" << oendl;
if ( str.startsWith( "wifi" ) )
{
odebug << "ONetwork: ignoring hostap control interface" << oendl;
s.readLine();
continue;
}
ONetworkInterface* iface = 0;
if ( isWirelessInterface( str ) )
{
iface = new OWirelessNetworkInterface( this, (const char*) str );
odebug << "ONetwork: interface '" << str << "' has Wireless Extensions" << oendl;
}
else
{
iface = new ONetworkInterface( this, (const char*) str );
}
_interfaces.insert( str, iface );
s.readLine();
}
}
short ONetwork::wirelessExtensionCompileVersion()
{
return WIRELESS_EXT;
}
int ONetwork::count() const
{
return _interfaces.count();
}
ONetworkInterface* ONetwork::interface( const QString& iface ) const
{
return _interfaces[iface];
}
ONetwork* ONetwork::instance()
{
if ( !_instance ) _instance = new ONetwork();
return _instance;
}
ONetwork::InterfaceIterator ONetwork::iterator() const
{
return ONetwork::InterfaceIterator( _interfaces );
}
bool ONetwork::isPresent( const char* name ) const
{
int sfd = socket( AF_INET, SOCK_STREAM, 0 );
struct ifreq ifr;
memset( &ifr, 0, sizeof( struct ifreq ) );
strcpy( (char*) &ifr.ifr_name, name );
int result = ::ioctl( sfd, SIOCGIFFLAGS, &ifr );
return result != -1;
}
bool ONetwork::isWirelessInterface( const char* name ) const
{
int sfd = socket( AF_INET, SOCK_STREAM, 0 );
struct iwreq iwr;
memset( &iwr, 0, sizeof( struct iwreq ) );
strcpy( (char*) &iwr.ifr_name, name );
int result = ::ioctl( sfd, SIOCGIWNAME, &iwr );
return result != -1;
}
/*======================================================================================
* ONetworkInterface
*======================================================================================*/
ONetworkInterface::ONetworkInterface( QObject* parent, const char* name )
:QObject( parent, name ),
_sfd( socket( AF_INET, SOCK_DGRAM, 0 ) ), _mon( 0 )
{
odebug << "ONetworkInterface::ONetworkInterface()" << oendl;
init();
}
struct ifreq& ONetworkInterface::ifr() const
{
return _ifr;
}
void ONetworkInterface::init()
{
odebug << "ONetworkInterface::init()" << oendl;
-
memset( &_ifr, 0, sizeof( struct ifreq ) );
if ( _sfd == -1 )
{
odebug << "ONetworkInterface::init(): Warning - can't get socket for device '" << name() << "'" << oendl;
return;
}
}
bool ONetworkInterface::ioctl( int call, struct ifreq& ifreq ) const
{
#ifndef NODEBUG
int result = ::ioctl( _sfd, call, &ifreq );
if ( result == -1 )
odebug << "ONetworkInterface::ioctl (" << name() << ") call '" << debugmapper->map( call )
<< "' FAILED! " << result << " (" << strerror( errno ) << ")" << oendl;
else
odebug << "ONetworkInterface::ioctl (" << name() << ") call '" << debugmapper->map( call )
<< "' - Status: Ok." << oendl;
return ( result != -1 );
#else
return ::ioctl( _sfd, call, &ifreq ) != -1;
#endif
}
bool ONetworkInterface::ioctl( int call ) const
{
strcpy( _ifr.ifr_name, name() );
return ioctl( call, _ifr );
}
bool ONetworkInterface::isLoopback() const
{
ioctl( SIOCGIFFLAGS );
return _ifr.ifr_flags & IFF_LOOPBACK;
}
bool ONetworkInterface::setUp( bool b )
{
ioctl( SIOCGIFFLAGS );
if ( b ) _ifr.ifr_flags |= IFF_UP;
else _ifr.ifr_flags &= (~IFF_UP);
return ioctl( SIOCSIFFLAGS );
}
bool ONetworkInterface::isUp() const
{
ioctl( SIOCGIFFLAGS );
return _ifr.ifr_flags & IFF_UP;
}
void ONetworkInterface::setIPV4Address( const QHostAddress& addr )
{
struct sockaddr_in *sa = (struct sockaddr_in *) &_ifr.ifr_addr;
sa->sin_family = AF_INET;
sa->sin_port = 0;
sa->sin_addr.s_addr = htonl( addr.ip4Addr() );
ioctl( SIOCSIFADDR );
}
-QString ONetworkInterface::ipV4Address() const
+OHostAddress ONetworkInterface::ipV4Address() const
{
- if ( ioctl( SIOCGIFADDR ) )
- {
- struct sockaddr_in* sa = (struct sockaddr_in *) &_ifr.ifr_addr;
- //FIXME: Use QHostAddress here
- return QString( inet_ntoa( sa->sin_addr ) );
- }
- else
- return "<unknown>";
-
+ struct sockaddr_in* sa = (struct sockaddr_in *) &_ifr.ifr_addr;
+ return ioctl( SIOCGIFADDR ) ? OHostAddress( ntohl( sa->sin_addr.s_addr ) ) : OHostAddress();
}
void ONetworkInterface::setMacAddress( const OMacAddress& addr )
{
_ifr.ifr_hwaddr.sa_family = ARPHRD_ETHER;
memcpy( &_ifr.ifr_hwaddr.sa_data, addr.native(), 6 );
ioctl( SIOCSIFHWADDR );
}
OMacAddress ONetworkInterface::macAddress() const
{
if ( ioctl( SIOCGIFHWADDR ) )
{
return OMacAddress( _ifr );
}
else
{
return OMacAddress::unknown;
}
}
void ONetworkInterface::setIPV4Netmask( const QHostAddress& addr )
{
struct sockaddr_in *sa = (struct sockaddr_in *) &_ifr.ifr_addr;
sa->sin_family = AF_INET;
sa->sin_port = 0;
sa->sin_addr.s_addr = htonl( addr.ip4Addr() );
ioctl( SIOCSIFNETMASK );
}
-QString ONetworkInterface::ipV4Netmask() const
+OHostAddress ONetworkInterface::ipV4Netmask() const
{
- if ( ioctl( SIOCGIFNETMASK ) )
- {
- struct sockaddr_in* sa = (struct sockaddr_in *) &_ifr.ifr_addr;
- //FIXME: Use QHostAddress here
- return QString( inet_ntoa( sa->sin_addr ) );
- }
- else
- return "<unknown>";
+ struct sockaddr_in* sa = (struct sockaddr_in *) &_ifr.ifr_addr;
+ return ioctl( SIOCGIFNETMASK ) ? OHostAddress( ntohl( sa->sin_addr.s_addr ) ) : OHostAddress();
}
int ONetworkInterface::dataLinkType() const
{
if ( ioctl( SIOCGIFHWADDR ) )
{
return _ifr.ifr_hwaddr.sa_family;
}
else
{
return -1;
}
}
void ONetworkInterface::setMonitoring( OMonitoringInterface* m )
{
_mon = m;
odebug << "ONetwork::setMonitoring(): Installed monitoring driver '" << m->name() << "' on interface '" << name() << "'" << oendl;
}
OMonitoringInterface* ONetworkInterface::monitoring() const
{
return _mon;
}
ONetworkInterface::~ONetworkInterface()
{
odebug << "ONetworkInterface::~ONetworkInterface()" << oendl;
if ( _sfd != -1 ) ::close( _sfd );
}
bool ONetworkInterface::setPromiscuousMode( bool b )
{
ioctl( SIOCGIFFLAGS );
if ( b ) _ifr.ifr_flags |= IFF_PROMISC;
else _ifr.ifr_flags &= (~IFF_PROMISC);
return ioctl( SIOCSIFFLAGS );
}
bool ONetworkInterface::promiscuousMode() const
{
ioctl( SIOCGIFFLAGS );
return _ifr.ifr_flags & IFF_PROMISC;
}
bool ONetworkInterface::isWireless() const
{
return ioctl( SIOCGIWNAME );
}
ONetworkInterfaceDriverInfo ONetworkInterface::driverInfo() const
{
struct ethtool_drvinfo info;
info.cmd = ETHTOOL_GDRVINFO;
_ifr.ifr_data = (caddr_t) &info;
return ioctl( SIOCETHTOOL ) ? ONetworkInterfaceDriverInfo( info.driver, info.version, info.fw_version, info.bus_info) : ONetworkInterfaceDriverInfo();
}
/*======================================================================================
* OChannelHopper
*======================================================================================*/
OChannelHopper::OChannelHopper( OWirelessNetworkInterface* iface )
:QObject( 0, "Mickey's funky hopper" ),
_iface( iface ), _interval( 0 ), _tid( 0 )
{
int _maxChannel = iface->channels();
// generate fancy hopping sequence honoring the device capabilities
if ( _maxChannel >= 1 ) _channels.append( 1 );
if ( _maxChannel >= 7 ) _channels.append( 7 );
if ( _maxChannel >= 13 ) _channels.append( 13 );
if ( _maxChannel >= 2 ) _channels.append( 2 );
if ( _maxChannel >= 8 ) _channels.append( 8 );
if ( _maxChannel >= 3 ) _channels.append( 3 );
if ( _maxChannel >= 14 ) _channels.append( 14 );
if ( _maxChannel >= 9 ) _channels.append( 9 );
if ( _maxChannel >= 4 ) _channels.append( 4 );
if ( _maxChannel >= 10 ) _channels.append( 10 );
if ( _maxChannel >= 5 ) _channels.append( 5 );
if ( _maxChannel >= 11 ) _channels.append( 11 );
if ( _maxChannel >= 6 ) _channels.append( 6 );
if ( _maxChannel >= 12 ) _channels.append( 12 );
//FIXME: Add 802.11a/g channels
_channel = _channels.begin();
}
OChannelHopper::~OChannelHopper()
{
}
bool OChannelHopper::isActive() const
{
return _tid;
}
int OChannelHopper::channel() const
{
return *_channel;
}
void OChannelHopper::timerEvent( QTimerEvent* )
{
_iface->setChannel( *_channel );
emit( hopped( *_channel ) );
odebug << "OChannelHopper::timerEvent(): set channel " << *_channel << " on interface '" << _iface->name() << "'" << oendl;
if ( ++_channel == _channels.end() ) _channel = _channels.begin();
}
void OChannelHopper::setInterval( int interval )
{
if ( interval == _interval )
return;
if ( _interval )
killTimer( _tid );
_tid = 0;
_interval = interval;
if ( _interval )
{
_tid = startTimer( interval );
}
}
int OChannelHopper::interval() const
{
return _interval;
}
/*======================================================================================
* OWirelessNetworkInterface
*======================================================================================*/
OWirelessNetworkInterface::OWirelessNetworkInterface( QObject* parent, const char* name )
:ONetworkInterface( parent, name ), _hopper( 0 )
{
odebug << "OWirelessNetworkInterface::OWirelessNetworkInterface()" << oendl;
init();
}
OWirelessNetworkInterface::~OWirelessNetworkInterface()
{
}
struct iwreq& OWirelessNetworkInterface::iwr() const
{
return _iwr;
}
void OWirelessNetworkInterface::init()
{
odebug << "OWirelessNetworkInterface::init()" << oendl;
memset( &_iwr, 0, sizeof( struct iwreq ) );
buildInformation();
buildPrivateList();
dumpInformation();
}
bool OWirelessNetworkInterface::isAssociated() const
{
//FIXME: handle different modes
return !(associatedAP() == OMacAddress::unknown);
}
void OWirelessNetworkInterface::setAssociatedAP( const OMacAddress& mac ) const
{
_iwr.u.ap_addr.sa_family = ARPHRD_ETHER;
::memcpy(_iwr.u.ap_addr.sa_data, mac.native(), ETH_ALEN);
wioctl( SIOCSIWAP );
}
OMacAddress OWirelessNetworkInterface::associatedAP() const
{
if ( ioctl( SIOCGIWAP ) )
return (const unsigned char*) &_ifr.ifr_hwaddr.sa_data[0];
else
return OMacAddress::unknown;
}
void OWirelessNetworkInterface::buildInformation()
{
//ML: If you listen carefully enough, you can hear lots of WLAN drivers suck
//ML: The HostAP drivers need more than sizeof struct_iw range to complete
//ML: SIOCGIWRANGE otherwise they fail with "Invalid Argument Length".
//ML: The Wlan-NG drivers on the otherside fail (segfault!) if you allocate
//ML: _too much_ space. This is damn shitty crap *sigh*
//ML: We allocate a large memory region in RAM and check whether the
//ML: driver pollutes this extra space. The complaint will be made on stdout,
//ML: so please forward this...
struct iwreq wrq;
int len = sizeof( struct iw_range )*2;
char buffer[len];
memset( buffer, 0, len );
memcpy( wrq.ifr_name, name(), IFNAMSIZ);
wrq.u.data.pointer = (caddr_t) buffer;
wrq.u.data.length = sizeof buffer;
wrq.u.data.flags = 0;
- if ( ::ioctl( _sfd, SIOCGIWRANGE, &wrq ) == -1 )
+ int result = ::ioctl( _sfd, SIOCGIWRANGE, &wrq );
+ if ( result == -1 )
+ {
+ owarn << "OWirelessNetworkInterface::buildInformation(): SIOCGIWRANGE failed (" << strerror( errno ) << ") - retrying with smaller buffer..." << oendl;
+ wrq.u.data.length = sizeof( struct iw_range );
+ result = ::ioctl( _sfd, SIOCGIWRANGE, &wrq );
+ }
+
+ if ( result == -1 )
{
owarn << "OWirelessNetworkInterface::buildInformation(): Can't get driver information (" << strerror( errno ) << ") - using default values." << oendl;
_channels.insert( 2412, 1 ); // 2.412 GHz
_channels.insert( 2417, 2 ); // 2.417 GHz
_channels.insert( 2422, 3 ); // 2.422 GHz
_channels.insert( 2427, 4 ); // 2.427 GHz
_channels.insert( 2432, 5 ); // 2.432 GHz
_channels.insert( 2437, 6 ); // 2.437 GHz
_channels.insert( 2442, 7 ); // 2.442 GHz
_channels.insert( 2447, 8 ); // 2.447 GHz
_channels.insert( 2452, 9 ); // 2.452 GHz
_channels.insert( 2457, 10 ); // 2.457 GHz
_channels.insert( 2462, 11 ); // 2.462 GHz
memset( &_range, 0, sizeof( struct iw_range ) );
}
else
{
// <check if the driver overwrites stuff>
int max = 0;
for ( int r = sizeof( struct iw_range ); r < len; r++ )
if (buffer[r] != 0)
max = r;
if (max > 0)
{
owarn << "OWirelessNetworkInterface::buildInformation(): Driver for wireless interface '" << name()
<< "' sucks! It overwrote the buffer end with at least " << max - sizeof( struct iw_range ) << " bytes!" << oendl;
}
// </check if the driver overwrites stuff>
struct iw_range range;
memcpy( &range, buffer, sizeof range );
odebug << "OWirelessNetworkInterface::buildInformation(): Interface reported to have " << (int) range.num_frequency << " channels." << oendl;
for ( int i = 0; i < range.num_frequency; ++i )
{
int freq = (int) ( double( range.freq[i].m ) * pow( 10.0, range.freq[i].e ) / 1000000.0 );
odebug << "OWirelessNetworkInterface::buildInformation: Adding frequency " << freq << " as channel " << i+1 << oendl;
_channels.insert( freq, i+1 );
}
}
memcpy( &_range, buffer, sizeof( struct iw_range ) );
odebug << "OWirelessNetworkInterface::buildInformation(): Information block constructed." << oendl;
}
short OWirelessNetworkInterface::wirelessExtensionDriverVersion() const
{
return _range.we_version_compiled;
}
void OWirelessNetworkInterface::buildPrivateList()
{
odebug << "OWirelessNetworkInterface::buildPrivateList()" << oendl;
struct iw_priv_args priv[IW_MAX_PRIV_DEF];
_iwr.u.data.pointer = (char*) &priv;
_iwr.u.data.length = IW_MAX_PRIV_DEF; // length in terms of number of (sizeof iw_priv_args), not (sizeof iw_priv_args) itself
_iwr.u.data.flags = 0;
if ( !wioctl( SIOCGIWPRIV ) )
{
owarn << "OWirelessNetworkInterface::buildPrivateList(): Can't get private ioctl information (" << strerror( errno ) << ")." << oendl;
return;
}
for ( int i = 0; i < _iwr.u.data.length; ++i )
{
new OPrivateIOCTL( this, priv[i].name, priv[i].cmd, priv[i].get_args, priv[i].set_args );
}
odebug << "OWirelessNetworkInterface::buildPrivateList(): Private ioctl list constructed." << oendl;
}
void OWirelessNetworkInterface::dumpInformation() const
{
odebug << "OWirelessNetworkInterface::() -------------- dumping information block ----------------" << oendl;
odebug << " - driver's idea of maximum throughput is " << _range.throughput
<< " bps = " << ( _range.throughput / 8 ) << " byte/s = " << ( _range.throughput / 8 / 1024 )
<< " Kb/s = " << QString().sprintf("%f.2", float( _range.throughput ) / 8.0 / 1024.0 / 1024.0 )
<< " Mb/s" << oendl;
odebug << " - driver for '" << name() << "' (V" << _range.we_version_source
<< ") has been compiled against WE V" << _range.we_version_compiled << oendl;
if ( _range.we_version_compiled != WIRELESS_EXT )
{
owarn << "Version mismatch! WE_DRIVER = " << _range.we_version_compiled << " and WE_OPIENET = " << WIRELESS_EXT << oendl;
}
odebug << "OWirelessNetworkInterface::() ---------------------------------------------------------" << oendl;
}
int OWirelessNetworkInterface::channel() const
{
//FIXME: When monitoring enabled, then use it
//FIXME: to gather the current RF channel
//FIXME: Until then, get active channel from hopper.
if ( _hopper && _hopper->isActive() )
return _hopper->channel();
if ( !wioctl( SIOCGIWFREQ ) )
{
return -1;
}
else
{
return _channels[ static_cast<int>(double( _iwr.u.freq.m ) * pow( 10.0, _iwr.u.freq.e ) / 1000000) ];
}
}
void OWirelessNetworkInterface::setChannel( int c ) const
{
if ( !c )
{
oerr << "OWirelessNetworkInterface::setChannel( 0 ) called - fix your application!" << oendl;
return;
}
if ( !_mon )
{
memset( &_iwr, 0, sizeof( struct iwreq ) );