Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

OTGateway.cpp

Go to the documentation of this file.
00001 #include <qmessagebox.h>
00002 #include <qfile.h>
00003 #include <qdir.h>
00004 #include <qtextstream.h>
00005 #include <qpixmap.h>
00006 #include <qvector.h>
00007 #include <qpe/resource.h>
00008 
00009 #include <opie2/odebug.h>
00010 
00011 #include <bluezlib.h>
00012 
00013 #include <OTDevice.h>
00014 #include <OTDriver.h>
00015 #include <OTInquiry.h>
00016 #include <OTDriverList.h>
00017 #include <OTDeviceAddress.h>
00018 #include <OTGateway.h>
00019 
00020 using namespace Opietooth2;
00021 
00022 // single instance
00023 OTGateway * OTGateway::SingleGateway = 0;
00024 int OTGateway::UseCount = 0;
00025 
00026 OTGateway * OTGateway::getOTGateway( void ) {
00027       if(SingleGateway == 0 ) {
00028         SingleGateway = new OTGateway();
00029       }
00030 
00031       UseCount ++;
00032       return SingleGateway;
00033 }
00034 
00035 void OTGateway::releaseOTGateway( void ) {
00036       UseCount --;
00037       if( UseCount == 0 ) {
00038         delete SingleGateway;
00039         SingleGateway = 0;
00040       }
00041 }
00042 
00043 // open bluetooth system
00044 OTGateway::OTGateway( void ) : QObject( 0, "OTGateway" ),
00045                                AllDrivers( this ),
00046                                AllPeers() {
00047 
00048       ErrorConnectCount = 0;
00049       TheOTDevice = 0;
00050       Scanning = 0;
00051       AllPeersModified = 0;
00052       AllPeers.setAutoDelete( TRUE );
00053 
00054       if ( ( HciCtl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI)) < 0) {
00055         SLOT_ShowError( tr( "error opening hci socket" ) );
00056         return;
00057       }
00058 
00059       // load all known devices
00060       updateDrivers();
00061 
00062       // load all peers we have ever seen
00063       loadKnownPeers();
00064 
00065       // iterate over drivers and find active NetworkSetups
00066       // adding/updating peers
00067       loadActiveNetworkSetups();
00068 
00069       // check every 4 seconds the state of BT
00070       timerEvent(0);
00071       RefreshTimer = -1;
00072       setRefreshTimer( 4000 );
00073 
00074       // load known link keys
00075       readLinkKeys();
00076 }
00077 
00078 // close bluetooth system
00079 OTGateway::~OTGateway( void ) {
00080 
00081       if( AllPeersModified ) {
00082         saveKnownPeers();
00083       }
00084 
00085       if( Scanning )
00086         delete Scanning;
00087 
00088       if( TheOTDevice )
00089         delete TheOTDevice;
00090 
00091       if( HciCtl >= 0 ) {
00092         ::close( HciCtl );
00093       }
00094 }
00095 
00096 void OTGateway::setRefreshTimer( int T ) {
00097       if( RefreshTimer != -1 ) {
00098         killTimer( RefreshTimer );
00099       }
00100 
00101       if( T == 0 ) 
00102         T = 4000;
00103       RefreshTimer = startTimer( T );
00104 }
00105 
00106 OTDevice * OTGateway::getOTDevice( ) {
00107       if( TheOTDevice == 0 ) {
00108         // load bluetooth device and check state
00109         TheOTDevice = new OTDevice( this );
00110         connect( TheOTDevice, 
00111                  SIGNAL( isEnabled( int, bool ) ),
00112                  this, 
00113                  SLOT( SLOT_Enabled( int, bool ) ) );
00114 
00115         connect( TheOTDevice, 
00116                  SIGNAL( error( const QString & ) ),
00117                  this, 
00118                  SLOT( SLOT_ShowError( const QString & ) ) );
00119       }
00120 
00121       return TheOTDevice;
00122 }
00123 
00124 // start bluetooth (if stopped)
00125 // return TRUE if started
00126 void OTGateway::SLOT_SetEnabled( bool Mode ) {
00127       if( Mode ) {
00128         SLOT_Enable();
00129         return;
00130       }
00131       SLOT_Disable();
00132 }
00133 
00134 void OTGateway::SLOT_Enable() {
00135       getOTDevice()->attach();
00136 }
00137 
00138 void OTGateway::SLOT_Disable() {
00139       getOTDevice()->detach();
00140 }
00141 
00142 bool OTGateway::needsEnabling() {
00143       return getOTDevice()->needsAttach();
00144 }
00145 
00146 bool OTGateway::isEnabled() {
00147       if( getOTDevice()->deviceNr() >= 0 &&
00148           AllDrivers.count() != 0 &&
00149           driver( getOTDevice()->deviceNr() )->isUp() )
00150         return TRUE;
00151 
00152       // else check system
00153       return getOTDevice()->isAttached();
00154 }
00155 
00156 void OTGateway::SLOT_ShowError( const QString & S ) {
00157 
00158       odebug << S << oendl;
00159 
00160       if( ErrorConnectCount > 0 ) {
00161         // pass error
00162         emit error( QString( "<p>" ) + S + "</p>" );
00163         return;
00164       }
00165 
00166       QMessageBox::warning( 0,
00167           tr("OTGateway error"),
00168           S );
00169 }
00170 
00171 void OTGateway::connectNotify( const char * S ) {
00172       if( S && strcmp( S, "error(const QString&)" ) == 0 ) {
00173         ErrorConnectCount ++;
00174       }
00175 }
00176 
00177 void OTGateway::disconnectNotify( const char * S ) {
00178       if( S && strcmp( S, "error(const QString&)" ) == 0 ) {
00179         ErrorConnectCount --;
00180       }
00181 }
00182 
00183 void OTGateway::timerEvent( QTimerEvent * ) {
00184 
00185       OTDriver * D;
00186       unsigned int oldc = AllDrivers.count();
00187       bool old;
00188 
00189       AllDrivers.update();
00190 
00191       if( oldc != AllDrivers.count() ) {
00192         updateDrivers();
00193       } else {
00194         for( unsigned int i = 0;
00195              i < AllDrivers.count();
00196              i ++ ) {
00197           D = AllDrivers[i];
00198           old = D->isUp();
00199           if( D->currentState() >= 0 ) {
00200             if( old != D->isUp() ) {
00201               emit stateChange( D, D->isUp() );
00202             }
00203           } else {
00204             // if one driver is unable to provide info
00205             // we refresh all devices
00206             updateDrivers();
00207             return;
00208           }
00209         }
00210       }
00211 }
00212 
00213 void OTGateway::SLOT_Enabled( int id, bool Up ) {
00214       odebug << "device " << id << " state " << Up << oendl;
00215       if( Up ) {
00216         // device is up -> detect it
00217         updateDrivers();
00218         if( (unsigned)id >= AllDrivers.count() ) {
00219           // to make sure that the driver really IS detected
00220           AllDrivers[id]->bringUp();
00221         }
00222       } // if DOWN device already down
00223       emit deviceEnabled( Up );
00224 }
00225 
00226 void OTGateway::updateDrivers( void ) {
00227       OTDriver * D;
00228 
00229       AllDrivers.update();
00230 
00231       odebug << "updated drivers. now " << AllDrivers.count() << oendl;
00232 
00233       // connect signals for each driver
00234       for( unsigned int i = 0;
00235            i < AllDrivers.count();
00236            i ++ ) {
00237         D = AllDrivers[i];
00238 
00239         connect( D, 
00240                  SIGNAL( error( const QString & ) ),
00241                  this, 
00242                  SLOT( SLOT_ShowError( const QString & ) )
00243                );
00244 
00245         connect( D, 
00246                  SIGNAL( stateChange( OTDriver *, bool ) ),
00247                  this, 
00248                  SIGNAL( stateChange( OTDriver *, bool ) )
00249                );
00250 
00251         connect( D, 
00252                  SIGNAL( driverDisappeared( OTDriver * ) ),
00253                  this, 
00254                  SLOT( SLOT_DriverDisappeared( OTDriver * ) )
00255                );
00256       }
00257 
00258       // verify main device too
00259       if( TheOTDevice )
00260         TheOTDevice->checkAttach();
00261 
00262       // set to default scanning hardware
00263       setScanWith( 0 );
00264 
00265       emit driverListChanged();
00266 }
00267 
00268 void OTGateway::SLOT_DriverDisappeared( OTDriver * D ) {
00269       odebug << "Driver " << D->devname() << " when offline" << oendl;
00270       updateDrivers();
00271 }
00272 
00273 void OTGateway::scanNeighbourhood( OTDriver * D ) {
00274 
00275       if( Scanning ) {
00276         stopScanOfNeighbourhood();
00277       }
00278 
00279       if( D ) {
00280         setScanWith( D );
00281       }
00282 
00283       Scanning = new OTInquiry( scanWith() );
00284 
00285       connect( Scanning,
00286                SIGNAL( peerFound( OTPeer *, bool )),
00287                this,
00288                SLOT( SLOT_PeerDetected( OTPeer *, bool ) )
00289              );
00290       connect( Scanning,
00291                SIGNAL( finished()),
00292                this,
00293                SLOT( SLOT_FinishedDetecting() )
00294              );
00295 
00296       // start scanning
00297       Scanning->inquire( 30.0 );
00298 }
00299 
00300 OTPeer* OTGateway::findPeer( const OTDeviceAddress & Addr ) {
00301       for( unsigned int i = 0 ; i < AllPeers.count(); i ++ ) {
00302         if( AllPeers[i]->address() == Addr ) {
00303           return AllPeers[i];
00304         }
00305       }
00306       return 0;
00307 }
00308 
00309 OTDriver* OTGateway::findDriver( const OTDeviceAddress & Addr ) {
00310       for( unsigned int i = 0 ; i < AllDrivers.count(); i ++ ) {
00311         if( AllDrivers[i]->address() == Addr ) {
00312           return AllDrivers[i];
00313         }
00314       }
00315       return 0;
00316 }
00317 
00318 void OTGateway::SLOT_PeerDetected( OTPeer * P, bool IsNew ) {
00319 
00320       if( IsNew ) {
00321         // new peer
00322         odebug << "New peer " << P->name() << oendl;
00323         addPeer( P );
00324       }
00325 
00326       emit detectedPeer( P, IsNew );
00327 }
00328 
00329 void OTGateway::addPeer( OTPeer * P ) {
00330       AllPeers.resize( AllPeers.size()+1);
00331       AllPeers.insert( AllPeers.size()-1, P );
00332       AllPeersModified = 1;
00333 }
00334 
00335 void OTGateway::removePeer( OTPeer * P ) {
00336       int i = AllPeers.find( P );
00337       if( i ) {
00338         AllPeers.remove( i );
00339         AllPeersModified = 1;
00340       }
00341 }
00342 
00343 void OTGateway::stopScanOfNeighbourhood( void ) {
00344       if( Scanning ) {
00345         delete Scanning;
00346         Scanning = 0;
00347       }
00348 }
00349 
00350 void OTGateway::SLOT_FinishedDetecting() {
00351       stopScanOfNeighbourhood();
00352       emit finishedDetecting();
00353 }
00354 
00355 const char * OTGateway::deviceTypeToName( int cls ) {
00356     switch ( (cls & 0x001F00) >> 8) {
00357       case 0x00:
00358         return "misc";
00359       case 0x01:
00360         return "computer";
00361       case 0x02:
00362         return "phone";
00363       case 0x03:
00364         return "lan";
00365       case 0x04:
00366         return "av";
00367       case 0x05:
00368         return "peripheral";
00369       case 0x06:
00370         return "imaging";
00371       case 0x07:
00372       default :
00373         break;
00374     }
00375     return "unknown";
00376 }
00377 
00378 PANNetworkSetupVector OTGateway::getPANNetworkSetups( void ) {
00379         PANNetworkSetupVector V;
00380 
00381         struct bnep_connlist_req req;
00382         struct bnep_conninfo ci[48];
00383 
00384         V.setAutoDelete(TRUE);
00385 
00386         int ctl = socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_BNEP);
00387         if (ctl < 0) {
00388           odebug << "Failed to open control socket" << oendl;
00389           return V;
00390         }
00391 
00392         req.cnum = 48;
00393         req.ci   = ci;
00394         if (ioctl(ctl, BNEPGETCONNLIST, &req)) {
00395           odebug << "Failed to get NetworkSetup list" << oendl;
00396           ::close( ctl );
00397           return V;
00398         }
00399 
00400         for ( unsigned i=0; i < req.cnum; i++) {
00401           V.resize( V.size() + 1 );
00402           if( ci[i].role == BNEP_SVC_PANU ) {
00403             // we are the client
00404             V.insert( V.size()-1, new OTPANNetworkSetup(
00405                             ci[i].device,
00406                             batostr((bdaddr_t *) ci[i].dst)
00407                           ) );
00408           }
00409         }
00410 
00411         ::close( ctl );
00412         return V;
00413 }
00414 
00415 struct link_key {
00416         bdaddr_t sba;
00417         bdaddr_t dba;
00418         uint8_t  key[16];
00419         uint8_t  type;
00420         time_t   time;
00421 };
00422 
00423 void OTGateway::readLinkKeys( void ) {
00424 
00425         struct link_key k;
00426         int rv;
00427 
00428         AllKeys.truncate(0);
00429 
00430         QFile F( "/etc/bluetooth/link_key" );
00431 
00432         if( ! F.open( IO_ReadOnly ) ) {
00433           emit error( tr("Cannot open link_key file") );
00434           return;
00435         }
00436 
00437         while( 1 ) {
00438           rv = F.readBlock( (char *)&k, sizeof( k ) );
00439           if( rv == 0 )
00440             // EOF
00441             break;
00442 
00443           if( rv < 0 ) {
00444             emit error( tr("Read error in link key file") );
00445           }
00446 
00447           AllKeys.resize( AllKeys.size()+1 );
00448           AllKeys[ AllKeys.size()-1 ].From.setBDAddr( k.sba );
00449           AllKeys[ AllKeys.size()-1 ].To.setBDAddr( k.dba );
00450         }
00451 }
00452 
00453 bool OTGateway::removeLinkKey( unsigned int Index ) {
00454         OTLinkKey & LK = AllKeys[Index];
00455 
00456         struct link_key k;
00457         int rv;
00458 
00459         QFile F( "/etc/bluetooth/link_key" );
00460         QFile OutF( "/etc/bluetooth/newlink_key" );
00461 
00462         if( ! F.open( IO_ReadOnly ) ) {
00463           emit error( tr("Cannot open link_key file") );
00464           return 0;
00465         }
00466 
00467         if( ! OutF.open( IO_WriteOnly | IO_Truncate ) ) {
00468           emit error( tr("Cannot open temporary link_key file") );
00469           return 0;
00470         }
00471 
00472         while( 1 ) {
00473           rv = F.readBlock( (char *)&k, sizeof( k ) );
00474           if( rv == 0 )
00475             // EOF
00476             break;
00477 
00478           if( rv < 0 ) {
00479             emit error( tr("Read error in link key file") );
00480             return 0;
00481           }
00482 
00483           if( LK.from() != OTDeviceAddress( k.sba ) ||
00484               LK.to() != OTDeviceAddress( k.dba ) ) {
00485             // copy
00486             OutF.writeBlock( (char *)&k, sizeof( k ) );
00487           } // else remove this key
00488         }
00489 
00490         // rename files
00491         QDir D( "/etc/bluetooth" );
00492 
00493         D.remove( "link_key" );
00494         D.rename( "newlink_key", "link_key" );
00495 
00496         // restart hcid
00497         system( "/etc/init.d/hcid stop" );
00498         system( "/etc/init.d/hcid start" );
00499 
00500         // remove from table
00501         if( Index < (AllKeys.size()-1) ) {
00502           // collapse array
00503           AllKeys[Index] = AllKeys[AllKeys.size()-1];
00504         }
00505 
00506         // remove last element
00507         AllKeys.resize( AllKeys.size()-1 );
00508 
00509         return 1;
00510 }
00511 
00512 #define MAXCONNECTIONS 10
00513 void OTGateway::loadActiveNetworkSetups( void ) {
00514 
00515         struct hci_conn_list_req *cl;
00516         struct hci_conn_info *ci;
00517         OTDeviceAddress Addr;
00518         OTPeer * P;
00519 
00520         if (!(cl = (struct hci_conn_list_req *)malloc( 
00521                       MAXCONNECTIONS * sizeof(*ci) + sizeof(*cl)))) {
00522           emit error( tr("Can't allocate memory") );
00523           return;
00524         }
00525         memset( cl, 0, MAXCONNECTIONS * sizeof(*ci) + sizeof(*cl) );
00526 
00527         for( unsigned int i = 0;
00528              i < AllDrivers.count();
00529              i ++ ) {
00530 
00531           if( ! AllDrivers[i]->isUp() ) {
00532             continue;
00533           }
00534 
00535           // driver is up -> check NetworkSetups
00536           cl->dev_id = AllDrivers[i]->devId();
00537           cl->conn_num = MAXCONNECTIONS;
00538           ci = cl->conn_info;
00539 
00540           if (ioctl( getSocket(), HCIGETCONNLIST, (void *) cl)) {
00541             emit error( tr("Can't get NetworkSetup list") );
00542             break;
00543           }
00544 
00545           for ( int k = 0; k < cl->conn_num; k++, ci++) {
00546 
00547             if( ci->state != BT_CONNECTED ) {
00548               // not yet connected
00549               continue;
00550             }
00551 
00552             Addr.setBDAddr( ci->bdaddr );
00553             P = findPeer( Addr );
00554             if( ! P ) {
00555               // peer not yet known -> add
00556               P = new OTPeer( this );
00557               addPeer( P );
00558               P->setAddress( Addr );
00559               // infoQueue.push_back(info);
00560               P->setName( AllDrivers[i]->getPeerName( Addr ) ); 
00561             } 
00562             P->setState( OTPeer::Peer_Up );
00563             P->setConnectedTo( AllDrivers[i] );
00564           }
00565         }
00566 
00567         free( cl );
00568 }
00569 
00570 void OTGateway::loadKnownPeers( void ) {
00571     QDir SaveDir = QDir::home();
00572 
00573     if( ! SaveDir.exists( "Settings" ) ) {
00574       return;
00575     }
00576     SaveDir.cd( "Settings" );
00577 
00578     if( ! SaveDir.exists( "opietooth" ) ) {
00579       return;
00580     }
00581     SaveDir.cd( "opietooth" );
00582 
00583     QFile F( SaveDir.path() + "/SeenDevices.conf" );
00584 
00585     if( F.open( IO_ReadOnly ) ) {
00586       QTextStream TS(&F);
00587       long count;
00588 
00589       count = TS.readLine().toLong();
00590 
00591       while( count > 0 ) {
00592         addPeer( new OTPeer( TS, this ) );
00593         count --;
00594       }
00595     }
00596 
00597     AllPeersModified = 0;
00598 }
00599 
00600 void OTGateway::saveKnownPeers( void ) {
00601     QDir SaveDir = QDir::home();
00602 
00603     if( ! SaveDir.exists( "Settings" ) ) {
00604       SaveDir.mkdir( "Settings" );
00605     }
00606     SaveDir.cd( "Settings" );
00607 
00608     if( ! SaveDir.exists( "opietooth" ) ) {
00609       SaveDir.mkdir( "opietooth" );
00610     }
00611     SaveDir.cd( "opietooth" );
00612 
00613     QFile F( SaveDir.path() + "/SeenDevices.conf" );
00614 
00615     if( F.open( IO_WriteOnly | IO_Truncate ) ) {
00616       QTextStream TS(&F);
00617       QString S;
00618 
00619       TS << AllPeers.count() << endl;
00620 
00621       for( unsigned int i = 0;
00622            i < AllPeers.count();
00623            i ++ ) {
00624         AllPeers[i]->save( TS );
00625       }
00626       AllPeersModified = 0;
00627     }
00628     AllPeersModified = 0;
00629 }
00630 
00631 int OTGateway::connectedToRFCommChannel( const OTDeviceAddress & Addr, 
00632                                          int channel ) {
00633 
00634     int s;
00635 
00636     if( (s = ::socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_RFCOMM)) < 0 ) {
00637       emit error( tr("Can't open RFCOMM control socket") );
00638       return 0;
00639     }
00640 
00641     // get all rfcomm devices
00642     { struct rfcomm_dev_list_req *dl;
00643       struct rfcomm_dev_info *di, *dr;
00644       int i;
00645 
00646       dl = (struct rfcomm_dev_list_req *)alloca(
00647               sizeof(*dl) + RFCOMM_MAX_DEV * sizeof(*di));
00648       memset( dl, 0, sizeof(*dl) + RFCOMM_MAX_DEV * sizeof(*di) );
00649       dl->dev_num = RFCOMM_MAX_DEV;
00650       di = dl->dev_info;
00651 
00652       if( ::ioctl(s, RFCOMMGETDEVLIST, (void *) dl) < 0) {
00653         emit error( tr("Can't get device list") );
00654         ::close( s );
00655         return 0;
00656       }
00657 
00658       dr = di;
00659       for (i = 0; i < dl->dev_num; i++, dr++) {
00660         // connected to Peer
00661         if( Addr == OTDeviceAddress( dr->dst ) &&
00662             channel == dr->channel &&
00663             ( dr->state != 0 )
00664           ) {
00665           // return device ID
00666           return dr->id;
00667         }
00668       }
00669     }
00670 
00671     // no device
00672     return -1;
00673 }
00674 
00675 static int byID( struct rfcomm_dev_info * d1,
00676                  struct rfcomm_dev_info * d2 ) {
00677     return d1->id - d2->id;
00678 }
00679 
00680 int OTGateway::getFreeRFCommDevice( void ) {
00681 
00682     int s;
00683 
00684     if( (s = ::socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_RFCOMM)) < 0 ) {
00685       emit error( tr("Can't open RFCOMM control socket") );
00686       return 0;
00687     }
00688 
00689     // get all rfcomm devices
00690     { struct rfcomm_dev_list_req *dl;
00691       struct rfcomm_dev_info *di, *dr;
00692       int i;
00693 
00694       dl = (struct rfcomm_dev_list_req *)alloca(
00695               sizeof(*dl) + RFCOMM_MAX_DEV * sizeof(*di));
00696 
00697       dl->dev_num = RFCOMM_MAX_DEV;
00698       di = dl->dev_info;
00699 
00700       if( ::ioctl(s, RFCOMMGETDEVLIST, (void *) dl) < 0) {
00701         emit error( tr("Can't get device list") );
00702         ::close( s );
00703         return 0;
00704       }
00705 
00706       // s
00707       if( dl->dev_num ) {
00708         qsort( di, sizeof(struct rfcomm_dev_info), 
00709                dl->dev_num, (int(*)(const void*,const void*))byID );
00710         int id = 0;
00711 
00712         dr = di;
00713         // find lowest free device number
00714         for (i = 0; i < dl->dev_num; i++, dr++) {
00715           if( id != dr->id ) {
00716             return id;
00717           }
00718           id ++;
00719         }
00720         return id;
00721       } else {
00722         return 0;
00723       }
00724     }
00725 }
00726 
00727 int OTGateway::releaseRFCommDevice( int devnr ) {
00728 
00729     int s;
00730 
00731     if( (s = ::socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_RFCOMM)) < 0 ) {
00732       emit error( tr("Can't open RFCOMM control socket") );
00733       return 0;
00734     }
00735 
00736     // get all rfcomm devices
00737     { struct rfcomm_dev_list_req *dl;
00738       struct rfcomm_dev_info *di, *dr;
00739       int i;
00740 
00741       dl = (struct rfcomm_dev_list_req *)alloca(
00742               sizeof(*dl) + RFCOMM_MAX_DEV * sizeof(*di));
00743       memset( dl, 0, sizeof(*dl) + RFCOMM_MAX_DEV * sizeof(*di) );
00744       dl->dev_num = RFCOMM_MAX_DEV;
00745       di = dl->dev_info;
00746 
00747       if( ::ioctl(s, RFCOMMGETDEVLIST, (void *) dl) < 0) {
00748         emit error( tr("Can't get device list") );
00749         ::close( s );
00750         return 0;
00751       }
00752 
00753       dr = di;
00754       for (i = 0; i < dl->dev_num; i++, dr++) {
00755         if( dr->id == devnr ) {
00756           // still in NetworkSetup list 
00757           struct rfcomm_dev_req req;
00758           int err;
00759 
00760           memset(&req, 0, sizeof(req));
00761           req.dev_id = devnr;
00762 
00763           if ((err = ioctl(s, RFCOMMRELEASEDEV, &req)) < 0 ) {
00764             return err;
00765           }
00766           return 0;
00767         }
00768       }
00769     }
00770 
00771     // no device -> nothing to release eiterh
00772     return 0;
00773 }
00774 

Generated on Sat Nov 5 16:17:55 2005 for OPIE by  doxygen 1.4.2