Source to iokit/Families/IONetworking/IONetworkStack.cpp


Enter a symbol's name here to quickly find it.

/*
 * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
 *
 * @APPLE_LICENSE_HEADER_START@
 * 
 * The contents of this file constitute Original Code as defined in and
 * are subject to the Apple Public Source License Version 1.1 (the
 * "License").  You may not use this file except in compliance with the
 * License.  Please obtain a copy of the License at
 * http://www.apple.com/publicsource and read it before using this file.
 * 
 * This Original Code and all software distributed under the License are
 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
 * License for the specific language governing rights and limitations
 * under the License.
 * 
 * @APPLE_LICENSE_HEADER_END@
 */
/*
 * Copyright (c) 1999 Apple Computer, Inc.  All rights reserved. 
 *
 * IONetworkStack.cpp - An IOKit proxy for the BSD network stack.
 *
 * HISTORY
 *
 * IONetworkStack abstracts certain essential network stack services.
 * Those services include attaching/detaching network interfaces, and
 * interface naming. Note that although BSD network stack does not assign
 * interface names, it is the responsibility of this object to manage the
 * interface name space.
 *
 * IONetworkStack is a client of IONetworkInterface. This object uses the
 * standard IOKit matching mechanism to discover and attach to interface
 * objects. Each interface object is expected to have only a single
 * IONetworkStack client. Under IOKit, the stack object initiates the
 * action to attach to an interface. And subsequently, detaches from an
 * interface when signaled to do so.
 *
 * The packet flow bypasses this object for efficiency sake. The interface
 * object interact directly with the 'real' network stack to send and
 * receive packets.
 */

#include <IOKit/assert.h>
#include <IOKit/IOLib.h>
#include <IOKit/IOBSD.h>
#include <IOKit/IOMessage.h>
#include <IOKit/network/IONetworkInterface.h>
#include <IOKit/network/IONetworkController.h>
#include "IONetworkStack.h"

extern "C" {
#include <sys/param.h>
#include <sys/mbuf.h>
#include <sys/socket.h>
#include <net/bpf.h>
#include <net/if.h>
#include <netinet/if_ether.h>
}

#define super IOService

OSDefineMetaClassAndStructorsWithInit( IONetworkStack,
                                       IOService,
                                       IONetworkStack::initialize())

#ifdef  DEBUG
#define DLOG(fmt, args...)  IOLog(fmt, ## args)
#else
#define DLOG
#endif

// Maintain a linked list of network interfaces.
// Each time a new interface is added, an unit number is assigned,
// and an interface entry is added to the list. When the interface
// goes away, the entry is removed from the list and deallocated.
//
static queue_head_t         netifTable;
static IOLock *             netifTableLock;

typedef struct {
    IONetworkInterface *    netif;
    const char *            name;
    short                   unit;
    queue_chain_t           link;
} netifEntry;

#define BSD_IFNET_ENTRY     ((IONetworkInterface *) 0)
#define NETIF_LOCK          IOTakeLock(netifTableLock)
#define NETIF_UNLOCK        IOUnlock(netifTableLock)

#define LOCK                IOTakeLock(_lock);
#define UNLOCK              IOUnlock(_lock);

// --------------------------------------------------------------------------
//
// Add a new entry to the netifTable for the interface 'netif'.
// Return true if the entry was added successfully, otherwise
// returns false.
//
// The table lock must be held by the caller of this function.
//
static bool addNetworkInterfaceEntry(IONetworkInterface * netif,
                                     const char *         name,
                                     short                unit)
{
    if (!netif || !name || (unit < 0)) return false;

    netifEntry * entry = (netifEntry *) IOMalloc(sizeof(netifEntry));
    if (!entry)
        return false;
    bzero(entry, sizeof(*entry));

    entry->netif = netif;
    entry->unit  = unit;
    entry->name  = name;

    queue_enter(&netifTable, entry, netifEntry *, link);

    return true;
}

// --------------------------------------------------------------------------
//
// Release the table entry occupied by the 'netif' instance.
// Returns true if an entry was found and removed, otherwise
// return false.
//
static bool releaseNetworkInterfaceEntry(IONetworkInterface * netif)
{
    netifEntry * foundEntry = 0;

    if (!netif) return false;

    NETIF_LOCK;
    if (!queue_empty(&netifTable)) {
        netifEntry * entry;
        queue_iterate(&netifTable, entry, netifEntry *, link) {
            if (entry->netif == netif) {
                foundEntry = entry;
                break;
            }
        }
    }
    if (foundEntry) {
        queue_remove(&netifTable, foundEntry, netifEntry *, link);
        IOFree(foundEntry, sizeof(*foundEntry));
    }
    NETIF_UNLOCK;

    return (foundEntry ? true : false);
}

// --------------------------------------------------------------------------
//
// Initialize the table, and preload it with any existing BSD network
// interfaces.
//
static void initNetifTable()
{
    netifTableLock = IOLockAlloc();
    assert(netifTableLock);

    IOLockInitWithState(netifTableLock, kIOLockStateUnlocked);

    queue_init(&netifTable);

    // Insert entries for all existing 'BSD' network interfaces into the 
    // netifTable. Hopefully only lo0 will be found.
    //
#if 1   // FreeBSD 3.2
    for (struct ifnet * ifp = ifnet.tqh_first;
         ifp;
         ifp = ifp->if_link.tqe_next)
        addNetworkInterfaceEntry(BSD_IFNET_ENTRY, ifp->if_name, ifp->if_unit);
#else
    for (struct ifnet * ifp = ifnet; ifp; ifp = ifp->if_next)
        addNetworkInterfaceEntry(BSD_IFNET_ENTRY, ifp->if_name, ifp->if_unit);
#endif
}

// --------------------------------------------------------------------------
//
// Add a entry for the interface object 'netif', with name prefix 'name'.
// The chosen unit number is returned in 'unit'. Returns true on success.
//
static bool reserveNetworkInterfaceEntry(IONetworkInterface * netif,
                                         const char *         name,
                                         short *              unit)
{
    bool ret = true;
    bool addEntry = true;   // add new entry to list.
    bool error = false;

    if (!netif || !name || !unit || (*unit < 0)) return false;

    NETIF_LOCK;

    if (!queue_empty(&netifTable)) {
        bool rescan;
        netifEntry * entry;

        do {
            rescan = false;
            
            // Scan through the interface list and search for duplicates
            // and conflicts. If a conflict is found, increment the unit
            // number and rescan.
            //
            queue_iterate(&netifTable, entry, netifEntry *, link) {
                if (entry->netif == netif) {    // can't have duplicates
                    addEntry = false;           // re-use existing entry
                    *unit = entry->unit;
                    break;
                }
                if ((entry->unit == *unit) && !strcmp(entry->name, name)) {
                    // name conflict detected.
                    if (++(*unit) > 0)
                        rescan = true;
                    else
                        error = true;
                    break;
                }
            }
        } while (rescan);
    }

    if (error)
        ret = false;
    else if (addEntry)
        ret = addNetworkInterfaceEntry(netif, name, *unit);

    NETIF_UNLOCK;

    return ret;
}

// --------------------------------------------------------------------------
//
// IONetworkStack class initializer.

void IONetworkStack::initialize()
{
    initNetifTable();
}

// --------------------------------------------------------------------------
//
// init method.

bool IONetworkStack::init(OSDictionary * properties)
{
    _netif = 0;     // IONetworkInterface instance (provider).
    _ifp   = 0;     // ifnet struct for the interface.
    _lock  = 0;     // big serialization lock.
    _state = kIONetworkStackStateInit;  // default state.

    if (!super::init())
        return false;

    // Allocate a lock which will protect all accesses to this object.
    //
    _lock = IOLockAlloc();
    if (!_lock)
        return false;

    return true;
}

// --------------------------------------------------------------------------
//
// probe. the score forces the probe and start in IONetworkStack to occur
// before the notification from IONetworkInterface is sent. We need to delay
// that until the network stack object has assigned a BSD name to the
// interface.

IOService * IONetworkStack::probe(IOService * provider,
                                  SInt32 *    score)
{
    if (!super::probe(provider, score))
        return 0;

    // We are not picky about our provider, but it must be an
    // IONetworkInterface instance.
    //
    IONetworkInterface * netif = OSDynamicCast(IONetworkInterface, provider);
    if (!netif)
        return 0;

    *score = 32;    // must be larger than notification score.
    
    // Query interface for any requirements before qualifying the probe.
    // For now, there is nothing that needs to be done. Return 'this' to
    // indicate successful probe.

    return this;
}

// --------------------------------------------------------------------------
//
// start method. We have attached to our provider, now start ourselve up.

bool IONetworkStack::start(IOService * provider)
{
    IONetworkInterface * netif = OSDynamicCast(IONetworkInterface, provider);
    bool                 ret    = false;
    bool                 opened = false;

    if (!netif) return false;

    LOCK;

    do {
        // Catch illegal state transitions.
        //
        if (_state != kIONetworkStackStateInit)
            break;

        // Our provider must reveal its ifnet structure.
        //
        _netif = netif;
        _ifp   = _netif->getIfnet();
        if (!_ifp || (_netif != (IONetworkInterface *) _ifp->if_private))
            break;

        // Pass start() to our superclass.
        //
        if (!super::start(provider))
            break;

        // Open our provider.
        //
        if (!_netif->open(this))
            break;
        opened = true;

        // Assign a name for the interface. Must do this before the
        // if_attach() call. Remember to release the OSString object
        // obtained through this call.
        //
        OSString * ifname = _assignInterfaceName(_netif);
        if (!ifname) {
            releaseNetworkInterfaceEntry(_netif);
            break;
        }
        ifname->release();

        // When IONetworkStack gets probed, we assume that BSD is already
        // up and running. So it is safe to call BSD to attach the network 
        // interface.
        //
        // FIXME: This will only work with Ethernet interfaces. Switch to
        // new DLIL API once that is available.
        //
        _netif->lock();

        // Set the if_free() function pointer in the ifnet to point to our
        // detachCallBack() static function.
        //
        // _ifp->if_free  = detachCallBackHandler;
        // _netif->_stack = this;

#if 1   // FreeBSD 3.2
        bpfattach(_ifp, DLT_EN10MB,sizeof(struct ether_header));
#else
        bpfattach(&_ifp->if_bpf, _ifp, DLT_EN10MB,sizeof(struct ether_header));
#endif  

        ether_ifattach(_ifp); 
        
        _netif->unlock();

        // Network stack is now attached to the interface.
        //
        _state = kIONetworkStackStateAttached;

        ret = true;
    }
    while (0);

    if (!ret)
    {
        // start failed, undo any actions performed.
        //
        if (opened)
            _netif->close(this);
        
        _netif = 0;
        _ifp   = 0;
    }

    UNLOCK;

    return ret;
}

// --------------------------------------------------------------------------
//
// stop method.

void IONetworkStack::stop(IOService * provider)
{
    LOCK;

    // Catch an illegal stop.
    //
    assert((_state == kIONetworkStackStateInit) ||
           (_state == kIONetworkStackStateDetached));

    // Remove the interface from linked list.
    //
    if (_netif) {
        assert(_netif == (IONetworkInterface *) provider);
        releaseNetworkInterfaceEntry(_netif);
    }

    _netif = 0;
    _ifp   = 0;
    _state = kIONetworkStackStateInit;

    UNLOCK;
    
    super::stop(provider);
}

// --------------------------------------------------------------------------
//
// sendIfDetachRequest
//
// Handle a detach request from our provider and signal to the network stack 
// that the interface wishes to detach. The network stack will callback when 
// the interface is allowed to proceed with the detach. There is no hard
// limit on how soon the callback will occur.
//
// Returns true if the request was handled. Otherwise, returns false.

bool IONetworkStack::sendIfDetachRequest()
{
    bool ret = false;

    DLOG("IONetworkStack::sendIfDetachRequest() called state = %d\n", _state);

    LOCK;

    if (_state == kIONetworkStackStateAttached) {
    
        // Send a detach request to the network stack and wait for
        // a callback indicating detach operation complete.
        //
        // if_detach() is a new proposed DLIL call and does not exist yet.

        _state = kIONetworkStackStateDetaching;

        ret = true; // detach request handled.
    }
    
    UNLOCK;
    
    return ret;
}

// --------------------------------------------------------------------------
//
// ifDetachCallback method.

void IONetworkStack::ifDetachCallback()
{
    LOCK;
    
    if (_state == kIONetworkStackStateDetaching) {
        
        // We previously sent a detach request, the network stack is now
        // calling back to indicate detach completion.
        //
        assert(_netif && _ifp);

        // Close our provider.
        //
        _netif->close(this);
 
        // Detach is now complete.
        //
        _state = kIONetworkStackStateDetached;
    }
    else {
        DLOG("%s: Unexpected detach callback\n", getName());
    }

    UNLOCK;
}

// --------------------------------------------------------------------------
//
// This static member function is registered as the if_free() handler in
// the ifnet structure of our provider. The IONetworkStack instance is 
// discovered and its ifFreeCallback() method is called.

void IONetworkStack::ifDetachCallbackHandler(struct ifnet * ifp)
{
    IONetworkInterface *    netif;
    IONetworkStack *        stack;
    
    netif = OSDynamicCast(IONetworkInterface,
                          (IONetworkInterface *) ifp->if_private);
    assert(netif);

    netif->lockForArbitration();
    
    stack = (IONetworkStack *) netif->_client;
    if (stack)
        stack->ifDetachCallback();
    else
        DLOG("IONetworkStack: No target for ifDetachCallback\n");

    netif->unlockForArbitration();
}

// --------------------------------------------------------------------------
//
// Release allocated resources.

void IONetworkStack::free()
{
    assert(_state == kIONetworkStackStateInit);

    if (_lock)
        IOLockFree(_lock);
}

// --------------------------------------------------------------------------
//
// Facility provided by IOService for general purpose provider-to-client 
// notification. We catch the kIOMessageServiceIsTerminated message.

IOReturn IONetworkStack::message(UInt32 type, IOService * provider,
                                 void * argument = 0)
{
    // Our provider has gone into an inactive state, we should begin the
    // tear-down process by signalling the network stack to unregister
    // and detach the network interface.
    //
    // We do not look at the argument, which contains the options given
    // to the terminate() method.
    //
    if (type == kIOMessageServiceIsTerminated) {
        sendIfDetachRequest();
        return kIOReturnSuccess;
    }
    
    return kIOReturnUnsupported;
}

// --------------------------------------------------------------------------
//
// Assign a BSD friendly name to the network interface. The interface
// object has to assist in this process by returning its name prefix,
// i.e. "en". This routine will pick an unit number that does not
// conflict with any existing interface.

OSString * IONetworkStack::_assignInterfaceName(IONetworkInterface * netif)
{
    SInt16                  unit = 0;
    UInt32                  index = 0;
    const char *            namePrefix = netif->getNamePrefix();
    char                    nameBuf[40];
    OSString *              nameString;
    IONetworkController *   ctlr = OSDynamicCast(IONetworkController, 
                                                 netif->getProvider());

    if (!ctlr || !namePrefix || !*namePrefix)
        return 0;

    // First, we need to determine the initial interface unit number.
    // The current scheme needs a lot of work. Currently, motherboard
    // devices gets unit 0, while add-on PCI cards are assigned
    // unit 1 and up. Here, we need to determine whether this is an
    // onboard or a PCI network controller.
    //
    if (ctlr->getProvider()) {
            OSObject * propObject = ctlr->getProvider()->getProperty("built-in");
        
        if (!propObject) {
            propObject = ctlr->getProvider()->getProperty("AAPL,slot-name");
            if (propObject) {
                unit = 1;   // PCI add-on card
                
                // If we have an index number, increment
                // the unit by the index number.
                // (for multiport PCI cards).
                ctlr->doGetControllerIndex(this, &index);
                unit += index;
            }       
        }
    }

    // "unit" is now the initial unit number requested by the interface.
    // If this unit number is already taken by an existing interface, we
    // will automatically increment the unit number until there are no 
    // conflicts. We don't want to confuse BSD with identical names.
    //
    // Now try to reserve the chosen name.
    //
    if (!reserveNetworkInterfaceEntry(netif, namePrefix, &unit))
        return 0;

    // Update the interface object with its assigned name.
    //
    sprintf(nameBuf, "%s%d", namePrefix, unit);
    nameString = OSString::withCString(nameBuf);
    if (nameString) {
        //
        // Now fill in the ifnet name fields.
        //      
        netif->setInterfaceNameInt(namePrefix);
        netif->setUnitNumberInt(unit);
        
        // Set the interface's kIOBSDName property.
        //
        netif->setProperty(kIOBSDName, nameString);
    }

    return nameString;
}