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 * IONetworkController.cpp
28 * 9-Dec-1998 Joe Liu (jliu) created.
32 #include <IOKit/assert.h>
33 #include <IOKit/IOCommandGate.h>
34 #include <IOKit/network/IONetworkController.h>
35 #include <IOKit/network/IOOutputQueue.h>
36 #include <IOKit/network/IONetworkMedium.h>
38 // IONetworkController (and its subclasses) needs to know about mbufs,
39 // but it shall have no further dependencies on BSD networking.
42 #include <sys/param.h> // mbuf limits defined here.
44 #include <sys/kdebug.h>
46 // osfmk/kern/spl.h - Need splimp for mbuf macros.
48 typedef unsigned spl_t
;
49 extern spl_t (splimp
)(void);
52 //-------------------------------------------------------------------------
55 #define super IOService
57 OSDefineMetaClassAndAbstractStructors( IONetworkController
, IOService
)
58 OSMetaClassDefineReservedUnused( IONetworkController
, 0);
59 OSMetaClassDefineReservedUnused( IONetworkController
, 1);
60 OSMetaClassDefineReservedUnused( IONetworkController
, 2);
61 OSMetaClassDefineReservedUnused( IONetworkController
, 3);
62 OSMetaClassDefineReservedUnused( IONetworkController
, 4);
63 OSMetaClassDefineReservedUnused( IONetworkController
, 5);
64 OSMetaClassDefineReservedUnused( IONetworkController
, 6);
65 OSMetaClassDefineReservedUnused( IONetworkController
, 7);
66 OSMetaClassDefineReservedUnused( IONetworkController
, 8);
67 OSMetaClassDefineReservedUnused( IONetworkController
, 9);
68 OSMetaClassDefineReservedUnused( IONetworkController
, 10);
69 OSMetaClassDefineReservedUnused( IONetworkController
, 11);
70 OSMetaClassDefineReservedUnused( IONetworkController
, 12);
71 OSMetaClassDefineReservedUnused( IONetworkController
, 13);
72 OSMetaClassDefineReservedUnused( IONetworkController
, 14);
73 OSMetaClassDefineReservedUnused( IONetworkController
, 15);
74 OSMetaClassDefineReservedUnused( IONetworkController
, 16);
75 OSMetaClassDefineReservedUnused( IONetworkController
, 17);
76 OSMetaClassDefineReservedUnused( IONetworkController
, 18);
77 OSMetaClassDefineReservedUnused( IONetworkController
, 19);
78 OSMetaClassDefineReservedUnused( IONetworkController
, 20);
79 OSMetaClassDefineReservedUnused( IONetworkController
, 21);
80 OSMetaClassDefineReservedUnused( IONetworkController
, 22);
81 OSMetaClassDefineReservedUnused( IONetworkController
, 23);
82 OSMetaClassDefineReservedUnused( IONetworkController
, 24);
83 OSMetaClassDefineReservedUnused( IONetworkController
, 25);
84 OSMetaClassDefineReservedUnused( IONetworkController
, 26);
85 OSMetaClassDefineReservedUnused( IONetworkController
, 27);
86 OSMetaClassDefineReservedUnused( IONetworkController
, 28);
87 OSMetaClassDefineReservedUnused( IONetworkController
, 29);
88 OSMetaClassDefineReservedUnused( IONetworkController
, 30);
89 OSMetaClassDefineReservedUnused( IONetworkController
, 31);
91 static bool isPowerOfTwo(UInt32 num
)
93 return (num
== (num
& ~(num
- 1)));
96 #define MEDIUM_LOCK IOTakeLock(_mediumLock);
97 #define MEDIUM_UNLOCK IOUnlock(_mediumLock);
100 #define DLOG(fmt, args...) IOLog(fmt, ## args)
102 #define DLOG(fmt, args...)
105 // OSSymbols for frequently used keys.
107 static const OSSymbol
* gIOActiveMediumKey
;
108 static const OSSymbol
* gIOCurrentMediumKey
;
109 static const OSSymbol
* gIODefaultMediumKey
;
110 static const OSSymbol
* gIONullMediumName
;
111 static const OSSymbol
* gIOLinkDataKey
;
112 static const OSData
* gIONullLinkData
;
116 const OSSymbol
* gIONetworkFilterGroup
;
117 const OSSymbol
* gIOEthernetWakeOnLANFilterGroup
;
119 // Constants for handleCommand().
127 //---------------------------------------------------------------------------
128 // IONetworkController class initializer. Create often used OSSymbol objects
129 // that are used as keys. This method is called explicitly by a line in
130 // IOStartIOKit.cpp and not by the OSDefineMetaClassAndInit() mechanism, to
131 // ensure that this method is called after the OSSymbol class is initialized.
133 void IONetworkController::initialize()
135 gIOActiveMediumKey
= OSSymbol::withCStringNoCopy(kIOActiveMedium
);
136 gIOCurrentMediumKey
= OSSymbol::withCStringNoCopy(kIOSelectedMedium
);
137 gIODefaultMediumKey
= OSSymbol::withCStringNoCopy(kIODefaultMedium
);
138 gIONullMediumName
= OSSymbol::withCStringNoCopy("");
139 gIOLinkDataKey
= OSSymbol::withCStringNoCopy(kIOLinkData
);
140 gIONullLinkData
= OSData::withCapacity(0);
141 gIONetworkFilterGroup
142 = OSSymbol::withCStringNoCopy(kIONetworkFilterGroup
);
144 gIOEthernetWakeOnLANFilterGroup
145 = OSSymbol::withCStringNoCopy("IOEthernetWakeOnLANFilterGroup");
147 assert( gIOEthernetWakeOnLANFilterGroup
);
149 assert(gIOActiveMediumKey
&&
150 gIOCurrentMediumKey
&&
151 gIODefaultMediumKey
&&
155 gIONetworkFilterGroup
);
157 IONetworkData::initialize();
160 //---------------------------------------------------------------------------
161 // Initialize the IONetworkController instance. Instance variables are
162 // set to their default values, then super::init() is called.
164 // properties: A dictionary object containing a property table
165 // associated with this instance.
167 // Returns true on success, false otherwise.
169 bool IONetworkController::init(OSDictionary
* properties
)
171 // Initialize instance variables.
179 _propertiesPublished
= false;
181 _lastLinkData
= gIONullLinkData
;
182 _lastActiveMediumName
= gIONullMediumName
;
183 _lastCurrentMediumName
= gIONullMediumName
;
185 if (super::init(properties
) == false)
187 DLOG("IONetworkController: super::init() failed\n");
194 //-------------------------------------------------------------------------
195 // Called after the controller driver was successfully matched to a provider,
196 // to start running. IONetworkController will allocate resources and gather
197 // controller properties. No I/O will be performed until the subclass
198 // attaches a client object from its start() method. Subclasses must override
199 // this method and call super::start() at the beginning of its implementation.
200 // Then check the return value to make sure the superclass was started
201 // successfully before continuing. The resources allocated by
202 // IONetworkController include:
204 // - An IOCommandGate object to handle client commands.
205 // - An OSSet to track our clients.
206 // - An optional IOOutputQueue object for output queueing.
208 // Tasks that are usually performed by a typical network driver in start
211 // - Resource allocation
212 // - Hardware initialization
213 // - Allocation of IOEventSources and attaching them to an IOWorkLoop object.
214 // - Publishing a medium dictionary.
215 // - And finally, attaching an interface object after the driver is ready
216 // to handle client requests.
218 // provider: The provider that the controller was matched
219 // (and attached) to.
221 // Returns true on success, false otherwise.
223 bool IONetworkController::start(IOService
* provider
)
225 // Most drivers will probably want to wait for BSD due to their
226 // dependency on mbufs, which is not available until BSD is
229 if ((getFeatures() & kIONetworkFeatureNoBSDWait
) == 0)
230 waitForService(resourceMatching( "IOBSD" ));
232 // Start our superclass.
234 if (!super::start(provider
))
237 // Create an OSSet to store our clients.
239 _clientSet
= OSSet::withCapacity(2);
243 _clientSetIter
= OSCollectionIterator::withCollection(_clientSet
);
244 if (_clientSetIter
== 0)
247 // Initialize link status properties.
249 if (!setProperty(gIOActiveMediumKey
, (OSSymbol
*) gIONullMediumName
) ||
250 !setProperty(gIOCurrentMediumKey
, (OSSymbol
*) gIONullMediumName
))
253 _linkStatus
= OSNumber::withNumber((UInt64
) 0, 32);
254 if (!_linkStatus
|| !setProperty(kIOLinkStatus
, _linkStatus
))
259 _linkSpeed
= OSNumber::withNumber((UInt64
) 0, 64);
260 if (!_linkSpeed
|| !setProperty(kIOLinkSpeed
, _linkSpeed
))
265 // Allocate a mutex lock to serialize access to the medium dictionary.
267 _mediumLock
= IOLockAlloc();
270 IOLockInitWithState(_mediumLock
, kIOLockStateUnlocked
);
272 // Tell the driver that now is the time to create a work loop
273 // (if it wants one).
275 if ( createWorkLoop() != true )
277 DLOG("%s: createWorkLoop() error\n", getName());
283 _workLoop
= getWorkLoop();
284 if ( _workLoop
== 0 )
286 DLOG("%s: IOWorkLoop allocation failed\n", getName());
291 // Create a 'private' IOCommandGate object and attach it to
292 // our workloop created above. This is used by executeCommand().
294 _cmdGate
= IOCommandGate::commandGate(this);
296 (_workLoop
->addEventSource(_cmdGate
) != kIOReturnSuccess
))
298 DLOG("%s: IOCommandGate initialization failed\n", getName());
302 // Try to allocate an IOOutputQueue instance. This is optional and
303 // _outputQueue may be 0.
305 _outputQueue
= createOutputQueue();
307 // Query the controller's mbuf buffer restrictions.
309 IOPacketBufferConstraints constraints
;
310 getPacketBufferConstraints(&constraints
);
311 if ((constraints
.alignStart
> kIOPacketBufferAlign32
) ||
312 (constraints
.alignLength
> kIOPacketBufferAlign32
) ||
313 !isPowerOfTwo(constraints
.alignStart
) ||
314 !isPowerOfTwo(constraints
.alignLength
))
316 IOLog("%s: Invalid alignment: start:%ld, length:%ld\n",
318 constraints
.alignStart
,
319 constraints
.alignLength
);
323 // Make it easier to satisfy both constraints.
325 if (constraints
.alignStart
< constraints
.alignLength
)
326 constraints
.alignStart
= constraints
.alignLength
;
328 // Convert to alignment masks.
330 _alignStart
= (constraints
.alignStart
) ? constraints
.alignStart
- 1 : 0;
331 _alignLength
= (constraints
.alignLength
) ? constraints
.alignLength
- 1 : 0;
332 _alignPadding
= _alignStart
+ _alignLength
;
334 // Called by a policy-maker to initialize itself for power-management.
335 // IONetworkController is the policy-maker.
339 // Called by a policy-maker on its nub, to be attached into the
340 // power management hierarchy.
342 provider
->joinPMtree(this);
347 //---------------------------------------------------------------------------
348 // The opposite of start(). The controller has been instructed to stop running.
349 // This method should release resources and undo actions performed by start().
350 // Subclasses must override this method and call super::stop() at the end of
351 // its implementation.
353 // provider: The provider that the controller was matched
354 // (and attached) to.
356 void IONetworkController::stop(IOService
* provider
)
358 // Called by a policy-maker to resign its responsibilities as the
363 super::stop(provider
);
366 //---------------------------------------------------------------------------
367 // Power-management hooks for subclasses.
369 IOReturn
IONetworkController::registerWithPolicyMaker(IOService
* policyMaker
)
371 // An opportunity for subclasses to call
372 // policyMaker->registerPowerDriver(...)
373 // and other future PM requirements.
374 return kIOReturnUnsupported
;
377 //---------------------------------------------------------------------------
378 // Catch calls to createWorkLoop() for drivers that choose not implement this
381 bool IONetworkController::createWorkLoop()
386 //---------------------------------------------------------------------------
387 // Get the IOCommandGate object created by IONetworkController.
388 // An IOCommandGate is created and attached to the internal workloop by
389 // the start() method.
390 // This IOCommandGate object is used to handle client commands sent to
391 // executeCommand(). Subclasses that need an IOCommandGate should use the
392 // object returned by this method, rather than creating
393 // a new instance. See IOCommandGate.
395 // Returns the IOCommandGate object created by IONetworkController.
397 IOCommandGate
* IONetworkController::getCommandGate() const
402 //---------------------------------------------------------------------------
403 // Get the address of the method designated to handle output packets.
405 // Returns the address of the outputPacket() method.
407 IOOutputAction
IONetworkController::getOutputHandler() const
409 return (IOOutputAction
) &IONetworkController::outputPacket
;
412 //---------------------------------------------------------------------------
413 // Create a new interface object and attach it to the controller.
414 // The createInterface() method is called to perform the allocation and
415 // initialization, followed by a call to configureInterface() to configure
416 // the interface. Subclasses can override those methods to customize the
417 // interface client attached. Drivers will usually call this method from
418 // their start() implementation, after they are ready to process client
421 // interfaceP: If successful (return value is true), then the interface
422 // object will be written to the handle provided.
424 // doRegister: If true, then registerService() is called to register
425 // the interface, which will trigger the matching process,
426 // and cause the interface to become registered with the network
427 // layer. For drivers that wish to delay the registration, and
428 // hold off servicing requests and data packets from the network
429 // layer, set doRegister to false and call registerService() on
430 // the interface object when the controller becomes ready.
431 // This allows the driver to attach an interface but without
432 // making it available to the rest of the system.
434 // Returns true on success, false otherwise.
437 IONetworkController::attachInterface(IONetworkInterface
** interfaceP
,
438 bool doRegister
= true)
440 IONetworkInterface
* netif
;
444 // We delay some initialization until the first time that
445 // attachInterface() is called by the subclass.
447 if (executeCommand(this, &IONetworkController::handleCommand
,
448 this, (void *) kCommandPrepare
) != kIOReturnSuccess
)
454 // Allocate a concrete subclass of IONetworkInterface
455 // by calling createInterface().
457 netif
= createInterface();
461 // Configure the interface instance by calling
462 // configureInterface(), then attach it as our client.
464 if ( !configureInterface(netif
) || !netif
->attach(this) )
472 // Register the interface nub. Spawns a matching thread.
475 netif
->registerService();
477 return true; // success
481 return false; // failure
484 //---------------------------------------------------------------------------
485 // Detach the interface object. This method will check that the object
486 // provided is indeed an IONetworkInterface, and if so its terminate()
487 // method is called. Note that a registered interface object will close
488 // and detach from its controller only after the network layer has removed
489 // all references to the data structures exposed by the interface.
491 // interface: An interface object to be detached.
492 // sync: If true, the interface is terminated synchronously.
493 // Note that this may cause detachInterface() to block
494 // for an indeterminate of time.
497 IONetworkController::detachInterface(IONetworkInterface
* interface
,
500 IOOptionBits options
= kIOServiceRequired
;
502 if (OSDynamicCast(IONetworkInterface
, interface
) == 0)
506 options
|= kIOServiceSynchronous
;
508 interface
->terminate(options
);
511 //---------------------------------------------------------------------------
512 // This method is called by attachInterface() or attachDebuggerClient() on
513 // the workloop context, to prepare the controller before attaching the client
514 // object. This method will call publishProperties() to publish controller
515 // capabilities and properties that may be used by client objects. However,
516 // publishProperties() will be called only once, even if prepare() is called
519 // kIOReturnSuccess on success, or an error code otherwise.
520 // Returning an error will cause the client attach to fail.
522 IOReturn
IONetworkController::prepare()
524 IOReturn ret
= kIOReturnSuccess
;
526 if ( _propertiesPublished
== false )
528 if ( publishProperties() == true )
530 _propertiesPublished
= true;
534 registerWithPolicyMaker( this );
539 ret
= kIOReturnError
;
546 //---------------------------------------------------------------------------
547 // Handle a client open on the controller object. IOService calls this method
548 // with the arbitration lock held. Subclasses are not expected to override
551 // client: The client that is attempting to open the controller.
552 // options: See IOService.
553 // argument: See IOService.
555 // Returns true to accept the client open, false to refuse it.
557 bool IONetworkController::handleOpen(IOService
* client
,
558 IOOptionBits options
,
562 return _clientSet
->setObject(client
);
565 //---------------------------------------------------------------------------
566 // Handle a close from one of the client objects. IOService calls this method
567 // with the arbitration lock held. Subclasses are not expected to override this
570 // client: The client that is closing the controller.
571 // options: See IOService.
573 void IONetworkController::handleClose(IOService
* client
, IOOptionBits options
)
575 _clientSet
->removeObject(client
);
578 //---------------------------------------------------------------------------
579 // This method is always called by IOService with the arbitration lock held.
580 // Subclasses should not override this method.
582 // Returns true if the specified client, or any client if none is
583 // specified, presently has an open on this object.
585 bool IONetworkController::handleIsOpen(const IOService
* client
) const
588 return _clientSet
->containsObject(client
);
590 return (_clientSet
->getCount() > 0);
593 //---------------------------------------------------------------------------
594 // Free the IONetworkController instance by releasing all allocated resources,
595 // then call super::free().
597 void IONetworkController::free()
599 #define RELEASE(x) do { if (x) { (x)->release(); (x) = 0; } } while (0)
601 // We should have no clients at this point. If we do,
602 // then something is very wrong! It means that a client
603 // has an open on us, and yet we are being freed.
605 if (_clientSet
) assert(_clientSet
->getCount() == 0);
607 RELEASE( _outputQueue
);
609 RELEASE( _workLoop
);
610 RELEASE( _clientSetIter
);
611 RELEASE( _clientSet
);
612 RELEASE( _linkStatus
);
613 RELEASE( _linkSpeed
);
615 if (_mediumLock
) { IOLockFree(_mediumLock
); _mediumLock
= 0; }
620 //---------------------------------------------------------------------------
621 // Handle an enable request from a client.
623 IOReturn
IONetworkController::enable(IOService
* client
)
625 if (OSDynamicCast(IONetworkInterface
, client
))
626 return enable((IONetworkInterface
*) client
);
628 if (OSDynamicCast(IOKernelDebugger
, client
))
629 return enable((IOKernelDebugger
*) client
);
631 IOLog("%s::%s Unknown client type\n", getName(), __FUNCTION__
);
632 return kIOReturnBadArgument
;
635 //---------------------------------------------------------------------------
636 // Handle a disable request from a client.
638 IOReturn
IONetworkController::disable(IOService
* client
)
640 if (OSDynamicCast(IONetworkInterface
, client
))
641 return disable((IONetworkInterface
*) client
);
643 if (OSDynamicCast(IOKernelDebugger
, client
))
644 return disable((IOKernelDebugger
*) client
);
646 IOLog("%s::%s Unknown client type\n", getName(), __FUNCTION__
);
647 return kIOReturnBadArgument
;
650 //---------------------------------------------------------------------------
651 // Called by an interface client to enable the controller.
653 IOReturn
IONetworkController::enable(IONetworkInterface
* interface
)
655 IOLog("IONetworkController::%s\n", __FUNCTION__
);
656 return kIOReturnUnsupported
;
659 //---------------------------------------------------------------------------
660 // Called by an interface client to disable the controller.
662 IOReturn
IONetworkController::disable(IONetworkInterface
* interface
)
664 IOLog("IONetworkController::%s\n", __FUNCTION__
);
665 return kIOReturnUnsupported
;
668 //---------------------------------------------------------------------------
669 // Discover and publish controller capabilities to the property table.
670 // This method is called by prepare() on the workloop context.
672 // Returns true if all capabilities were discovered and published
673 // successfully, false otherwise. Returning false will prevent client
674 // objects from attaching to the controller since a vital property that
675 // a client requires may be missing.
677 bool IONetworkController::publishProperties()
680 const OSString
* string
;
682 OSDictionary
* dict
= 0;
683 OSNumber
* numObj
= 0;
688 string
= newVendorString();
690 status
= setProperty(kIOVendor
, (OSObject
*) string
);
692 if (status
!= true) break;
695 string
= newModelString();
697 status
= setProperty(kIOModel
, (OSObject
*) string
);
699 if (status
!= true) break;
702 string
= newRevisionString();
704 status
= setProperty(kIORevision
, (OSObject
*) string
);
706 if (status
!= true) break;
709 // Publish controller feature flags.
712 if ( !setProperty(kIOFeatures
, num
, sizeof(num
) * 8) )
715 // Publish max/min packet size.
717 if ( ( getMaxPacketSize(&num
) != kIOReturnSuccess
) ||
718 ( !setProperty(kIOMaxPacketSize
, num
, sizeof(num
) * 8) ) )
721 if ( ( getMinPacketSize(&num
) != kIOReturnSuccess
) ||
722 ( !setProperty(kIOMinPacketSize
, num
, sizeof(num
) * 8) ) )
725 // Publish supported packet filters.
727 if (getPacketFilters(gIONetworkFilterGroup
, &num
) != kIOReturnSuccess
)
730 dict
= OSDictionary::withCapacity(4);
731 numObj
= OSNumber::withNumber(num
, sizeof(num
) * 8);
732 if ( (dict
== 0) || (numObj
== 0) ) break;
734 if ( !dict
->setObject(gIONetworkFilterGroup
, numObj
) ||
735 !setProperty(kIOPacketFilters
, dict
) )
743 DLOG("IONetworkController::%s error\n", __FUNCTION__
);
745 if ( dict
) dict
->release();
746 if ( numObj
) numObj
->release();
751 //---------------------------------------------------------------------------
752 // Send a network event to all attached interface objects.
754 bool IONetworkController::_broadcastEvent(UInt32 type
, void * data
= 0)
756 IONetworkInterface
* netif
;
758 lockForArbitration(); // locks open/close/state changes.
760 if (_clientSet
->getCount())
762 _clientSetIter
->reset();
764 while ((netif
= (IONetworkInterface
*)_clientSetIter
->getNextObject()))
766 if (OSDynamicCast(IONetworkInterface
, netif
) == 0)
767 continue; // only send events to IONetworkInterface objects.
768 netif
->inputEvent(type
, data
);
772 unlockForArbitration();
777 //---------------------------------------------------------------------------
778 // A client request for the controller to change to a new MTU size.
780 IOReturn
IONetworkController::setMaxPacketSize(UInt32 maxSize
)
782 return kIOReturnUnsupported
;
785 //---------------------------------------------------------------------------
786 // Transmit a packet mbuf.
788 UInt32
IONetworkController::outputPacket(struct mbuf
* m
, void * param
)
790 // The implementation here is simply a sink-hole, all packets are
793 if (m
) freePacket(m
);
797 //---------------------------------------------------------------------------
798 // Report features supported by the controller and/or driver.
800 UInt32
IONetworkController::getFeatures() const
805 //---------------------------------------------------------------------------
806 // Create default description strings.
808 const OSString
* IONetworkController::newVendorString() const
813 const OSString
* IONetworkController::newModelString() const
818 const OSString
* IONetworkController::newRevisionString() const
823 //---------------------------------------------------------------------------
824 // Encode a client command received by executeCommand().
829 IONetworkController::Action action
;
837 //---------------------------------------------------------------------------
838 // Get the command client object.
840 OSObject
* IONetworkController::getCommandClient() const
842 return ( _workLoop
->inGate() ? _cmdClient
: 0 );
845 //---------------------------------------------------------------------------
846 // Configure an interface object created through createInterface().
847 // IONetworkController will register its output handler with the interface
848 // object provided. After the interface is registered and opened by its
849 // client, it will refuse requests to change its properties through its
850 // public methods. Since this method is called before the interface object
851 // is published and registered, subclasses of IONetworkController may override
852 // this method to configure and customize the interface object.
854 // interface: The interface object to be configured.
856 // Returns true if configuration was successful, false otherwise (this
857 // will cause attachInterface() to fail).
859 bool IONetworkController::configureInterface(IONetworkInterface
* interface
)
861 IOOutputAction handler
;
864 IONetworkData
* stats
;
866 if (!OSDynamicCast(IONetworkInterface
, interface
))
869 IOOutputQueue
* outQueue
= getOutputQueue();
871 // Must register an output handler with the interface object.
872 // The interface will send output packets, to its registered
873 // output handler. If we allocated an output queue, then we
874 // register the queue as the output handler, otherwise, we
875 // become the output handler.
880 handler
= outQueue
->getOutputHandler();
882 stats
= outQueue
->getStatisticsData();
883 interface
->addNetworkData(stats
);
888 handler
= getOutputHandler();
890 ret
= interface
->registerOutputHandler(target
, handler
);
895 //---------------------------------------------------------------------------
896 // Called by start() to create an optional IOOutputQueue instance to handle
897 // output queueing. The default implementation will always return 0, hence
898 // no output queue will be created. A driver may override this method and
899 // return a subclass of IOOutputQueue. IONetworkController will keep a
900 // reference to the queue created, and will release the object when
901 // IONetworkController is freed. Also see getOutputQueue().
903 // Returns a newly allocated and initialized IOOutputQueue instance.
905 IOOutputQueue
* IONetworkController::createOutputQueue()
910 //---------------------------------------------------------------------------
911 // Return the output queue allocated though createOutputQueue().
913 IOOutputQueue
* IONetworkController::getOutputQueue() const
918 //---------------------------------------------------------------------------
919 // Called by start() to obtain the constraints on the memory buffer
920 // associated with each mbuf allocated through allocatePacket().
921 // Drivers can override this method to specify their buffer constraints
922 // imposed by their bus master hardware. Note that outbound packets,
923 // those that originate from the network stack, are not subject
924 // to the constraints reported here.
926 // constraintsP: A pointer to an IOPacketBufferConstraints structure
927 // that that this method is expected to initialize.
928 // See IOPacketBufferConstraints structure definition.
930 void IONetworkController::getPacketBufferConstraints(
931 IOPacketBufferConstraints
* constraintsP
) const
933 assert(constraintsP
);
934 constraintsP
->alignStart
= kIOPacketBufferAlign1
;
935 constraintsP
->alignLength
= kIOPacketBufferAlign1
;
938 //---------------------------------------------------------------------------
939 // Allocates a mbuf chain. Each mbuf in the chain is aligned according to
940 // the constraints from IONetworkController::getPacketBufferConstraints().
941 // The last mbuf in the chain will be guaranteed to be length aligned if
942 // the 'size' argument is a multiple of the length alignment.
944 // The m->m_len and m->pkthdr.len fields are updated by this function.
945 // This allows the driver to pass the mbuf chain obtained through this
946 // function to the IOMbufMemoryCursor object directly.
948 // If (size + alignments) is smaller than MCLBYTES, then this function
949 // will always return a single mbuf header or cluster.
951 // The allocation is guaranteed not to block. If a packet cannot be
952 // allocated, this function will return NULL.
954 #define IO_APPEND_MBUF(head, tail, m) { \
956 (tail)->m_next = (m); \
960 (head) = (tail) = (m); \
961 (head)->m_pkthdr.len = 0; \
965 #define IO_ALIGN_MBUF_START(m, mask) { \
966 if ( (mask) & mtod((m), vm_address_t) ) { \
967 (m)->m_data = (caddr_t) (( mtod((m), vm_address_t) + (mask) ) \
972 #define IO_ALIGN_MBUF(m, size, smask, lmask) { \
973 IO_ALIGN_MBUF_START((m), (smask)); \
974 (m)->m_len = ((size) - (smask)) & ~(lmask); \
977 static struct mbuf
* allocateMbuf( UInt32 size
, UInt32 smask
, UInt32 lmask
)
980 struct mbuf
* head
= 0;
981 struct mbuf
* tail
= 0;
986 // Allocate a mbuf. For the initial mbuf segment, allocate a
991 MGETHDR( m
, M_DONTWAIT
, MT_DATA
);
996 MGET( m
, M_DONTWAIT
, MT_DATA
);
1000 if ( m
== 0 ) goto error
; // mbuf allocation error
1002 // Append the new mbuf to the tail of the mbuf chain.
1004 IO_APPEND_MBUF( head
, tail
, m
);
1006 // If the remaining size exceed the buffer size of a normal mbuf,
1007 // then promote it to a cluster. Currently, the cluster size is
1008 // fixed to MCLBYTES bytes.
1010 if ( ( size
+ smask
+ lmask
) > capacity
)
1012 MCLGET( m
, M_DONTWAIT
);
1013 if ( (m
->m_flags
& M_EXT
) == 0 ) goto error
;
1014 capacity
= MCLBYTES
;
1017 // Align the mbuf per driver's specifications.
1019 IO_ALIGN_MBUF( m
, capacity
, smask
, lmask
);
1021 // Compute the number of bytes needed after accounting for the
1022 // current mbuf allocation.
1024 if ( (UInt
) m
->m_len
> size
)
1029 // Update the total length in the packet header.
1031 head
->m_pkthdr
.len
+= m
->m_len
;
1037 if ( head
) m_freem(head
);
1041 struct mbuf
* IONetworkController::allocatePacket( UInt32 size
)
1046 // Handle the simple case where the requested size
1047 // is small enough for a single mbuf. Otherwise,
1048 // go to the more costly route and call the
1049 // generic mbuf allocation routine.
1051 if ( ( size
+ _alignStart
) <= MCLBYTES
) {
1052 if ( ( size
+ _alignStart
) > MHLEN
) {
1053 m
= m_getpacket(); /* MGETHDR+MCLGET under one single lock */
1054 if ( m
== 0 ) break;
1058 MGETHDR( m
, M_DONTWAIT
, MT_DATA
);
1059 if ( m
== 0 ) break;
1062 // Align start of mbuf buffer.
1064 IO_ALIGN_MBUF_START( m
, _alignStart
);
1066 // No length adjustment for single mbuf.
1067 // Driver gets what it asked for.
1069 m
->m_pkthdr
.len
= m
->m_len
= size
;
1073 m
= allocateMbuf(size
, _alignStart
, _alignLength
);
1080 //---------------------------------------------------------------------------
1081 // Release the mbuf back to the free pool.
1083 void IONetworkController::freePacket(struct mbuf
* m
, IOOptionBits options
)
1087 if ( options
& kDelayFree
)
1089 m
->m_nextpkt
= _freeList
;
1098 UInt32
IONetworkController::releaseFreePackets()
1104 count
= m_freem_list( _freeList
);
1110 static inline bool IO_COPY_MBUF(
1111 const struct mbuf
* src
,
1115 caddr_t src_dat
, dst_dat
;
1116 int dst_len
, src_len
;
1120 dst_len
= dst
->m_len
;
1121 dst_dat
= dst
->m_data
;
1125 src_len
= src
->m_len
;
1126 src_dat
= src
->m_data
;
1128 if (src_len
> length
)
1133 if (dst_len
>= src_len
) {
1134 // copy entire src mbuf to dst mbuf.
1136 bcopy(src_dat
, dst_dat
, src_len
);
1143 // fill up dst mbuf with some portion of the data in
1146 bcopy(src_dat
, dst_dat
, dst_len
); // dst_len = 0?
1152 // Go to the next destination mbuf segment.
1155 if (!(dst
= dst
->m_next
))
1156 return (length
== 0);
1157 dst_len
= dst
->m_len
;
1158 dst_dat
= dst
->m_data
;
1161 } /* while (src_len) */
1167 return (length
== 0); // returns true on success.
1170 //---------------------------------------------------------------------------
1171 // Replace the mbuf pointed by the given pointer with another mbuf.
1172 // Drivers can call this method to replace a mbuf before passing the
1173 // original mbuf, which contains a received frame, to the network layer.
1175 // mp: A pointer to the original mbuf that shall be updated by this
1176 // method to point to the new mbuf.
1177 // size: If size is 0, then the new mbuf shall have the same size
1178 // as the original mbuf that is being replaced. Otherwise, the new
1179 // mbuf shall have the size specified here.
1181 // If mbuf allocation was successful, then the replacement will
1182 // take place and the original mbuf will be returned. Otherwise,
1183 // a NULL is returned.
1185 struct mbuf
* IONetworkController::replacePacket(struct mbuf
** mp
,
1188 assert((mp
!= NULL
) && (*mp
!= NULL
));
1190 struct mbuf
* m
= *mp
;
1192 // If size is zero, then size is taken from the source mbuf.
1194 if (size
== 0) size
= m
->m_pkthdr
.len
;
1196 // Allocate a new packet to replace the current packet.
1198 if ( (*mp
= allocatePacket(size
)) == 0 )
1206 //---------------------------------------------------------------------------
1207 // Make a copy of a mbuf, and return the copy. The source mbuf is not modified.
1209 // m: The source mbuf.
1210 // size: The number of bytes to copy. If set to 0, then the entire
1211 // source mbuf is copied.
1213 // Returns a new mbuf created from the source packet.
1215 struct mbuf
* IONetworkController::copyPacket(const struct mbuf
* m
,
1222 // If size is zero, then size is taken from the source mbuf.
1224 if (size
== 0) size
= m
->m_pkthdr
.len
;
1226 // Copy the current mbuf to the new mbuf, and return the new mbuf.
1227 // The input mbuf is left intact.
1229 if ( (mn
= allocatePacket(size
)) == 0 ) return 0;
1231 if (!IO_COPY_MBUF(m
, mn
, size
))
1233 freePacket(mn
); mn
= 0;
1239 //---------------------------------------------------------------------------
1240 // Either replace or copy the source mbuf given depending on the amount of
1241 // data in the source mbuf. This method will either perform a copy or replace
1242 // the source mbuf, whichever is more time efficient. If replaced, then the
1243 // original mbuf is returned, and a new mbuf is allocated to take its place.
1244 // If copied, the source mbuf is left intact, while a copy is returned that
1245 // is just big enough to hold all the data from the source mbuf.
1247 // mp: A pointer to the source mbuf that may be updated by this
1248 // method to point to the new mbuf if replaced.
1249 // rcvlen: The number of data bytes in the source mbuf.
1250 // replacedP: Pointer to a bool that is set to true if the
1251 // source mbuf was replaced, or set to false if the
1252 // source mbuf was copied.
1254 // Returns a replacement or a copy of the source mbuf, 0 if mbuf
1255 // allocation failed.
1257 struct mbuf
* IONetworkController::replaceOrCopyPacket(struct mbuf
** mp
,
1263 assert((mp
!= NULL
) && (*mp
!= NULL
));
1265 if ( (rcvlen
+ _alignPadding
) > MHLEN
)
1267 // Large packet, it is more efficient to allocate a new mbuf
1268 // to replace the original mbuf than to make a copy. The new
1269 // packet shall have exactly the same size as the original
1270 // mbuf being replaced.
1274 if ( (*mp
= allocatePacket(m
->m_pkthdr
.len
)) == 0 )
1276 *mp
= m
; m
= 0; // error recovery
1283 // The copy will fit within a header mbuf. Fine, make a copy
1284 // of the original mbuf instead of replacing it. We only copy
1285 // the rcvlen bytes, not the entire source mbuf.
1287 if ( (m
= allocatePacket(rcvlen
)) == 0 ) return 0;
1289 if (!IO_COPY_MBUF(*mp
, m
, rcvlen
))
1291 freePacket(m
); m
= 0;
1300 //---------------------------------------------------------------------------
1301 // Get hardware support of network/transport layer checksums.
1304 IONetworkController::getChecksumSupport( UInt32
* checksumMask
,
1305 UInt32 checksumFamily
,
1308 return kIOReturnUnsupported
;
1311 //---------------------------------------------------------------------------
1312 // Update a mbuf with the result from the hardware checksum engine.
1314 #define kTransportLayerPartialChecksums \
1315 ( kChecksumTCPNoPseudoHeader | \
1316 kChecksumUDPNoPseudoHeader | \
1319 #define kTransportLayerFullChecksums \
1320 ( kChecksumTCP | kChecksumUDP )
1323 IONetworkController::setChecksumResult( struct mbuf
* m
,
1330 #ifdef HW_CSUM_SUPPORT
1331 // Reporting something that is valid without checking for it
1336 // Initialize checksum result fields in the packet.
1338 m
->m_pkthdr
.csum_flags
= 0;
1340 if ( family
!= kChecksumFamilyTCPIP
)
1345 // Set the result for the network layer (IP) checksum.
1347 if ( result
& kChecksumIP
)
1349 m
->m_pkthdr
.csum_flags
= CSUM_IP_CHECKED
;
1350 if ( valid
& kChecksumIP
)
1351 m
->m_pkthdr
.csum_flags
|= CSUM_IP_VALID
;
1354 // Now examine the transport layer checksum flags.
1356 if ( valid
& kTransportLayerFullChecksums
)
1358 // Excellent, hardware did account for the pseudo-header
1359 // and no "partial" checksum value is required.
1361 m
->m_pkthdr
.csum_flags
|= ( CSUM_DATA_VALID
| CSUM_PSEUDO_HDR
);
1362 m
->m_pkthdr
.csum_data
= 0xffff; // fake a valid checksum value
1364 else if ( result
& kTransportLayerPartialChecksums
)
1366 // Hardware does not account for the pseudo-header.
1367 // Driver must pass up the partial TCP/UDP checksum,
1368 // and the transport layer must adjust for the missing
1369 // 12-byte pseudo-header.
1371 m
->m_pkthdr
.csum_flags
|= CSUM_DATA_VALID
;
1372 m
->m_pkthdr
.csum_data
= (UInt16
) param0
;
1374 if ( result
& kChecksumTCPSum16
)
1376 // A very simple engine that only computes a ones complement
1377 // sum of 16-bit words (UDP/TCP style checksum), from a fixed
1378 // offset, without the ability to scan for the IP or UDP/TCP
1379 // headers. Must pass up the offset to the packet data where
1380 // the checksum computation started from.
1382 m
->m_pkthdr
.csum_flags
|= CSUM_TCP_SUM
; // XXX - fake constant
1383 m
->m_pkthdr
.csum_data
|= (((UInt16
) param1
) << 16);
1389 #endif HW_CSUM_SUPPORT
1392 //---------------------------------------------------------------------------
1393 // Get the checksums that must be performed by the hardware for the
1394 // given packet, before it is sent on the network.
1397 IONetworkController::getChecksumDemand( const struct mbuf
* m
,
1398 UInt32 checksumFamily
,
1399 UInt32
* demandMask
,
1403 #ifdef HW_CSUM_SUPPORT
1404 if ( checksumFamily
!= kChecksumFamilyTCPIP
)
1406 *demandMask
= 0; return;
1409 *demandMask
= m
->m_pkthdr
.csum_flags
& ( kChecksumIP
|
1412 kChecksumTCPSum16
);
1414 if ( m
->m_pkthdr
.csum_flags
& kChecksumTCPSum16
)
1416 // param0 is start offset (XXX - range?)
1417 // param1 is stuff offset (XXX - range?)
1420 *((UInt16
*) param0
) = (UInt16
) (m
->m_pkthdr
.csum_data
);
1422 *((UInt16
*) param1
) = (UInt16
) (m
->m_pkthdr
.csum_data
>> 16);
1427 #endif HW_CSUM_SUPPORT
1431 //---------------------------------------------------------------------------
1432 // Used for debugging only. Log the mbuf fields.
1434 static void _logMbuf(struct mbuf
* m
)
1437 IOLog("logMbuf: NULL mbuf\n");
1442 IOLog("m_next : %08x\n", (UInt
) m
->m_next
);
1443 IOLog("m_nextpkt: %08x\n", (UInt
) m
->m_nextpkt
);
1444 IOLog("m_len : %d\n", (UInt
) m
->m_len
);
1445 IOLog("m_data : %08x\n", (UInt
) m
->m_data
);
1446 IOLog("m_type : %08x\n", (UInt
) m
->m_type
);
1447 IOLog("m_flags : %08x\n", (UInt
) m
->m_flags
);
1449 if (m
->m_flags
& M_PKTHDR
)
1450 IOLog("m_pkthdr.len : %d\n", (UInt
) m
->m_pkthdr
.len
);
1452 if (m
->m_flags
& M_EXT
) {
1453 IOLog("m_ext.ext_buf : %08x\n", (UInt
) m
->m_ext
.ext_buf
);
1454 IOLog("m_ext.ext_size: %d\n", (UInt
) m
->m_ext
.ext_size
);
1463 //---------------------------------------------------------------------------
1464 // Allocate and attache a new IOKernelDebugger client object.
1466 // debuggerP: A handle that is updated by this method
1467 // with the allocated IOKernelDebugger instance.
1469 // Returns true on success, false otherwise.
1471 bool IONetworkController::attachDebuggerClient(IOKernelDebugger
** debugger
)
1473 IOKernelDebugger
* client
;
1476 // Prepare the controller.
1478 if (executeCommand(this, &IONetworkController::handleCommand
,
1479 this, (void *) kCommandPrepare
) != kIOReturnSuccess
)
1484 // Create a debugger client nub and register the static
1485 // member functions as the polled-mode handlers.
1487 client
= IOKernelDebugger::debugger( this,
1491 if ( client
&& !client
->attach(this) )
1493 // Unable to attach the client object.
1494 client
->terminate( kIOServiceRequired
| kIOServiceSynchronous
);
1503 client
->registerService();
1510 //---------------------------------------------------------------------------
1511 // Detach and terminate the IOKernelDebugger client object provided.
1512 // A synchronous termination is issued, and this method returns after
1513 // the debugger client has been terminated.
1515 // debugger: The IOKernelDebugger instance to be detached and terminated.
1516 // If the argument provided is NULL or is not an IOKernelDebugger,
1517 // this method will return immediately.
1519 void IONetworkController::detachDebuggerClient(IOKernelDebugger
* debugger
)
1521 if (OSDynamicCast(IOKernelDebugger
, debugger
) == 0)
1524 // Terminate the debugger client and return after the client has
1527 debugger
->terminate(kIOServiceRequired
| kIOServiceSynchronous
);
1530 //---------------------------------------------------------------------------
1531 // An enable request from an IOKernelDebugger client.
1533 IOReturn
IONetworkController::enable(IOKernelDebugger
* debugger
)
1535 return kIOReturnSuccess
;
1538 //---------------------------------------------------------------------------
1539 // A disable request from an IOKernelDebugger client.
1541 IOReturn
IONetworkController::disable(IOKernelDebugger
* debugger
)
1543 return kIOReturnSuccess
;
1546 //---------------------------------------------------------------------------
1547 // Take and release the debugger lock.
1549 void IONetworkController::reserveDebuggerLock()
1551 if ( _debugLockCount
++ == 0 )
1553 _debugLockState
= IODebuggerLock( this );
1557 void IONetworkController::releaseDebuggerLock()
1559 if ( --_debugLockCount
== 0 )
1561 IODebuggerUnlock( _debugLockState
);
1563 assert( _debugLockCount
>= 0 );
1566 //---------------------------------------------------------------------------
1567 // This static C++ member function is registered by attachDebuggerClient()
1568 // as the debugger receive handler. IOKernelDebugger will call this
1569 // function when KDP is polling for a received packet. This function will
1570 // in turn will call the receivePacket() member function implemented by
1571 // a driver with debugger support.
1573 void IONetworkController::debugRxHandler(IOService
* handler
,
1578 ((IONetworkController
*) handler
)->receivePacket(buffer
,
1583 //---------------------------------------------------------------------------
1584 // This static C++ member function is registered by attachDebuggerClient()
1585 // as the debugger transmit handler. IOKernelDebugger will call this
1586 // function when KDP sends an outgoing packet. This function will in turn
1587 // call the sendPacket() member function implemented by a driver with
1588 // debugger support.
1590 void IONetworkController::debugTxHandler(IOService
* handler
,
1594 ((IONetworkController
*) handler
)->sendPacket(buffer
, length
);
1597 //---------------------------------------------------------------------------
1598 // This method must be implemented by a driver that supports kernel debugging.
1599 // After a debugger client is attached through attachDebuggerClient(), this
1600 // method will be called by the debugger client to poll for a incoming packet
1601 // when the debugger session is active. This method may be called from the
1602 // primary interrupt context, implementation must avoid any memory allocation,
1603 // and must never block. The receivePacket() method in IONetworkController is
1604 // used as a placeholder and should not be called. A driver that attaches
1605 // a debugger client must override this method.
1607 // pkt: Pointer to a receive buffer where the received packet should
1608 // be stored to. The buffer has enough space for 1518 bytes.
1609 // pkt_len: The length of the received packet must be written to the
1610 // integer pointed by pkt_len.
1611 // timeout: The maximum amount of time in milliseconds to poll for
1612 // a packet to arrive before this method must return.
1614 void IONetworkController::receivePacket(void * /*pkt*/,
1615 UInt32
* /*pkt_len*/,
1618 IOLog("IONetworkController::%s()\n", __FUNCTION__
);
1621 //---------------------------------------------------------------------------
1622 // Debugger polled-mode transmit handler. This method must be implemented
1623 // by a driver that supports kernel debugging. After a debugger client is
1624 // attached through attachDebuggerClient(), this method will be called by the
1625 // debugger to send an outbound packet when the kernel debugger is active.
1626 // This method may be called from the primary interrupt context, and the
1627 // implementation must avoid any memory allocation, and must never block.
1628 // sendPacket() method in IONetworkController is used as a placeholder
1629 // and should not be called. A driver that attaches a debugger client
1630 // must override this method.
1632 // pkt: Pointer to a transmit buffer containing the packet to be sent.
1633 // pkt_len: The amount of data in the transmit buffer.
1635 void IONetworkController::sendPacket(void * /*pkt*/, UInt32
/*pkt_len*/)
1637 IOLog("IONetworkController::%s()\n", __FUNCTION__
);
1640 //---------------------------------------------------------------------------
1641 // Report the link status and the active medium.
1643 bool IONetworkController::setLinkStatus(
1645 const IONetworkMedium
* activeMedium
,
1649 bool success
= true;
1650 bool changed
= false;
1651 UInt32 linkEvent
= 0;
1652 const OSSymbol
* name
= activeMedium
? activeMedium
->getName() :
1656 data
= (OSData
*) gIONullLinkData
;
1658 if ((speed
== 0) && activeMedium
)
1659 speed
= activeMedium
->getSpeed();
1663 // Update kIOActiveMedium property.
1665 if (name
!= _lastActiveMediumName
)
1667 if ( setProperty(gIOActiveMediumKey
, (OSSymbol
*) name
) )
1670 _lastActiveMediumName
= name
;
1676 // Update kIOLinkData property.
1678 if (data
!= _lastLinkData
)
1680 if ( setProperty(gIOLinkDataKey
, data
) )
1683 _lastLinkData
= data
;
1689 // Update kIOLinkStatus property.
1691 if (status
!= _linkStatus
->unsigned32BitValue())
1693 if (status
& kIONetworkLinkValid
)
1695 linkEvent
= (status
& kIONetworkLinkActive
) ?
1696 kIONetworkEventTypeLinkUp
:
1697 kIONetworkEventTypeLinkDown
;
1699 _linkStatus
->setValue(status
);
1703 // Update kIOLinkSpeed property.
1705 if (speed
!= _linkSpeed
->unsigned64BitValue())
1707 _linkSpeed
->setValue(speed
);
1713 // Broadcast a link event to interface objects.
1716 _broadcastEvent(linkEvent
);
1721 //---------------------------------------------------------------------------
1722 // Returns the medium dictionary published by the driver through
1723 // publishMediumDictionary(). Use copyMediumDictionary() to get a copy
1724 // of the medium dictionary.
1726 // Returns the published medium dictionary, or 0 if the driver has not
1727 // yet published a medium dictionary through publishMediumDictionary().
1729 const OSDictionary
* IONetworkController::getMediumDictionary() const
1731 return (OSDictionary
*) getProperty(kIOMediumDictionary
);
1734 //---------------------------------------------------------------------------
1735 // Returns a copy of the medium dictionary published by the driver.
1736 // The caller is responsible for releasing the dictionary object returned.
1737 // Use getMediumDictionary() to get a reference to the published medium
1738 // dictionary instead of creating a copy.
1740 // Returns a copy of the medium dictionary, or 0 if the driver has not
1741 // published a medium dictionary through publishMediumDictionary().
1743 OSDictionary
* IONetworkController::copyMediumDictionary() const
1745 const OSDictionary
* mediumDict
;
1746 OSDictionary
* copy
= 0;
1750 mediumDict
= getMediumDictionary();
1754 copy
= OSDictionary::withDictionary(mediumDict
,
1755 mediumDict
->getCount());
1763 //---------------------------------------------------------------------------
1764 // A client request to change the media selection.
1766 IOReturn
IONetworkController::selectMedium(const IONetworkMedium
* medium
)
1768 return kIOReturnUnsupported
;
1771 //---------------------------------------------------------------------------
1772 // Private function to lookup a key in the medium dictionary and call
1773 // setMedium() if a match is found. This function is called by our
1774 // clients to change the medium selection by passing a name for the desired
1777 IOReturn
IONetworkController::selectMediumWithName(const OSSymbol
* mediumName
)
1779 OSSymbol
* currentMediumName
;
1780 IONetworkMedium
* newMedium
= 0;
1781 bool doChange
= true;
1782 IOReturn ret
= kIOReturnSuccess
;
1784 if (OSDynamicCast(OSSymbol
, mediumName
) == 0)
1785 return kIOReturnBadArgument
;
1790 const OSDictionary
* mediumDict
= getMediumDictionary();
1793 // no medium dictionary, bail out.
1794 ret
= kIOReturnUnsupported
;
1798 // Lookup the new medium in the dictionary.
1800 newMedium
= (IONetworkMedium
*) mediumDict
->getObject(mediumName
);
1803 ret
= kIOReturnBadArgument
;
1804 break; // not found, invalid mediumName.
1807 newMedium
->retain();
1809 // Lookup the current medium key to avoid unnecessary
1812 currentMediumName
= (OSSymbol
*) getProperty(gIOCurrentMediumKey
);
1814 // Is change necessary?
1816 if (currentMediumName
&& mediumName
->isEqualTo(currentMediumName
))
1825 // Call the driver's selectMedium() without holding the medium lock.
1828 ret
= selectMedium(newMedium
);
1830 // Remove the earlier retain.
1832 newMedium
->release();
1838 //---------------------------------------------------------------------------
1839 // Designate an entry in the published medium dictionary as
1840 // the current selected medium.
1842 bool IONetworkController::setSelectedMedium(const IONetworkMedium
* medium
)
1844 bool success
= true;
1845 bool changed
= false;
1846 const OSSymbol
* name
= medium
? medium
->getName() : gIONullMediumName
;
1850 if (name
!= _lastCurrentMediumName
)
1852 if ( setProperty(gIOCurrentMediumKey
, (OSSymbol
*) name
) )
1855 _lastCurrentMediumName
= name
;
1865 _broadcastEvent(kIONetworkEventTypeLinkChange
);
1871 //---------------------------------------------------------------------------
1872 // Get the current selected medium.
1874 const IONetworkMedium
* IONetworkController::getSelectedMedium() const
1876 IONetworkMedium
* medium
= 0;
1877 OSSymbol
* mediumName
;
1882 const OSDictionary
* mediumDict
= getMediumDictionary();
1883 if (!mediumDict
) // no medium dictionary, bail out.
1886 // Fetch the current medium name from the property table.
1888 mediumName
= (OSSymbol
*) getProperty(gIOCurrentMediumKey
);
1890 // Make sure the current medium name points to an entry in
1891 // the medium dictionary.
1893 medium
= (IONetworkMedium
*) mediumDict
->getObject(mediumName
);
1895 // Invalid current medium, try the default medium.
1901 // This comes from the driver's property list.
1902 // More checking is done to avoid surprises.
1904 aString
= OSDynamicCast( OSString
,
1905 getProperty(gIODefaultMediumKey
) );
1907 medium
= (IONetworkMedium
*) mediumDict
->getObject(aString
);
1917 //---------------------------------------------------------------------------
1918 // A private function to verify a medium dictionary. Returns true if the
1919 // dictionary is OK.
1921 static bool verifyMediumDictionary(const OSDictionary
* mediumDict
)
1923 OSCollectionIterator
* iter
;
1924 bool verifyOk
= true;
1927 if (!OSDynamicCast(OSDictionary
, mediumDict
))
1928 return false; // invalid argument
1930 if (mediumDict
->getCount() == 0)
1931 return false; // empty dictionary
1933 iter
= OSCollectionIterator::withCollection((OSDictionary
*) mediumDict
);
1935 return false; // cannot allocate iterator
1937 while ((key
= (OSSymbol
*) iter
->getNextObject()))
1939 if ( !OSDynamicCast(IONetworkMedium
, mediumDict
->getObject(key
)) )
1941 verifyOk
= false; // non-medium object in dictionary
1951 //---------------------------------------------------------------------------
1952 // Publish a dictionary of IONetworkMedium objects.
1955 IONetworkController::publishMediumDictionary(const OSDictionary
* mediumDict
)
1957 OSDictionary
* cloneDict
;
1960 if (!verifyMediumDictionary(mediumDict
))
1961 return false; // invalid dictionary
1963 // Create a clone of the source dictionary. This prevents the driver
1964 // from adding/removing entries after the medium dictionary is added
1965 // to the property table.
1967 cloneDict
= OSDictionary::withDictionary(mediumDict
,
1968 mediumDict
->getCount());
1970 return false; // unable to create a copy
1974 // Add the dictionary to the property table.
1976 if (setProperty(kIOMediumDictionary
, cloneDict
))
1978 const OSSymbol
* mediumName
;
1980 // Update kIOSelectedMedium property.
1982 mediumName
= (OSSymbol
*) getProperty(gIOCurrentMediumKey
);
1983 if (cloneDict
->getObject(mediumName
) == 0)
1985 mediumName
= gIONullMediumName
;
1987 setProperty(gIOCurrentMediumKey
, (OSSymbol
*) mediumName
);
1988 _lastCurrentMediumName
= mediumName
;
1990 // Update kIOActiveMedium property.
1992 mediumName
= (OSSymbol
*) getProperty(gIOActiveMediumKey
);
1993 if (cloneDict
->getObject(mediumName
) == 0)
1995 mediumName
= gIONullMediumName
;
1997 setProperty(gIOActiveMediumKey
, (OSSymbol
*) mediumName
);
1998 _lastActiveMediumName
= mediumName
;
2005 // Retained by the property table. drop our retain count.
2007 cloneDict
->release();
2010 // Broadcast a link change event.
2012 _broadcastEvent(kIONetworkEventTypeLinkChange
);
2018 //---------------------------------------------------------------------------
2019 // Static function called by the internal IOCommandGate object to
2020 // handle a runAction() request invoked by executeCommand().
2022 IOReturn
IONetworkController::executeCommandAction(OSObject
* owner
,
2028 IONetworkController
* self
= (IONetworkController
*) owner
;
2029 cmdStruct
* cmdP
= (cmdStruct
*) arg0
;
2032 OSObject
* oldClient
;
2034 assert(cmdP
&& self
);
2036 oldClient
= self
->_cmdClient
;
2040 // Command rejected.
2041 ret
= kIOReturnNotPermitted
;
2045 self
->_cmdClient
= cmdP
->client
;
2047 cmdP
->ret
= (*cmdP
->action
)( cmdP
->target
,
2053 self
->_cmdClient
= oldClient
;
2055 ret
= kIOReturnSuccess
;
2061 //---------------------------------------------------------------------------
2062 // Perform an "action" that is synchronized by the command gate.
2064 IOReturn
IONetworkController::executeCommand(OSObject
* client
,
2075 cmd
.client
= client
;
2076 cmd
.action
= action
;
2077 cmd
.target
= target
;
2078 cmd
.param0
= param0
;
2079 cmd
.param1
= param1
;
2080 cmd
.param2
= param2
;
2081 cmd
.param3
= param3
;
2083 // Execute the client command through the command gate. Client commands
2084 // are thus synchronized with the workloop returned by getWorkLoop().
2086 ret
= _cmdGate
->runAction( (IOCommandGate::Action
)
2087 &IONetworkController::executeCommandAction
,
2088 (void *) &cmd
); /* arg0 - cmdStruct */
2090 // If executeCommandAction() executed successfully, then return the
2091 // status from the client command that was executed.
2093 if (ret
== kIOReturnSuccess
)
2099 //---------------------------------------------------------------------------
2100 // Called by executeCommand() to handle the client command on the
2101 // workloop context.
2103 IOReturn
IONetworkController::handleCommand(void * target
,
2110 IONetworkController
* self
= (IONetworkController
*) target
;
2111 UInt32 command
= (UInt32
) param0
;
2112 IOService
* client
= (IOService
*) param1
;
2117 case kCommandEnable
:
2118 ret
= self
->enable(client
);
2121 case kCommandDisable
:
2122 ret
= self
->disable(client
);
2125 case kCommandPrepare
:
2126 ret
= self
->prepare();
2130 ret
= kIOReturnUnsupported
;
2137 //---------------------------------------------------------------------------
2138 // Issue an kCommandEnable command to handleCommand().
2140 IOReturn
IONetworkController::doEnable(IOService
* client
)
2142 return executeCommand( client
,
2143 &IONetworkController::handleCommand
,
2145 (void *) kCommandEnable
,
2149 //---------------------------------------------------------------------------
2150 // Issue an kCommandDisable command to handleCommand().
2152 IOReturn
IONetworkController::doDisable(IOService
* client
)
2154 return executeCommand( client
,
2155 &IONetworkController::handleCommand
,
2157 (void *) kCommandDisable
,