2 * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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.
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
20 * @APPLE_LICENSE_HEADER_END@
23 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
25 * IOEthernetInterface.cpp
28 * 8-Jan-1999 Joe Liu (jliu) created.
32 #include <IOKit/assert.h>
33 #include <IOKit/IOLib.h>
34 #include <libkern/c++/OSData.h>
35 #include <IOKit/network/IOEthernetInterface.h>
36 #include <IOKit/network/IOEthernetController.h>
37 #include <IOKit/network/IONetworkUserClient.h>
40 #include <sys/param.h>
41 #include <sys/errno.h>
42 #include <sys/socket.h>
44 #include <net/etherdefs.h>
45 #include <net/if_dl.h>
46 #include <net/if_types.h>
47 #include <sys/sockio.h>
48 #include <netinet/in_var.h>
49 #include <sys/malloc.h>
50 void arpwhohas(struct arpcom
* ac
, struct in_addr
* addr
);
53 //---------------------------------------------------------------------------
55 #define super IONetworkInterface
57 OSDefineMetaClassAndStructors( IOEthernetInterface
, IONetworkInterface
)
58 OSMetaClassDefineReservedUnused( IOEthernetInterface
, 0);
59 OSMetaClassDefineReservedUnused( IOEthernetInterface
, 1);
60 OSMetaClassDefineReservedUnused( IOEthernetInterface
, 2);
61 OSMetaClassDefineReservedUnused( IOEthernetInterface
, 3);
62 OSMetaClassDefineReservedUnused( IOEthernetInterface
, 4);
63 OSMetaClassDefineReservedUnused( IOEthernetInterface
, 5);
64 OSMetaClassDefineReservedUnused( IOEthernetInterface
, 6);
65 OSMetaClassDefineReservedUnused( IOEthernetInterface
, 7);
66 OSMetaClassDefineReservedUnused( IOEthernetInterface
, 8);
67 OSMetaClassDefineReservedUnused( IOEthernetInterface
, 9);
68 OSMetaClassDefineReservedUnused( IOEthernetInterface
, 10);
69 OSMetaClassDefineReservedUnused( IOEthernetInterface
, 11);
70 OSMetaClassDefineReservedUnused( IOEthernetInterface
, 12);
71 OSMetaClassDefineReservedUnused( IOEthernetInterface
, 13);
72 OSMetaClassDefineReservedUnused( IOEthernetInterface
, 14);
73 OSMetaClassDefineReservedUnused( IOEthernetInterface
, 15);
75 // The name prefix for all BSD Ethernet interfaces.
77 #define kIOEthernetInterfaceNamePrefix "en"
79 //---------------------------------------------------------------------------
83 #define DLOG(fmt, args...) IOLog(fmt, ## args)
85 #define DLOG(fmt, args...)
88 UInt32
IOEthernetInterface::getFilters(const OSDictionary
* dict
,
89 const OSSymbol
* group
)
94 assert( dict
&& group
);
96 if (( num
= (OSNumber
*) dict
->getObject(group
) ))
98 filters
= num
->unsigned32BitValue();
103 bool IOEthernetInterface::setFilters(OSDictionary
* dict
,
104 const OSSymbol
* group
,
110 assert( dict
&& group
);
112 num
= (OSNumber
*) dict
->getObject(group
);
115 if (( num
= OSNumber::withNumber(filters
, 32) ))
117 ret
= dict
->setObject(group
, num
);
123 num
->setValue(filters
);
129 #define GET_REQUIRED_FILTERS(g) getFilters(_requiredFilters, (g))
130 #define GET_ACTIVE_FILTERS(g) getFilters(_activeFilters, (g))
131 #define GET_SUPPORTED_FILTERS(g) getFilters(_supportedFilters, (g))
133 #define SET_REQUIRED_FILTERS(g, v) setFilters(_requiredFilters, (g), (v))
134 #define SET_ACTIVE_FILTERS(g, v) setFilters(_activeFilters, (g), (v))
136 //---------------------------------------------------------------------------
137 // Initialize an IOEthernetInterface instance. Instance variables are
138 // initialized, and an arpcom structure is allocated.
140 bool IOEthernetInterface::init(IONetworkController
* controller
)
142 // Allocate an arpcom structure, then call super::init().
143 // We expect our superclass to call getIfnet() during its init()
144 // method, so arpcom must be allocated before calling super::init().
146 if ( (_arpcom
= (struct arpcom
*) IOMalloc(sizeof(*_arpcom
))) == 0 )
148 DLOG("IOEthernetInterface: arpcom allocation failed\n");
152 // Pass the init() call to our superclass.
154 if ( super::init(controller
) == false )
157 // Add an IONetworkData with room to hold an IOEthernetStats structure.
158 // This class does not reference the data object created, and no harm
159 // is done if the data object is released or replaced.
161 IONetworkData
* data
= IONetworkData::withInternalBuffer(
163 sizeof(IOEthernetStats
));
166 addNetworkData(data
);
170 // Create and initialize the filter dictionaries.
172 _requiredFilters
= OSDictionary::withCapacity(4);
173 _activeFilters
= OSDictionary::withCapacity(4);
175 if ( (_requiredFilters
== 0) || (_activeFilters
== 0) )
178 _supportedFilters
= OSDynamicCast(OSDictionary
,
179 controller
->getProperty(kIOPacketFilters
));
180 if ( _supportedFilters
== 0 ) return false;
181 _supportedFilters
->retain();
183 // Controller's Unicast (directed) and Broadcast filters should always
184 // be enabled. Those bits should never be cleared.
186 if ( !SET_REQUIRED_FILTERS( gIONetworkFilterGroup
,
187 kIOPacketFilterUnicast
|
188 kIOPacketFilterBroadcast
)
189 || !SET_REQUIRED_FILTERS( gIOEthernetWakeOnLANFilterGroup
, 0 )
190 || !SET_ACTIVE_FILTERS( gIONetworkFilterGroup
, 0 )
191 || !SET_ACTIVE_FILTERS( gIOEthernetWakeOnLANFilterGroup
, 0 ) )
196 // Publish filter dictionaries to property table.
198 setProperty( kIORequiredPacketFilters
, _requiredFilters
);
199 setProperty( kIOActivePacketFilters
, _activeFilters
);
204 //---------------------------------------------------------------------------
205 // Initialize the given ifnet structure. The argument specified is a pointer
206 // to an ifnet structure obtained through getIfnet(). IOEthernetInterface
207 // will initialize this structure in a manner that is appropriate for most
208 // Ethernet interfaces, then call super::initIfnet() to allow the superclass
209 // to perform generic interface initialization.
211 // ifp: Pointer to the ifnet structure to be initialized.
213 // Returns true on success, false otherwise.
215 bool IOEthernetInterface::initIfnet(struct ifnet
* ifp
)
217 struct arpcom
* ac
= (struct arpcom
*) ifp
;
223 bzero(ac
, sizeof(*ac
));
225 // Set defaults suitable for Ethernet interfaces.
227 setInterfaceType( IFT_ETHER
);
228 setMaxTransferUnit( ETHERMTU
);
229 setMediaAddressLength( NUM_EN_ADDR_BYTES
);
230 setMediaHeaderLength( ETHERHDRSIZE
);
231 setFlags( IFF_BROADCAST
| IFF_SIMPLEX
| IFF_NOTRAILERS
);
235 return super::initIfnet(ifp
);
238 //---------------------------------------------------------------------------
239 // Free the IOEthernetInterface instance. The memory allocated
240 // for the arpcom structure is released.
242 void IOEthernetInterface::free()
246 IOFree(_arpcom
, sizeof(*_arpcom
));
250 if ( _requiredFilters
)
252 _requiredFilters
->release();
253 _requiredFilters
= 0;
256 if ( _activeFilters
)
258 _activeFilters
->release();
262 if ( _supportedFilters
)
264 _supportedFilters
->release();
265 _supportedFilters
= 0;
271 //---------------------------------------------------------------------------
272 // This method returns a pointer to an ifnet structure maintained
273 // by the family specific interface object. IOEthernetInterface
274 // allocates an arpcom structure in init(), and returns a pointer
275 // to that structure when this method is called.
277 // Returns a pointer to an ifnet structure.
279 struct ifnet
* IOEthernetInterface::getIfnet() const
281 return (&(_arpcom
->ac_if
));
284 //---------------------------------------------------------------------------
285 // The name of the interface advertised to the network layer
286 // is generated by concatenating the string returned by this method,
287 // and an unit number.
289 // Returns a pointer to a constant string "en". Thus Ethernet interfaces
290 // will be registered as en0, en1, etc.
292 const char * IOEthernetInterface::getNamePrefix() const
294 return kIOEthernetInterfaceNamePrefix
;
297 //---------------------------------------------------------------------------
298 // Prepare the 'Ethernet' controller after it has been opened. This is called
299 // by IONetworkInterface after a controller has accepted an open from this
300 // interface. IOEthernetInterface uses this method to inspect the controller,
301 // and to cache certain controller properties, such as its hardware address.
302 // This method is called with the arbitration lock held.
304 // controller: The controller object that was opened.
306 // Returns true on success, false otherwise
307 // (which will cause the controller to be closed).
309 bool IOEthernetInterface::controllerDidOpen(IONetworkController
* ctr
)
313 IOEthernetAddress
* addr
;
316 // Call the controllerDidOpen() in superclass first.
318 if ( (ctr
== 0) || (super::controllerDidOpen(ctr
) == false) )
321 // If the controller supports some form of multicast filtering,
322 // then set the ifnet IFF_MULTICAST flag.
324 if ( GET_SUPPORTED_FILTERS(gIONetworkFilterGroup
) &
325 (kIOPacketFilterMulticast
| kIOPacketFilterMulticastAll
) )
327 setFlags(IFF_MULTICAST
);
330 // Get the controller's MAC/Ethernet address.
332 addrData
= OSDynamicCast(OSData
, ctr
->getProperty(kIOMACAddress
));
333 if ( (addrData
== 0) || (addrData
->getLength() != NUM_EN_ADDR_BYTES
) )
335 DLOG("%s: kIOMACAddress property access error (len %d)\n",
336 getName(), addrData
? addrData
->getLength() : 0);
340 addr
= (IOEthernetAddress
*) addrData
->getBytesNoCopy();
342 #if 1 // Print the address
343 IOLog("%s: Ethernet address %02x:%02x:%02x:%02x:%02x:%02x\n",
353 // Copy the hardware address we obtained from the controller
354 // to the arpcom structure.
356 bcopy(addr
, _arpcom
->ac_enaddr
, NUM_EN_ADDR_BYTES
);
365 //---------------------------------------------------------------------------
366 // When a close from our last client is received, the interface will
367 // close the controller. But before the controller is closed, this method
368 // will be called by our superclass to perform any final cleanup. This
369 // method is called with the arbitration lock held.
371 // IOEthernetInterface will ensure that the controller is disabled.
373 // controller: The currently opened controller object.
375 void IOEthernetInterface::controllerWillClose(IONetworkController
* ctr
)
377 super::controllerWillClose(ctr
);
380 //---------------------------------------------------------------------------
381 // Handle ioctl commands originated from the network layer.
382 // Commands not handled by this method are passed to our superclass.
384 // Argument convention is:
386 // arg0 - (struct ifnet *)
389 // The commands handled by IOEthernetInterface are:
396 // Returns an error code defined in errno.h (BSD).
398 SInt32
IOEthernetInterface::performCommand( IONetworkController
* ctr
,
405 assert( arg0
== _arpcom
);
407 if ( ctr
== 0 ) return EINVAL
;
416 ret
= (int) ctr
->executeCommand(
418 (IONetworkController::Action
)
419 &IOEthernetInterface::performGatedCommand
,
422 (void *) cmd
, /* param1 */
428 // Unknown command, let our superclass deal with it.
429 ret
= super::performCommand(ctr
, cmd
, arg0
, arg1
);
436 //---------------------------------------------------------------------------
437 // Handle an ioctl command on the controller's workloop context.
439 int IOEthernetInterface::performGatedCommand(void * target
,
445 IOEthernetInterface
* self
= (IOEthernetInterface
*) target
;
446 IONetworkController
* ctr
= (IONetworkController
*) arg1_ctr
;
447 SInt ret
= EOPNOTSUPP
;
449 // Refuse to perform controller I/O if the controller is in a
450 // low-power state that makes it "unusable".
452 if ( self
->_controllerLostPower
) return EPWROFF
;
456 switch ( (UInt32
) arg2_cmd
)
459 ret
= self
->syncSIOCSIFADDR(ctr
);
463 ret
= self
->syncSIOCSIFFLAGS(ctr
);
467 ret
= self
->syncSIOCADDMULTI(ctr
);
471 ret
= self
->syncSIOCDELMULTI(ctr
);
480 //---------------------------------------------------------------------------
481 // enableController() is reponsible for calling the controller's enable()
482 // method and restoring the state of the controller. We assume that
483 // controllers can completely reset its state upon receiving a disable()
484 // method call. And when it is brought back up, the interface should
485 // assist in restoring the previous state of the Ethernet controller.
487 IOReturn
IOEthernetInterface::enableController(IONetworkController
* ctr
)
489 IOReturn ret
= kIOReturnSuccess
;
490 bool enabled
= false;
496 // Is controller already enabled? If so, exit and return success.
501 // Send the controller an enable command.
503 if ( (ret
= ctr
->enable((IOService
*) this)) != kIOReturnSuccess
)
504 break; // unable to enable the controller.
508 // Disable all Wake-On-LAN filters.
510 filters
= GET_ACTIVE_FILTERS(gIOEthernetWakeOnLANFilterGroup
);
512 for (UInt i
= 0; i
< (sizeof(filters
) * 8); i
++)
514 if ((1 << i
) & filters
)
516 disableFilter(ctr
, gIOEthernetWakeOnLANFilterGroup
,
521 // Restore current filter selection.
523 SET_ACTIVE_FILTERS(gIONetworkFilterGroup
, 0);
524 filters
= GET_REQUIRED_FILTERS(gIONetworkFilterGroup
);
526 for (UInt i
= 0; i
< (sizeof(filters
) * 8); i
++)
528 if ((1 << i
) & filters
)
530 if ( (ret
= enableFilter(ctr
, gIONetworkFilterGroup
,
532 != kIOReturnSuccess
)
536 if ( ret
!= kIOReturnSuccess
)
539 // Restore multicast filter settings.
541 syncSIOCADDMULTI(ctr
);
547 // Disable the controller if a serious error has occurred after the
548 // controller has been enabled.
550 if ( enabled
&& (ret
!= kIOReturnSuccess
) )
552 ctr
->disable((IOService
*) this);
558 //---------------------------------------------------------------------------
559 // Handles SIOCSIFFLAGS ioctl command for Ethernet interfaces. The network
560 // stack has changed the if_flags field in ifnet. Our job is to go
561 // through if_flags and see what has changed, and act accordingly.
563 // The fact that if_flags contains both generic and Ethernet specific bits
564 // means that we cannot move some of the default flag processing to the
567 int IOEthernetInterface::syncSIOCSIFFLAGS(IONetworkController
* ctr
)
569 UInt16 flags
= getFlags();
570 IOReturn ret
= kIOReturnSuccess
;
572 if ( ( ((flags
& IFF_UP
) == 0) || _controllerLostPower
) &&
573 ( flags
& IFF_RUNNING
) )
575 // If interface is marked down and it is currently running,
578 ctr
->disable((IOService
*) this);
579 flags
&= ~IFF_RUNNING
;
582 else if ( ( flags
& IFF_UP
) &&
583 ( _controllerLostPower
== false ) &&
584 ((flags
& IFF_RUNNING
) == 0) )
586 // If interface is marked up and it is currently stopped,
589 if ( (ret
= enableController(ctr
)) == kIOReturnSuccess
)
590 flags
|= IFF_RUNNING
;
593 if ( flags
& IFF_RUNNING
)
597 // We don't expect multiple flags to be changed for a given
598 // SIOCSIFFLAGS call.
602 rc
= (flags
& IFF_PROMISC
) ?
603 enableFilter(ctr
, gIONetworkFilterGroup
,
604 kIOPacketFilterPromiscuous
) :
605 disableFilter(ctr
, gIONetworkFilterGroup
,
606 kIOPacketFilterPromiscuous
);
608 if (ret
== kIOReturnSuccess
) ret
= rc
;
610 // Multicast-All mode
612 rc
= (flags
& IFF_ALLMULTI
) ?
613 enableFilter(ctr
, gIONetworkFilterGroup
,
614 kIOPacketFilterMulticastAll
) :
615 disableFilter(ctr
, gIONetworkFilterGroup
,
616 kIOPacketFilterMulticastAll
);
618 if (ret
== kIOReturnSuccess
) ret
= rc
;
621 // Update the flags field to pick up any modifications. Also update the
622 // property table to reflect any flag changes.
624 setFlags(flags
, ~flags
);
626 return errnoFromReturn(ret
);
629 //---------------------------------------------------------------------------
630 // Handles SIOCSIFADDR ioctl.
632 SInt
IOEthernetInterface::syncSIOCSIFADDR(IONetworkController
* ctr
)
634 IOReturn ret
= kIOReturnSuccess
;
636 // Interface is implicitly brought up by an SIOCSIFADDR ioctl.
640 if ( (getFlags() & IFF_RUNNING
) == 0 )
642 if ( (ret
= enableController(ctr
)) == kIOReturnSuccess
)
643 setFlags(IFF_RUNNING
);
646 return errnoFromReturn(ret
);
649 //---------------------------------------------------------------------------
650 // Handle SIOCADDMULTI ioctl command.
652 SInt
IOEthernetInterface::syncSIOCADDMULTI(IONetworkController
* ctr
)
656 // Make sure multicast filter is active.
658 ret
= enableFilter(ctr
, gIONetworkFilterGroup
, kIOPacketFilterMulticast
);
660 if ( ret
== kIOReturnSuccess
)
662 // Load multicast addresses only if the filter was activated.
664 ret
= setupMulticastFilter(ctr
);
666 // If the list is now empty, then deactivate the multicast filter.
668 if ( _mcAddrCount
== 0 )
670 IOReturn dret
= disableFilter(ctr
, gIONetworkFilterGroup
,
671 kIOPacketFilterMulticast
);
673 if (ret
== kIOReturnSuccess
) ret
= dret
;
677 return errnoFromReturn(ret
);
680 //---------------------------------------------------------------------------
681 // Handle SIOCDELMULTI ioctl command.
683 SInt
IOEthernetInterface::syncSIOCDELMULTI(IONetworkController
* ctr
)
685 return syncSIOCADDMULTI(ctr
);
688 //---------------------------------------------------------------------------
689 // Enable a packet filter.
692 IOEthernetInterface::enableFilter(IONetworkController
* ctr
,
693 const OSSymbol
* group
,
695 IOOptionBits options
= 0)
701 // If the controller does not support the packet filter,
702 // there's no need to proceed.
704 if (( GET_SUPPORTED_FILTERS(group
) & filter
) == 0)
705 return kIOReturnUnsupported
;
708 // Add specified filter to the set of required filters.
710 reqFilters
= GET_REQUIRED_FILTERS(group
) | filter
;
711 SET_REQUIRED_FILTERS(group
, reqFilters
);
713 // Abort if no changes are needed.
715 ret
= kIOReturnSuccess
;
717 actFilters
= GET_ACTIVE_FILTERS(group
);
719 if ( (( actFilters
^ reqFilters
) & filter
) == 0 )
722 // Send a command to the controller driver.
724 ret
= ctr
->enablePacketFilter(group
, filter
, actFilters
, options
);
726 if ( ret
== kIOReturnSuccess
)
728 SET_ACTIVE_FILTERS(group
, actFilters
| filter
);
736 //---------------------------------------------------------------------------
737 // Disable a packet filter.
740 IOEthernetInterface::disableFilter(IONetworkController
* ctr
,
741 const OSSymbol
* group
,
743 IOOptionBits options
= 0)
750 // Remove specified filter from the set of required filters.
752 reqFilters
= GET_REQUIRED_FILTERS(group
) & ~filter
;
753 SET_REQUIRED_FILTERS(group
, reqFilters
);
755 // Abort if no changes are needed.
757 ret
= kIOReturnSuccess
;
759 actFilters
= GET_ACTIVE_FILTERS(group
);
761 if ( (( actFilters
^ reqFilters
) & filter
) == 0 )
764 // Send a command to the controller driver.
766 ret
= ctr
->disablePacketFilter(group
, filter
, actFilters
, options
);
768 if ( ret
== kIOReturnSuccess
)
770 SET_ACTIVE_FILTERS(group
, actFilters
& ~filter
);
778 //---------------------------------------------------------------------------
779 // Cache the list of multicast addresses and send a command to the
780 // controller to update the multicast list.
783 IOEthernetInterface::setupMulticastFilter(IONetworkController
* ctr
)
785 void * multiAddrs
= 0;
788 struct ifnet
* ifp
= (struct ifnet
*) _arpcom
;
789 struct ifmultiaddr
* ifma
;
790 IOReturn ret
= kIOReturnSuccess
;
795 // Update the multicast addresses count ivar.
798 for (ifma
= ifp
->if_multiaddrs
.lh_first
;
800 ifma
= ifma
->ifma_link
.le_next
)
802 if ((ifma
->ifma_addr
->sa_family
== AF_UNSPEC
) ||
803 (ifma
->ifma_addr
->sa_family
== AF_LINK
))
806 _mcAddrCount
= mcount
;
812 mcData
= OSData::withCapacity(mcount
* NUM_EN_ADDR_BYTES
);
815 DLOG("%s: no memory for multicast address list\n", getName());
816 return kIOReturnNoMemory
;
819 // Loop through the linked multicast structures and write the
820 // address to the OSData.
822 for (ifma
= ifp
->if_multiaddrs
.lh_first
;
824 ifma
= ifma
->ifma_link
.le_next
)
826 if (ifma
->ifma_addr
->sa_family
== AF_UNSPEC
)
827 addrp
= &ifma
->ifma_addr
->sa_data
[0];
829 if (ifma
->ifma_addr
->sa_family
== AF_LINK
)
830 addrp
= LLADDR((struct sockaddr_dl
*) ifma
->ifma_addr
);
834 ok
= mcData
->appendBytes((const void *) addrp
, NUM_EN_ADDR_BYTES
);
838 multiAddrs
= (void *) mcData
->getBytesNoCopy();
842 // Issue a controller command to setup the multicast filter.
844 ret
= ((IOEthernetController
*)ctr
)->setMulticastList(
845 (IOEthernetAddress
*) multiAddrs
,
849 if (ret
== kIOReturnSuccess
)
850 setProperty(kIOMulticastAddressList
, mcData
);
855 removeProperty(kIOMulticastAddressList
);
861 //---------------------------------------------------------------------------
862 // Power management support.
864 // Handlers called, with the controller's gate closed, in response to a
865 // controller power state change.
868 IOEthernetInterface::controllerWillChangePowerState(
869 IONetworkController
* ctr
,
870 IOPMPowerFlags flags
,
872 IOService
* policyMaker
)
874 if ( ( (flags
& IOPMDeviceUsable
) == 0) &&
875 ( _controllerLostPower
== false ) )
877 _controllerLostPower
= true;
879 // Enable Magic Packet if supported.
881 if ( GET_SUPPORTED_FILTERS(gIOEthernetWakeOnLANFilterGroup
) &
882 kIOEthernetWakeOnMagicPacket
)
884 enableFilter(ctr
, gIOEthernetWakeOnLANFilterGroup
,
885 kIOEthernetWakeOnMagicPacket
);
888 // Set _controllerLostPower, then call the SIOCSIFFLAGS handler to
889 // disable the controller, then mark the interface as Not Running.
891 syncSIOCSIFFLAGS(ctr
);
894 return super::controllerWillChangePowerState( ctr
, flags
,
900 IOEthernetInterface::controllerDidChangePowerState(
901 IONetworkController
* ctr
,
902 IOPMPowerFlags flags
,
904 IOService
* policyMaker
)
906 IOReturn ret
= super::controllerDidChangePowerState( ctr
, flags
,
910 if ( ( flags
& IOPMDeviceUsable
) && ( _controllerLostPower
== true ) )
912 _controllerLostPower
= false;
914 // Clear _controllerLostPower, then call the SIOCSIFFLAGS handler to
915 // perhaps enable the controller, restore all Ethernet controller
916 // state, then mark the interface as Running.
918 syncSIOCSIFFLAGS(ctr
);