-rw-r--r-- | libopie2/examples/opienet/onetworkdemo/onetworkdemo.cpp | 12 | ||||
-rw-r--r-- | libopie2/opienet/onetwork.cpp | 113 | ||||
-rw-r--r-- | libopie2/opienet/onetwork.h | 29 |
3 files changed, 131 insertions, 23 deletions
diff --git a/libopie2/examples/opienet/onetworkdemo/onetworkdemo.cpp b/libopie2/examples/opienet/onetworkdemo/onetworkdemo.cpp index 607d8f1..fc2026f 100644 --- a/libopie2/examples/opienet/onetworkdemo/onetworkdemo.cpp +++ b/libopie2/examples/opienet/onetworkdemo/onetworkdemo.cpp @@ -47,24 +47,36 @@ int main( int argc, char** argv ) qDebug( "DEMO: Operation Mode change successful." ); // RF channel qDebug( "DEMO: Current Channel is '%d'", iface->channel() ); iface->setChannel( 1 ); if ( iface->channel() != 1 ) qDebug( "DEMO: Warning! Can't change RF channel" ); else qDebug( "DEMO: RF channel change successful." ); iface->setMode( "managed" ); + // network scan + + int stations = iface->scanNetwork(); + if ( stations != -1 ) + { + qDebug( "DEMO: # of stations around = %d", stations ); + } + else + { + qDebug( "DEMO: Warning! Scan didn't work!" ); + } + /* // first some wrong calls to check if this is working iface->setPrivate( "seppel", 10 ); iface->setPrivate( "monitor", 0 ); // now the real deal iface->setPrivate( "monitor", 2, 2, 3 ); // trying to set hw address to 12:34:56:AB:CD:EF /* diff --git a/libopie2/opienet/onetwork.cpp b/libopie2/opienet/onetwork.cpp index dc2e388..be45924 100644 --- a/libopie2/opienet/onetwork.cpp +++ b/libopie2/opienet/onetwork.cpp @@ -67,24 +67,25 @@ ONetwork* ONetwork::_instance = 0; ONetwork::ONetwork() { qDebug( "ONetwork::ONetwork()" ); qDebug( "ONetwork: This code has been compiled against Wireless Extensions V%d", WIRELESS_EXT ); 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 ) { qDebug( "ONetwork: /proc/net/dev not existing. No network devices available" ); return; } QTextStream s( &f ); s.readLine(); @@ -179,27 +180,27 @@ void ONetworkInterface::init() if ( _sfd == -1 ) { qDebug( "ONetworkInterface::init(): Warning - can't get socket for device '%s'", name() ); return; } } bool ONetworkInterface::ioctl( int call, struct ifreq& ifreq ) const { int result = ::ioctl( _sfd, call, &ifreq ); if ( result == -1 ) - qDebug( "ONetworkInterface::ioctl (%s) call %d - Status: Failed: %d (%s)", name(), call, result, strerror( errno ) ); + qDebug( "ONetworkInterface::ioctl (%s) call %d (0x%04X) - Status: Failed: %d (%s)", name(), call, call, result, strerror( errno ) ); else - qDebug( "ONetworkInterface::ioctl (%s) call %d - Status: Ok.", name(), call ); + qDebug( "ONetworkInterface::ioctl (%s) call %d (0x%04X) - Status: Ok.", name(), call, call ); return ( result != -1 ); } bool ONetworkInterface::ioctl( int call ) const { strcpy( _ifr.ifr_name, name() ); return ioctl( call, _ifr ); } bool ONetworkInterface::isLoopback() const @@ -445,26 +446,34 @@ OWirelessNetworkInterface::~OWirelessNetworkInterface() struct iwreq& OWirelessNetworkInterface::iwr() const { return _iwr; } void OWirelessNetworkInterface::init() { qDebug( "OWirelessNetworkInterface::init()" ); memset( &_iwr, 0, sizeof( struct iwreq ) ); - buildChannelList(); + buildInformation(); buildPrivateList(); + dumpInformation(); +} + + +bool OWirelessNetworkInterface::isAssociated() const +{ + //FIXME: handle different modes + return associatedAP() != "44:44:44:44:44:44"; } QString OWirelessNetworkInterface::associatedAP() const { //FIXME: use OMacAddress QString mac; if ( ioctl( SIOCGIWAP ) ) { mac.sprintf( "%.2X:%.2X:%.2X:%.2X:%.2X:%.2X", _ifr.ifr_hwaddr.sa_data[0]&0xff, @@ -473,86 +482,89 @@ QString OWirelessNetworkInterface::associatedAP() const _ifr.ifr_hwaddr.sa_data[3]&0xff, _ifr.ifr_hwaddr.sa_data[4]&0xff, _ifr.ifr_hwaddr.sa_data[5]&0xff ); } else { mac = "<Unknown>"; } return mac; } -void OWirelessNetworkInterface::buildChannelList() +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 = (char*) malloc( len ); //FIXME: Validate if we actually got the memory block memset( buffer, 0, len ); memcpy( wrq.ifr_name, name(), IFNAMSIZ); wrq.u.data.pointer = (caddr_t) buffer; wrq.u.data.length = sizeof( struct iw_range ); wrq.u.data.flags = 0; if ( ::ioctl( _sfd, SIOCGIWRANGE, &wrq ) == -1 ) { - qDebug( "OWirelessNetworkInterface::buildChannelList(): SIOCGIWRANGE failed (%s) - defaulting to 11 channels", strerror( errno ) ); + qDebug( "OWirelessNetworkInterface::buildInformation(): SIOCGIWRANGE failed (%s) - using default values.", strerror( errno ) ); _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) { - qWarning( "OWirelessNetworkInterface::buildChannelList(): Driver for wireless interface '%s'" - "overwrote buffer end with at least %i bytes!\n", name(), max - sizeof( struct iw_range ) ); + qWarning( "OWirelessNetworkInterface::buildInformation(): Driver for wireless interface '%s' sucks!\n" + "It overwrote the buffer end with at least %i bytes!\n", name(), max - sizeof( struct iw_range ) ); } // </check if the driver overwrites stuff> struct iw_range range; memcpy( &range, buffer, sizeof range ); - qDebug( "OWirelessNetworkInterface::buildChannelList(): Interface %s reported to have %d channels.", name(), range.num_frequency ); + qDebug( "OWirelessNetworkInterface::buildInformation(): Interface %s reported to have %d channels.", name(), range.num_frequency ); 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 ); _channels.insert( freq, i+1 ); } } - qDebug( "OWirelessNetworkInterface::buildChannelList(): Channel list constructed." ); + memcpy( &_range, buffer, sizeof( struct iw_range ) ); + qDebug( "OWirelessNetworkInterface::buildInformation(): Information block constructed." ); free(buffer); } void OWirelessNetworkInterface::buildPrivateList() { qDebug( "OWirelessNetworkInterface::buildPrivateList()" ); 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 @@ -563,24 +575,35 @@ void OWirelessNetworkInterface::buildPrivateList() qDebug( "OWirelessNetworkInterface::buildPrivateList(): SIOCGIWPRIV failed (%s) - can't get private ioctl information.", strerror( errno ) ); 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 ); } qDebug( "OWirelessNetworkInterface::buildPrivateList(): Private IOCTL list constructed." ); } +void OWirelessNetworkInterface::dumpInformation() const +{ + qDebug( "OWirelessNetworkInterface::() -------------- dumping information block ----------------" ); + + qDebug( " - driver's idea of maximum throughput is %d bps = %d byte/s = %d Kb/s = %f.2 Mb/s", _range.throughput, _range.throughput / 8, _range.throughput / 8 / 1024, float( _range.throughput ) / 8.0 / 1024.0 / 1024.0 ); + qDebug( " - driver for '%s' has been compiled against WE V%d (source=V%d)", name(), _range.we_version_compiled, _range.we_version_source ); + + qDebug( "OWirelessNetworkInterface::() ---------------------------------------------------------" ); +} + + 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; } @@ -652,72 +675,69 @@ OChannelHopper* OWirelessNetworkInterface::channelHopper() const return _hopper; } void OWirelessNetworkInterface::setMode( const QString& mode ) { if ( mode == "auto" ) _iwr.u.mode = IW_MODE_AUTO; else if ( mode == "adhoc" ) _iwr.u.mode = IW_MODE_ADHOC; else if ( mode == "managed" ) _iwr.u.mode = IW_MODE_INFRA; else if ( mode == "master" ) _iwr.u.mode = IW_MODE_MASTER; else if ( mode == "repeater" ) _iwr.u.mode = IW_MODE_REPEAT; else if ( mode == "secondary" ) _iwr.u.mode = IW_MODE_SECOND; - #if WIRELESS_EXT > 14 else if ( mode == "monitor" ) _iwr.u.mode = IW_MODE_MONITOR; - #endif else { qDebug( "ONetwork: Warning! Invalid IEEE 802.11 mode '%s' specified.", (const char*) mode ); return; } wioctl( SIOCSIWMODE ); } QString OWirelessNetworkInterface::mode() const { if ( !wioctl( SIOCGIWMODE ) ) { return "<unknown>"; } switch ( _iwr.u.mode ) { case IW_MODE_AUTO: return "auto"; case IW_MODE_ADHOC: return "adhoc"; case IW_MODE_INFRA: return "managed"; case IW_MODE_MASTER: return "master"; case IW_MODE_REPEAT: return "repeater"; case IW_MODE_SECOND: return "secondary"; - #if WIRELESS_EXT > 14 case IW_MODE_MONITOR: return "monitor"; - #endif default: assert( 0 ); // shouldn't happen } } void OWirelessNetworkInterface::setMonitorMode( bool b ) { if ( _mon ) _mon->setEnabled( b ); else qDebug( "ONetwork(): can't switch monitor mode without installed monitoring interface" ); } bool OWirelessNetworkInterface::monitorMode() const { qDebug( "dataLinkType = %d", dataLinkType() ); return ( dataLinkType() == ARPHRD_IEEE80211 || dataLinkType() == 802 ); - // 802 is the header type for PRISM - Linux support for this is pending... + //FIXME: 802 is the header type for PRISM - Linux support for this is pending... + //FIXME: What is 119, by the way? } void OWirelessNetworkInterface::setNickName( const QString& nickname ) { _iwr.u.essid.pointer = const_cast<char*>( (const char*) nickname ); _iwr.u.essid.length = nickname.length(); wioctl( SIOCSIWNICKN ); } QString OWirelessNetworkInterface::nickName() const @@ -791,31 +811,92 @@ QString OWirelessNetworkInterface::SSID() const } } void OWirelessNetworkInterface::setSSID( const QString& ssid ) { _iwr.u.essid.pointer = const_cast<char*>( (const char*) ssid ); _iwr.u.essid.length = ssid.length(); wioctl( SIOCSIWESSID ); } +int OWirelessNetworkInterface::scanNetwork() +{ + _iwr.u.param.flags = IW_SCAN_DEFAULT; + _iwr.u.param.value = 0; + if ( !wioctl( SIOCSIWSCAN ) ) + { + return -1; + } + + int timeout = 1000000; + + qDebug( "ONetworkInterface::scanNetwork() - scan started." ); + + bool results = false; + struct timeval tv; + tv.tv_sec = 0; + tv.tv_usec = 250000; // initial timeout ~ 250ms + char buffer[IW_SCAN_MAX_DATA]; + + while ( !results && timeout > 0 ) + { + timeout -= tv.tv_usec; + select( 0, 0, 0, 0, &tv ); + + _iwr.u.data.pointer = &buffer[0]; + _iwr.u.data.flags = 0; + _iwr.u.data.length = sizeof buffer; + if ( wioctl( SIOCGIWSCAN ) ) + { + results = true; + continue; + } + else if ( errno == EAGAIN) + { + qDebug( "ONetworkInterface::scanNetwork() - scan in progress..." ); + #if 0 + if ( qApp ) + { + qApp->processEvents( 100 ); + continue; + } + #endif + tv.tv_sec = 0; + tv.tv_usec = 100000; + continue; + } + } + + qDebug( "ONetworkInterface::scanNetwork() - scan finished." ); + + if ( results ) + { + qDebug( " - results are in!" ); + } + else + { + qDebug( " - no results :(" ); + } +} + + bool OWirelessNetworkInterface::wioctl( int call, struct iwreq& iwreq ) const { int result = ::ioctl( _sfd, call, &iwreq ); if ( result == -1 ) - qDebug( "ONetworkInterface::wioctl (%s) call %d - Status: Failed: %d (%s)", name(), call, result, strerror( errno ) ); + qDebug( "ONetworkInterface::wioctl (%s) call %d (0x%04X) - Status: Failed: %d (%s)", name(), call, call, result, strerror( errno ) ); else - qDebug( "ONetworkInterface::wioctl (%s) call %d - Status: Ok.", name(), call ); + qDebug( "ONetworkInterface::wioctl (%s) call %d (0x%04X) - Status: Ok.", name(), call, call ); return ( result != -1 ); } bool OWirelessNetworkInterface::wioctl( int call ) const { strcpy( _iwr.ifr_name, name() ); return wioctl( call, _iwr ); } /*====================================================================================== diff --git a/libopie2/opienet/onetwork.h b/libopie2/opienet/onetwork.h index b170ea2..e1545dd 100644 --- a/libopie2/opienet/onetwork.h +++ b/libopie2/opienet/onetwork.h @@ -352,25 +352,25 @@ class OWirelessNetworkInterface : public ONetworkInterface virtual QString mode() const; /** * Setting the monitor mode on a wireless network interface enables * listening to IEEE 802.11 data and management frames which normally * are handled by the device firmware. This can be used to detect * other wireless network devices, e.g. Access Points or Ad-hoc stations. * @warning Standard wireless network drives don't support the monitor mode. * @warning You need a patched driver for this to work. * @note Enabling the monitor mode is highly driver dependent and requires * the proper @ref OMonitoringInterface to be associated with the interface. * @see OMonitoringInterface */ - virtual void setMonitorMode( bool ); //FIXME: ==> setMode( "monitor" ); + virtual void setMonitorMode( bool ); //FIXME: ==> setMode( "monitor" ); Use IW_MONITOR first, if this doesn't work, then use iwpriv! /** * @returns true if the device is listening in IEEE 802.11 monitor mode */ virtual bool monitorMode() const; //FIXME: ==> mode() /** * Set the channel hopping @a interval. An @a interval of 0 disables channel hopping. * @see OChannelHopper */ virtual void setChannelHopping( int interval = 0 ); /** * @returns the channel hopping interval or 0, if channel hopping is disabled. */ @@ -388,53 +388,62 @@ class OWirelessNetworkInterface : public ONetworkInterface */ virtual QString nickName() const; /** * Invoke the private IOCTL @a command with a @number of parameters on the network interface. * @see OPrivateIOCTL */ virtual void setPrivate( const QString& command, int number, ... ); /** * @returns true if the interface is featuring the private IOCTL @command. */ virtual bool hasPrivate( const QString& command ); virtual void getPrivate( const QString& command ); //FIXME: Implement and document this - - virtual bool isAssociated() const {}; //FIXME: Implement and document this /** - * @returns the MAC address of the Access Point if the - * device is in infrastructure mode. @returns a (more or less random) CELL - * address if the device is in adhoc mode. + * @returns true if the interface is associated to an access point + * @note: This information is only valid if the interface is in managed mode. + */ + virtual bool isAssociated() const; + /** + * @returns the MAC address of the Access Point if the device is in infrastructure mode. + * @returns a (more or less random) cell ID address if the device is in adhoc mode. */ virtual QString associatedAP() const; /** * Set the @a ssid (Service Set ID) string. This is used to decide * which network to associate with (use "any" to let the driver decide). */ virtual void setSSID( const QString& ssid ); /** * @returns the current SSID (Service Set ID). */ virtual QString SSID() const; + /** + * Perform scanning the wireless network neighbourhood. + * @note: UNSTABLE API - UNDER CONSTRUCTION - DON'T USE! + */ + virtual int scanNetwork(); protected: - void buildChannelList(); + void buildInformation(); void buildPrivateList(); + void dumpInformation() const; virtual void init(); struct iwreq& iwr() const; bool wioctl( int call ) const; bool wioctl( int call, struct iwreq& ) const; protected: mutable struct iwreq _iwr; QMap<int,int> _channels; + struct iw_range _range; private: OChannelHopper* _hopper; }; /*====================================================================================== * OMonitoringInterface *======================================================================================*/ class OMonitoringInterface @@ -466,60 +475,66 @@ class OMonitoringInterface class OCiscoMonitoringInterface : public OMonitoringInterface { public: OCiscoMonitoringInterface( ONetworkInterface*, bool _prismHeader ); virtual ~OCiscoMonitoringInterface(); virtual void setEnabled( bool ); virtual QString name() const; virtual void setChannel( int ); }; + /*====================================================================================== * OWlanNGMonitoringInterface *======================================================================================*/ + class OWlanNGMonitoringInterface : public OMonitoringInterface { public: OWlanNGMonitoringInterface( ONetworkInterface*, bool _prismHeader ); virtual ~OWlanNGMonitoringInterface(); public: virtual void setEnabled( bool ); virtual QString name() const; virtual void setChannel( int ); }; + /*====================================================================================== * OHostAPMonitoringInterface *======================================================================================*/ + class OHostAPMonitoringInterface : public OMonitoringInterface { public: OHostAPMonitoringInterface( ONetworkInterface*, bool _prismHeader ); virtual ~OHostAPMonitoringInterface(); public: virtual void setEnabled( bool ); virtual QString name() const; }; + /*====================================================================================== * OOrinocoMonitoringInterface *======================================================================================*/ + class OOrinocoMonitoringInterface : public OMonitoringInterface { public: OOrinocoMonitoringInterface( ONetworkInterface*, bool _prismHeader ); virtual ~OOrinocoMonitoringInterface(); public: virtual void setChannel( int ); virtual void setEnabled( bool ); virtual QString name() const; }; |