]> git.saurik.com Git - apple/xnu.git/blob - iokit/Families/IONetworking/IOEthernetInterface.cpp
4b975a606f323edb56a968d25241eecaaf8a2a9d
[apple/xnu.git] / iokit / Families / IONetworking / IOEthernetInterface.cpp
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 * IOEthernetInterface.cpp
26 *
27 * HISTORY
28 * 8-Jan-1999 Joe Liu (jliu) created.
29 *
30 */
31
32 #include <IOKit/assert.h>
33 #include <IOKit/IOLib.h>
34 #include <libkern/c++/OSData.h>
35 #include <IOKit/network/IOEthernetInterface.h>
36 #include <IOKit/network/IOEthernetController.h>
37 #include <IOKit/network/IONetworkUserClient.h>
38
39 extern "C" {
40 #include <sys/param.h>
41 #include <sys/errno.h>
42 #include <sys/socket.h>
43 #include <net/if.h>
44 #include <net/etherdefs.h>
45 #include <net/if_dl.h>
46 #include <net/if_types.h>
47 #include <sys/sockio.h>
48 #include <netinet/in_var.h>
49 #include <sys/malloc.h>
50 void arpwhohas(struct arpcom * ac, struct in_addr * addr);
51 }
52
53 //---------------------------------------------------------------------------
54
55 #define super IONetworkInterface
56
57 OSDefineMetaClassAndStructors( IOEthernetInterface, IONetworkInterface )
58 OSMetaClassDefineReservedUnused( IOEthernetInterface, 0);
59 OSMetaClassDefineReservedUnused( IOEthernetInterface, 1);
60 OSMetaClassDefineReservedUnused( IOEthernetInterface, 2);
61 OSMetaClassDefineReservedUnused( IOEthernetInterface, 3);
62 OSMetaClassDefineReservedUnused( IOEthernetInterface, 4);
63 OSMetaClassDefineReservedUnused( IOEthernetInterface, 5);
64 OSMetaClassDefineReservedUnused( IOEthernetInterface, 6);
65 OSMetaClassDefineReservedUnused( IOEthernetInterface, 7);
66 OSMetaClassDefineReservedUnused( IOEthernetInterface, 8);
67 OSMetaClassDefineReservedUnused( IOEthernetInterface, 9);
68 OSMetaClassDefineReservedUnused( IOEthernetInterface, 10);
69 OSMetaClassDefineReservedUnused( IOEthernetInterface, 11);
70 OSMetaClassDefineReservedUnused( IOEthernetInterface, 12);
71 OSMetaClassDefineReservedUnused( IOEthernetInterface, 13);
72 OSMetaClassDefineReservedUnused( IOEthernetInterface, 14);
73 OSMetaClassDefineReservedUnused( IOEthernetInterface, 15);
74
75 // The name prefix for all BSD Ethernet interfaces.
76 //
77 #define kIOEthernetInterfaceNamePrefix "en"
78
79 //---------------------------------------------------------------------------
80 // Macros
81
82 #ifdef DEBUG
83 #define DLOG(fmt, args...) IOLog(fmt, ## args)
84 #else
85 #define DLOG(fmt, args...)
86 #endif
87
88 UInt32 IOEthernetInterface::getFilters(const OSDictionary * dict,
89 const OSSymbol * group)
90 {
91 OSNumber * num;
92 UInt32 filters = 0;
93
94 assert( dict && group );
95
96 if (( num = (OSNumber *) dict->getObject(group) ))
97 {
98 filters = num->unsigned32BitValue();
99 }
100 return filters;
101 }
102
103 bool IOEthernetInterface::setFilters(OSDictionary * dict,
104 const OSSymbol * group,
105 UInt32 filters)
106 {
107 OSNumber * num;
108 bool ret = false;
109
110 assert( dict && group );
111
112 num = (OSNumber *) dict->getObject(group);
113 if ( num == 0 )
114 {
115 if (( num = OSNumber::withNumber(filters, 32) ))
116 {
117 ret = dict->setObject(group, num);
118 num->release();
119 }
120 }
121 else
122 {
123 num->setValue(filters);
124 ret = true;
125 }
126 return ret;
127 }
128
129 #define GET_REQUIRED_FILTERS(g) getFilters(_requiredFilters, (g))
130 #define GET_ACTIVE_FILTERS(g) getFilters(_activeFilters, (g))
131 #define GET_SUPPORTED_FILTERS(g) getFilters(_supportedFilters, (g))
132
133 #define SET_REQUIRED_FILTERS(g, v) setFilters(_requiredFilters, (g), (v))
134 #define SET_ACTIVE_FILTERS(g, v) setFilters(_activeFilters, (g), (v))
135
136 //---------------------------------------------------------------------------
137 // Initialize an IOEthernetInterface instance. Instance variables are
138 // initialized, and an arpcom structure is allocated.
139
140 bool IOEthernetInterface::init(IONetworkController * controller)
141 {
142 // Allocate an arpcom structure, then call super::init().
143 // We expect our superclass to call getIfnet() during its init()
144 // method, so arpcom must be allocated before calling super::init().
145
146 if ( (_arpcom = (struct arpcom *) IOMalloc(sizeof(*_arpcom))) == 0 )
147 {
148 DLOG("IOEthernetInterface: arpcom allocation failed\n");
149 return false;
150 }
151
152 // Pass the init() call to our superclass.
153
154 if ( super::init(controller) == false )
155 return false;
156
157 // Add an IONetworkData with room to hold an IOEthernetStats structure.
158 // This class does not reference the data object created, and no harm
159 // is done if the data object is released or replaced.
160
161 IONetworkData * data = IONetworkData::withInternalBuffer(
162 kIOEthernetStatsKey,
163 sizeof(IOEthernetStats));
164 if (data)
165 {
166 addNetworkData(data);
167 data->release();
168 }
169
170 // Create and initialize the filter dictionaries.
171
172 _requiredFilters = OSDictionary::withCapacity(4);
173 _activeFilters = OSDictionary::withCapacity(4);
174
175 if ( (_requiredFilters == 0) || (_activeFilters == 0) )
176 return false;
177
178 _supportedFilters = OSDynamicCast(OSDictionary,
179 controller->getProperty(kIOPacketFilters));
180 if ( _supportedFilters == 0 ) return false;
181 _supportedFilters->retain();
182
183 // Controller's Unicast (directed) and Broadcast filters should always
184 // be enabled. Those bits should never be cleared.
185
186 if ( !SET_REQUIRED_FILTERS( gIONetworkFilterGroup,
187 kIOPacketFilterUnicast |
188 kIOPacketFilterBroadcast )
189 || !SET_REQUIRED_FILTERS( gIOEthernetWakeOnLANFilterGroup, 0 )
190 || !SET_ACTIVE_FILTERS( gIONetworkFilterGroup, 0 )
191 || !SET_ACTIVE_FILTERS( gIOEthernetWakeOnLANFilterGroup, 0 ) )
192 {
193 return false;
194 }
195
196 // Publish filter dictionaries to property table.
197
198 setProperty( kIORequiredPacketFilters, _requiredFilters );
199 setProperty( kIOActivePacketFilters, _activeFilters );
200
201 return true;
202 }
203
204 //---------------------------------------------------------------------------
205 // Initialize the given ifnet structure. The argument specified is a pointer
206 // to an ifnet structure obtained through getIfnet(). IOEthernetInterface
207 // will initialize this structure in a manner that is appropriate for most
208 // Ethernet interfaces, then call super::initIfnet() to allow the superclass
209 // to perform generic interface initialization.
210 //
211 // ifp: Pointer to the ifnet structure to be initialized.
212 //
213 // Returns true on success, false otherwise.
214
215 bool IOEthernetInterface::initIfnet(struct ifnet * ifp)
216 {
217 struct arpcom * ac = (struct arpcom *) ifp;
218
219 assert(ac);
220
221 lock();
222
223 bzero(ac, sizeof(*ac));
224
225 // Set defaults suitable for Ethernet interfaces.
226
227 setInterfaceType( IFT_ETHER );
228 setMaxTransferUnit( ETHERMTU );
229 setMediaAddressLength( NUM_EN_ADDR_BYTES );
230 setMediaHeaderLength( ETHERHDRSIZE );
231 setFlags( IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS );
232
233 unlock();
234
235 return super::initIfnet(ifp);
236 }
237
238 //---------------------------------------------------------------------------
239 // Free the IOEthernetInterface instance. The memory allocated
240 // for the arpcom structure is released.
241
242 void IOEthernetInterface::free()
243 {
244 if ( _arpcom )
245 {
246 IOFree(_arpcom, sizeof(*_arpcom));
247 _arpcom = 0;
248 }
249
250 if ( _requiredFilters )
251 {
252 _requiredFilters->release();
253 _requiredFilters = 0;
254 }
255
256 if ( _activeFilters )
257 {
258 _activeFilters->release();
259 _activeFilters = 0;
260 }
261
262 if ( _supportedFilters )
263 {
264 _supportedFilters->release();
265 _supportedFilters = 0;
266 }
267
268 super::free();
269 }
270
271 //---------------------------------------------------------------------------
272 // This method returns a pointer to an ifnet structure maintained
273 // by the family specific interface object. IOEthernetInterface
274 // allocates an arpcom structure in init(), and returns a pointer
275 // to that structure when this method is called.
276 //
277 // Returns a pointer to an ifnet structure.
278
279 struct ifnet * IOEthernetInterface::getIfnet() const
280 {
281 return (&(_arpcom->ac_if));
282 }
283
284 //---------------------------------------------------------------------------
285 // The name of the interface advertised to the network layer
286 // is generated by concatenating the string returned by this method,
287 // and an unit number.
288 //
289 // Returns a pointer to a constant string "en". Thus Ethernet interfaces
290 // will be registered as en0, en1, etc.
291
292 const char * IOEthernetInterface::getNamePrefix() const
293 {
294 return kIOEthernetInterfaceNamePrefix;
295 }
296
297 //---------------------------------------------------------------------------
298 // Prepare the 'Ethernet' controller after it has been opened. This is called
299 // by IONetworkInterface after a controller has accepted an open from this
300 // interface. IOEthernetInterface uses this method to inspect the controller,
301 // and to cache certain controller properties, such as its hardware address.
302 // This method is called with the arbitration lock held.
303 //
304 // controller: The controller object that was opened.
305 //
306 // Returns true on success, false otherwise
307 // (which will cause the controller to be closed).
308
309 bool IOEthernetInterface::controllerDidOpen(IONetworkController * ctr)
310 {
311 bool ret = false;
312 OSData * addrData;
313 IOEthernetAddress * addr;
314
315 do {
316 // Call the controllerDidOpen() in superclass first.
317
318 if ( (ctr == 0) || (super::controllerDidOpen(ctr) == false) )
319 break;
320
321 // If the controller supports some form of multicast filtering,
322 // then set the ifnet IFF_MULTICAST flag.
323
324 if ( GET_SUPPORTED_FILTERS(gIONetworkFilterGroup) &
325 (kIOPacketFilterMulticast | kIOPacketFilterMulticastAll) )
326 {
327 setFlags(IFF_MULTICAST);
328 }
329
330 // Get the controller's MAC/Ethernet address.
331
332 addrData = OSDynamicCast(OSData, ctr->getProperty(kIOMACAddress));
333 if ( (addrData == 0) || (addrData->getLength() != NUM_EN_ADDR_BYTES) )
334 {
335 DLOG("%s: kIOMACAddress property access error (len %d)\n",
336 getName(), addrData ? addrData->getLength() : 0);
337 break;
338 }
339
340 addr = (IOEthernetAddress *) addrData->getBytesNoCopy();
341
342 #if 1 // Print the address
343 IOLog("%s: Ethernet address %02x:%02x:%02x:%02x:%02x:%02x\n",
344 ctr->getName(),
345 addr->bytes[0],
346 addr->bytes[1],
347 addr->bytes[2],
348 addr->bytes[3],
349 addr->bytes[4],
350 addr->bytes[5]);
351 #endif
352
353 // Copy the hardware address we obtained from the controller
354 // to the arpcom structure.
355
356 bcopy(addr, _arpcom->ac_enaddr, NUM_EN_ADDR_BYTES);
357
358 ret = true;
359 }
360 while (0);
361
362 return ret;
363 }
364
365 //---------------------------------------------------------------------------
366 // When a close from our last client is received, the interface will
367 // close the controller. But before the controller is closed, this method
368 // will be called by our superclass to perform any final cleanup. This
369 // method is called with the arbitration lock held.
370 //
371 // IOEthernetInterface will ensure that the controller is disabled.
372 //
373 // controller: The currently opened controller object.
374
375 void IOEthernetInterface::controllerWillClose(IONetworkController * ctr)
376 {
377 super::controllerWillClose(ctr);
378 }
379
380 //---------------------------------------------------------------------------
381 // Handle ioctl commands originated from the network layer.
382 // Commands not handled by this method are passed to our superclass.
383 //
384 // Argument convention is:
385 //
386 // arg0 - (struct ifnet *)
387 // arg1 - (void *)
388 //
389 // The commands handled by IOEthernetInterface are:
390 //
391 // SIOCSIFADDR
392 // SIOCSIFFLAGS
393 // SIOCADDMULTI
394 // SIOCDELMULTI
395 //
396 // Returns an error code defined in errno.h (BSD).
397
398 SInt32 IOEthernetInterface::performCommand( IONetworkController * ctr,
399 UInt32 cmd,
400 void * arg0,
401 void * arg1 )
402 {
403 SInt32 ret;
404
405 assert( arg0 == _arpcom );
406
407 if ( ctr == 0 ) return EINVAL;
408
409 switch ( cmd )
410 {
411 case SIOCSIFFLAGS:
412 case SIOCADDMULTI:
413 case SIOCDELMULTI:
414 case SIOCSIFADDR:
415
416 ret = (int) ctr->executeCommand(
417 this, /* client */
418 (IONetworkController::Action)
419 &IOEthernetInterface::performGatedCommand,
420 this, /* target */
421 ctr, /* param0 */
422 (void *) cmd, /* param1 */
423 arg0, /* param2 */
424 arg1 ); /* param3 */
425 break;
426
427 default:
428 // Unknown command, let our superclass deal with it.
429 ret = super::performCommand(ctr, cmd, arg0, arg1);
430 break;
431 }
432
433 return ret;
434 }
435
436 //---------------------------------------------------------------------------
437 // Handle an ioctl command on the controller's workloop context.
438
439 int IOEthernetInterface::performGatedCommand(void * target,
440 void * arg1_ctr,
441 void * arg2_cmd,
442 void * arg3_0,
443 void * arg4_1)
444 {
445 IOEthernetInterface * self = (IOEthernetInterface *) target;
446 IONetworkController * ctr = (IONetworkController *) arg1_ctr;
447 SInt ret = EOPNOTSUPP;
448
449 // Refuse to perform controller I/O if the controller is in a
450 // low-power state that makes it "unusable".
451
452 if ( self->_controllerLostPower ) return EPWROFF;
453
454 self->lock();
455
456 switch ( (UInt32) arg2_cmd )
457 {
458 case SIOCSIFADDR:
459 ret = self->syncSIOCSIFADDR(ctr);
460 break;
461
462 case SIOCSIFFLAGS:
463 ret = self->syncSIOCSIFFLAGS(ctr);
464 break;
465
466 case SIOCADDMULTI:
467 ret = self->syncSIOCADDMULTI(ctr);
468 break;
469
470 case SIOCDELMULTI:
471 ret = self->syncSIOCDELMULTI(ctr);
472 break;
473 }
474
475 self->unlock();
476
477 return ret;
478 }
479
480 //---------------------------------------------------------------------------
481 // enableController() is reponsible for calling the controller's enable()
482 // method and restoring the state of the controller. We assume that
483 // controllers can completely reset its state upon receiving a disable()
484 // method call. And when it is brought back up, the interface should
485 // assist in restoring the previous state of the Ethernet controller.
486
487 IOReturn IOEthernetInterface::enableController(IONetworkController * ctr)
488 {
489 IOReturn ret = kIOReturnSuccess;
490 bool enabled = false;
491 UInt32 filters;
492
493 assert(ctr);
494
495 do {
496 // Is controller already enabled? If so, exit and return success.
497
498 if ( _ctrEnabled )
499 break;
500
501 // Send the controller an enable command.
502
503 if ( (ret = ctr->enable((IOService *) this)) != kIOReturnSuccess )
504 break; // unable to enable the controller.
505
506 enabled = true;
507
508 // Disable all Wake-On-LAN filters.
509
510 filters = GET_ACTIVE_FILTERS(gIOEthernetWakeOnLANFilterGroup);
511
512 for (UInt i = 0; i < (sizeof(filters) * 8); i++)
513 {
514 if ((1 << i) & filters)
515 {
516 disableFilter(ctr, gIOEthernetWakeOnLANFilterGroup,
517 (1 << i));
518 }
519 }
520
521 // Restore current filter selection.
522
523 SET_ACTIVE_FILTERS(gIONetworkFilterGroup, 0);
524 filters = GET_REQUIRED_FILTERS(gIONetworkFilterGroup);
525
526 for (UInt i = 0; i < (sizeof(filters) * 8); i++)
527 {
528 if ((1 << i) & filters)
529 {
530 if ( (ret = enableFilter(ctr, gIONetworkFilterGroup,
531 (1 << i)))
532 != kIOReturnSuccess )
533 break;
534 }
535 }
536 if ( ret != kIOReturnSuccess )
537 break;
538
539 // Restore multicast filter settings.
540
541 syncSIOCADDMULTI(ctr);
542
543 _ctrEnabled = true;
544
545 } while (false);
546
547 // Disable the controller if a serious error has occurred after the
548 // controller has been enabled.
549
550 if ( enabled && (ret != kIOReturnSuccess) )
551 {
552 ctr->disable((IOService *) this);
553 }
554
555 return ret;
556 }
557
558 //---------------------------------------------------------------------------
559 // Handles SIOCSIFFLAGS ioctl command for Ethernet interfaces. The network
560 // stack has changed the if_flags field in ifnet. Our job is to go
561 // through if_flags and see what has changed, and act accordingly.
562 //
563 // The fact that if_flags contains both generic and Ethernet specific bits
564 // means that we cannot move some of the default flag processing to the
565 // superclass.
566
567 int IOEthernetInterface::syncSIOCSIFFLAGS(IONetworkController * ctr)
568 {
569 UInt16 flags = getFlags();
570 IOReturn ret = kIOReturnSuccess;
571
572 if ( ( ((flags & IFF_UP) == 0) || _controllerLostPower ) &&
573 ( flags & IFF_RUNNING ) )
574 {
575 // If interface is marked down and it is currently running,
576 // then stop it.
577
578 ctr->disable((IOService *) this);
579 flags &= ~IFF_RUNNING;
580 _ctrEnabled = false;
581 }
582 else if ( ( flags & IFF_UP ) &&
583 ( _controllerLostPower == false ) &&
584 ((flags & IFF_RUNNING) == 0) )
585 {
586 // If interface is marked up and it is currently stopped,
587 // then start it.
588
589 if ( (ret = enableController(ctr)) == kIOReturnSuccess )
590 flags |= IFF_RUNNING;
591 }
592
593 if ( flags & IFF_RUNNING )
594 {
595 IOReturn rc;
596
597 // We don't expect multiple flags to be changed for a given
598 // SIOCSIFFLAGS call.
599
600 // Promiscuous mode
601
602 rc = (flags & IFF_PROMISC) ?
603 enableFilter(ctr, gIONetworkFilterGroup,
604 kIOPacketFilterPromiscuous) :
605 disableFilter(ctr, gIONetworkFilterGroup,
606 kIOPacketFilterPromiscuous);
607
608 if (ret == kIOReturnSuccess) ret = rc;
609
610 // Multicast-All mode
611
612 rc = (flags & IFF_ALLMULTI) ?
613 enableFilter(ctr, gIONetworkFilterGroup,
614 kIOPacketFilterMulticastAll) :
615 disableFilter(ctr, gIONetworkFilterGroup,
616 kIOPacketFilterMulticastAll);
617
618 if (ret == kIOReturnSuccess) ret = rc;
619 }
620
621 // Update the flags field to pick up any modifications. Also update the
622 // property table to reflect any flag changes.
623
624 setFlags(flags, ~flags);
625
626 return errnoFromReturn(ret);
627 }
628
629 //---------------------------------------------------------------------------
630 // Handles SIOCSIFADDR ioctl.
631
632 SInt IOEthernetInterface::syncSIOCSIFADDR(IONetworkController * ctr)
633 {
634 IOReturn ret = kIOReturnSuccess;
635
636 // Interface is implicitly brought up by an SIOCSIFADDR ioctl.
637
638 setFlags(IFF_UP);
639
640 if ( (getFlags() & IFF_RUNNING) == 0 )
641 {
642 if ( (ret = enableController(ctr)) == kIOReturnSuccess )
643 setFlags(IFF_RUNNING);
644 }
645
646 return errnoFromReturn(ret);
647 }
648
649 //---------------------------------------------------------------------------
650 // Handle SIOCADDMULTI ioctl command.
651
652 SInt IOEthernetInterface::syncSIOCADDMULTI(IONetworkController * ctr)
653 {
654 IOReturn ret;
655
656 // Make sure multicast filter is active.
657
658 ret = enableFilter(ctr, gIONetworkFilterGroup, kIOPacketFilterMulticast);
659
660 if ( ret == kIOReturnSuccess )
661 {
662 // Load multicast addresses only if the filter was activated.
663
664 ret = setupMulticastFilter(ctr);
665
666 // If the list is now empty, then deactivate the multicast filter.
667
668 if ( _mcAddrCount == 0 )
669 {
670 IOReturn dret = disableFilter(ctr, gIONetworkFilterGroup,
671 kIOPacketFilterMulticast);
672
673 if (ret == kIOReturnSuccess) ret = dret;
674 }
675 }
676
677 return errnoFromReturn(ret);
678 }
679
680 //---------------------------------------------------------------------------
681 // Handle SIOCDELMULTI ioctl command.
682
683 SInt IOEthernetInterface::syncSIOCDELMULTI(IONetworkController * ctr)
684 {
685 return syncSIOCADDMULTI(ctr);
686 }
687
688 //---------------------------------------------------------------------------
689 // Enable a packet filter.
690
691 IOReturn
692 IOEthernetInterface::enableFilter(IONetworkController * ctr,
693 const OSSymbol * group,
694 UInt32 filter,
695 IOOptionBits options = 0)
696 {
697 IOReturn ret;
698 UInt32 reqFilters;
699 UInt32 actFilters;
700
701 // If the controller does not support the packet filter,
702 // there's no need to proceed.
703
704 if (( GET_SUPPORTED_FILTERS(group) & filter ) == 0)
705 return kIOReturnUnsupported;
706
707 do {
708 // Add specified filter to the set of required filters.
709
710 reqFilters = GET_REQUIRED_FILTERS(group) | filter;
711 SET_REQUIRED_FILTERS(group, reqFilters);
712
713 // Abort if no changes are needed.
714
715 ret = kIOReturnSuccess;
716
717 actFilters = GET_ACTIVE_FILTERS(group);
718
719 if ( (( actFilters ^ reqFilters ) & filter) == 0 )
720 break;
721
722 // Send a command to the controller driver.
723
724 ret = ctr->enablePacketFilter(group, filter, actFilters, options);
725
726 if ( ret == kIOReturnSuccess )
727 {
728 SET_ACTIVE_FILTERS(group, actFilters | filter);
729 }
730 }
731 while (false);
732
733 return ret;
734 }
735
736 //---------------------------------------------------------------------------
737 // Disable a packet filter.
738
739 IOReturn
740 IOEthernetInterface::disableFilter(IONetworkController * ctr,
741 const OSSymbol * group,
742 UInt32 filter,
743 IOOptionBits options = 0)
744 {
745 IOReturn ret;
746 UInt32 reqFilters;
747 UInt32 actFilters;
748
749 do {
750 // Remove specified filter from the set of required filters.
751
752 reqFilters = GET_REQUIRED_FILTERS(group) & ~filter;
753 SET_REQUIRED_FILTERS(group, reqFilters);
754
755 // Abort if no changes are needed.
756
757 ret = kIOReturnSuccess;
758
759 actFilters = GET_ACTIVE_FILTERS(group);
760
761 if ( (( actFilters ^ reqFilters ) & filter) == 0 )
762 break;
763
764 // Send a command to the controller driver.
765
766 ret = ctr->disablePacketFilter(group, filter, actFilters, options);
767
768 if ( ret == kIOReturnSuccess )
769 {
770 SET_ACTIVE_FILTERS(group, actFilters & ~filter);
771 }
772 }
773 while (false);
774
775 return ret;
776 }
777
778 //---------------------------------------------------------------------------
779 // Cache the list of multicast addresses and send a command to the
780 // controller to update the multicast list.
781
782 IOReturn
783 IOEthernetInterface::setupMulticastFilter(IONetworkController * ctr)
784 {
785 void * multiAddrs = 0;
786 UInt mcount;
787 OSData * mcData = 0;
788 struct ifnet * ifp = (struct ifnet *) _arpcom;
789 struct ifmultiaddr * ifma;
790 IOReturn ret = kIOReturnSuccess;
791 bool ok;
792
793 assert(ifp);
794
795 // Update the multicast addresses count ivar.
796
797 mcount = 0;
798 for (ifma = ifp->if_multiaddrs.lh_first;
799 ifma != NULL;
800 ifma = ifma->ifma_link.le_next)
801 {
802 if ((ifma->ifma_addr->sa_family == AF_UNSPEC) ||
803 (ifma->ifma_addr->sa_family == AF_LINK))
804 mcount++;
805 }
806 _mcAddrCount = mcount;
807
808 if ( mcount )
809 {
810 char * addrp;
811
812 mcData = OSData::withCapacity(mcount * NUM_EN_ADDR_BYTES);
813 if (!mcData)
814 {
815 DLOG("%s: no memory for multicast address list\n", getName());
816 return kIOReturnNoMemory;
817 }
818
819 // Loop through the linked multicast structures and write the
820 // address to the OSData.
821
822 for (ifma = ifp->if_multiaddrs.lh_first;
823 ifma != NULL;
824 ifma = ifma->ifma_link.le_next)
825 {
826 if (ifma->ifma_addr->sa_family == AF_UNSPEC)
827 addrp = &ifma->ifma_addr->sa_data[0];
828 else
829 if (ifma->ifma_addr->sa_family == AF_LINK)
830 addrp = LLADDR((struct sockaddr_dl *) ifma->ifma_addr);
831 else
832 continue;
833
834 ok = mcData->appendBytes((const void *) addrp, NUM_EN_ADDR_BYTES);
835 assert(ok);
836 }
837
838 multiAddrs = (void *) mcData->getBytesNoCopy();
839 assert(multiAddrs);
840 }
841
842 // Issue a controller command to setup the multicast filter.
843
844 ret = ((IOEthernetController *)ctr)->setMulticastList(
845 (IOEthernetAddress *) multiAddrs,
846 mcount);
847 if (mcData)
848 {
849 if (ret == kIOReturnSuccess)
850 setProperty(kIOMulticastAddressList, mcData);
851
852 mcData->release();
853 }
854 else {
855 removeProperty(kIOMulticastAddressList);
856 }
857
858 return ret;
859 }
860
861 //---------------------------------------------------------------------------
862 // Power management support.
863 //
864 // Handlers called, with the controller's gate closed, in response to a
865 // controller power state change.
866
867 IOReturn
868 IOEthernetInterface::controllerWillChangePowerState(
869 IONetworkController * ctr,
870 IOPMPowerFlags flags,
871 UInt32 stateNumber,
872 IOService * policyMaker )
873 {
874 if ( ( (flags & IOPMDeviceUsable ) == 0) &&
875 ( _controllerLostPower == false ) )
876 {
877 _controllerLostPower = true;
878
879 // Enable Magic Packet if supported.
880
881 if ( GET_SUPPORTED_FILTERS(gIOEthernetWakeOnLANFilterGroup) &
882 kIOEthernetWakeOnMagicPacket )
883 {
884 enableFilter(ctr, gIOEthernetWakeOnLANFilterGroup,
885 kIOEthernetWakeOnMagicPacket);
886 }
887
888 // Set _controllerLostPower, then call the SIOCSIFFLAGS handler to
889 // disable the controller, then mark the interface as Not Running.
890
891 syncSIOCSIFFLAGS(ctr);
892 }
893
894 return super::controllerWillChangePowerState( ctr, flags,
895 stateNumber,
896 policyMaker );
897 }
898
899 IOReturn
900 IOEthernetInterface::controllerDidChangePowerState(
901 IONetworkController * ctr,
902 IOPMPowerFlags flags,
903 UInt32 stateNumber,
904 IOService * policyMaker )
905 {
906 IOReturn ret = super::controllerDidChangePowerState( ctr, flags,
907 stateNumber,
908 policyMaker );
909
910 if ( ( flags & IOPMDeviceUsable ) && ( _controllerLostPower == true ) )
911 {
912 _controllerLostPower = false;
913
914 // Clear _controllerLostPower, then call the SIOCSIFFLAGS handler to
915 // perhaps enable the controller, restore all Ethernet controller
916 // state, then mark the interface as Running.
917
918 syncSIOCSIFFLAGS(ctr);
919 }
920
921 return ret;
922 }