1/*
2 * Copyright (c) 1998-2011 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License").  You may not use this file except in compliance with the
9 * License.  Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22/*
23 * IONetworkStack.cpp - An IOKit proxy for the BSD networking stack.
24 *
25 * HISTORY
26 *
27 * IONetworkStack abstracts essential network stack services. These
28 * include registering/unregistering network interfaces, and interface
29 * name space management.
30 *
31 * Only a single IONetworkStack object is instantiated. This object will
32 * register to receive a notification when a network interface object is
33 * first published. The notification handler is responsible for attaching
34 * the network stack object to the interface object as a client. When the
35 * interface is terminated, this linkage is severed.
36 *
37 * This object does not participate in the data/packet flow. The interface
38 * object will interact directly with DLIL to send and to receive packets.
39 */
40
41extern "C" {
42#include <net/if.h>
43#include <sys/sockio.h>
44}
45
46#include <IOKit/assert.h>
47#include <IOKit/IOLib.h>
48#include <IOKit/IOBSD.h>
49#include <IOKit/IOKitKeys.h>
50#include <IOKit/network/IONetworkInterface.h>
51#include <IOKit/network/IOEthernetController.h>  // for setAggressiveness()
52#include "IONetworkStack.h"
53#include "IONetworkDebug.h"
54
55#define super IOService
56OSDefineMetaClassAndFinalStructors( IONetworkStack, IOService )
57
58#define NIF_VAR(n)              ((n)->_clientVar[0])
59#define NIF_SET(n, x)           (NIF_VAR(n) |= (x))
60#define NIF_CLR(n, x)           (NIF_VAR(n) &= ~(x))
61#define NIF_TEST(n, x)          (NIF_VAR(n) & (x))
62
63#define NIF_CAST(x)             ((IONetworkInterface *) x)
64#define NIF_SAFECAST(x)         (OSDynamicCast(IONetworkInterface, x))
65
66#define NIF_NO_BSD_ATTACH(n)    ((n)->_clientVar[2])
67
68#define LOCK()                  IOLockLock(_stateLock)
69#define UNLOCK()                IOLockUnlock(_stateLock)
70
71#define kDetachStateKey         "detach state"
72
73static IONetworkStack * gIONetworkStack = 0;
74
75// Flags encoded on the interface object.
76//
77enum {
78    kInterfaceStateInactive     = 0x01, // terminated
79    kInterfaceStatePublished    = 0x02, // waiting to be named
80    kInterfaceStateNamed        = 0x04, // name and unit assigned
81    kInterfaceStateAttaching    = 0x08, // will attach to BSD
82    kInterfaceStateAttached     = 0x10, // attached to BSD
83    kInterfaceStateAbandoned    = 0x20  // failed to attach to BSD
84};
85
86// IONetworkStackUserClient definition
87//
88#include <IOKit/IOUserClient.h>
89
90class IONetworkStackUserClient : public IOUserClient
91{
92    OSDeclareFinalStructors( IONetworkStackUserClient )
93
94protected:
95    IONetworkStack * _provider;
96
97public:
98    virtual bool initWithTask(	task_t			owningTask,
99                                void *			securityID,
100                                UInt32			type,
101                                OSDictionary *	properties );
102    virtual bool start( IOService * provider );
103    virtual IOReturn clientClose( void );
104    virtual IOReturn clientDied( void );
105    virtual IOReturn setProperties( OSObject * properties );
106};
107
108//------------------------------------------------------------------------------
109
110bool IONetworkStack::start( IOService * provider )
111{
112    OSDictionary *      matching;
113    IOService *         rootDomain;
114    const OSSymbol *    ucClassName;
115
116    DLOG("IONetworkStack::start(%p) %p\n", provider, this);
117
118    // Only a single IONetworkStack object is created, and a reference
119    // to this object is stored in a global variable.
120    // When the boot process is VERY VERY slow for some unknown reason
121    // we get two instances of IONetworkStack and theassert below fires.
122    // so I am commenting the assert and replacing it with an if statement.
123    // assert( gIONetworkStack == 0 );
124
125    if (gIONetworkStack)
126        goto fail;
127
128    if (super::start(provider) == false)
129        goto fail;
130
131    _stateLock = IOLockAlloc();
132    if (!_stateLock)
133        goto fail;
134
135    _ifListNaming = OSSet::withCapacity(8);
136    if (!_ifListNaming)
137        goto fail;
138
139    _ifPrefixDict = OSDictionary::withCapacity(4);
140    if (!_ifPrefixDict)
141        goto fail;
142
143    _asyncThread = thread_call_allocate(
144        OSMemberFunctionCast(thread_call_func_t, this,
145            &IONetworkStack::asyncWork), this);
146    if (!_asyncThread)
147        goto fail;
148
149    _noBSDAttachSymbol = OSSymbol::withCStringNoCopy(kIONetworkNoBSDAttachKey);
150    if (!_noBSDAttachSymbol)
151        goto fail;
152
153    // Call the IOPMrootDomain object, which sits at the root of the
154    // power management hierarchy, to set the default Ethernet WOL
155    // settings. Setting the WOL through setAggressiveness rather
156    // than on each interface object makes it easy to handle an
157    // IOPMSetAggressiveness() call from loginwindow since it will
158    // simply override the default value set here.
159
160    if ((rootDomain = (IOService *) getPMRootDomain()))
161    {
162        rootDomain->IOService::setAggressiveness(kPMEthernetWakeOnLANSettings,
163            kIOEthernetWakeOnMagicPacket | kIOEthernetWakeOnPacketAddressMatch);
164    }
165
166    // Sign up for a notification when a network interface is published.
167
168    matching = serviceMatching(kIONetworkInterfaceClass);
169    if (!matching)
170        goto fail;
171
172    gIONetworkStack = this;
173
174    _ifNotifier = addMatchingNotification(
175            /* type     */ gIOPublishNotification,
176            /* match    */ matching,
177            /* action   */ OSMemberFunctionCast(
178                                    IOServiceMatchingNotificationHandler,
179                                    this, &IONetworkStack::interfacePublished),
180            /* target   */ this,
181            /* refCon   */ this,
182            /* priority */ 1000 );
183
184    matching->release();
185    if (!_ifNotifier)
186        goto fail;
187
188    ucClassName = OSSymbol::withCStringNoCopy("IONetworkStackUserClient");
189    if (ucClassName)
190    {
191        setProperty(gIOUserClientClassKey, (OSObject *) ucClassName);
192        ucClassName->release();
193    }
194
195    registerService();
196    return true;
197
198fail:
199    LOG("IONetworkStack::start(%p) %p failed\n", provider, this);
200    return false;
201}
202
203//------------------------------------------------------------------------------
204
205void IONetworkStack::free( void )
206{
207    LOG("IONetworkStack::free() %p\n", this);
208
209    if (this == gIONetworkStack)
210        gIONetworkStack = 0;
211
212    if ( _ifNotifier )
213    {
214        _ifNotifier->remove();
215        _ifNotifier = 0;
216    }
217
218    if (_ifPrefixDict)
219    {
220        _ifPrefixDict->release();
221        _ifPrefixDict = 0;
222    }
223
224    if (_ifListNaming)
225    {
226        _ifListNaming->release();
227        _ifListNaming = 0;
228    }
229
230    if (_ifListDetach)
231    {
232        _ifListDetach->release();
233        _ifListDetach = 0;
234    }
235
236    if (_ifListAttach)
237    {
238        _ifListAttach->release();
239        _ifListAttach = 0;
240    }
241
242    if (_noBSDAttachSymbol)
243    {
244        _noBSDAttachSymbol->release();
245        _noBSDAttachSymbol = 0;
246    }
247
248    if (_asyncThread)
249    {
250        thread_call_free(_asyncThread);
251        _asyncThread = 0;
252    }
253
254    if (_stateLock)
255    {
256        IOLockFree(_stateLock);
257        _stateLock = 0;
258    }
259
260    super::free();
261}
262
263//------------------------------------------------------------------------------
264
265bool IONetworkStack::insertNetworkInterface( IONetworkInterface * netif )
266{
267    const char *   prefix = netif->getNamePrefix();
268    OSOrderedSet * set;
269    bool           ok = true;
270
271    if (prefix == 0)
272        return false;
273
274    // Look for a Set object associated with the name prefix.
275
276    set = (OSOrderedSet *) _ifPrefixDict->getObject(prefix);
277
278    // If not found, then create one and add it to the dictionary.
279
280    if (!set && ((set = OSOrderedSet::withCapacity(8, orderNetworkInterfaces))))
281    {
282        ok = _ifPrefixDict->setObject(prefix, set);
283        set->release();
284    }
285
286    // Add the interface object to the named set.
287    // All objects in a set will have the same name prefix.
288
289    ok = (set && ok) ? set->setObject(netif) : false;
290
291    if (set && (set->getCount() == 0))
292    {
293        _ifPrefixDict->removeObject(prefix);
294    }
295
296    return ok;
297}
298
299void IONetworkStack::removeNetworkInterface( IONetworkInterface * netif )
300{
301    const char *   prefix = netif->getNamePrefix();
302    OSOrderedSet * set;
303
304    if ( prefix )
305    {
306        set = (OSOrderedSet *) _ifPrefixDict->getObject(prefix);
307        if ( set )
308        {
309            // Remove interface from set
310
311            set->removeObject(netif);
312            DLOG("IONetworkStack::removeNetworkInterface %s count = %d\n",
313                prefix, set->getCount());
314
315            // Remove the empty set from the dictionary
316
317            if (set->getCount() == 0)
318                _ifPrefixDict->removeObject(prefix);
319        }
320    }
321}
322
323//------------------------------------------------------------------------------
324// Get the next available unit number in the set of registered interfaces
325// with the specified prefix.
326
327uint32_t IONetworkStack::getNextAvailableUnitNumber(
328    const char *    prefix,
329    uint32_t        startingUnit )
330{
331    IONetworkInterface * netif;
332    OSOrderedSet *       set;
333
334    assert(prefix);
335
336    set = (OSOrderedSet *) _ifPrefixDict->getObject(prefix);
337    netif = set ? NIF_CAST(set->getLastObject()) : 0;
338
339    if (!netif || (netif->getUnitNumber() < startingUnit))
340    {
341        // The unit number provided is acceptable.
342    }
343    else if (netif->getUnitNumber() == startingUnit)
344    {
345        // Conflict, bump proposed unit number by one.
346        startingUnit++;
347    }
348    else if (set)
349    {
350        for ( uint32_t index = 0; ; index++ )
351        {
352            netif = NIF_CAST(set->getObject(index));
353
354            if (!netif || (netif->getUnitNumber() > startingUnit))
355                break;
356            else if (netif->getUnitNumber() < startingUnit)
357                continue;
358            else /* == */
359                startingUnit = netif->getUnitNumber() + 1;
360        }
361    }
362
363    return startingUnit;
364}
365
366//------------------------------------------------------------------------------
367
368bool IONetworkStack::interfacePublished(
369    void *          refCon __unused,
370    IOService *     service,
371    IONotifier *    notifier __unused )
372{
373    IONetworkInterface * netif = NIF_SAFECAST(service);
374    bool isNew, ok = false;
375
376    if (!netif)
377        return false;
378
379    DLOG("IONetworkStack::interfacePublished(%p, state 0x%x, parent %d, noattach %d)\n",
380        netif, (uint32_t) NIF_VAR(netif), isParent(netif, gIOServicePlane),
381        (uint32_t) NIF_NO_BSD_ATTACH(netif));
382
383    isNew = (false == isParent(netif, gIOServicePlane));
384    if (isNew && !attach(netif))
385        return false;
386
387    LOCK();
388
389    do {
390        if (isNew)
391        {
392            // Must be a new network interface
393            if (NIF_VAR(netif) != 0)
394                break;
395
396            // Stop if interface is waiting for a name
397            if (_ifListNaming->containsObject(netif))
398            {
399                ok = true;
400                break;
401            }
402
403            _ifListNaming->setObject(netif);
404
405            if (netif->getProperty(_noBSDAttachSymbol) == kOSBooleanTrue)
406            {
407                NIF_NO_BSD_ATTACH(netif) = true;
408            }
409
410            // Initialize private interface state
411            NIF_VAR(netif) = kInterfaceStatePublished;
412            ok = true;
413        }
414        else
415        {
416            ok = true;
417            if (NIF_NO_BSD_ATTACH(netif) == false)
418                break;
419
420            // bail if still not allowed to BSD attach
421            if (netif->getProperty(_noBSDAttachSymbol) == kOSBooleanTrue)
422                break;
423
424            // reject invalid interface states
425            if (NIF_TEST(netif,
426                kInterfaceStateInactive  | kInterfaceStateAttached  |
427                kInterfaceStateAttaching | kInterfaceStateAbandoned ))
428                break;
429
430            NIF_NO_BSD_ATTACH(netif) = false;
431            if (!NIF_TEST(netif, kInterfaceStateNamed))
432            {
433                // simple case if interface has not received a name yet
434                break;
435            }
436
437            NIF_SET(netif, kInterfaceStateAttaching);
438            if (!_ifListAttach)
439                _ifListAttach = OSArray::withCapacity(1);
440            if (_ifListAttach)
441            {
442                _ifListAttach->setObject(netif);
443                thread_call_enter(_asyncThread);
444            }
445        }
446    }
447    while (false);
448
449    UNLOCK();
450
451    if (isNew && !ok)
452    {
453        netif->setProperty(kDetachStateKey, NIF_VAR(netif), 32);
454        detach(netif);
455    }
456
457    return ok;
458}
459
460//------------------------------------------------------------------------------
461
462void IONetworkStack::asyncWork( void )
463{
464    IONetworkInterface * d_netif;
465    IONetworkInterface * a_netif;
466    uint32_t             varBits;
467
468    while (1)
469    {
470        d_netif = a_netif = 0;
471
472        LOCK();
473        if (_ifListDetach)
474        {
475            d_netif = NIF_CAST(_ifListDetach->getObject(0));
476            if (d_netif)
477            {
478                d_netif->retain();
479                _ifListDetach->removeObject(0);
480                varBits = NIF_VAR(d_netif);
481            }
482        }
483        if (_ifListAttach)
484        {
485            a_netif = NIF_CAST(_ifListAttach->getObject(0));
486            if (a_netif)
487            {
488                a_netif->retain();
489                _ifListAttach->removeObject(0);
490            }
491        }
492        UNLOCK();
493
494        if (!d_netif && !a_netif)
495            break;
496
497        if (d_netif)
498        {
499            DLOG("IONetworkStack::asyncWork detach %s %p, state 0x%x\n",
500                d_netif->getName(), d_netif, varBits);
501
502            // Interface must be named, but may not have attached to BSD
503
504            if (varBits & kInterfaceStateAttached)
505            {
506                // Interface is about to detach from DLIL
507                d_netif->setInterfaceState( 0, kIONetworkInterfaceRegisteredState );
508
509                // detachFromDataLinkLayer will block until BSD detach is complete
510                d_netif->detachFromDataLinkLayer(0, 0);
511            }
512
513            LOCK();
514
515            assert(NIF_TEST(d_netif, kInterfaceStateInactive));
516            assert(NIF_TEST(d_netif, kInterfaceStateNamed));
517            assert(!NIF_TEST(d_netif, kInterfaceStateAttaching));
518
519            // Drop interface from list of attached interfaces.
520            // Unit number assigned to interface is up for grabs.
521
522            removeNetworkInterface(d_netif);
523
524            UNLOCK();
525
526            // Close interface and allow it to proceed with termination
527            d_netif->close( this );
528            d_netif->release();
529        }
530
531        if (a_netif)
532        {
533            DLOG("IONetworkStack::asyncWork attach %s %p, state 0x%x\n",
534                a_netif->getName(), a_netif, (uint32_t) NIF_VAR(a_netif));
535
536            assert(NIF_TEST(a_netif, kInterfaceStateAttaching));
537            attachNetworkInterfaceToBSD(a_netif);
538            a_netif->release();
539        }
540    }
541}
542
543//------------------------------------------------------------------------------
544
545bool IONetworkStack::didTerminate(
546        IOService * provider, IOOptionBits options, bool * defer )
547{
548    IONetworkInterface * netif = NIF_SAFECAST(provider);
549    bool wakeThread = false;
550
551    DLOG("IONetworkStack::didTerminate(%s %p state 0x%x, 0x%x)\n",
552        provider->getName(), provider, (uint32_t) options,
553        (uint32_t) NIF_VAR(netif));
554
555    if (!netif)
556        return true;
557
558    LOCK();
559
560    do {
561        // Interface has become inactive, it is no longer possible
562        // to open or to attach to the interface object.
563        // Mark the interface as unfit for naming / BSD attach.
564
565        NIF_SET(netif, kInterfaceStateInactive);
566        _ifListNaming->removeObject(netif);
567
568        // Interface is attaching to BSD. Postpone termination until
569        // the attach is complete.
570
571        if (NIF_TEST(netif, kInterfaceStateAttaching))
572            break;
573
574        // If interface was never named or attached to BSD, we are done
575        // since we don't have an open on the interface.
576
577        if (NIF_TEST(netif, kInterfaceStateAttached) ||
578            NIF_TEST(netif, kInterfaceStateNamed))
579        {
580            // Detach interface from BSD asynchronously.
581            // The interface termination will be waiting for our close.
582
583            if (!_ifListDetach)
584                _ifListDetach = OSArray::withCapacity(8);
585            if (_ifListDetach)
586            {
587                _ifListDetach->setObject(netif);
588                wakeThread = true;
589            }
590        }
591    }
592    while ( false );
593
594    UNLOCK();
595
596    if (wakeThread)
597        thread_call_enter(_asyncThread);
598
599    return true;
600}
601
602//------------------------------------------------------------------------------
603
604bool IONetworkStack::reserveInterfaceUnitNumber(
605    IONetworkInterface *    netif,
606    uint32_t                unit,
607    bool                    isUnitFixed,
608    bool *                  attachToBSD )
609{
610    const char *    prefix  = netif->getNamePrefix();
611    uint32_t        inUnit  = unit;
612    bool            opened  = false;
613    bool            ok      = false;
614
615    DLOG("IONetworkStack::reserveInterfaceUnitNumber(%p, %s, %u)\n",
616        netif, prefix ? prefix : "", unit);
617
618    *attachToBSD = false;
619
620    LOCK();
621
622    // netif retained by caller
623    _ifListNaming->removeObject(netif);
624
625    do {
626        if (!prefix)
627        {
628            LOG("interface name prefix is null\n");
629            break;
630        }
631
632        // Interface must be in the published state.
633
634        if (NIF_VAR(netif) != kInterfaceStatePublished)
635        {
636            LOG("unable to name interface in state 0x%x as %s%u\n",
637                (uint32_t) NIF_VAR(netif), prefix, inUnit);
638            break;
639        }
640
641        // The unit argument provided is a hint to indicate the lowest unit
642        // number that can be assigned to the interface. We are allowed to
643        // increment the unit number provided if the number is already
644        // taken.
645
646        unit = getNextAvailableUnitNumber(prefix, unit);
647        if ((isUnitFixed == true) && (unit != inUnit))
648        {
649            LOG("interface name %s%u is unavailable\n", prefix, inUnit);
650            break;
651        }
652
653        // Open the interface object. This will fail if the interface
654        // object has become inactive.
655
656        UNLOCK();
657        ok = netif->open(this);
658        LOCK();
659
660        if (!ok)
661        {
662            LOG("interface %s%u open failed\n", prefix, inUnit);
663            break;
664        }
665        opened = true;
666        ok = false;
667
668        // Must not reserve an unit number or attempt to BSD attach
669        // if preempted by interface termination.
670
671        if (NIF_TEST(netif, kInterfaceStateInactive))
672        {
673            LOG("interface %s%u became inactive\n", prefix, inUnit);
674            break;
675        }
676
677        // Update interface unit and add the interface to the named
678        // collection to reserve its assigned unit number.
679
680        if ((netif->setUnitNumber(unit)    == false) ||
681            (insertNetworkInterface(netif) == false))
682        {
683            LOG("interface %s%u name assigment failed\n", prefix, inUnit);
684            break;
685        }
686
687        ok = true;
688    }
689    while ( false );
690
691    if (ok)
692    {
693        NIF_SET(netif, kInterfaceStateNamed);
694        if (NIF_NO_BSD_ATTACH(netif) == false)
695        {
696            NIF_SET(netif, kInterfaceStateAttaching);
697            *attachToBSD = true;
698        }
699    }
700
701    UNLOCK();
702
703    if (!ok && opened)
704    {
705        netif->close(this);
706    }
707
708    return ok;
709}
710
711//------------------------------------------------------------------------------
712
713IOReturn IONetworkStack::attachNetworkInterfaceToBSD( IONetworkInterface * netif )
714{
715    bool        attachOK     = false;
716    bool        detachWakeup = false;
717    bool        pingMatching = false;
718    char        ifname[32];
719    IOReturn    result;
720
721    assert( netif );
722    if ((result = netif->attachToDataLinkLayer(0, 0)) == kIOReturnSuccess)
723    {
724        // Hack to sync up the interface flags. The UP flag may already
725        // be set, and this will issue an SIOCSIFFLAGS to the interface.
726
727        ifnet_ioctl(netif->getIfnet(), 0, SIOCSIFFLAGS, 0);
728
729        // Interface is now attached to BSD.
730        netif->setInterfaceState( kIONetworkInterfaceRegisteredState );
731
732        // Add a kIOBSDNameKey property to the interface AFTER the interface
733        // has attached to BSD. The order is very important to avoid rooting
734        // from an interface which is not yet known by BSD.
735
736        snprintf(ifname, sizeof(ifname), "%s%u",
737            netif->getNamePrefix(), netif->getUnitNumber());
738        netif->setProperty(kIOBSDNameKey, ifname);
739        attachOK = true;
740    }
741
742    // Update state bits and detect for untimely interface termination.
743
744    LOCK();
745    assert(NIF_TEST(netif, kInterfaceStateNamed));
746    assert(( NIF_VAR(netif) &
747           ( kInterfaceStateAttaching | kInterfaceStateAttached )) ==
748             kInterfaceStateAttaching );
749    NIF_CLR( netif, kInterfaceStateAttaching );
750
751    if (attachOK)
752    {
753        NIF_SET( netif, kInterfaceStateAttached  );
754        pingMatching = true;
755
756        if (NIF_TEST(netif, kInterfaceStateInactive))
757        {
758            if (!_ifListDetach)
759                _ifListDetach = OSArray::withCapacity(8);
760            if (_ifListDetach)
761            {
762                _ifListDetach->setObject(netif);
763                detachWakeup = true;
764            }
765            pingMatching = false;
766        }
767    }
768    else
769    {
770        // BSD attach failed, drop from list of attached interfaces
771        removeNetworkInterface(netif);
772        NIF_SET(netif, kInterfaceStateAbandoned);
773    }
774
775    UNLOCK();
776
777    if (!attachOK)
778    {
779        netif->setProperty(kDetachStateKey, NIF_VAR(netif), 32);
780        netif->close( this );
781        detach(netif);
782    }
783
784    if (detachWakeup)
785    {
786        // In the event that an interface was terminated while attaching
787        // to BSD, re-schedule the BSD detach and interface close.
788        thread_call_enter(_asyncThread);
789    }
790
791    if (pingMatching)
792    {
793        // Re-register interface after setting kIOBSDNameKey.
794        netif->registerService();
795    }
796
797    return result;
798}
799
800//------------------------------------------------------------------------------
801
802IOReturn IONetworkStack::registerAllNetworkInterfaces( void )
803{
804    IONetworkInterface *    netif;
805    OSSet *                 list;
806    bool                    attachToBSD;
807
808    LOCK();
809
810    if (!_ifListNaming || (_ifListNaming->getCount() == 0))
811    {
812        UNLOCK();
813        return kIOReturnSuccess;
814    }
815
816    list = OSSet::withSet( _ifListNaming );
817
818    UNLOCK();
819
820    if (list == 0)
821    {
822        return kIOReturnNoMemory;
823    }
824
825    while ((netif = NIF_CAST(list->getAnyObject())))
826    {
827        if (reserveInterfaceUnitNumber( netif, 0, false, &attachToBSD ) &&
828            attachToBSD)
829            attachNetworkInterfaceToBSD( netif );
830
831        list->removeObject(netif);
832    }
833
834    list->release();
835
836    return kIOReturnSuccess;
837}
838
839//------------------------------------------------------------------------------
840
841IOReturn IONetworkStack::registerNetworkInterface(
842    IONetworkInterface * netif,
843    uint32_t             unit,
844    bool                 isUnitFixed )
845{
846    IOReturn result = kIOReturnNoSpace;
847    bool attachToBSD = false;
848
849    if (reserveInterfaceUnitNumber( netif, unit, isUnitFixed, &attachToBSD ))
850    {
851        result = (attachToBSD) ? attachNetworkInterfaceToBSD( netif ) :
852                                 kIOReturnSuccess;
853    }
854
855    return result;
856}
857
858//------------------------------------------------------------------------------
859// Registered interfaces are ordered by their assigned unit number. Those with
860// larger unit numbers will be placed behind those with smaller unit numbers.
861// This ordering makes it easier to hunt for an available unit number slot for
862// a new interface.
863
864SInt32 IONetworkStack::orderNetworkInterfaces(
865    const OSMetaClassBase * obj1,
866    const OSMetaClassBase * obj2,
867    void *                  ref )
868{
869    const IONetworkInterface * netif1 = (const IONetworkInterface *) obj1;
870    const IONetworkInterface * netif2 = (const IONetworkInterface *) obj2;
871
872    assert( netif1 && netif2 );
873    return (netif2->getUnitNumber() - netif1->getUnitNumber());
874}
875
876//------------------------------------------------------------------------------
877
878IOReturn IONetworkStack::setProperties( OSObject * properties )
879{
880    IONetworkInterface *    netif = 0;
881    OSDictionary *          dict = OSDynamicCast(OSDictionary, properties);
882    OSString *              path;
883    OSNumber *              num;
884    OSNumber *              unit;
885    OSData *                data;
886    uint32_t                cmdType;
887    IOReturn                error = kIOReturnBadArgument;
888
889    do {
890        if (!dict)
891            break;
892
893        // [optional] Type of interface naming operation
894        // IORegisterNetworkInterface() does not set this for netboot case.
895
896        num = OSDynamicCast( OSNumber,
897                             dict->getObject(kIONetworkStackUserCommandKey));
898        if (num)
899            cmdType = num->unsigned32BitValue();
900        else
901            cmdType = kIONetworkStackRegisterInterfaceWithLowestUnit;
902
903        if (kIONetworkStackRegisterInterfaceAll == cmdType)
904        {
905            error = registerAllNetworkInterfaces();
906            break;
907        }
908
909        // [required] Interface unit number
910        unit = OSDynamicCast(OSNumber, dict->getObject(kIOInterfaceUnit));
911        if (!unit)
912            break;
913
914        // [optional] Registry entry ID for interface object
915        data = OSDynamicCast(OSData, dict->getObject(kIORegistryEntryIDKey));
916
917        // [optional] Device path to interface objecy
918        path = OSDynamicCast(OSString, dict->getObject(kIOPathMatchKey));
919
920        if (data && (data->getLength() == sizeof(uint64_t)))
921        {
922            OSDictionary *  matching;
923            OSIterator *    iter;
924            uint64_t        entryID = *(uint64_t *) data->getBytesNoCopy();
925
926            matching = registryEntryIDMatching(entryID);
927            if (!matching)
928            {
929                error = kIOReturnNoMemory;
930                break;
931            }
932
933            iter = getMatchingServices(matching);
934            matching->release();
935            if (!iter)
936            {
937                error = kIOReturnNotFound;
938                break;
939            }
940
941            if (iter)
942            {
943                netif = OSDynamicCast(IONetworkInterface, iter->getNextObject());
944                if (netif)
945                    netif->retain();
946                iter->release();
947            }
948        }
949        else if (path)
950        {
951            IORegistryEntry * entry;
952
953            entry = IORegistryEntry::fromPath(path->getCStringNoCopy());
954            if (entry && OSDynamicCast(IONetworkInterface, entry))
955                netif = (IONetworkInterface *) entry;
956            else if (entry)
957                entry->release();
958        }
959        else
960        {
961            // no path nor registry entry ID provided
962            break;
963        }
964
965        if (!netif)
966        {
967            error = kIOReturnNoDevice;
968            break;
969        }
970
971        switch ( cmdType )
972        {
973            case kIONetworkStackRegisterInterfaceWithUnit:
974                error = registerNetworkInterface(
975                            netif,
976                            unit->unsigned32BitValue(),
977                            true  /* fixedUnit   */ );
978                break;
979
980            case kIONetworkStackRegisterInterfaceWithLowestUnit:
981                error = registerNetworkInterface(
982                            netif,
983                            unit->unsigned32BitValue(),
984                            false /* fixedUnit   */ );
985                break;
986
987            default:
988                error = kIOReturnUnsupported;
989                break;
990        }
991    } while (false);
992
993    if (netif)
994        netif->release();
995
996    return error;
997}
998
999//------------------------------------------------------------------------------
1000// IONetworkStackUserClient
1001
1002#undef  super
1003#define super IOUserClient
1004OSDefineMetaClassAndFinalStructors( IONetworkStackUserClient, IOUserClient )
1005
1006bool IONetworkStackUserClient::initWithTask(	task_t			owningTask,
1007                                                void *			securityID,
1008                                                UInt32			type,
1009                                                OSDictionary *	properties )
1010{
1011	if (!super::initWithTask(owningTask, securityID, type, properties))
1012		return false;
1013
1014	if (IOUserClient::clientHasPrivilege(
1015		securityID, kIOClientPrivilegeAdministrator) != kIOReturnSuccess)
1016		return false;
1017
1018    return true;
1019}
1020
1021bool IONetworkStackUserClient::start( IOService * provider )
1022{
1023    if ( super::start(provider) == false )
1024        return false;
1025
1026    if ( provider->open(this) == false )
1027        return false;
1028
1029    _provider = OSDynamicCast(IONetworkStack, provider);
1030    if (!_provider)
1031    {
1032        provider->close(this);
1033        return false;
1034    }
1035
1036    return true;
1037}
1038
1039IOReturn IONetworkStackUserClient::clientClose( void )
1040{
1041    if (_provider)
1042    {
1043        _provider->close(this);
1044        detach(_provider);
1045    }
1046    return kIOReturnSuccess;
1047}
1048
1049IOReturn IONetworkStackUserClient::clientDied( void )
1050{
1051    return clientClose();
1052}
1053
1054IOReturn IONetworkStackUserClient::setProperties( OSObject * properties )
1055{
1056    if (kIOReturnSuccess != IOUserClient::clientHasPrivilege(
1057        current_task(), kIOClientPrivilegeAdministrator))
1058    {
1059        return kIOReturnNotPrivileged;
1060    }
1061
1062    return ( _provider ) ?
1063        _provider->setProperties( properties ) :
1064        kIOReturnNotReady;
1065}
1066