]>
Commit | Line | Data |
---|---|---|
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 | // | |
41 | extern "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 | // | |
48 | typedef unsigned spl_t; | |
49 | extern spl_t (splimp)(void); | |
50 | } | |
51 | ||
52 | //------------------------------------------------------------------------- | |
53 | // Macros. | |
54 | ||
55 | #define super IOService | |
56 | ||
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); | |
90 | ||
91 | static 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 | // | |
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; | |
113 | ||
114 | // Global symbols. | |
115 | // | |
116 | const OSSymbol * gIONetworkFilterGroup; | |
117 | const OSSymbol * gIOEthernetWakeOnLANFilterGroup; | |
118 | ||
119 | // Constants for handleCommand(). | |
120 | // | |
121 | enum { | |
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 | ||
133 | void 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 | ||
169 | bool 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 | ||
223 | bool 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 | ||
356 | void 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 | ||
369 | IOReturn 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 | ||
381 | bool 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 | ||
397 | IOCommandGate * 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 | ||
407 | IOOutputAction 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 | ||
436 | bool | |
437 | IONetworkController::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 | ||
496 | void | |
497 | IONetworkController::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 | ||
522 | IOReturn 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 | ||
557 | bool 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 | ||
573 | void 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 | ||
585 | bool 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 | ||
597 | void 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 | ||
623 | IOReturn 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 | ||
638 | IOReturn 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 | ||
653 | IOReturn 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 | ||
662 | IOReturn 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 | ||
677 | bool 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 | ||
754 | bool 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 | ||
780 | IOReturn IONetworkController::setMaxPacketSize(UInt32 maxSize) | |
781 | { | |
782 | return kIOReturnUnsupported; | |
783 | } | |
784 | ||
785 | //--------------------------------------------------------------------------- | |
786 | // Transmit a packet mbuf. | |
787 | ||
788 | UInt32 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 | ||
800 | UInt32 IONetworkController::getFeatures() const | |
801 | { | |
802 | return 0; | |
803 | } | |
804 | ||
805 | //--------------------------------------------------------------------------- | |
806 | // Create default description strings. | |
807 | ||
808 | const OSString * IONetworkController::newVendorString() const | |
809 | { | |
810 | return 0; | |
811 | } | |
812 | ||
813 | const OSString * IONetworkController::newModelString() const | |
814 | { | |
815 | return 0; | |
816 | } | |
817 | ||
818 | const OSString * IONetworkController::newRevisionString() const | |
819 | { | |
820 | return 0; | |
821 | } | |
822 | ||
823 | //--------------------------------------------------------------------------- | |
824 | // Encode a client command received by executeCommand(). | |
825 | ||
826 | struct 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 | ||
840 | OSObject * 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 | ||
859 | bool 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 | ||
905 | IOOutputQueue * IONetworkController::createOutputQueue() | |
906 | { | |
907 | return 0; | |
908 | } | |
909 | ||
910 | //--------------------------------------------------------------------------- | |
911 | // Return the output queue allocated though createOutputQueue(). | |
912 | ||
913 | IOOutputQueue * 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 | ||
930 | void 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 | ||
977 | static 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 | ||
1036 | error: | |
1037 | if ( head ) m_freem(head); | |
1038 | return 0; | |
1039 | } | |
1040 | ||
1041 | struct 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 | ||
1083 | void 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 | ||
1098 | UInt32 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 | ||
1110 | static 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 | ||
1185 | struct 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 | ||
1215 | struct 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 | ||
1257 | struct 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 | ||
1303 | IOReturn | |
1304 | IONetworkController::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 | ||
1322 | bool | |
1323 | IONetworkController::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 | ||
1396 | void | |
1397 | IONetworkController::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 | ||
1434 | static 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 | ||
1471 | bool 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 | ||
1519 | void 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 | ||
1533 | IOReturn IONetworkController::enable(IOKernelDebugger * debugger) | |
1534 | { | |
1535 | return kIOReturnSuccess; | |
1536 | } | |
1537 | ||
1538 | //--------------------------------------------------------------------------- | |
1539 | // A disable request from an IOKernelDebugger client. | |
1540 | ||
1541 | IOReturn IONetworkController::disable(IOKernelDebugger * debugger) | |
1542 | { | |
1543 | return kIOReturnSuccess; | |
1544 | } | |
1545 | ||
1546 | //--------------------------------------------------------------------------- | |
1547 | // Take and release the debugger lock. | |
1548 | ||
1549 | void IONetworkController::reserveDebuggerLock() | |
1550 | { | |
1551 | if ( _debugLockCount++ == 0 ) | |
1552 | { | |
1553 | _debugLockState = IODebuggerLock( this ); | |
1554 | } | |
1555 | } | |
1556 | ||
1557 | void 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 | ||
1573 | void 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 | ||
1590 | void 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 | ||
1614 | void 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 | ||
1635 | void 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 | ||
1643 | bool 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 | ||
1729 | const 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 | ||
1743 | OSDictionary * 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 | ||
1766 | IOReturn 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 | ||
1777 | IOReturn 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 | ||
1842 | bool 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 | ||
1874 | const 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 | ||
1921 | static 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 | ||
1954 | bool | |
1955 | IONetworkController::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 | ||
2022 | IOReturn 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 | ||
2064 | IOReturn 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 | ||
2103 | IOReturn 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 | ||
2140 | IOReturn 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 | ||
2152 | IOReturn IONetworkController::doDisable(IOService * client) | |
2153 | { | |
2154 | return executeCommand( client, | |
2155 | &IONetworkController::handleCommand, | |
2156 | this, | |
2157 | (void *) kCommandDisable, | |
2158 | (void *) client); | |
2159 | } |