]> git.saurik.com Git - apple/xnu.git/blame - iokit/Families/IONetworking/IONetworkController.cpp
xnu-124.13.tar.gz
[apple/xnu.git] / iokit / Families / IONetworking / IONetworkController.cpp
CommitLineData
1c79356b
A
1/*
2 * Copyright (c) 1998-2000 Apple Computer, 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 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
24 *
25 * IONetworkController.cpp
26 *
27 * HISTORY
28 * 9-Dec-1998 Joe Liu (jliu) created.
29 *
30 */
31
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>
37
38// IONetworkController (and its subclasses) needs to know about mbufs,
39// but it shall have no further dependencies on BSD networking.
40//
41extern "C" {
42#include <sys/param.h> // mbuf limits defined here.
43#include <sys/mbuf.h>
44#include <sys/kdebug.h>
45//
46// osfmk/kern/spl.h - Need splimp for mbuf macros.
47//
48typedef unsigned spl_t;
49extern spl_t (splimp)(void);
50}
51
52//-------------------------------------------------------------------------
53// Macros.
54
55#define super IOService
56
57OSDefineMetaClassAndAbstractStructors( IONetworkController, IOService )
58OSMetaClassDefineReservedUnused( IONetworkController, 0);
59OSMetaClassDefineReservedUnused( IONetworkController, 1);
60OSMetaClassDefineReservedUnused( IONetworkController, 2);
61OSMetaClassDefineReservedUnused( IONetworkController, 3);
62OSMetaClassDefineReservedUnused( IONetworkController, 4);
63OSMetaClassDefineReservedUnused( IONetworkController, 5);
64OSMetaClassDefineReservedUnused( IONetworkController, 6);
65OSMetaClassDefineReservedUnused( IONetworkController, 7);
66OSMetaClassDefineReservedUnused( IONetworkController, 8);
67OSMetaClassDefineReservedUnused( IONetworkController, 9);
68OSMetaClassDefineReservedUnused( IONetworkController, 10);
69OSMetaClassDefineReservedUnused( IONetworkController, 11);
70OSMetaClassDefineReservedUnused( IONetworkController, 12);
71OSMetaClassDefineReservedUnused( IONetworkController, 13);
72OSMetaClassDefineReservedUnused( IONetworkController, 14);
73OSMetaClassDefineReservedUnused( IONetworkController, 15);
74OSMetaClassDefineReservedUnused( IONetworkController, 16);
75OSMetaClassDefineReservedUnused( IONetworkController, 17);
76OSMetaClassDefineReservedUnused( IONetworkController, 18);
77OSMetaClassDefineReservedUnused( IONetworkController, 19);
78OSMetaClassDefineReservedUnused( IONetworkController, 20);
79OSMetaClassDefineReservedUnused( IONetworkController, 21);
80OSMetaClassDefineReservedUnused( IONetworkController, 22);
81OSMetaClassDefineReservedUnused( IONetworkController, 23);
82OSMetaClassDefineReservedUnused( IONetworkController, 24);
83OSMetaClassDefineReservedUnused( IONetworkController, 25);
84OSMetaClassDefineReservedUnused( IONetworkController, 26);
85OSMetaClassDefineReservedUnused( IONetworkController, 27);
86OSMetaClassDefineReservedUnused( IONetworkController, 28);
87OSMetaClassDefineReservedUnused( IONetworkController, 29);
88OSMetaClassDefineReservedUnused( IONetworkController, 30);
89OSMetaClassDefineReservedUnused( IONetworkController, 31);
90
91static bool isPowerOfTwo(UInt32 num)
92{
93 return (num == (num & ~(num - 1)));
94}
95
96#define MEDIUM_LOCK IOTakeLock(_mediumLock);
97#define MEDIUM_UNLOCK IOUnlock(_mediumLock);
98
99#ifdef DEBUG
100#define DLOG(fmt, args...) IOLog(fmt, ## args)
101#else
102#define DLOG(fmt, args...)
103#endif
104
105// OSSymbols for frequently used keys.
106//
107static const OSSymbol * gIOActiveMediumKey;
108static const OSSymbol * gIOCurrentMediumKey;
109static const OSSymbol * gIODefaultMediumKey;
110static const OSSymbol * gIONullMediumName;
111static const OSSymbol * gIOLinkDataKey;
112static const OSData * gIONullLinkData;
113
114// Global symbols.
115//
116const OSSymbol * gIONetworkFilterGroup;
117const OSSymbol * gIOEthernetWakeOnLANFilterGroup;
118
119// Constants for handleCommand().
120//
121enum {
122 kCommandEnable = 1,
123 kCommandDisable = 2,
124 kCommandPrepare = 3
125};
126
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.
132
133void IONetworkController::initialize()
134{
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);
143
144 gIOEthernetWakeOnLANFilterGroup
145 = OSSymbol::withCStringNoCopy("IOEthernetWakeOnLANFilterGroup");
146
147 assert( gIOEthernetWakeOnLANFilterGroup );
148
149 assert(gIOActiveMediumKey &&
150 gIOCurrentMediumKey &&
151 gIODefaultMediumKey &&
152 gIONullMediumName &&
153 gIOLinkDataKey &&
154 gIONullLinkData &&
155 gIONetworkFilterGroup);
156
157 IONetworkData::initialize();
158}
159
160//---------------------------------------------------------------------------
161// Initialize the IONetworkController instance. Instance variables are
162// set to their default values, then super::init() is called.
163//
164// properties: A dictionary object containing a property table
165// associated with this instance.
166//
167// Returns true on success, false otherwise.
168
169bool IONetworkController::init(OSDictionary * properties)
170{
171 // Initialize instance variables.
172 //
173 _workLoop = 0;
174 _cmdGate = 0;
175 _outputQueue = 0;
176 _clientSet = 0;
177 _clientSetIter = 0;
178 _cmdClient = 0;
179 _propertiesPublished = false;
180 _mediumLock = 0;
181 _lastLinkData = gIONullLinkData;
182 _lastActiveMediumName = gIONullMediumName;
183 _lastCurrentMediumName = gIONullMediumName;
184
185 if (super::init(properties) == false)
186 {
187 DLOG("IONetworkController: super::init() failed\n");
188 return false;
189 }
190
191 return true;
192}
193
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:
203//
204// - An IOCommandGate object to handle client commands.
205// - An OSSet to track our clients.
206// - An optional IOOutputQueue object for output queueing.
207//
208// Tasks that are usually performed by a typical network driver in start
209// include:
210//
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.
217//
218// provider: The provider that the controller was matched
219// (and attached) to.
220//
221// Returns true on success, false otherwise.
222
223bool IONetworkController::start(IOService * provider)
224{
225 // Most drivers will probably want to wait for BSD due to their
226 // dependency on mbufs, which is not available until BSD is
227 // initialized.
228
229 if ((getFeatures() & kIONetworkFeatureNoBSDWait) == 0)
230 waitForService(resourceMatching( "IOBSD" ));
231
232 // Start our superclass.
233
234 if (!super::start(provider))
235 return false;
236
237 // Create an OSSet to store our clients.
238
239 _clientSet = OSSet::withCapacity(2);
240 if (_clientSet == 0)
241 return false;
242
243 _clientSetIter = OSCollectionIterator::withCollection(_clientSet);
244 if (_clientSetIter == 0)
245 return false;
246
247 // Initialize link status properties.
248
249 if (!setProperty(gIOActiveMediumKey, (OSSymbol *) gIONullMediumName) ||
250 !setProperty(gIOCurrentMediumKey, (OSSymbol *) gIONullMediumName))
251 return false;
252
253 _linkStatus = OSNumber::withNumber((UInt64) 0, 32);
254 if (!_linkStatus || !setProperty(kIOLinkStatus, _linkStatus))
255 {
256 return false;
257 }
258
259 _linkSpeed = OSNumber::withNumber((UInt64) 0, 64);
260 if (!_linkSpeed || !setProperty(kIOLinkSpeed, _linkSpeed))
261 {
262 return false;
263 }
264
265 // Allocate a mutex lock to serialize access to the medium dictionary.
266
267 _mediumLock = IOLockAlloc();
268 if (!_mediumLock)
269 return false;
270 IOLockInitWithState(_mediumLock, kIOLockStateUnlocked);
271
272 // Tell the driver that now is the time to create a work loop
273 // (if it wants one).
274
275 if ( createWorkLoop() != true )
276 {
277 DLOG("%s: createWorkLoop() error\n", getName());
278 return false;
279 }
280
281 // Get the workloop.
282
283 _workLoop = getWorkLoop();
284 if ( _workLoop == 0 )
285 {
286 DLOG("%s: IOWorkLoop allocation failed\n", getName());
287 return false;
288 }
289 _workLoop->retain();
290
291 // Create a 'private' IOCommandGate object and attach it to
292 // our workloop created above. This is used by executeCommand().
293
294 _cmdGate = IOCommandGate::commandGate(this);
295 if (!_cmdGate ||
296 (_workLoop->addEventSource(_cmdGate) != kIOReturnSuccess))
297 {
298 DLOG("%s: IOCommandGate initialization failed\n", getName());
299 return false;
300 }
301
302 // Try to allocate an IOOutputQueue instance. This is optional and
303 // _outputQueue may be 0.
304
305 _outputQueue = createOutputQueue();
306
307 // Query the controller's mbuf buffer restrictions.
308
309 IOPacketBufferConstraints constraints;
310 getPacketBufferConstraints(&constraints);
311 if ((constraints.alignStart > kIOPacketBufferAlign32) ||
312 (constraints.alignLength > kIOPacketBufferAlign32) ||
313 !isPowerOfTwo(constraints.alignStart) ||
314 !isPowerOfTwo(constraints.alignLength))
315 {
316 IOLog("%s: Invalid alignment: start:%ld, length:%ld\n",
317 getName(),
318 constraints.alignStart,
319 constraints.alignLength);
320 return false;
321 }
322
323 // Make it easier to satisfy both constraints.
324
325 if (constraints.alignStart < constraints.alignLength)
326 constraints.alignStart = constraints.alignLength;
327
328 // Convert to alignment masks.
329
330 _alignStart = (constraints.alignStart) ? constraints.alignStart - 1 : 0;
331 _alignLength = (constraints.alignLength) ? constraints.alignLength - 1 : 0;
332 _alignPadding = _alignStart + _alignLength;
333
334 // Called by a policy-maker to initialize itself for power-management.
335 // IONetworkController is the policy-maker.
336
337 PMinit();
338
339 // Called by a policy-maker on its nub, to be attached into the
340 // power management hierarchy.
341
342 provider->joinPMtree(this);
343
344 return true;
345}
346
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.
352//
353// provider: The provider that the controller was matched
354// (and attached) to.
355
356void IONetworkController::stop(IOService * provider)
357{
358 // Called by a policy-maker to resign its responsibilities as the
359 // policy-maker.
360
361 PMstop();
362
363 super::stop(provider);
364}
365
366//---------------------------------------------------------------------------
367// Power-management hooks for subclasses.
368
369IOReturn IONetworkController::registerWithPolicyMaker(IOService * policyMaker)
370{
371 // An opportunity for subclasses to call
372 // policyMaker->registerPowerDriver(...)
373 // and other future PM requirements.
374 return kIOReturnUnsupported;
375}
376
377//---------------------------------------------------------------------------
378// Catch calls to createWorkLoop() for drivers that choose not implement this
379// method.
380
381bool IONetworkController::createWorkLoop()
382{
383 return true;
384}
385
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.
394//
395// Returns the IOCommandGate object created by IONetworkController.
396
397IOCommandGate * IONetworkController::getCommandGate() const
398{
399 return _cmdGate;
400}
401
402//---------------------------------------------------------------------------
403// Get the address of the method designated to handle output packets.
404//
405// Returns the address of the outputPacket() method.
406
407IOOutputAction IONetworkController::getOutputHandler() const
408{
409 return (IOOutputAction) &IONetworkController::outputPacket;
410}
411
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
419// requests.
420//
421// interfaceP: If successful (return value is true), then the interface
422// object will be written to the handle provided.
423//
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.
433//
434// Returns true on success, false otherwise.
435
436bool
437IONetworkController::attachInterface(IONetworkInterface ** interfaceP,
438 bool doRegister = true)
439{
440 IONetworkInterface * netif;
441
442 *interfaceP = 0;
443
444 // We delay some initialization until the first time that
445 // attachInterface() is called by the subclass.
446
447 if (executeCommand(this, &IONetworkController::handleCommand,
448 this, (void *) kCommandPrepare) != kIOReturnSuccess)
449 {
450 return false;
451 }
452
453 do {
454 // Allocate a concrete subclass of IONetworkInterface
455 // by calling createInterface().
456
457 netif = createInterface();
458 if (!netif)
459 break;
460
461 // Configure the interface instance by calling
462 // configureInterface(), then attach it as our client.
463
464 if ( !configureInterface(netif) || !netif->attach(this) )
465 {
466 netif->release();
467 break;
468 }
469
470 *interfaceP = netif;
471
472 // Register the interface nub. Spawns a matching thread.
473
474 if (doRegister)
475 netif->registerService();
476
477 return true; // success
478 }
479 while (0);
480
481 return false; // failure
482}
483
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.
490//
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.
495
496void
497IONetworkController::detachInterface(IONetworkInterface * interface,
498 bool sync = false)
499{
500 IOOptionBits options = kIOServiceRequired;
501
502 if (OSDynamicCast(IONetworkInterface, interface) == 0)
503 return;
504
505 if (sync)
506 options |= kIOServiceSynchronous;
507
508 interface->terminate(options);
509}
510
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
517// multiple times.
518//
519// kIOReturnSuccess on success, or an error code otherwise.
520// Returning an error will cause the client attach to fail.
521
522IOReturn IONetworkController::prepare()
523{
524 IOReturn ret = kIOReturnSuccess;
525
526 if ( _propertiesPublished == false )
527 {
528 if ( publishProperties() == true )
529 {
530 _propertiesPublished = true;
531
532 if (pm_vars != 0)
533 {
534 registerWithPolicyMaker( this );
535 }
536 }
537 else
538 {
539 ret = kIOReturnError;
540 }
541 }
542
543 return ret;
544}
545
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
549// this method.
550//
551// client: The client that is attempting to open the controller.
552// options: See IOService.
553// argument: See IOService.
554//
555// Returns true to accept the client open, false to refuse it.
556
557bool IONetworkController::handleOpen(IOService * client,
558 IOOptionBits options,
559 void * argument)
560{
561 assert(client);
562 return _clientSet->setObject(client);
563}
564
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
568// method.
569//
570// client: The client that is closing the controller.
571// options: See IOService.
572
573void IONetworkController::handleClose(IOService * client, IOOptionBits options)
574{
575 _clientSet->removeObject(client);
576}
577
578//---------------------------------------------------------------------------
579// This method is always called by IOService with the arbitration lock held.
580// Subclasses should not override this method.
581//
582// Returns true if the specified client, or any client if none is
583// specified, presently has an open on this object.
584
585bool IONetworkController::handleIsOpen(const IOService * client) const
586{
587 if (client)
588 return _clientSet->containsObject(client);
589 else
590 return (_clientSet->getCount() > 0);
591}
592
593//---------------------------------------------------------------------------
594// Free the IONetworkController instance by releasing all allocated resources,
595// then call super::free().
596
597void IONetworkController::free()
598{
599#define RELEASE(x) do { if (x) { (x)->release(); (x) = 0; } } while (0)
600
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.
604
605 if (_clientSet) assert(_clientSet->getCount() == 0);
606
607 RELEASE( _outputQueue );
608 RELEASE( _cmdGate );
609 RELEASE( _workLoop );
610 RELEASE( _clientSetIter );
611 RELEASE( _clientSet );
612 RELEASE( _linkStatus );
613 RELEASE( _linkSpeed );
614
615 if (_mediumLock) { IOLockFree(_mediumLock); _mediumLock = 0; }
616
617 super::free();
618}
619
620//---------------------------------------------------------------------------
621// Handle an enable request from a client.
622
623IOReturn IONetworkController::enable(IOService * client)
624{
625 if (OSDynamicCast(IONetworkInterface, client))
626 return enable((IONetworkInterface *) client);
627
628 if (OSDynamicCast(IOKernelDebugger, client))
629 return enable((IOKernelDebugger *) client);
630
631 IOLog("%s::%s Unknown client type\n", getName(), __FUNCTION__);
632 return kIOReturnBadArgument;
633}
634
635//---------------------------------------------------------------------------
636// Handle a disable request from a client.
637
638IOReturn IONetworkController::disable(IOService * client)
639{
640 if (OSDynamicCast(IONetworkInterface, client))
641 return disable((IONetworkInterface *) client);
642
643 if (OSDynamicCast(IOKernelDebugger, client))
644 return disable((IOKernelDebugger *) client);
645
646 IOLog("%s::%s Unknown client type\n", getName(), __FUNCTION__);
647 return kIOReturnBadArgument;
648}
649
650//---------------------------------------------------------------------------
651// Called by an interface client to enable the controller.
652
653IOReturn IONetworkController::enable(IONetworkInterface * interface)
654{
655 IOLog("IONetworkController::%s\n", __FUNCTION__);
656 return kIOReturnUnsupported;
657}
658
659//---------------------------------------------------------------------------
660// Called by an interface client to disable the controller.
661
662IOReturn IONetworkController::disable(IONetworkInterface * interface)
663{
664 IOLog("IONetworkController::%s\n", __FUNCTION__);
665 return kIOReturnUnsupported;
666}
667
668//---------------------------------------------------------------------------
669// Discover and publish controller capabilities to the property table.
670// This method is called by prepare() on the workloop context.
671//
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.
676
677bool IONetworkController::publishProperties()
678{
679 bool ret = false;
680 const OSString * string;
681 UInt32 num;
682 OSDictionary * dict = 0;
683 OSNumber * numObj = 0;
684
685 do {
686 bool status;
687
688 string = newVendorString();
689 if (string) {
690 status = setProperty(kIOVendor, (OSObject *) string);
691 string->release();
692 if (status != true) break;
693 }
694
695 string = newModelString();
696 if (string) {
697 status = setProperty(kIOModel, (OSObject *) string);
698 string->release();
699 if (status != true) break;
700 }
701
702 string = newRevisionString();
703 if (string) {
704 status = setProperty(kIORevision, (OSObject *) string);
705 string->release();
706 if (status != true) break;
707 }
708
709 // Publish controller feature flags.
710
711 num = getFeatures();
712 if ( !setProperty(kIOFeatures, num, sizeof(num) * 8) )
713 break;
714
715 // Publish max/min packet size.
716
717 if ( ( getMaxPacketSize(&num) != kIOReturnSuccess ) ||
718 ( !setProperty(kIOMaxPacketSize, num, sizeof(num) * 8) ) )
719 break;
720
721 if ( ( getMinPacketSize(&num) != kIOReturnSuccess ) ||
722 ( !setProperty(kIOMinPacketSize, num, sizeof(num) * 8) ) )
723 break;
724
725 // Publish supported packet filters.
726
727 if (getPacketFilters(gIONetworkFilterGroup, &num) != kIOReturnSuccess)
728 break;
729
730 dict = OSDictionary::withCapacity(4);
731 numObj = OSNumber::withNumber(num, sizeof(num) * 8);
732 if ( (dict == 0) || (numObj == 0) ) break;
733
734 if ( !dict->setObject(gIONetworkFilterGroup, numObj) ||
735 !setProperty(kIOPacketFilters, dict) )
736 break;
737
738 ret = true;
739 }
740 while (false);
741
742 if (ret == false) {
743 DLOG("IONetworkController::%s error\n", __FUNCTION__);
744 }
745 if ( dict ) dict->release();
746 if ( numObj ) numObj->release();
747
748 return ret;
749}
750
751//---------------------------------------------------------------------------
752// Send a network event to all attached interface objects.
753
754bool IONetworkController::_broadcastEvent(UInt32 type, void * data = 0)
755{
756 IONetworkInterface * netif;
757
758 lockForArbitration(); // locks open/close/state changes.
759
760 if (_clientSet->getCount())
761 {
762 _clientSetIter->reset();
763
764 while ((netif = (IONetworkInterface *)_clientSetIter->getNextObject()))
765 {
766 if (OSDynamicCast(IONetworkInterface, netif) == 0)
767 continue; // only send events to IONetworkInterface objects.
768 netif->inputEvent(type, data);
769 }
770 }
771
772 unlockForArbitration();
773
774 return true;
775}
776
777//---------------------------------------------------------------------------
778// A client request for the controller to change to a new MTU size.
779
780IOReturn IONetworkController::setMaxPacketSize(UInt32 maxSize)
781{
782 return kIOReturnUnsupported;
783}
784
785//---------------------------------------------------------------------------
786// Transmit a packet mbuf.
787
788UInt32 IONetworkController::outputPacket(struct mbuf * m, void * param)
789{
790 // The implementation here is simply a sink-hole, all packets are
791 // dropped.
792
793 if (m) freePacket(m);
794 return 0;
795}
796
797//---------------------------------------------------------------------------
798// Report features supported by the controller and/or driver.
799
800UInt32 IONetworkController::getFeatures() const
801{
802 return 0;
803}
804
805//---------------------------------------------------------------------------
806// Create default description strings.
807
808const OSString * IONetworkController::newVendorString() const
809{
810 return 0;
811}
812
813const OSString * IONetworkController::newModelString() const
814{
815 return 0;
816}
817
818const OSString * IONetworkController::newRevisionString() const
819{
820 return 0;
821}
822
823//---------------------------------------------------------------------------
824// Encode a client command received by executeCommand().
825
826struct cmdStruct {
827 OSObject * client;
828 void * target;
829 IONetworkController::Action action;
830 void * param0;
831 void * param1;
832 void * param2;
833 void * param3;
834 IOReturn ret;
835};
836
837//---------------------------------------------------------------------------
838// Get the command client object.
839
840OSObject * IONetworkController::getCommandClient() const
841{
842 return ( _workLoop->inGate() ? _cmdClient : 0 );
843}
844
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.
853//
854// interface: The interface object to be configured.
855//
856// Returns true if configuration was successful, false otherwise (this
857// will cause attachInterface() to fail).
858
859bool IONetworkController::configureInterface(IONetworkInterface * interface)
860{
861 IOOutputAction handler;
862 OSObject * target;
863 bool ret;
864 IONetworkData * stats;
865
866 if (!OSDynamicCast(IONetworkInterface, interface))
867 return false;
868
869 IOOutputQueue * outQueue = getOutputQueue();
870
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.
876
877 if (outQueue)
878 {
879 target = outQueue;
880 handler = outQueue->getOutputHandler();
881
882 stats = outQueue->getStatisticsData();
883 interface->addNetworkData(stats);
884 }
885 else
886 {
887 target = this;
888 handler = getOutputHandler();
889 }
890 ret = interface->registerOutputHandler(target, handler);
891
892 return ret;
893}
894
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().
902//
903// Returns a newly allocated and initialized IOOutputQueue instance.
904
905IOOutputQueue * IONetworkController::createOutputQueue()
906{
907 return 0;
908}
909
910//---------------------------------------------------------------------------
911// Return the output queue allocated though createOutputQueue().
912
913IOOutputQueue * IONetworkController::getOutputQueue() const
914{
915 return _outputQueue;
916}
917
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.
925//
926// constraintsP: A pointer to an IOPacketBufferConstraints structure
927// that that this method is expected to initialize.
928// See IOPacketBufferConstraints structure definition.
929
930void IONetworkController::getPacketBufferConstraints(
931 IOPacketBufferConstraints * constraintsP) const
932{
933 assert(constraintsP);
934 constraintsP->alignStart = kIOPacketBufferAlign1;
935 constraintsP->alignLength = kIOPacketBufferAlign1;
936}
937
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.
943//
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.
947//
948// If (size + alignments) is smaller than MCLBYTES, then this function
949// will always return a single mbuf header or cluster.
950//
951// The allocation is guaranteed not to block. If a packet cannot be
952// allocated, this function will return NULL.
953
954#define IO_APPEND_MBUF(head, tail, m) { \
955 if (tail) { \
956 (tail)->m_next = (m); \
957 (tail) = (m); \
958 } \
959 else { \
960 (head) = (tail) = (m); \
961 (head)->m_pkthdr.len = 0; \
962 } \
963}
964
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) ) \
968 & ~(mask)); \
969 } \
970}
971
972#define IO_ALIGN_MBUF(m, size, smask, lmask) { \
973 IO_ALIGN_MBUF_START((m), (smask)); \
974 (m)->m_len = ((size) - (smask)) & ~(lmask); \
975}
976
977static struct mbuf * allocateMbuf( UInt32 size, UInt32 smask, UInt32 lmask )
978{
979 struct mbuf * m;
980 struct mbuf * head = 0;
981 struct mbuf * tail = 0;
982 UInt32 capacity;
983
984 while ( size )
985 {
986 // Allocate a mbuf. For the initial mbuf segment, allocate a
987 // mbuf header.
988
989 if ( head == 0 )
990 {
991 MGETHDR( m, M_DONTWAIT, MT_DATA );
992 capacity = MHLEN;
993 }
994 else
995 {
996 MGET( m, M_DONTWAIT, MT_DATA );
997 capacity = MLEN;
998 }
999
1000 if ( m == 0 ) goto error; // mbuf allocation error
1001
1002 // Append the new mbuf to the tail of the mbuf chain.
1003
1004 IO_APPEND_MBUF( head, tail, m );
1005
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.
1009
1010 if ( ( size + smask + lmask ) > capacity )
1011 {
1012 MCLGET( m, M_DONTWAIT );
1013 if ( (m->m_flags & M_EXT) == 0 ) goto error;
1014 capacity = MCLBYTES;
1015 }
1016
1017 // Align the mbuf per driver's specifications.
1018
1019 IO_ALIGN_MBUF( m, capacity, smask, lmask );
1020
1021 // Compute the number of bytes needed after accounting for the
1022 // current mbuf allocation.
1023
1024 if ( (UInt) m->m_len > size )
1025 m->m_len = size;
1026
1027 size -= m->m_len;
1028
1029 // Update the total length in the packet header.
1030
1031 head->m_pkthdr.len += m->m_len;
1032 }
1033
1034 return head;
1035
1036error:
1037 if ( head ) m_freem(head);
1038 return 0;
1039}
1040
1041struct mbuf * IONetworkController::allocatePacket( UInt32 size )
1042{
1043 struct mbuf * m;
1044
1045 do {
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.
1050
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;
1055 }
1056 else
1057 {
1058 MGETHDR( m, M_DONTWAIT, MT_DATA );
1059 if ( m == 0 ) break;
1060 }
1061
1062 // Align start of mbuf buffer.
1063
1064 IO_ALIGN_MBUF_START( m, _alignStart );
1065
1066 // No length adjustment for single mbuf.
1067 // Driver gets what it asked for.
1068
1069 m->m_pkthdr.len = m->m_len = size;
1070 }
1071 else
1072 {
1073 m = allocateMbuf(size, _alignStart, _alignLength);
1074 }
1075 } while ( false );
1076
1077 return m;
1078}
1079
1080//---------------------------------------------------------------------------
1081// Release the mbuf back to the free pool.
1082
1083void IONetworkController::freePacket(struct mbuf * m, IOOptionBits options)
1084{
1085 assert(m);
1086
1087 if ( options & kDelayFree )
1088 {
1089 m->m_nextpkt = _freeList;
1090 _freeList = m;
1091 }
1092 else
1093 {
1094 m_freem_list(m);
1095 }
1096}
1097
1098UInt32 IONetworkController::releaseFreePackets()
1099{
1100 UInt32 count = 0;
1101
1102 if ( _freeList )
1103 {
1104 count = m_freem_list( _freeList );
1105 _freeList = 0;
1106 }
1107 return count;
1108}
1109
1110static inline bool IO_COPY_MBUF(
1111 const struct mbuf * src,
1112 struct mbuf * dst,
1113 int length)
1114{
1115 caddr_t src_dat, dst_dat;
1116 int dst_len, src_len;
1117
1118 assert(src && dst);
1119
1120 dst_len = dst->m_len;
1121 dst_dat = dst->m_data;
1122
1123 while (src) {
1124
1125 src_len = src->m_len;
1126 src_dat = src->m_data;
1127
1128 if (src_len > length)
1129 src_len = length;
1130
1131 while (src_len) {
1132
1133 if (dst_len >= src_len) {
1134 // copy entire src mbuf to dst mbuf.
1135
1136 bcopy(src_dat, dst_dat, src_len);
1137 length -= src_len;
1138 dst_len -= src_len;
1139 dst_dat += src_len;
1140 src_len = 0;
1141 }
1142 else {
1143 // fill up dst mbuf with some portion of the data in
1144 // the src mbuf.
1145
1146 bcopy(src_dat, dst_dat, dst_len); // dst_len = 0?
1147 length -= dst_len;
1148 dst_len = 0;
1149 src_len -= dst_len;
1150 }
1151
1152 // Go to the next destination mbuf segment.
1153
1154 if (dst_len == 0) {
1155 if (!(dst = dst->m_next))
1156 return (length == 0);
1157 dst_len = dst->m_len;
1158 dst_dat = dst->m_data;
1159 }
1160
1161 } /* while (src_len) */
1162
1163 src = src->m_next;
1164
1165 } /* while (src) */
1166
1167 return (length == 0); // returns true on success.
1168}
1169
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.
1174//
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.
1180//
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.
1184
1185struct mbuf * IONetworkController::replacePacket(struct mbuf ** mp,
1186 UInt32 size = 0)
1187{
1188 assert((mp != NULL) && (*mp != NULL));
1189
1190 struct mbuf * m = *mp;
1191
1192 // If size is zero, then size is taken from the source mbuf.
1193
1194 if (size == 0) size = m->m_pkthdr.len;
1195
1196 // Allocate a new packet to replace the current packet.
1197
1198 if ( (*mp = allocatePacket(size)) == 0 )
1199 {
1200 *mp = m; m = 0;
1201 }
1202
1203 return m;
1204}
1205
1206//---------------------------------------------------------------------------
1207// Make a copy of a mbuf, and return the copy. The source mbuf is not modified.
1208//
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.
1212//
1213// Returns a new mbuf created from the source packet.
1214
1215struct mbuf * IONetworkController::copyPacket(const struct mbuf * m,
1216 UInt32 size = 0)
1217{
1218 struct mbuf * mn;
1219
1220 assert(m != NULL);
1221
1222 // If size is zero, then size is taken from the source mbuf.
1223
1224 if (size == 0) size = m->m_pkthdr.len;
1225
1226 // Copy the current mbuf to the new mbuf, and return the new mbuf.
1227 // The input mbuf is left intact.
1228
1229 if ( (mn = allocatePacket(size)) == 0 ) return 0;
1230
1231 if (!IO_COPY_MBUF(m, mn, size))
1232 {
1233 freePacket(mn); mn = 0;
1234 }
1235
1236 return mn;
1237}
1238
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.
1246//
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.
1253//
1254// Returns a replacement or a copy of the source mbuf, 0 if mbuf
1255// allocation failed.
1256
1257struct mbuf * IONetworkController::replaceOrCopyPacket(struct mbuf ** mp,
1258 UInt32 rcvlen,
1259 bool * replacedP)
1260{
1261 struct mbuf * m;
1262
1263 assert((mp != NULL) && (*mp != NULL));
1264
1265 if ( (rcvlen + _alignPadding) > MHLEN )
1266 {
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.
1271
1272 m = *mp;
1273
1274 if ( (*mp = allocatePacket(m->m_pkthdr.len)) == 0 )
1275 {
1276 *mp = m; m = 0; // error recovery
1277 }
1278
1279 *replacedP = true;
1280 }
1281 else
1282 {
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.
1286
1287 if ( (m = allocatePacket(rcvlen)) == 0 ) return 0;
1288
1289 if (!IO_COPY_MBUF(*mp, m, rcvlen))
1290 {
1291 freePacket(m); m = 0;
1292 }
1293
1294 *replacedP = false;
1295 }
1296
1297 return m;
1298}
1299
1300//---------------------------------------------------------------------------
1301// Get hardware support of network/transport layer checksums.
1302
1303IOReturn
1304IONetworkController::getChecksumSupport( UInt32 * checksumMask,
1305 UInt32 checksumFamily,
1306 bool isOutput )
1307{
1308 return kIOReturnUnsupported;
1309}
1310
1311//---------------------------------------------------------------------------
1312// Update a mbuf with the result from the hardware checksum engine.
1313
1314#define kTransportLayerPartialChecksums \
1315 ( kChecksumTCPNoPseudoHeader | \
1316 kChecksumUDPNoPseudoHeader | \
1317 kChecksumTCPSum16 )
1318
1319#define kTransportLayerFullChecksums \
1320 ( kChecksumTCP | kChecksumUDP )
1321
1322bool
1323IONetworkController::setChecksumResult( struct mbuf * m,
1324 UInt32 family,
1325 UInt32 result,
1326 UInt32 valid,
1327 UInt32 param0 = 0,
1328 UInt32 param1 = 0 )
1329{
1330#ifdef HW_CSUM_SUPPORT
1331 // Reporting something that is valid without checking for it
1332 // is forbidden.
1333
1334 valid &= result;
1335
1336 // Initialize checksum result fields in the packet.
1337
1338 m->m_pkthdr.csum_flags = 0;
1339
1340 if ( family != kChecksumFamilyTCPIP )
1341 {
1342 return false;
1343 }
1344
1345 // Set the result for the network layer (IP) checksum.
1346
1347 if ( result & kChecksumIP )
1348 {
1349 m->m_pkthdr.csum_flags = CSUM_IP_CHECKED;
1350 if ( valid & kChecksumIP )
1351 m->m_pkthdr.csum_flags |= CSUM_IP_VALID;
1352 }
1353
1354 // Now examine the transport layer checksum flags.
1355
1356 if ( valid & kTransportLayerFullChecksums )
1357 {
1358 // Excellent, hardware did account for the pseudo-header
1359 // and no "partial" checksum value is required.
1360
1361 m->m_pkthdr.csum_flags |= ( CSUM_DATA_VALID | CSUM_PSEUDO_HDR );
1362 m->m_pkthdr.csum_data = 0xffff; // fake a valid checksum value
1363 }
1364 else if ( result & kTransportLayerPartialChecksums )
1365 {
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.
1370
1371 m->m_pkthdr.csum_flags |= CSUM_DATA_VALID;
1372 m->m_pkthdr.csum_data = (UInt16) param0;
1373
1374 if ( result & kChecksumTCPSum16 )
1375 {
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.
1381
1382 m->m_pkthdr.csum_flags |= CSUM_TCP_SUM; // XXX - fake constant
1383 m->m_pkthdr.csum_data |= (((UInt16) param1) << 16);
1384 }
1385 }
1386 return true;
1387#else
1388 return false;
1389#endif HW_CSUM_SUPPORT
1390}
1391
1392//---------------------------------------------------------------------------
1393// Get the checksums that must be performed by the hardware for the
1394// given packet, before it is sent on the network.
1395
1396void
1397IONetworkController::getChecksumDemand( const struct mbuf * m,
1398 UInt32 checksumFamily,
1399 UInt32 * demandMask,
1400 void * param0 = 0,
1401 void * param1 = 0 )
1402{
1403#ifdef HW_CSUM_SUPPORT
1404 if ( checksumFamily != kChecksumFamilyTCPIP )
1405 {
1406 *demandMask = 0; return;
1407 }
1408
1409 *demandMask = m->m_pkthdr.csum_flags & ( kChecksumIP |
1410 kChecksumTCP |
1411 kChecksumUDP |
1412 kChecksumTCPSum16 );
1413
1414 if ( m->m_pkthdr.csum_flags & kChecksumTCPSum16 )
1415 {
1416 // param0 is start offset (XXX - range?)
1417 // param1 is stuff offset (XXX - range?)
1418
1419 if (param0)
1420 *((UInt16 *) param0) = (UInt16) (m->m_pkthdr.csum_data);
1421 if (param1)
1422 *((UInt16 *) param1) = (UInt16) (m->m_pkthdr.csum_data >> 16);
1423 }
1424#else
1425 *demandMask = 0;
1426 return;
1427#endif HW_CSUM_SUPPORT
1428}
1429
1430#if 0
1431//---------------------------------------------------------------------------
1432// Used for debugging only. Log the mbuf fields.
1433
1434static void _logMbuf(struct mbuf * m)
1435{
1436 if (!m) {
1437 IOLog("logMbuf: NULL mbuf\n");
1438 return;
1439 }
1440
1441 while (m) {
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);
1448
1449 if (m->m_flags & M_PKTHDR)
1450 IOLog("m_pkthdr.len : %d\n", (UInt) m->m_pkthdr.len);
1451
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);
1455 }
1456
1457 m = m->m_next;
1458 }
1459 IOLog("\n");
1460}
1461#endif /* 0 */
1462
1463//---------------------------------------------------------------------------
1464// Allocate and attache a new IOKernelDebugger client object.
1465//
1466// debuggerP: A handle that is updated by this method
1467// with the allocated IOKernelDebugger instance.
1468//
1469// Returns true on success, false otherwise.
1470
1471bool IONetworkController::attachDebuggerClient(IOKernelDebugger ** debugger)
1472{
1473 IOKernelDebugger * client;
1474 bool ret = false;
1475
1476 // Prepare the controller.
1477
1478 if (executeCommand(this, &IONetworkController::handleCommand,
1479 this, (void *) kCommandPrepare) != kIOReturnSuccess)
1480 {
1481 return false;
1482 }
1483
1484 // Create a debugger client nub and register the static
1485 // member functions as the polled-mode handlers.
1486
1487 client = IOKernelDebugger::debugger( this,
1488 &debugTxHandler,
1489 &debugRxHandler );
1490
1491 if ( client && !client->attach(this) )
1492 {
1493 // Unable to attach the client object.
1494 client->terminate( kIOServiceRequired | kIOServiceSynchronous );
1495 client->release();
1496 client = 0;
1497 }
1498
1499 *debugger = client;
1500
1501 if ( client )
1502 {
1503 client->registerService();
1504 ret = true;
1505 }
1506
1507 return ret;
1508}
1509
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.
1514//
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.
1518
1519void IONetworkController::detachDebuggerClient(IOKernelDebugger * debugger)
1520{
1521 if (OSDynamicCast(IOKernelDebugger, debugger) == 0)
1522 return;
1523
1524 // Terminate the debugger client and return after the client has
1525 // been terminated.
1526
1527 debugger->terminate(kIOServiceRequired | kIOServiceSynchronous);
1528}
1529
1530//---------------------------------------------------------------------------
1531// An enable request from an IOKernelDebugger client.
1532
1533IOReturn IONetworkController::enable(IOKernelDebugger * debugger)
1534{
1535 return kIOReturnSuccess;
1536}
1537
1538//---------------------------------------------------------------------------
1539// A disable request from an IOKernelDebugger client.
1540
1541IOReturn IONetworkController::disable(IOKernelDebugger * debugger)
1542{
1543 return kIOReturnSuccess;
1544}
1545
1546//---------------------------------------------------------------------------
1547// Take and release the debugger lock.
1548
1549void IONetworkController::reserveDebuggerLock()
1550{
1551 if ( _debugLockCount++ == 0 )
1552 {
1553 _debugLockState = IODebuggerLock( this );
1554 }
1555}
1556
1557void IONetworkController::releaseDebuggerLock()
1558{
1559 if ( --_debugLockCount == 0 )
1560 {
1561 IODebuggerUnlock( _debugLockState );
1562 }
1563 assert( _debugLockCount >= 0 );
1564}
1565
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.
1572
1573void IONetworkController::debugRxHandler(IOService * handler,
1574 void * buffer,
1575 UInt32 * length,
1576 UInt32 timeout)
1577{
1578 ((IONetworkController *) handler)->receivePacket(buffer,
1579 length,
1580 timeout);
1581}
1582
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.
1589
1590void IONetworkController::debugTxHandler(IOService * handler,
1591 void * buffer,
1592 UInt32 length)
1593{
1594 ((IONetworkController *) handler)->sendPacket(buffer, length);
1595}
1596
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.
1606//
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.
1613
1614void IONetworkController::receivePacket(void * /*pkt*/,
1615 UInt32 * /*pkt_len*/,
1616 UInt32 /*timeout*/)
1617{
1618 IOLog("IONetworkController::%s()\n", __FUNCTION__);
1619}
1620
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.
1631//
1632// pkt: Pointer to a transmit buffer containing the packet to be sent.
1633// pkt_len: The amount of data in the transmit buffer.
1634
1635void IONetworkController::sendPacket(void * /*pkt*/, UInt32 /*pkt_len*/)
1636{
1637 IOLog("IONetworkController::%s()\n", __FUNCTION__);
1638}
1639
1640//---------------------------------------------------------------------------
1641// Report the link status and the active medium.
1642
1643bool IONetworkController::setLinkStatus(
1644 UInt32 status,
1645 const IONetworkMedium * activeMedium,
1646 UInt64 speed,
1647 OSData * data)
1648{
1649 bool success = true;
1650 bool changed = false;
1651 UInt32 linkEvent = 0;
1652 const OSSymbol * name = activeMedium ? activeMedium->getName() :
1653 gIONullMediumName;
1654
1655 if (data == 0)
1656 data = (OSData *) gIONullLinkData;
1657
1658 if ((speed == 0) && activeMedium)
1659 speed = activeMedium->getSpeed();
1660
1661 MEDIUM_LOCK;
1662
1663 // Update kIOActiveMedium property.
1664
1665 if (name != _lastActiveMediumName)
1666 {
1667 if ( setProperty(gIOActiveMediumKey, (OSSymbol *) name) )
1668 {
1669 changed = true;
1670 _lastActiveMediumName = name;
1671 }
1672 else
1673 success = false;
1674 }
1675
1676 // Update kIOLinkData property.
1677
1678 if (data != _lastLinkData)
1679 {
1680 if ( setProperty(gIOLinkDataKey, data) )
1681 {
1682 changed = true;
1683 _lastLinkData = data;
1684 }
1685 else
1686 success = false;
1687 }
1688
1689 // Update kIOLinkStatus property.
1690
1691 if (status != _linkStatus->unsigned32BitValue())
1692 {
1693 if (status & kIONetworkLinkValid)
1694 {
1695 linkEvent = (status & kIONetworkLinkActive) ?
1696 kIONetworkEventTypeLinkUp :
1697 kIONetworkEventTypeLinkDown;
1698 }
1699 _linkStatus->setValue(status);
1700 changed = true;
1701 }
1702
1703 // Update kIOLinkSpeed property.
1704
1705 if (speed != _linkSpeed->unsigned64BitValue())
1706 {
1707 _linkSpeed->setValue(speed);
1708 changed = true;
1709 }
1710
1711 MEDIUM_UNLOCK;
1712
1713 // Broadcast a link event to interface objects.
1714
1715 if (linkEvent)
1716 _broadcastEvent(linkEvent);
1717
1718 return success;
1719}
1720
1721//---------------------------------------------------------------------------
1722// Returns the medium dictionary published by the driver through
1723// publishMediumDictionary(). Use copyMediumDictionary() to get a copy
1724// of the medium dictionary.
1725//
1726// Returns the published medium dictionary, or 0 if the driver has not
1727// yet published a medium dictionary through publishMediumDictionary().
1728
1729const OSDictionary * IONetworkController::getMediumDictionary() const
1730{
1731 return (OSDictionary *) getProperty(kIOMediumDictionary);
1732}
1733
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.
1739//
1740// Returns a copy of the medium dictionary, or 0 if the driver has not
1741// published a medium dictionary through publishMediumDictionary().
1742
1743OSDictionary * IONetworkController::copyMediumDictionary() const
1744{
1745 const OSDictionary * mediumDict;
1746 OSDictionary * copy = 0;
1747
1748 MEDIUM_LOCK;
1749
1750 mediumDict = getMediumDictionary();
1751
1752 if (mediumDict)
1753 {
1754 copy = OSDictionary::withDictionary(mediumDict,
1755 mediumDict->getCount());
1756 }
1757
1758 MEDIUM_UNLOCK;
1759
1760 return copy;
1761}
1762
1763//---------------------------------------------------------------------------
1764// A client request to change the media selection.
1765
1766IOReturn IONetworkController::selectMedium(const IONetworkMedium * medium)
1767{
1768 return kIOReturnUnsupported;
1769}
1770
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
1775// medium.
1776
1777IOReturn IONetworkController::selectMediumWithName(const OSSymbol * mediumName)
1778{
1779 OSSymbol * currentMediumName;
1780 IONetworkMedium * newMedium = 0;
1781 bool doChange = true;
1782 IOReturn ret = kIOReturnSuccess;
1783
1784 if (OSDynamicCast(OSSymbol, mediumName) == 0)
1785 return kIOReturnBadArgument;
1786
1787 MEDIUM_LOCK;
1788
1789 do {
1790 const OSDictionary * mediumDict = getMediumDictionary();
1791 if (!mediumDict)
1792 {
1793 // no medium dictionary, bail out.
1794 ret = kIOReturnUnsupported;
1795 break;
1796 }
1797
1798 // Lookup the new medium in the dictionary.
1799
1800 newMedium = (IONetworkMedium *) mediumDict->getObject(mediumName);
1801 if (!newMedium)
1802 {
1803 ret = kIOReturnBadArgument;
1804 break; // not found, invalid mediumName.
1805 }
1806
1807 newMedium->retain();
1808
1809 // Lookup the current medium key to avoid unnecessary
1810 // medium changes.
1811
1812 currentMediumName = (OSSymbol *) getProperty(gIOCurrentMediumKey);
1813
1814 // Is change necessary?
1815
1816 if (currentMediumName && mediumName->isEqualTo(currentMediumName))
1817 doChange = false;
1818 }
1819 while (0);
1820
1821 MEDIUM_UNLOCK;
1822
1823 if (newMedium)
1824 {
1825 // Call the driver's selectMedium() without holding the medium lock.
1826
1827 if (doChange)
1828 ret = selectMedium(newMedium);
1829
1830 // Remove the earlier retain.
1831
1832 newMedium->release();
1833 }
1834
1835 return ret;
1836}
1837
1838//---------------------------------------------------------------------------
1839// Designate an entry in the published medium dictionary as
1840// the current selected medium.
1841
1842bool IONetworkController::setSelectedMedium(const IONetworkMedium * medium)
1843{
1844 bool success = true;
1845 bool changed = false;
1846 const OSSymbol * name = medium ? medium->getName() : gIONullMediumName;
1847
1848 MEDIUM_LOCK;
1849
1850 if (name != _lastCurrentMediumName)
1851 {
1852 if ( setProperty(gIOCurrentMediumKey, (OSSymbol *) name) )
1853 {
1854 changed = true;
1855 _lastCurrentMediumName = name;
1856 }
1857 else
1858 success = false;
1859 }
1860
1861 MEDIUM_UNLOCK;
1862
1863#if 0
1864 if (changed)
1865 _broadcastEvent(kIONetworkEventTypeLinkChange);
1866#endif
1867
1868 return success;
1869}
1870
1871//---------------------------------------------------------------------------
1872// Get the current selected medium.
1873
1874const IONetworkMedium * IONetworkController::getSelectedMedium() const
1875{
1876 IONetworkMedium * medium = 0;
1877 OSSymbol * mediumName;
1878
1879 MEDIUM_LOCK;
1880
1881 do {
1882 const OSDictionary * mediumDict = getMediumDictionary();
1883 if (!mediumDict) // no medium dictionary, bail out.
1884 break;
1885
1886 // Fetch the current medium name from the property table.
1887
1888 mediumName = (OSSymbol *) getProperty(gIOCurrentMediumKey);
1889
1890 // Make sure the current medium name points to an entry in
1891 // the medium dictionary.
1892
1893 medium = (IONetworkMedium *) mediumDict->getObject(mediumName);
1894
1895 // Invalid current medium, try the default medium.
1896
1897 if ( medium == 0 )
1898 {
1899 OSString * aString;
1900
1901 // This comes from the driver's property list.
1902 // More checking is done to avoid surprises.
1903
1904 aString = OSDynamicCast( OSString,
1905 getProperty(gIODefaultMediumKey) );
1906
1907 medium = (IONetworkMedium *) mediumDict->getObject(aString);
1908 }
1909 }
1910 while (0);
1911
1912 MEDIUM_UNLOCK;
1913
1914 return medium;
1915}
1916
1917//---------------------------------------------------------------------------
1918// A private function to verify a medium dictionary. Returns true if the
1919// dictionary is OK.
1920
1921static bool verifyMediumDictionary(const OSDictionary * mediumDict)
1922{
1923 OSCollectionIterator * iter;
1924 bool verifyOk = true;
1925 OSSymbol * key;
1926
1927 if (!OSDynamicCast(OSDictionary, mediumDict))
1928 return false; // invalid argument
1929
1930 if (mediumDict->getCount() == 0)
1931 return false; // empty dictionary
1932
1933 iter = OSCollectionIterator::withCollection((OSDictionary *) mediumDict);
1934 if (!iter)
1935 return false; // cannot allocate iterator
1936
1937 while ((key = (OSSymbol *) iter->getNextObject()))
1938 {
1939 if ( !OSDynamicCast(IONetworkMedium, mediumDict->getObject(key)) )
1940 {
1941 verifyOk = false; // non-medium object in dictionary
1942 break;
1943 }
1944 }
1945
1946 iter->release();
1947
1948 return verifyOk;
1949}
1950
1951//---------------------------------------------------------------------------
1952// Publish a dictionary of IONetworkMedium objects.
1953
1954bool
1955IONetworkController::publishMediumDictionary(const OSDictionary * mediumDict)
1956{
1957 OSDictionary * cloneDict;
1958 bool ret = false;
1959
1960 if (!verifyMediumDictionary(mediumDict))
1961 return false; // invalid dictionary
1962
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.
1966
1967 cloneDict = OSDictionary::withDictionary(mediumDict,
1968 mediumDict->getCount());
1969 if (!cloneDict)
1970 return false; // unable to create a copy
1971
1972 MEDIUM_LOCK;
1973
1974 // Add the dictionary to the property table.
1975
1976 if (setProperty(kIOMediumDictionary, cloneDict))
1977 {
1978 const OSSymbol * mediumName;
1979
1980 // Update kIOSelectedMedium property.
1981
1982 mediumName = (OSSymbol *) getProperty(gIOCurrentMediumKey);
1983 if (cloneDict->getObject(mediumName) == 0)
1984 {
1985 mediumName = gIONullMediumName;
1986 }
1987 setProperty(gIOCurrentMediumKey, (OSSymbol *) mediumName);
1988 _lastCurrentMediumName = mediumName;
1989
1990 // Update kIOActiveMedium property.
1991
1992 mediumName = (OSSymbol *) getProperty(gIOActiveMediumKey);
1993 if (cloneDict->getObject(mediumName) == 0)
1994 {
1995 mediumName = gIONullMediumName;
1996 }
1997 setProperty(gIOActiveMediumKey, (OSSymbol *) mediumName);
1998 _lastActiveMediumName = mediumName;
1999
2000 ret = true;
2001 }
2002
2003 MEDIUM_UNLOCK;
2004
2005 // Retained by the property table. drop our retain count.
2006
2007 cloneDict->release();
2008
2009#if 0
2010 // Broadcast a link change event.
2011
2012 _broadcastEvent(kIONetworkEventTypeLinkChange);
2013#endif
2014
2015 return ret;
2016}
2017
2018//---------------------------------------------------------------------------
2019// Static function called by the internal IOCommandGate object to
2020// handle a runAction() request invoked by executeCommand().
2021
2022IOReturn IONetworkController::executeCommandAction(OSObject * owner,
2023 void * arg0,
2024 void * /* arg1 */,
2025 void * /* arg2 */,
2026 void * /* arg3 */)
2027{
2028 IONetworkController * self = (IONetworkController *) owner;
2029 cmdStruct * cmdP = (cmdStruct *) arg0;
2030 IOReturn ret;
2031 bool accept = true;
2032 OSObject * oldClient;
2033
2034 assert(cmdP && self);
2035
2036 oldClient = self->_cmdClient;
2037
2038 if (accept != true)
2039 {
2040 // Command rejected.
2041 ret = kIOReturnNotPermitted;
2042 }
2043 else
2044 {
2045 self->_cmdClient = cmdP->client;
2046
2047 cmdP->ret = (*cmdP->action)( cmdP->target,
2048 cmdP->param0,
2049 cmdP->param1,
2050 cmdP->param2,
2051 cmdP->param3 );
2052
2053 self->_cmdClient = oldClient;
2054
2055 ret = kIOReturnSuccess;
2056 }
2057
2058 return ret;
2059}
2060
2061//---------------------------------------------------------------------------
2062// Perform an "action" that is synchronized by the command gate.
2063
2064IOReturn IONetworkController::executeCommand(OSObject * client,
2065 Action action,
2066 void * target,
2067 void * param0,
2068 void * param1,
2069 void * param2,
2070 void * param3)
2071{
2072 cmdStruct cmd;
2073 IOReturn ret;
2074
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;
2082
2083 // Execute the client command through the command gate. Client commands
2084 // are thus synchronized with the workloop returned by getWorkLoop().
2085
2086 ret = _cmdGate->runAction( (IOCommandGate::Action)
2087 &IONetworkController::executeCommandAction,
2088 (void *) &cmd ); /* arg0 - cmdStruct */
2089
2090 // If executeCommandAction() executed successfully, then return the
2091 // status from the client command that was executed.
2092
2093 if (ret == kIOReturnSuccess)
2094 ret = cmd.ret;
2095
2096 return ret;
2097}
2098
2099//---------------------------------------------------------------------------
2100// Called by executeCommand() to handle the client command on the
2101// workloop context.
2102
2103IOReturn IONetworkController::handleCommand(void * target,
2104 void * param0,
2105 void * param1,
2106 void * param2,
2107 void * param3)
2108{
2109
2110 IONetworkController * self = (IONetworkController *) target;
2111 UInt32 command = (UInt32) param0;
2112 IOService * client = (IOService *) param1;
2113 IOReturn ret;
2114
2115 switch (command)
2116 {
2117 case kCommandEnable:
2118 ret = self->enable(client);
2119 break;
2120
2121 case kCommandDisable:
2122 ret = self->disable(client);
2123 break;
2124
2125 case kCommandPrepare:
2126 ret = self->prepare();
2127 break;
2128
2129 default:
2130 ret = kIOReturnUnsupported;
2131 break;
2132 }
2133
2134 return ret;
2135}
2136
2137//---------------------------------------------------------------------------
2138// Issue an kCommandEnable command to handleCommand().
2139
2140IOReturn IONetworkController::doEnable(IOService * client)
2141{
2142 return executeCommand( client,
2143 &IONetworkController::handleCommand,
2144 this,
2145 (void *) kCommandEnable,
2146 (void *) client);
2147}
2148
2149//---------------------------------------------------------------------------
2150// Issue an kCommandDisable command to handleCommand().
2151
2152IOReturn IONetworkController::doDisable(IOService * client)
2153{
2154 return executeCommand( client,
2155 &IONetworkController::handleCommand,
2156 this,
2157 (void *) kCommandDisable,
2158 (void *) client);
2159}