summaryrefslogtreecommitdiff
authormickeyl <mickeyl>2005-05-15 13:41:19 (UTC)
committer mickeyl <mickeyl>2005-05-15 13:41:19 (UTC)
commit1de015fb8f267f2451dd26d992cc713e6e02af79 (patch) (side-by-side diff)
treea82bcaf6bce0b713910de85450a83862b2d0a73a
parent4451abf402aa1dd967ef8b70a7eba1192f13afb0 (diff)
downloadopie-1de015fb8f267f2451dd26d992cc713e6e02af79.zip
opie-1de015fb8f267f2451dd26d992cc713e6e02af79.tar.gz
opie-1de015fb8f267f2451dd26d992cc713e6e02af79.tar.bz2
submit iw_range*2 as argument to SIOCGIWRANGE.length to make it work on newer hostap drivers
let's see if this breaks it at another end again :/
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--libopie2/opienet/onetwork.cpp14
1 files changed, 6 insertions, 8 deletions
diff --git a/libopie2/opienet/onetwork.cpp b/libopie2/opienet/onetwork.cpp
index f4bdbe0..05513f8 100644
--- a/libopie2/opienet/onetwork.cpp
+++ b/libopie2/opienet/onetwork.cpp
@@ -436,268 +436,266 @@ void OChannelHopper::timerEvent( QTimerEvent* )
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 = (char*) malloc( len );
- //FIXME: Validate if we actually got the memory block
+ 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( struct iw_range );
+ wrq.u.data.length = sizeof buffer;
wrq.u.data.flags = 0;
if ( ::ioctl( _sfd, SIOCGIWRANGE, &wrq ) == -1 )
{
- owarn << "OWirelessNetworkInterface::buildInformation(): Can't get channel information - using default values." << oendl;
+ 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;
- free(buffer);
}
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." << oendl;
+ 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 ) );
_iwr.u.freq.m = c;
_iwr.u.freq.e = 0;
wioctl( SIOCSIWFREQ );
}
else
{
_mon->setChannel( c );
}
}
double OWirelessNetworkInterface::frequency() const
{
if ( !wioctl( SIOCGIWFREQ ) )
{
return -1.0;
}
else
{
return double( _iwr.u.freq.m ) * pow( 10.0, _iwr.u.freq.e ) / 1000000000.0;
}
}
int OWirelessNetworkInterface::channels() const
{
return _channels.count();
}
void OWirelessNetworkInterface::setChannelHopping( int interval )
{
if ( !_hopper ) _hopper = new OChannelHopper( this );
_hopper->setInterval( interval );
@@ -1065,199 +1063,199 @@ OStationList* OWirelessNetworkInterface::scanNetwork()
if((_range.we_version_compiled > 18) && (event_type == IW_HEADER_TYPE_POINT))
event_len -= IW_EV_POINT_OFF;
/* Check if we know about this event */
if(event_len <= IW_EV_LCP_LEN) {
/* Skip to next event */
stream.current += iwe.len;
continue;
}
event_len -= IW_EV_LCP_LEN;
/* Set pointer on data */
if(stream.value != NULL)
pointer = stream.value; /* Next value in event */
else
pointer = stream.current + IW_EV_LCP_LEN; /* First value in event */
if((pointer + event_len) > stream.end) {
/* Go to next event */
stream.current += iwe.len;
break;
}
/* Fixup for later version of WE */
if((_range.we_version_compiled > 18) && (event_type == IW_HEADER_TYPE_POINT))
memcpy((char *) &iwe + IW_EV_LCP_LEN + IW_EV_POINT_OFF, pointer, event_len);
else
memcpy((char *) &iwe + IW_EV_LCP_LEN, pointer, event_len);
/* Skip event in the stream */
pointer += event_len;
/* Special processing for iw_point events */
if(event_type == IW_HEADER_TYPE_POINT) {
/* Check the length of the payload */
if((iwe.len - (event_len + IW_EV_LCP_LEN)) > 0)
/* Set pointer on variable part (warning : non aligned) */
iwe.u.data.pointer = pointer;
else
/* No data */
iwe.u.data.pointer = NULL;
/* Go to next event */
stream.current += iwe.len;
}
else {
/* Is there more value in the event ? */
if((pointer + event_len) <= (stream.current + iwe.len))
/* Go to next value */
stream.value = pointer;
else {
/* Go to next event */
stream.value = NULL;
stream.current += iwe.len;
}
}
struct iw_event *we = &iwe;
//------
odebug << " - reading next event... cmd=" << we->cmd << ", len=" << we->len << oendl;
switch (we->cmd)
{
case SIOCGIWAP:
{
odebug << "SIOCGIWAP" << oendl;
stations->append( new OStation() );
stations->last()->macAddress = (const unsigned char*) &we->u.ap_addr.sa_data[0];
break;
}
case SIOCGIWMODE:
{
odebug << "SIOCGIWMODE" << oendl;
stations->last()->type = modeToString( we->u.mode );
break;
}
case SIOCGIWFREQ:
{
odebug << "SIOCGIWFREQ" << oendl;
if ( we->u.freq.m > 1000 )
stations->last()->channel = _channels[ static_cast<int>(double( we->u.freq.m ) * pow( 10.0, we->u.freq.e ) / 1000000) ];
else
stations->last()->channel = static_cast<int>(((double) we->u.freq.m) * pow( 10.0, we->u.freq.e ));
break;
}
case SIOCGIWESSID:
{
odebug << "SIOCGIWESSID" << oendl;
we->u.essid.length = '\0'; // make sure it is zero terminated
stations->last()->ssid = static_cast<const char*> (we->u.essid.pointer);
odebug << "ESSID: " << stations->last()->ssid << oendl;
break;
}
case IWEVQUAL:
{
- odebug << "IWEVQUAL" << oendl;
+ odebug << "IWEVQUAL" << oendl;
stations->last()->level = static_cast<int>(we->u.qual.level);
break; /* Quality part of statistics (scan) */
}
case SIOCGIWENCODE:
{
- odebug << "SIOCGIWENCODE" << oendl;
+ odebug << "SIOCGIWENCODE" << oendl;
stations->last()->encrypted = !(we->u.data.flags & IW_ENCODE_DISABLED);
break;
}
case SIOCGIWRATE:
{
odebug << "SIOCGIWRATE" << oendl;
stations->last()->rates.append(we->u.bitrate.value);
break;
}
case SIOCGIWSENS: odebug << "SIOCGIWSENS" << oendl; break;
case IWEVTXDROP: odebug << "IWEVTXDROP" << oendl; break; /* Packet dropped to excessive retry */
case IWEVCUSTOM: odebug << "IWEVCUSTOM" << oendl; break; /* Driver specific ascii string */
case IWEVREGISTERED: odebug << "IWEVREGISTERED" << oendl; break; /* Discovered a new node (AP mode) */
case IWEVEXPIRED: odebug << "IWEVEXPIRED" << oendl; break; /* Expired a node (AP mode) */
default: odebug << "unhandled event" << oendl;
}
} while (true);
}
else
{
odebug << " - no results (timeout) :(" << oendl;
}
return stations;
}
int OWirelessNetworkInterface::signalStrength() const
{
iw_statistics stat;
::memset( &stat, 0, sizeof stat );
_iwr.u.data.pointer = (char*) &stat;
_iwr.u.data.flags = 0;
_iwr.u.data.length = sizeof stat;
if ( !wioctl( SIOCGIWSTATS ) )
{
return -1;
}
int max = _range.max_qual.qual;
int cur = stat.qual.qual;
// int lev = stat.qual.level; //FIXME: Do something with them?
// int noi = stat.qual.noise; //FIXME: Do something with them?
return max != 0 ? cur*100/max: -1;
}
bool OWirelessNetworkInterface::wioctl( int call, struct iwreq& iwreq ) const
{
#ifndef NODEBUG
int result = ::ioctl( _sfd, call, &iwreq );
if ( result == -1 )
odebug << "ONetworkInterface::wioctl (" << name() << ") call '"
<< debugmapper->map( call ) << "' FAILED! " << result << " (" << strerror( errno ) << ")" << oendl;
else
odebug << "ONetworkInterface::wioctl (" << name() << ") call '"
<< debugmapper->map( call ) << "' - Status: Ok." << oendl;
return ( result != -1 );
#else
return ::ioctl( _sfd, call, &iwreq ) != -1;
#endif
}
bool OWirelessNetworkInterface::wioctl( int call ) const
{
strcpy( _iwr.ifr_name, name() );
return wioctl( call, _iwr );
}
/*======================================================================================
* OMonitoringInterface
*======================================================================================*/
OMonitoringInterface::OMonitoringInterface( ONetworkInterface* iface, bool prismHeader )
:_if( static_cast<OWirelessNetworkInterface*>( iface ) ), _prismHeader( prismHeader )
{
}
OMonitoringInterface::~OMonitoringInterface()
{
}
void OMonitoringInterface::setChannel( int c )
{
// use standard WE channel switching protocol
memset( &_if->_iwr, 0, sizeof( struct iwreq ) );