1: /*
     2:         
     3:         File:			WiFiController.cpp
     4:         Program:		GTDriver
     5: 	Author:			Michael Ro├čberg
     6: 				mick@binaervarianz.de
     7: 	Description:		GTDriver is a free driver for PrismGT based cards under OS X.
     8:                 
     9:         This file is part of GTDriver.
    10: 
    11:     GTDriver is free software; you can redistribute it and/or modify
    12:     it under the terms of the GNU General Public License as published by
    13:     the Free Software Foundation; either version 2 of the License, or
    14:     (at your option) any later version.
    15: 
    16:     GTDriver is distributed in the hope that it will be useful,
    17:     but WITHOUT ANY WARRANTY; without even the implied warranty of
    18:     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    19:     GNU General Public License for more details.
    20: 
    21:     You should have received a copy of the GNU General Public License
    22:     along with GTDriver; if not, write to the Free Software
    23:     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    24: */
    25: 
    26: #include "WiFiController.h" 
    27: 
    28: #include <IOKit/pccard/IOPCCard.h> 
    29: 
    30: #define ONE_SECOND_TICKS			1000 
    31: #define LOAD_STATISTICS_INTERVAL	(4 * ONE_SECOND_TICKS) 
    32: 
    33: #define super IOEthernetController 
    34: OSDefineMetaClassAndStructors(WiFiController, IOEthernetController)
    35: 
    36: extern "C" {
    37: #include <sys/sockio.h> 
    38: }
    39: 
    40: //---------------------------------------------------------------------------
    41: // Function: initDriver
    42: //
    43: // Create and initialize driver objects before the hardware is 
    44: // enabled.
    45: //
    46: // Returns true on sucess, and false if initialization failed.
    47: 
    48: bool WiFiController::_initDriver(IOService * provider) {
    49:     //currentMediumType = MEDIUM_TYPE_INVALID;
    50: 
    51:     // This driver will allocate and use an IOGatedOutputQueue.
    52:     //
    53:     _transmitQueue = getOutputQueue();
    54:     if (_transmitQueue == NULL) return false;
    55: 
    56:     // Allocate two IOMbufLittleMemoryCursor instances. One for transmit and
    57:     // the other for receive.
    58:     //
    59:     //rxMbufCursor = IOMbufLittleMemoryCursor::withSpecification(MAX_BUF_SIZE,1);
    60:     //txMbufCursor = IOMbufLittleMemoryCursor::withSpecification(MAX_BUF_SIZE, 
    61:     //                                                           TBDS_PER_TCB);
    62:     //if (!rxMbufCursor || !txMbufCursor)
    63:     //        return false;
    64: 
    65:     // Get a handle to our superclass' workloop.
    66:     //
    67:     IOWorkLoop *myWorkLoop = (IOWorkLoop *) getWorkLoop();
    68:     if (!myWorkLoop) return false;
    69: 
    70:     // Create and register an interrupt event source. The provider will
    71:     // take care of the low-level interrupt registration stuff.
    72:     //
    73:     _interruptSrc = IOInterruptEventSource::interruptEventSource(
    74:                this,
    75:                (IOInterruptEventAction) &WiFiController::interruptOccurred,
    76:                provider);
    77: 
    78:     if (!_interruptSrc ||
    79: 		(myWorkLoop->addEventSource(_interruptSrc) != kIOReturnSuccess))
    80: 		return false;
    81: 
    82:     // This is important. If the interrupt line is shared with other devices,
    83:     // then the interrupt vector will be enabled only if all corresponding
    84:     // interrupt event sources are enabled. To avoid masking interrupts for
    85:     // other devices that are sharing the interrupt line, the event source
    86:     // is enabled immediately.
    87: 
    88:     _interruptSrc->enable();
    89: 
    90:     // Register a timer event source. This is used as a watchdog timer.
    91:     //
    92:     _timerSrc = IOTimerEventSource::timerEventSource(this,
    93:            (IOTimerEventSource::Action)&WiFiController::timeoutOccurred);
    94:     if (!_timerSrc ||
    95:     	(myWorkLoop->addEventSource(_timerSrc) != kIOReturnSuccess))
    96:     	return false;
    97: 
    98:     // Create a dictionary to hold IONetworkMedium objects.
    99:     //
   100:     _mediumDict = OSDictionary::withCapacity(MEDIUM_TYPE_INVALID + 1);
   101:     if (!_mediumDict)
   102:     	return false;
   103: 
   104:     _addMediumType(kIOMediumIEEE80211None,  0,  MEDIUM_TYPE_NONE);
   105:     _addMediumType(kIOMediumIEEE80211Auto,  0,  MEDIUM_TYPE_AUTO);
   106:     /*_addMediumType(kIOMediumIEEE80211DS1,   1000000, MEDIUM_TYPE_1MBIT);
   107:     _addMediumType(kIOMediumIEEE80211DS2,   2000000, MEDIUM_TYPE_2MBIT);
   108:     _addMediumType(kIOMediumIEEE80211DS5,   5500000, MEDIUM_TYPE_5MBIT);
   109:     _addMediumType(kIOMediumIEEE80211DS11, 11000000, MEDIUM_TYPE_11MBIT);
   110:     _addMediumType(kIOMediumIEEE80211,     54000000, MEDIUM_TYPE_54MBIT, "OFDM54");
   111:      */   
   112:     _currentMediumType = MEDIUM_TYPE_AUTO;
   113: 
   114:     setLinkStatus(kIONetworkLinkValid, _getMediumWithType(MEDIUM_TYPE_NONE));
   115: 
   116:     return true;
   117: }
   118: /*
   119: 
   120: bool
   121: WiFiController::attachRawInterface(IONetworkInterface ** interfaceP,
   122:                                      bool  doRegister)
   123: {
   124:     IONetworkInterface * netif;
   125: 
   126:     *interfaceP = 0;
   127: 
   128:     do {
   129:         // Allocate a concrete subclass of IONetworkInterface
   130:         // by calling createInterface().
   131: 
   132:         netif = createRawInterface();
   133:         if (!netif)
   134:             break;
   135: 
   136:         // Configure the interface instance by calling 
   137:         // configureInterface(), then attach it as our client.
   138: 
   139:         if ( !configureInterface(netif) || !netif->attach(this) )
   140:         {
   141:             netif->release();
   142:             break;
   143:         }
   144: 
   145:         *interfaceP = netif;
   146: 
   147:         // Register the interface nub. Spawns a matching thread.
   148: 
   149:         if (doRegister)
   150:             netif->registerService();
   151: 
   152:         return true;    // success
   153:     }
   154:     while (0);
   155: 
   156:     return false;   // failure
   157: }
   158: 
   159: //---------------------------------------------------------------------------
   160: // Allocate and return a new BIWiFiInterface instance.
   161: 
   162: IONetworkInterface * WiFiController::createRawInterface()
   163: {
   164:     BIWiFiInterface * netif = new BIWiFiInterface;
   165: 
   166:     if ( netif && ( netif->init( this ) == false ) )
   167:     {
   168:         netif->release();
   169:         netif = 0;
   170:     }
   171:     return netif;
   172: }*/
   173: 
   174: //---------------------------------------------------------------------------
   175: // Function: start <IOService>
   176: //
   177: // Hardware was detected and initialized, start the driver.
   178: 
   179: bool WiFiController::start(IOService * provider) {
   180:     bool ret     = false;
   181:     bool started = false;
   182: 
   183:     memset(_ssid, 0, sizeof(_ssid));
   184:     _ssidLength = 0;
   185:     _linkSpeed = 0;
   186:     _currentState = stateIntializing;
   187:     _currentMode = modeClient;
   188:     _currentFrequency = 2412;
   189:     _packetQueue = IODataQueue::withCapacity(16384); // allocate 16KB for caching output in monitor mode
   190:     
   191:     do {
   192:         started = true;
   193:         
   194:         // Start our superclass first.
   195:         if (super::start(provider) == false)
   196:             break;
   197: 
   198:         if (startProvider(provider) == false) break;
   199:         
   200:         // Initialize the driver's event sources and other support objects.
   201:         if (_initDriver(provider) == false) break;
   202:         
   203:         // Get default driver settings (stored in property table).
   204:         //if (getDefaultSettings() == false) break;
   205: 
   206:         // Execute one-time initialization code.
   207:         if (startHardware() == false) break;
   208:         
   209:         if (publishMediumDictionary(_mediumDict) == false) {
   210:             WLLogErr("publishMediumDictionary failed\n");
   211:             break;
   212:         }
   213:         
   214:         ret = true;
   215:     }
   216:     while (false);
   217: 
   218:     _cardGone = false;
   219:     
   220:     // Close our provider, it will be re-opened on demand when
   221:     // our enable() method is called.
   222:     closeProvider();
   223: 
   224:     do {
   225:         if (ret == false) break;
   226: 
   227:         ret = false;
   228: 
   229:         // Allocate and attach an IOEthernetInterface instance to this driver
   230:         // object.
   231: 
   232:         if (attachInterface((IONetworkInterface **) &_netif, false) == false) break;
   233:         // Start matching for clients of IONetworkInterface.
   234:         /*
   235: 		IOEthernetAddress addr;
   236: 		addr.bytes[0] = 0x00;
   237:         addr.bytes[1] = 0x00;
   238: 		addr.bytes[2] = 0x00;
   239: 		addr.bytes[3] = 0x00;
   240: 		addr.bytes[4] = 0x00;
   241: 		addr.bytes[5] = 0x23;
   242: 		setProperty("IOMACAddress2",  (void *) &addr, kIOEthernetAddressSize);
   243: 						  
   244:         if (attachRawInterface((IONetworkInterface **) &_rawNetif, false) == false) break;
   245: 		*/
   246: 		
   247: 		_netif->registerService();
   248: 		//_rawNetif->registerService();
   249: 		registerService();
   250:         
   251:         ret = true;
   252: 	}
   253:     while (false);
   254: 
   255:     // Issue a stop on failure.
   256:     if (started && !ret) super::stop(provider);
   257: 
   258:     return ret;
   259: }
   260: 
   261: //---------------------------------------------------------------------------
   262: // Function: createWorkLoop <IONetworkController>
   263: //
   264: // Override IONetworkController::createWorkLoop() method to create and return
   265: // a new work loop object.
   266: 
   267: bool WiFiController::createWorkLoop() {
   268:     _workLoop = IOWorkLoop::workLoop();
   269: 
   270:     return (_workLoop != NULL);
   271: }
   272: 
   273: //---------------------------------------------------------------------------
   274: // Function: getWorkLoop <IOService>
   275: //
   276: // Override IOService::getWorkLoop() method and return a reference to our
   277: // work loop.
   278: 
   279: IOWorkLoop * WiFiController::getWorkLoop() const {
   280:     return _workLoop;
   281: }
   282: 
   283: //---------------------------------------------------------------------------
   284: // Function: configureInterface <IONetworkController>
   285: //
   286: // Configure a newly instantiated IONetworkInterface object.
   287: 
   288: bool WiFiController::configureInterface(IONetworkInterface * netif) {
   289:     IONetworkData * data;
   290:     
   291:     if (super::configureInterface(netif) == false)
   292:             return false;
   293:     
   294:     // Get the generic network statistics structure.
   295: 
   296:     data = netif->getParameter(kIONetworkStatsKey);
   297:     if (!data || !(_netStats = (IONetworkStats *)data->getBuffer())) {
   298:             return false;
   299:     }
   300: 
   301:     // Get the Ethernet statistics structure.
   302: 
   303:     data = netif->getParameter(kIOEthernetStatsKey);
   304:     if (!data || !(_etherStats = (IOEthernetStats *)data->getBuffer())) {
   305:             return false;
   306:     }
   307:     
   308:     return true;
   309: }
   310: 
   311: //---------------------------------------------------------------------------
   312: // Function: free <IOService>
   313: //
   314: // Deallocate all resources and destroy the instance.
   315: 
   316: void WiFiController::free() {
   317:     #define RELEASE(x) do { if(x) { (x)->release(); (x) = 0; } } while(0)
   318: 
   319:     RELEASE(_netif);
   320: 	//RELEASE(_rawNetif);
   321:     if (_interruptSrc && _workLoop) {
   322:         _workLoop->removeEventSource(_interruptSrc);
   323:     }
   324: 
   325:     freeHardware();
   326: 
   327:     RELEASE(_interruptSrc);
   328:     RELEASE(_timerSrc    );
   329:     RELEASE(_mediumDict  );
   330:     RELEASE(_workLoop    );
   331:     RELEASE(_packetQueue );
   332:     
   333:     freeProvider();
   334:     
   335:     if (_powerOffThreadCall) {
   336:         thread_call_free(_powerOffThreadCall);
   337:         _powerOffThreadCall = 0;
   338:     }
   339:     
   340:     if (_powerOnThreadCall) {
   341:         thread_call_free(_powerOnThreadCall);
   342:         _powerOnThreadCall = 0;
   343:     }
   344: 
   345:     super::free();	// pass it to our superclass
   346: }
   347: 
   348: //---------------------------------------------------------------------------
   349: // Function: enableAdapter
   350: //
   351: // Enables the adapter & driver to the given level of support.
   352: 
   353: bool WiFiController::enableAdapter() {
   354:     // Open provider.
   355:     //
   356:     if (!openProvider()) {
   357:         WLLogErr("Could not open Provider");
   358:         return false;
   359:     }
   360:     if (!enableHardware()) {
   361:         WLLogErr("Could not enable Hardware");
   362:         return false;
   363:     }
   364:     
   365:     // Start our IOOutputQueue object.
   366:     //
   367:     _transmitQueue->setCapacity(TRANSMIT_QUEUE_SIZE);
   368:     _transmitQueue->start();
   369: 
   370:     _timerSrc->setTimeoutMS(LOAD_STATISTICS_INTERVAL);
   371:     
   372:     return true;
   373: }
   374: 
   375: //---------------------------------------------------------------------------
   376: // Function: disableAdapter
   377: //
   378: // Disables the adapter & driver to the given level of support.
   379: 
   380: bool WiFiController::disableAdapter() {        
   381:     WLEnter();
   382:     
   383:     _timerSrc->cancelTimeout();
   384:     _transmitQueue->stop();
   385: 
   386:     // Report link status: valid and down.
   387:     //
   388:     setLinkStatus(kIONetworkLinkValid);
   389: 
   390:     // Flush all packets held in the queue and prevent it
   391:     // from accumulating any additional packets.
   392:     //
   393:     _transmitQueue->setCapacity(0);
   394:     _transmitQueue->flush();
   395: 
   396:     disableHardware();
   397:     // Close provider.
   398:     //
   399:     closeProvider();
   400: 
   401:     WLExit();
   402:     return true;
   403: }
   404: 
   405: //---------------------------------------------------------------------------
   406: // Function: enable <IONetworkController>
   407: //
   408: // A request from our interface client to enable the adapter.
   409: 
   410: IOReturn WiFiController::enable(IONetworkInterface * /*netif*/) {
   411:     if (_enabledForNetif) return kIOReturnSuccess;
   412: 
   413:     _enabledForNetif = enableAdapter();
   414:     WLLogInfo("Enabling Network: %d", _enabledForNetif);
   415: 
   416:     return (_enabledForNetif ? kIOReturnSuccess : kIOReturnIOError);
   417: }
   418: 
   419: //---------------------------------------------------------------------------
   420: // Function: disable <IONetworkController>
   421: //
   422: // A request from our interface client to disable the adapter.
   423: 
   424: IOReturn WiFiController::disable(IONetworkInterface * netif) {
   425:     WLEnter();
   426:     
   427:     _enabledForNetif = false;
   428: 
   429:     if (netif != _netif) {
   430:         WLLogErr("Wrong network interface!");
   431:         return kIOReturnInvalid;
   432:     }
   433:     
   434:     disableAdapter();
   435: 
   436:     WLExit();
   437:     return kIOReturnSuccess;
   438: }
   439: 
   440: IOReturn WiFiController::message(UInt32 type, IOService * provider, void * argument) {
   441:     if (type == kIOPCCardCSEventMessage) {
   442:         switch ((unsigned int)argument) {
   443: 	    case CS_EVENT_CARD_REMOVAL:
   444: 		WLLogInfo("PC Card was removed.\n");
   445:                 
   446:                 _cardGone = true; //make sure nobody does something stupid
   447:                 handleEjectionHardware();
   448:                 
   449: 		// Message our clients and tell them we're no longer available...
   450: 		super::message(kIOMessageServiceIsTerminated, this, 0);
   451:                 this->terminate(kIOServiceRequired); // we're gone, lets save memory.
   452:                 _currentState = stateCardEjected;
   453: 		break;
   454:             case CS_EVENT_CARD_INSERTION:
   455:                 //TODO Handle this              
   456: 		break;
   457: 	    default:
   458: 		WLLogWarn("PC Card generated untrapped message: %ud\n", (unsigned int)argument);
   459: 		break;
   460:         }
   461:     }
   462: 
   463:     return super::message(type, provider, argument);
   464: }
   465: 
   466: //---------------------------------------------------------------------------
   467: // Function: getPacketBufferConstraints <IONetworkController>
   468: //
   469: // Return our driver's packet alignment requirements.
   470: 
   471: void WiFiController::getPacketBufferConstraints(IOPacketBufferConstraints * constraints) const {
   472:     constraints->alignStart  = kIOPacketBufferAlign4;	// even word aligned.
   473:     constraints->alignLength = kIOPacketBufferAlign4;	// no restriction.
   474: }
   475: 
   476: //---------------------------------------------------------------------------
   477: // Function: getHardwareAddress <IOEthernetController>
   478: //
   479: // Return the adapter's hardware/Ethernet address.
   480: 
   481: IOReturn WiFiController::getHardwareAddress(IOEthernetAddress * addrs) {
   482:     bcopy(&_myAddress, addrs, sizeof(*addrs));
   483:     return kIOReturnSuccess;
   484: }
   485: 
   486: IOReturn WiFiController::setHardwareAddress(const void * addr, UInt32 addrBytes) {
   487:     IOReturn ret;
   488:     if (addrBytes != kIOEthernetAddressSize) return kIOReturnBadArgument;
   489:     
   490:     ret = setHardwareAddressHardware((UInt8*)addr);
   491:     if (ret == kIOReturnSuccess) {
   492:         bcopy(addr, &_myAddress, addrBytes);
   493:     }
   494:     return ret;
   495: }
   496: 
   497: #pragma mark - 
   498: 
   499: //---------------------------------------------------------------------------
   500: // Function: createOutputQueue <IONetworkController>
   501: //
   502: // Allocate an IOGatedOutputQueue instance.
   503: 
   504: IOOutputQueue * WiFiController::createOutputQueue(){	
   505: 	return IOGatedOutputQueue::withTarget(this, getWorkLoop());
   506: }
   507: 
   508: const OSString* WiFiController::newVendorString() const {
   509:     return OSString::withCString("binaervarianz");
   510: }
   511: 
   512: const OSString* WiFiController::newModelString() const {
   513:     return OSString::withCString("default controller");
   514: }
   515: 
   516: #pragma mark - 
   517: 
   518: //---------------------------------------------------------------------------
   519: // Function: timeoutOccurred
   520: //
   521: // Periodic timer that monitors the receiver status, updates error
   522: // and collision statistics, and update the current link status.
   523: 
   524: void WiFiController::timeoutOccurred(OSObject * owner, IOTimerEventSource * /*timer*/) {
   525:     WiFiController *self = (WiFiController*) owner; 
   526:     self->handleTimer();
   527:     
   528:     self->_timerSrc->setTimeoutMS(LOAD_STATISTICS_INTERVAL);
   529: }
   530: 
   531: void WiFiController::interruptOccurred(OSObject * owner, IOInterruptEventSource * src, int /*count*/) {
   532:     WiFiController *self = (WiFiController*) owner; 
   533: 	
   534: 	self->handleInterrupt();
   535: }
   536: 
   537: #pragma mark - 
   538: 
   539: UInt32 WiFiController::outputPacket(mbuf_t m, void * param) {
   540:     IOReturn ret;
   541:     
   542:     if (!_enabledForNetif) {		// drop the packet.
   543:         freePacket(m);
   544:         return kIOReturnOutputDropped;
   545:     }
   546: 
   547:     ret = outputPacketHardware(m);
   548:     
   549:     if (ret == kIOReturnOutputSuccess) _netStats->outputPackets++;
   550:     else if (ret == kIOReturnOutputDropped) {
   551:         _netStats->outputErrors++;
   552:         freePacket(m);
   553:     }
   554:     
   555:     return ret;
   556: }
   557: 
   558: #pragma mark - 
   559: 
   560: //---------------------------------------------------------------------------
   561: // Function: _phyAddMediumType
   562: //
   563: // Purpose:
   564: //   Add a single medium object to the medium dictionary.
   565: //   Also add the medium object to an array for fast lookup.
   566: 
   567: bool WiFiController::_addMediumType(UInt32 type, UInt32 speed, UInt32 code, char* name) {	
   568:     IONetworkMedium	* medium;
   569:     bool              ret = false;
   570:     
   571:     medium = IONetworkMedium::medium(type, speed, 0, code, name);
   572:     if (medium) {
   573:         ret = IONetworkMedium::addMedium(_mediumDict, medium);
   574:         if (ret)
   575:             _mediumTable[code] = medium;
   576:         medium->release();
   577:     }
   578:     return ret;
   579: }
   580: 
   581: //---------------------------------------------------------------------------
   582: // Function: _phyGetMediumWithCode
   583: //
   584: // Purpose:
   585: //   Returns the IONetworkMedium object associated with the given type.
   586: 
   587: IONetworkMedium *WiFiController::_getMediumWithType(UInt32 type) {
   588:     if (type < MEDIUM_TYPE_INVALID)
   589:         return _mediumTable[type];
   590:     else
   591:         return 0;
   592: }
   593: //---------------------------------------------------------------------------
   594: // Function: selectMedium <IONetworkController>
   595: //
   596: // Transition the controller/PHY to use a new medium. Note that
   597: // this function can be called my the driver, or by our client.
   598: 
   599: IOReturn WiFiController::selectMedium(const IONetworkMedium * medium) {
   600:     bool  r;
   601: 
   602:     if ( OSDynamicCast(IONetworkMedium, medium) == 0 ) {
   603:         // Defaults to Auto.
   604:         medium = _getMediumWithType(MEDIUM_TYPE_AUTO);
   605:         if (medium == 0) return kIOReturnError;
   606:     }
   607: 
   608:     // Program PHY to select the desired medium.
   609:     //
   610:     r = setMediumHardware((mediumType_t) medium->getIndex());
   611: 
   612:     // Update the current medium property.
   613:     //
   614:     if (r && !setCurrentMedium(medium))
   615:             WLLogErr("setCurrentMedium error\n");
   616: 
   617:     return (r ? kIOReturnSuccess : kIOReturnIOError);
   618: }
   619: 
   620: //---------------------------------------------------------------------------
   621: // Function: setMulticastMode <IOEthernetController>
   622: 
   623: IOReturn WiFiController::setMulticastMode(bool active) {
   624:     return kIOReturnSuccess;
   625: }
   626: 
   627: //---------------------------------------------------------------------------
   628: // Function: setMulticastList <IOEthernetController>
   629: 
   630: IOReturn WiFiController::setMulticastList(IOEthernetAddress * addrs, UInt32 count) {
   631:     IOReturn ret = kIOReturnSuccess;
   632: 
   633:     return ret;
   634: }
   635: 
   636: #pragma mark - 
   637: 
   638: //abstracts; are to be defined in sub-classes
   639: bool WiFiController::startProvider(IOService *provider) { return false; }
   640: bool WiFiController::openProvider() { return false; }
   641: bool WiFiController::closeProvider() { return false; }
   642: bool WiFiController::freeProvider() { return false; }
   643: 
   644: bool WiFiController::startHardware() { return false; }
   645: bool WiFiController::initHardware() { return false; }
   646: bool WiFiController::freeHardware() { return false; }
   647: bool WiFiController::enableHardware() { return false; }
   648: bool WiFiController::disableHardware() { return false; }
   649: bool WiFiController::getReadyForSleep() { return false; }
   650: bool WiFiController::handleEjectionHardware() { return false; }
   651: bool WiFiController::setMediumHardware(mediumType_t medium) { return medium == MEDIUM_TYPE_AUTO; }
   652: 
   653: bool WiFiController::handleInterrupt() { return false; }
   654: bool WiFiController::handleTimer() { return false; }
   655: 
   656: IOReturn WiFiController::outputPacketHardware(mbuf_t m) { return kIOReturnOutputDropped; }
   657: IOReturn WiFiController::setHardwareAddressHardware(UInt8 *addr) { return kIOReturnUnsupported; }
   658: 
   659: UInt32 WiFiController::getLinkSpeed() { return 0; }
   660: UInt32 WiFiController::getFrequency() { return 0; };
   661: bool WiFiController::setFrequency(UInt32 frequency) { return false; }
   662: bool WiFiController::setMode(wirelessMode mode) { return false; }
   663: bool WiFiController::setKey(UInt32 length, UInt8* key) { return false; }
   664: 
   665: wirelessState WiFiController::getConnectionState() { 
   666:     if (_currentState <= stateDisabled) return _currentState; 
   667:     if (_enabledForNetif) return _currentState;
   668:     return stateDisabled;
   669: }
   670: 
   671: bool WiFiController::setSSID(UInt32 length, UInt8* ssid) { 
   672:     length = length > 32 ? 32 : length;
   673:     memset(_ssid, 0, sizeof(_ssid));
   674:     memcpy(_ssid, ssid, length);
   675:     _ssidLength = length;
   676:     
   677:     WLLogDebug("Joining network with SSID <%s>, length: %d", _ssid, _ssidLength);
   678:     return false; 
   679: }
   680: 
   681: bool WiFiController::getBSSNodesInRange(UInt32 *size, UInt8* data) { 
   682:     *size = *size > _bssListCount * sizeof(bssItem) ? _bssListCount * sizeof(bssItem) : *size;
   683:     memcpy(data, _bssList, *size);
   684:     return true;
   685: }
   686: