1/*
2 * Copyright (c) 1998-2008 Apple 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 * IOEthernetInterface.cpp
24 *
25 * HISTORY
26 * 8-Jan-1999       Joe Liu (jliu) created.
27 *
28 */
29
30#include <IOKit/assert.h>
31#include <IOKit/IOLib.h>
32#include <libkern/c++/OSData.h>
33#include <IOEthernetInterface.h>
34#include <IOEthernetController.h>
35#include "IONetworkUserClient.h"
36#include "IONetworkDebug.h"
37#include "IONetworkControllerPrivate.h"
38
39#include <IOKit/pwr_mgt/RootDomain.h>	// publishFeature()
40
41extern "C" {
42#include <sys/param.h>
43#include <sys/errno.h>
44#include <sys/socket.h>
45#include <sys/mbuf.h>
46#include <net/if.h>
47#include <net/ethernet.h>
48#include <net/if_ether.h>
49#include <net/if_arp.h>
50#include <net/if_dl.h>
51#include <net/if_types.h>
52#include <net/dlil.h>
53#include <net/bpf.h>
54#include <netinet/if_ether.h>
55#include <sys/sockio.h>
56#include <sys/malloc.h>
57}
58
59//---------------------------------------------------------------------------
60
61#define super IONetworkInterface
62
63OSDefineMetaClassAndStructors( IOEthernetInterface, IONetworkInterface )
64OSMetaClassDefineReservedUnused( IOEthernetInterface,  0);
65OSMetaClassDefineReservedUnused( IOEthernetInterface,  1);
66OSMetaClassDefineReservedUnused( IOEthernetInterface,  2);
67OSMetaClassDefineReservedUnused( IOEthernetInterface,  3);
68OSMetaClassDefineReservedUnused( IOEthernetInterface,  4);
69OSMetaClassDefineReservedUnused( IOEthernetInterface,  5);
70OSMetaClassDefineReservedUnused( IOEthernetInterface,  6);
71OSMetaClassDefineReservedUnused( IOEthernetInterface,  7);
72OSMetaClassDefineReservedUnused( IOEthernetInterface,  8);
73OSMetaClassDefineReservedUnused( IOEthernetInterface,  9);
74OSMetaClassDefineReservedUnused( IOEthernetInterface, 10);
75OSMetaClassDefineReservedUnused( IOEthernetInterface, 11);
76OSMetaClassDefineReservedUnused( IOEthernetInterface, 12);
77OSMetaClassDefineReservedUnused( IOEthernetInterface, 13);
78OSMetaClassDefineReservedUnused( IOEthernetInterface, 14);
79OSMetaClassDefineReservedUnused( IOEthernetInterface, 15);
80
81// The name prefix for all BSD Ethernet interfaces.
82//
83#define kIOEthernetInterfaceNamePrefix      "en"
84
85// Options used for enableFilter(), disableFilter().
86enum {
87    //kFilterOptionDeferIO          = 0x0001,
88    //kFilterOptionNotInsideGate    = 0x0002,
89    kFilterOptionNoStateChange    = 0x0004,
90    //kFilterOptionDisableZeroBits  = 0x0008,
91    kFilterOptionSyncPendingIO    = 0x0010
92};
93
94//---------------------------------------------------------------------------
95// Macros
96
97#define _altMTU                 _reserved->altMTU
98#define _publishedFeatureID     _reserved->publishedFeatureID
99#define _supportedWakeFilters   _reserved->supportedWakeFilters
100#define _disabledWakeFilters    _reserved->disabledWakeFilters
101#define _wompEnabledAssertionID _reserved->wompEnabledAssertionID
102
103#define kWOMPFeatureKey         "WakeOnMagicPacket"
104
105UInt32
106IOEthernetInterface::getFilters(
107    const OSDictionary * dict,
108    const OSSymbol *     group )
109{
110    OSNumber * num;
111    UInt32     filters = 0;
112
113    assert( dict && group );
114
115    if (( num = (OSNumber *) dict->getObject(group) ))
116    {
117        filters = num->unsigned32BitValue();
118    }
119    return filters;
120}
121
122bool
123IOEthernetInterface::setFilters(
124    OSDictionary *   dict,
125    const OSSymbol * group,
126    UInt32           filters )
127{
128    OSNumber * num;
129    bool       ret = false;
130
131    assert( dict && group );
132
133    num = (OSNumber *) dict->getObject(group);
134    if ( num == 0 )
135    {
136        if (( num = OSNumber::withNumber(filters, 32) ))
137        {
138            ret = dict->setObject(group, num);
139            num->release();
140        }
141    }
142    else
143    {
144        num->setValue(filters);
145        ret = true;
146    }
147    return ret;
148}
149
150#define GET_REQUIRED_FILTERS(g)     getFilters(_requiredFilters, (g))
151#define GET_ACTIVE_FILTERS(g)       getFilters(_activeFilters, (g))
152#define GET_SUPPORTED_FILTERS(g)    getFilters(_supportedFilters, (g))
153
154#define SET_REQUIRED_FILTERS(g, v)  setFilters(_requiredFilters, (g), (v))
155#define SET_ACTIVE_FILTERS(g, v)    setFilters(_activeFilters, (g), (v))
156
157//---------------------------------------------------------------------------
158// Initialize an IOEthernetInterface instance. Instance variables are
159// initialized
160
161bool IOEthernetInterface::init(IONetworkController * controller)
162{
163    OSObject *  obj;
164
165    _reserved = IONew( ExpansionData, 1 );
166	if( _reserved == 0 )
167		return false;
168	memset(_reserved, 0, sizeof(ExpansionData));
169
170    if ( super::init(controller) == false )
171    	return false;
172
173	// initialize enet specific fields.
174	setInterfaceType(IFT_ETHER);
175	setMaxTransferUnit( ETHERMTU );
176	setMediaAddressLength( ETHER_ADDR_LEN );
177	setMediaHeaderLength( ETHER_HDR_LEN );
178	setFlags( IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS,
179			  IFF_RUNNING   | IFF_MULTICAST );
180
181    // Add an IONetworkData with room to hold an IOEthernetStats structure.
182    // This class does not reference the data object created, and no harm
183    // is done if the data object is released or replaced.
184
185    IONetworkData * data = IONetworkData::withInternalBuffer(
186                                              kIOEthernetStatsKey,
187                                              sizeof(IOEthernetStats));
188    if (data)
189    {
190        addNetworkData(data);
191        data->release();
192    }
193
194    _inputEventThreadCall = thread_call_allocate(
195                            handleEthernetInputEvent, this );
196    if (!_inputEventThreadCall)
197        return false;
198
199    // Create and initialize the filter dictionaries.
200
201    _requiredFilters = OSDictionary::withCapacity(2);
202    _activeFilters   = OSDictionary::withCapacity(2);
203
204    if ( (_requiredFilters == 0) || (_activeFilters == 0) )
205        return false;
206
207    obj = controller->copyProperty(kIOPacketFilters);
208    if (obj && ((_supportedFilters = OSDynamicCast(OSDictionary, obj)) == 0))
209        obj->release();
210    if (!_supportedFilters)
211        return false;
212
213    // Cache the bit mask of wake filters supported by the driver.
214    // This value will not change.
215
216    _supportedWakeFilters = GET_SUPPORTED_FILTERS(
217                            gIOEthernetWakeOnLANFilterGroup );
218
219    // Retain the Disabled WOL filters OSNumber.
220    // Its value will be updated live for link and WOL changed events.
221
222    obj = _supportedFilters->getObject(
223            gIOEthernetDisabledWakeOnLANFilterGroup );
224    _disabledWakeFilters = OSDynamicCast(OSNumber, obj);
225    if (_disabledWakeFilters)
226        _disabledWakeFilters->retain();
227
228    // Controller's Unicast (directed) and Broadcast filters should always
229    // be enabled. Those bits should never be cleared.
230
231    if ( !SET_REQUIRED_FILTERS( gIONetworkFilterGroup,
232                                kIOPacketFilterUnicast |
233                                kIOPacketFilterBroadcast )
234      || !SET_REQUIRED_FILTERS( gIOEthernetWakeOnLANFilterGroup, 0 )
235      || !SET_ACTIVE_FILTERS(   gIONetworkFilterGroup, 0 )
236      || !SET_ACTIVE_FILTERS(   gIOEthernetWakeOnLANFilterGroup, 0 ) )
237    {
238         return false;
239    }
240
241    _publishedFeatureID = 0;
242
243    // Publish filter dictionaries to property table.
244
245    setProperty( kIORequiredPacketFilters, _requiredFilters );
246    setProperty( kIOActivePacketFilters,   _activeFilters );
247
248    return true;
249}
250
251static const u_char ether_broadcast_addr[ETHER_ADDR_LEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
252
253bool IOEthernetInterface::initIfnetParams(struct ifnet_init_params *params)
254{
255	OSData *uniqueID;
256	//get the default values
257    super::initIfnetParams( params );
258
259    uniqueID = OSDynamicCast(OSData, getProvider()->getProperty(kIOMACAddress));
260    if ( (uniqueID == 0) || (uniqueID->getLength() != ETHER_ADDR_LEN) )
261    {
262        DLOG("%s: kIOMACAddress property access error (len %d)\n",
263             getName(), uniqueID ? uniqueID->getLength() : 0);
264        return false;
265    }
266
267	// fill in ethernet specific values
268	params->uniqueid = uniqueID->getBytesNoCopy();
269	params->uniqueid_len = uniqueID->getLength();
270	params->family = APPLE_IF_FAM_ETHERNET;
271	params->demux = ether_demux;
272	params->add_proto = ether_add_proto;
273	params->del_proto = ether_del_proto;
274	params->framer = ether_frameout;
275	params->check_multi = ether_check_multi;
276	params->broadcast_addr = ether_broadcast_addr;
277	params->broadcast_len = sizeof(ether_broadcast_addr);
278    return true;
279}
280
281//---------------------------------------------------------------------------
282// Free the IOEthernetInterface instance.
283
284void IOEthernetInterface::free()
285{
286    if ( _requiredFilters )
287    {
288        _requiredFilters->release();
289        _requiredFilters = 0;
290    }
291
292    if ( _activeFilters )
293    {
294        _activeFilters->release();
295        _activeFilters = 0;
296    }
297
298    if ( _supportedFilters )
299    {
300        _supportedFilters->release();
301        _supportedFilters = 0;
302    }
303
304    if ( _inputEventThreadCall )
305    {
306        thread_call_free( _inputEventThreadCall );
307        _inputEventThreadCall = 0;
308    }
309
310	if ( _reserved )
311	{
312        if (kIOPMUndefinedDriverAssertionID != _wompEnabledAssertionID)
313        {
314            getPMRootDomain()->releasePMAssertion(_wompEnabledAssertionID);
315            _wompEnabledAssertionID = kIOPMUndefinedDriverAssertionID;
316        }
317
318        if (_disabledWakeFilters)
319        {
320            _disabledWakeFilters->release();
321            _disabledWakeFilters = 0;
322        }
323		IODelete( _reserved, ExpansionData, 1 );
324        _reserved = 0;
325    }
326
327    super::free();
328}
329
330//---------------------------------------------------------------------------
331// The name of the interface advertised to the network layer
332// is generated by concatenating the string returned by this method,
333// and an unit number.
334//
335// Returns a pointer to a constant string "en". Thus Ethernet interfaces
336// will be registered as en0, en1, etc.
337
338const char * IOEthernetInterface::getNamePrefix() const
339{
340    return kIOEthernetInterfaceNamePrefix;
341}
342
343//---------------------------------------------------------------------------
344// Prepare the 'Ethernet' controller after it has been opened. This is called
345// by IONetworkInterface after a controller has accepted an open from this
346// interface. IOEthernetInterface uses this method to inspect the controller,
347// and to cache certain controller properties, such as its hardware address.
348// This method is called with the arbitration lock held.
349//
350// controller: The controller object that was opened.
351//
352// Returns true on success, false otherwise
353// (which will cause the controller to be closed).
354
355bool IOEthernetInterface::controllerDidOpen(IONetworkController * ctr)
356{
357    bool                 ret = false;
358    OSData *             addrData;
359    IOEthernetAddress *  addr;
360
361    do {
362        // Call the controllerDidOpen() in superclass first.
363
364        if ( (ctr == 0) || (super::controllerDidOpen(ctr) == false) )
365             break;
366
367        // If the controller supports some form of multicast filtering,
368        // then set the ifnet IFF_MULTICAST flag.
369
370        if ( GET_SUPPORTED_FILTERS(gIONetworkFilterGroup) &
371             (kIOPacketFilterMulticast | kIOPacketFilterMulticastAll) )
372        {
373            setFlags(IFF_MULTICAST);
374        }
375
376        // Advertise Wake on Magic Packet feature if supported.
377
378        if ( _supportedWakeFilters & kIOEthernetWakeOnMagicPacket )
379        {
380            IOPMrootDomain * root = getPMRootDomain();
381            if ( root ) root->publishFeature( kWOMPFeatureKey,
382                             kIOPMSupportedOnAC | kIOPMSupportedOnUPS,
383                             (uint32_t *)&_publishedFeatureID);
384        }
385
386        // Get the controller's MAC/Ethernet address.
387
388        addrData = OSDynamicCast(OSData, ctr->getProperty(kIOMACAddress));
389        if ( (addrData == 0) || (addrData->getLength() != ETHER_ADDR_LEN) )
390        {
391            DLOG("%s: kIOMACAddress property access error (len %d)\n",
392                 getName(), addrData ? addrData->getLength() : 0);
393            break;
394        }
395
396        addr = (IOEthernetAddress *) addrData->getBytesNoCopy();
397
398        DLOG("%s: Ethernet address %02x:%02x:%02x:%02x:%02x:%02x\n",
399              ctr->getName(),
400              addr->bytes[0],
401              addr->bytes[1],
402              addr->bytes[2],
403              addr->bytes[3],
404              addr->bytes[4],
405              addr->bytes[5]);
406
407        ret = true;
408    }
409    while (0);
410
411    return ret;
412}
413
414//---------------------------------------------------------------------------
415// When a close from our last client is received, the interface will
416// close the controller. But before the controller is closed, this method
417// will be called by our superclass to perform any final cleanup. This
418// method is called with the arbitration lock held.
419//
420// IOEthernetInterface will ensure that the controller is disabled.
421//
422// controller: The currently opened controller object.
423
424void IOEthernetInterface::controllerWillClose(IONetworkController * ctr)
425{
426    if ( _supportedWakeFilters & kIOEthernetWakeOnMagicPacket )
427    {
428        IOPMrootDomain * root = getPMRootDomain();
429        if ( root ) root->removePublishedFeature( _publishedFeatureID );
430        _publishedFeatureID = 0;
431    }
432
433    super::controllerWillClose(ctr);
434}
435
436//---------------------------------------------------------------------------
437// Handle ioctl commands originated from the network layer.
438// Commands not handled by this method are passed to our superclass.
439//
440// Argument convention is:
441//
442//    arg0 - (struct ifnet *)
443//    arg1 - (void *)
444//
445// The commands handled by IOEthernetInterface are:
446//
447//    SIOCSIFADDR
448//    SIOCSIFFLAGS
449//    SIOCADDMULTI
450//    SIOCDELMULTI
451//
452// Returns an error code defined in errno.h (BSD).
453
454SInt32 IOEthernetInterface::performCommand( IONetworkController * ctr,
455                                            unsigned long         cmd,
456                                            void *                arg0,
457                                            void *                arg1 )
458{
459    SInt32  ret;
460
461    if ( ctr == 0 ) return EINVAL;
462
463    switch ( cmd )
464    {
465        case SIOCSIFFLAGS:
466        case SIOCADDMULTI:
467        case SIOCDELMULTI:
468        case SIOCSIFADDR:
469        case SIOCSIFMTU:
470		case SIOCSIFDEVMTU:
471		case SIOCGIFDEVMTU:
472        case SIOCSIFLLADDR:
473            ret = (int) ctr->executeCommand(
474                             this,            /* client */
475                             (IONetworkController::Action)
476                                &IOEthernetInterface::performGatedCommand,
477                             this,            /* target */
478                             ctr,             /* param0 */
479                             (void *) cmd,    /* param1 */
480                             arg0,            /* param2 */
481                             arg1 );          /* param3 */
482            break;
483
484        default:
485            // Unknown command, let our superclass deal with it.
486            ret = super::performCommand(ctr, cmd, arg0, arg1);
487            break;
488    }
489
490    return ret;
491}
492
493//---------------------------------------------------------------------------
494// Handle an ioctl command on the controller's workloop context.
495
496int IOEthernetInterface::performGatedCommand(void * target,
497                                             void * arg1_ctr,
498                                             void * arg2_cmd,
499                                             void * arg3_0,
500                                             void * arg4_1)
501{
502    IOEthernetInterface * self = (IOEthernetInterface *) target;
503    IONetworkController * ctr  = (IONetworkController *) arg1_ctr;
504    struct ifreq *        ifr  = (struct ifreq *) arg4_1;
505    SInt                  ret  = EOPNOTSUPP;
506
507    // Refuse to perform controller I/O if the controller is in a
508    // low-power state that makes it "unusable".
509
510    if ( self->_controllerLostPower ||
511        ( self->getInterfaceState() & kIONetworkInterfaceDisabledState ) )
512         return EPWROFF;
513
514    switch ( (uintptr_t) arg2_cmd )
515    {
516        case SIOCSIFADDR:
517            ret = self->syncSIOCSIFADDR(ctr);
518            break;
519
520        case SIOCSIFFLAGS:
521            ret = self->syncSIOCSIFFLAGS(ctr);
522            break;
523
524        case SIOCADDMULTI:
525            ret = self->syncSIOCADDMULTI(ctr);
526            break;
527
528        case SIOCDELMULTI:
529            ret = self->syncSIOCDELMULTI(ctr);
530            break;
531
532        case SIOCSIFMTU:
533            ret = self->syncSIOCSIFMTU( ctr, ifr, 0 );
534            break;
535
536		case SIOCSIFDEVMTU:
537			ret = self->syncSIOCSIFMTU(ctr, ifr, 1);
538			break;
539
540		case SIOCGIFDEVMTU:
541			ret = self->syncSIOCGIFDEVMTU(ctr, ifr);
542			break;
543
544        case SIOCSIFLLADDR:
545            ret = self->syncSIOCSIFLLADDR( ctr, ifr->ifr_addr.sa_data,
546                                           ifr->ifr_addr.sa_len );
547            break;
548    }
549
550    return ret;
551}
552
553//---------------------------------------------------------------------------
554// enableController() is reponsible for calling the controller's enable()
555// method and restoring the state of the controller. We assume that
556// controllers can completely reset its state upon receiving a disable()
557// method call. And when it is brought back up, the interface should
558// assist in restoring the previous state of the Ethernet controller.
559
560IOReturn IOEthernetInterface::enableController(IONetworkController * ctr)
561{
562    IOReturn   ret     = kIOReturnSuccess;
563    bool       enabled = false;
564
565    assert(ctr);
566
567    do {
568        // Is controller already enabled? If so, exit and return success.
569
570        if ( _ctrEnabled )
571            break;
572
573        // Send the controller an enable command.
574
575        if ( (ret = ctr->doEnable(this)) != kIOReturnSuccess )
576            break;     // unable to enable the controller.
577
578        enabled = true;
579
580        // Disable all Wake-On-LAN filters.
581
582        disableFilter(ctr, gIOEthernetWakeOnLANFilterGroup, ~0,
583                      kFilterOptionNoStateChange);
584
585        // Restore current filter selection.
586
587        SET_ACTIVE_FILTERS(gIONetworkFilterGroup, 0);
588        ret = enableFilter(ctr, gIONetworkFilterGroup, 0,
589                           kFilterOptionSyncPendingIO);
590        if ( ret != kIOReturnSuccess ) break;
591
592        // Restore multicast filter settings.
593
594        syncSIOCADDMULTI(ctr);
595
596        // Re-apply the user supplied link-level address.
597
598        OSData * lladdr = OSDynamicCast(OSData, getProperty(kIOMACAddress));
599        if ( lladdr && lladdr->getLength() == ETHER_ADDR_LEN )
600        {
601            ctr->setHardwareAddress( lladdr->getBytesNoCopy(),
602                                     lladdr->getLength() );
603        }
604
605        _ctrEnabled = true;
606
607        // Publish WOL support flags after interface is marked enabled.
608
609        reportInterfaceWakeFlags(ctr);
610
611    } while (false);
612
613    // Disable the controller if a serious error has occurred after the
614    // controller has been enabled.
615
616    if ( enabled && (ret != kIOReturnSuccess) )
617    {
618        ctr->doDisable(this);
619    }
620
621    return ret;
622}
623
624//---------------------------------------------------------------------------
625// Handles SIOCSIFFLAGS ioctl command for Ethernet interfaces. The network
626// stack has changed the if_flags field in ifnet. Our job is to go
627// through if_flags and see what has changed, and act accordingly.
628//
629// The fact that if_flags contains both generic and Ethernet specific bits
630// means that we cannot move some of the default flag processing to the
631// superclass.
632
633int IOEthernetInterface::syncSIOCSIFFLAGS(IONetworkController * ctr)
634{
635    UInt16    flags = getFlags();
636    IOReturn  ret   = kIOReturnSuccess;
637
638    if ( ( ((flags & IFF_UP) == 0) || _controllerLostPower ) &&
639         ( flags & IFF_RUNNING ) )
640    {
641        // If interface is marked down and it is currently running,
642        // then stop it.
643
644        ctr->doDisable(this);
645        flags &= ~IFF_RUNNING;
646        _ctrEnabled = false;
647    }
648    else if ( ( flags & IFF_UP )                &&
649              ( _controllerLostPower == false ) &&
650              ((flags & IFF_RUNNING) == 0) )
651    {
652        // If interface is marked up and it is currently stopped,
653        // then start it.
654
655        if ( (ret = enableController(ctr)) == kIOReturnSuccess )
656            flags |= IFF_RUNNING;
657    }
658
659    if ( flags & IFF_RUNNING )
660    {
661        IOReturn rc;
662
663        // We don't expect multiple flags to be changed for a given
664        // SIOCSIFFLAGS call.
665
666        // Promiscuous mode
667
668        rc = (flags & IFF_PROMISC) ?
669             enableFilter(ctr, gIONetworkFilterGroup,
670                          kIOPacketFilterPromiscuous) :
671             disableFilter(ctr, gIONetworkFilterGroup,
672                           kIOPacketFilterPromiscuous);
673
674        if (ret == kIOReturnSuccess) ret = rc;
675
676        // Multicast-All mode
677
678        rc = (flags & IFF_ALLMULTI) ?
679             enableFilter(ctr, gIONetworkFilterGroup,
680                          kIOPacketFilterMulticastAll) :
681             disableFilter(ctr, gIONetworkFilterGroup,
682                           kIOPacketFilterMulticastAll);
683
684        if (ret == kIOReturnSuccess) ret = rc;
685    }
686
687    // Update the flags field to pick up any modifications. Also update the
688    // property table to reflect any flag changes.
689
690    setFlags(flags, ~flags);
691
692    return errnoFromReturn(ret);
693}
694
695//---------------------------------------------------------------------------
696// Handles SIOCSIFADDR ioctl.
697
698SInt IOEthernetInterface::syncSIOCSIFADDR(IONetworkController * ctr)
699{
700    IOReturn ret = kIOReturnSuccess;
701
702    // Interface is implicitly brought up by an SIOCSIFADDR ioctl.
703
704    setFlags(IFF_UP);
705
706    if ( (getFlags() & IFF_RUNNING) == 0 )
707    {
708        if ( (ret = enableController(ctr)) == kIOReturnSuccess )
709            setFlags(IFF_RUNNING);
710    }
711
712    return errnoFromReturn(ret);
713}
714
715//---------------------------------------------------------------------------
716// Handle SIOCADDMULTI ioctl command.
717
718SInt IOEthernetInterface::syncSIOCADDMULTI(IONetworkController * ctr)
719{
720    IOReturn ret;
721
722    // Make sure multicast filter is active.
723
724    ret = enableFilter(ctr, gIONetworkFilterGroup, kIOPacketFilterMulticast);
725
726    if ( ret == kIOReturnSuccess )
727    {
728        // Load multicast addresses only if the filter was activated.
729
730        ret = setupMulticastFilter(ctr);
731
732        // If the list is now empty, then deactivate the multicast filter.
733
734        if ( _mcAddrCount == 0 )
735        {
736            IOReturn dret = disableFilter(ctr, gIONetworkFilterGroup,
737                                          kIOPacketFilterMulticast);
738
739            if (ret == kIOReturnSuccess) ret = dret;
740        }
741    }
742
743    return errnoFromReturn(ret);
744}
745
746//---------------------------------------------------------------------------
747// Handle SIOCDELMULTI ioctl command.
748
749SInt IOEthernetInterface::syncSIOCDELMULTI(IONetworkController * ctr)
750{
751    return syncSIOCADDMULTI(ctr);
752}
753
754#define MTU_TO_FRAMESIZE(x) \
755((x) + kIOEthernetCRCSize + sizeof(struct ether_header))
756
757#define FRAMESIZE_TO_MTU(x) \
758((x) - kIOEthernetCRCSize - sizeof(struct ether_header))
759
760int IOEthernetInterface::syncSIOCGIFDEVMTU( IONetworkController * ctr,
761											struct ifreq *        ifr )
762{
763	IOReturn ret;
764    UInt32  size;
765
766	ifr->ifr_devmtu.ifdm_current = max(_altMTU, getMaxTransferUnit());
767
768	ret =  ctr->getMaxPacketSize( &size );
769	if(ret == kIOReturnSuccess )
770	{
771		ifr->ifr_devmtu.ifdm_max = FRAMESIZE_TO_MTU(size);
772		ret = ctr->getMinPacketSize( &size );
773		if(ret == kIOReturnSuccess)
774			ifr->ifr_devmtu.ifdm_min = FRAMESIZE_TO_MTU( size );
775	}
776	return errnoFromReturn( ret );
777}
778
779//---------------------------------------------------------------------------
780// Handle SIOCSIFMTU ioctl.
781
782int IOEthernetInterface::syncSIOCSIFMTU( IONetworkController * ctr,
783                                         struct ifreq *        ifr,
784										 bool setAltMTU)
785{
786
787	IOReturn ret = kIOReturnSuccess;
788	UInt32	newControllerMTU, oldControllerMTU;
789	UInt32	softMTU = getMaxTransferUnit();
790	UInt32	requestedMTU = ifr->ifr_mtu;
791
792    UInt32  maxFrameSize = kIOEthernetMaxPacketSize;  // 1518
793	UInt32	minFrameSize = kIOEthernetMinPacketSize;
794	UInt32	tempSize;
795
796	// Determine controller's max allowable mtu...
797	if ( ctr->getMaxPacketSize( &tempSize ) == kIOReturnSuccess )
798		maxFrameSize = max( tempSize, kIOEthernetMaxPacketSize );
799
800	// ...and reject requests that are too big.
801	if ( MTU_TO_FRAMESIZE( requestedMTU ) > maxFrameSize )
802		return EINVAL;	// MTU is too large for the controller.
803
804	// Determine controller's min allowable mtu...
805	ctr->getMinPacketSize( &minFrameSize );
806
807	// ...and reject requests that are too small.
808	if ( MTU_TO_FRAMESIZE( requestedMTU ) < minFrameSize && !(setAltMTU && requestedMTU==0))  //allow setting dev MTU to 0 to turn it off
809		return EINVAL;	// MTU is too small for the controller.
810
811	//the controller gets the max of the mtu we're changing and the one we're not.
812	newControllerMTU = max(requestedMTU, setAltMTU ? softMTU : _altMTU);
813
814	// determine what's currently set on the controller (the max of current soft and alt settings)
815	oldControllerMTU = max(softMTU, _altMTU);
816
817	// we only have to change the controller if the new value is different from the old,
818	// and either the new value is bigger than the standard max ethernet or the old value was.
819	if(newControllerMTU != oldControllerMTU &&
820	   ( (MTU_TO_FRAMESIZE(newControllerMTU) > kIOEthernetMaxPacketSize) ||
821		 (MTU_TO_FRAMESIZE(oldControllerMTU) > kIOEthernetMaxPacketSize) )
822	   )
823	{
824		ret = ctr->setMaxPacketSize( max(MTU_TO_FRAMESIZE(newControllerMTU), kIOEthernetMaxPacketSize)); //don't set smaller than standard max ethernet
825	}
826	if(ret == kIOReturnSuccess) //if we successfully set value in controller (or didn't need to) then store the new value
827	{
828
829		if(setAltMTU)
830			_altMTU = requestedMTU;
831		else
832			setMaxTransferUnit( requestedMTU );
833	}
834	return errnoFromReturn( ret );
835}
836
837//---------------------------------------------------------------------------
838
839int IOEthernetInterface::syncSIOCSIFLLADDR( IONetworkController * ctr,
840                                            const char * lladdr, int len )
841{
842	unsigned char tempaddr[kIOEthernetAddressSize];
843	OSData *hardAddr;
844
845	if(len != kIOEthernetAddressSize)
846		return EINVAL;
847
848   if (_ctrEnabled != true)    /* reject if interface is down */
849        return (ENETDOWN);
850	// keep a backup in case stack refuses our change
851	hardAddr = OSDynamicCast(OSData, getProperty(kIOMACAddress));
852	if(hardAddr && hardAddr->getLength() == kIOEthernetAddressSize)
853		bcopy(hardAddr->getBytesNoCopy(), tempaddr, kIOEthernetAddressSize);
854
855	// change the hardware- we do it before the stack, in case the stack
856	// needs to generate traffic as a result.
857
858    if ( ctr->setHardwareAddress( lladdr, len ) == kIOReturnSuccess )
859    {
860		if( ifnet_set_lladdr(getIfnet(), lladdr, len) ) //uh-oh, stack didn't like this
861		{
862			// restore previous address
863			if(hardAddr)
864			   ctr->setHardwareAddress(tempaddr, sizeof(tempaddr));
865			return EINVAL;
866		}
867
868       setProperty(kIOMACAddress, (void *)lladdr, len);
869
870        DLOG("%s: SIOCSIFLLADDR %02x:%02x:%02x:%02x:%02x:%02x\n",
871              ctr->getName(),
872              lladdr[0], lladdr[1], lladdr[2],
873              lladdr[3], lladdr[4], lladdr[5]);
874   }
875
876    return 0;
877}
878
879//---------------------------------------------------------------------------
880// Enable a packet filter.
881
882#define getOneFilter(x)   ((x) & (~((x) - 1)))
883
884// this stub's sole purpose is to eliminate warning generated by gcc in enableFilter
885// when we try to cast a ptr to member function to a ptr to a 'C' function.
886
887IOReturn
888IOEthernetInterface::enableFilter_Wrapper(
889    IOEthernetInterface *   self,
890    IONetworkController *   ctr,
891    const OSSymbol *        group,
892    UInt32                  filters,
893    IOOptionBits            options)
894{
895	return self->enableFilter(ctr, group, filters, options);
896}
897
898IOReturn
899IOEthernetInterface::enableFilter(IONetworkController * ctr,
900                                  const OSSymbol *      group,
901                                  UInt32                filters,
902                                  IOOptionBits          options)
903{
904    IOReturn ret = kIOReturnSuccess;
905
906    // If the controller does not support the packet filter,
907    // there's no need to proceed.
908
909    if (( GET_SUPPORTED_FILTERS(group) & filters ) != filters)
910        return kIOReturnUnsupported;
911
912    do {
913        // Add new filter to the set of required filters.
914
915        UInt32 reqFilters = GET_REQUIRED_FILTERS(group) | filters;
916        UInt32 actFilters = GET_ACTIVE_FILTERS(group);
917        UInt32 resFilters = ( actFilters ^ reqFilters );
918
919        if ( (options & kFilterOptionSyncPendingIO) == 0 )
920        {
921            // Restrict filter update by using 'filters' as a mask.
922            resFilters &= filters;
923        }
924
925        while ( resFilters )
926        {
927            UInt32 oneFilter = getOneFilter(resFilters);
928
929            // Send a command to the controller driver.
930
931            ret = ctr->enablePacketFilter(group, oneFilter,
932                                          actFilters, options);
933            if ( ret != kIOReturnSuccess ) break;
934
935            resFilters &= ~oneFilter;
936            actFilters |= oneFilter;
937        }
938
939        if ( (options & kFilterOptionNoStateChange) == 0 )
940            SET_REQUIRED_FILTERS(group, reqFilters);
941        SET_ACTIVE_FILTERS(group, actFilters);
942    }
943    while (false);
944
945    return ret;
946}
947
948//---------------------------------------------------------------------------
949// Disable a packet filter.
950
951IOReturn
952IOEthernetInterface::disableFilter(IONetworkController * ctr,
953                                   const OSSymbol *      group,
954                                   UInt32                filters,
955                                   IOOptionBits          options)
956{
957    IOReturn ret = kIOReturnSuccess;
958
959    do {
960        // Remove specified filter from the set of required filters.
961
962        UInt32 reqFilters = GET_REQUIRED_FILTERS(group) & ~filters;
963        UInt32 actFilters = GET_ACTIVE_FILTERS(group);
964        UInt32 resFilters = ( actFilters ^ reqFilters ) & filters;
965
966        while ( resFilters )
967        {
968            UInt32 oneFilter = getOneFilter(resFilters);
969
970            // Send a command to the controller driver.
971
972            ret = ctr->disablePacketFilter(group, oneFilter,
973                                           actFilters, options);
974            if ( ret != kIOReturnSuccess ) break;
975
976            resFilters &= ~oneFilter;
977            actFilters &= ~oneFilter;
978        }
979
980        if ( (options & kFilterOptionNoStateChange) == 0 )
981            SET_REQUIRED_FILTERS(group, reqFilters);
982        SET_ACTIVE_FILTERS(group, actFilters);
983    }
984    while (false);
985
986    return ret;
987}
988
989//---------------------------------------------------------------------------
990// Cache the list of multicast addresses and send a command to the
991// controller to update the multicast list.
992
993IOReturn
994IOEthernetInterface::setupMulticastFilter(IONetworkController * ctr)
995{
996    void *               multiAddrs = 0;
997    UInt                 mcount;
998    OSData *             mcData = 0;
999    ifnet_t				interface;
1000    struct sockaddr  dlAddress;
1001    IOReturn             ret = kIOReturnSuccess;
1002    bool                 ok;
1003	ifmultiaddr_t		*addressList;
1004
1005    interface = getIfnet();
1006
1007	assert(interface);
1008
1009    // get the list and count how many mcast link addresses there are
1010	if(ifnet_get_multicast_list(interface, &addressList))
1011		return kIOReturnNoMemory;
1012	mcount = 0;
1013	for(int i=0; addressList[i]; i++)
1014	{
1015		ifmaddr_address(addressList[i], &dlAddress, sizeof(dlAddress));
1016
1017		if (dlAddress.sa_family == AF_UNSPEC || dlAddress.sa_family == AF_LINK)
1018			mcount++;
1019	}
1020
1021	_mcAddrCount = mcount;
1022
1023	// now rewalk the list and copy the addresses to a format suitable to give to the controller
1024    if ( mcount )
1025    {
1026        char * addrp;
1027
1028        mcData = OSData::withCapacity(mcount * ETHER_ADDR_LEN);
1029        if (!mcData)
1030        {
1031            DLOG("%s: no memory for multicast address list\n", getName());
1032			ifnet_free_multicast_list(addressList);
1033            return kIOReturnNoMemory;
1034        }
1035
1036        // Loop through the list and copy the link multicast
1037        // address to the OSData.
1038		for(int i = 0; addressList[i]; i++)
1039		{
1040			//retrieve the datalink mcast address
1041			ifmaddr_address(addressList[i], &dlAddress, sizeof(dlAddress));
1042
1043			if (dlAddress.sa_family == AF_UNSPEC)
1044                addrp = &dlAddress.sa_data[0];
1045            else if (dlAddress.sa_family == AF_LINK)
1046                addrp = LLADDR((struct sockaddr_dl *)&dlAddress);
1047            else
1048                continue;
1049
1050            ok = mcData->appendBytes((const void *) addrp, ETHER_ADDR_LEN);
1051            assert(ok);
1052        }
1053
1054        multiAddrs = (void *) mcData->getBytesNoCopy();
1055        assert(multiAddrs);
1056    }
1057
1058    // Issue a controller command to setup the multicast filter.
1059
1060    ret = ((IOEthernetController *)ctr)->setMulticastList(
1061                                            (IOEthernetAddress *) multiAddrs,
1062                                            mcount);
1063    if (mcData)
1064    {
1065        if (ret == kIOReturnSuccess)
1066            setProperty(kIOMulticastAddressList, mcData);
1067
1068        mcData->release();
1069    }
1070    else {
1071        removeProperty(kIOMulticastAddressList);
1072    }
1073	ifnet_free_multicast_list(addressList);
1074    return ret;
1075}
1076
1077//---------------------------------------------------------------------------
1078// Power management support.
1079//
1080// Handlers called, with the controller's gate closed, in response to a
1081// controller power state change.
1082
1083IOReturn
1084IOEthernetInterface::controllerWillChangePowerState(
1085                               IONetworkController * ctr,
1086                               IOPMPowerFlags        flags,
1087                               UInt32                stateNumber,
1088                               IOService *           policyMaker )
1089{
1090	if ( ( (flags & IOPMDeviceUsable ) == 0) &&
1091         ( _controllerLostPower == false ) )
1092    {
1093        _controllerLostPower = true;
1094
1095        if (_ctrEnabled && !ctr->isInactive())
1096        {
1097            if (policyMaker)
1098            {
1099                unsigned long filters;
1100
1101                // Called from PM instead of shutdown/restart context.
1102                // Get the "aggressiveness" factor from the policy maker.
1103
1104                ctr->getAggressiveness( kPMEthernetWakeOnLANSettings, &filters );
1105
1106                filters &= _supportedWakeFilters;
1107
1108                // Is the link up? If it is, leave the WOL filters intact,
1109                // otherwise mask out the WOL filters that would not function
1110                // without a proper link. This will reduce power consumption
1111                // for cases when a machine is put to sleep and there is no
1112                // network connection.
1113
1114                OSNumber * linkStatusNumber = (OSNumber *)
1115                                              ctr->getProperty( kIOLinkStatus );
1116
1117                if ( ( linkStatusNumber == 0 ) ||
1118                     ( ( linkStatusNumber->unsigned32BitValue() &
1119                         (kIONetworkLinkValid | kIONetworkLinkActive) ) ==
1120                          kIONetworkLinkValid ) )
1121                {
1122                    filters &= ~( kIOEthernetWakeOnMagicPacket |
1123                                  kIOEthernetWakeOnPacketAddressMatch );
1124                }
1125
1126                // Before controller is disabled, program its wake up filters.
1127                // The WOL setting is formed by a bitwise OR between the WOL filter
1128                // settings, and the aggresiveness factor from the policy maker.
1129
1130                enableFilter( ctr,
1131                              gIOEthernetWakeOnLANFilterGroup,
1132                              filters,
1133                              kFilterOptionNoStateChange |
1134                              kFilterOptionSyncPendingIO );
1135            }
1136
1137            // Call SIOCSIFFLAGS handler to disable the controller,
1138            // and mark the interface as Not Running.
1139
1140            syncSIOCSIFFLAGS(ctr);
1141        }
1142    }
1143
1144    return super::controllerWillChangePowerState( ctr, flags,
1145                                                  stateNumber,
1146                                                  policyMaker );
1147}
1148
1149IOReturn
1150IOEthernetInterface::controllerDidChangePowerState(
1151                               IONetworkController * ctr,
1152                               IOPMPowerFlags        flags,
1153                               UInt32                stateNumber,
1154                               IOService *           policyMaker )
1155{
1156    IOReturn ret = super::controllerDidChangePowerState( ctr, flags,
1157                                                         stateNumber,
1158                                                         policyMaker );
1159
1160    if ( ( flags & IOPMDeviceUsable ) && ( _controllerLostPower == true ) )
1161    {
1162        _controllerLostPower = false;
1163
1164        // Clear _controllerLostPower, then call the SIOCSIFFLAGS handler to
1165        // perhaps enable the controller, restore all Ethernet controller
1166        // state, then mark the interface as Running.
1167
1168        if (!ctr->isInactive())
1169            syncSIOCSIFFLAGS(ctr);
1170    }
1171
1172    return ret;
1173}
1174
1175//---------------------------------------------------------------------------
1176// willTerminate
1177
1178bool IOEthernetInterface::willTerminate( IOService *  provider,
1179                                         IOOptionBits options )
1180{
1181    bool ret = super::willTerminate( provider, options );
1182
1183    // willTerminate() is always called from the provider's work loop context.
1184    // But might be a different work loop than provider->getWorkLoop()
1185
1186    if (_ctrEnabled && (getController() == provider))
1187    {
1188        DLOG("IOEthernetInterface::willTerminate disabling controller\n");
1189        getController()->doDisable( this );
1190        _ctrEnabled = false;
1191    }
1192
1193    return ret;
1194}
1195
1196//---------------------------------------------------------------------------
1197
1198IOReturn IOEthernetInterface::attachToDataLinkLayer( IOOptionBits options,
1199                                                     void *       parameter )
1200{
1201    IOReturn ret = super::attachToDataLinkLayer( options, parameter );
1202    if ( ret == kIOReturnSuccess )
1203    {
1204		// on success, the interface is backed by an actual BSD ifnet_t.
1205		// now we can set a few important ethernet specific values on it.
1206		// Set defaults suitable for Ethernet interfaces.
1207		ifnet_set_baudrate(getIfnet(), 0);
1208		bpfattach( getIfnet(), DLT_EN10MB, sizeof(struct ether_header) );
1209   }
1210    return ret;
1211}
1212
1213#define VLAN_HEADER_LEN 4
1214// Temporarily stuff a vlan tag back into a packet so that tag shows up to bpf.
1215// We do it by creating a temp header mbuf with the enet/vlan header in it and
1216// then point its next field to the proper place (after the dest+src addresses) in the original
1217// mbuf.
1218void IOEthernetInterface::_fixupVlanPacket(mbuf_t mt, u_int16_t vlan_tag, int inputPacket)
1219{
1220	mbuf_t newmb;
1221	mbuf_t chain;
1222	size_t remainingBytes;
1223	size_t copyBytes = 0;  //initialize to prevent annoying, incorrect warning that it's used uninitialized
1224	char * destptr;
1225
1226	if( mbuf_gethdr(MBUF_DONTWAIT, MT_DATA, &newmb) )
1227		return;
1228
1229	//init enough of the mbuf to keep bpf happy
1230	mbuf_setlen(newmb, ETHER_ADDR_LEN*2 + VLAN_HEADER_LEN);
1231	mbuf_pkthdr_setlen(newmb, mbuf_pkthdr_len( mt ) + VLAN_HEADER_LEN);
1232	mbuf_pkthdr_setrcvif(newmb, mbuf_pkthdr_rcvif( mt ) );
1233
1234	//now walk the incoming mbuf to copy out its dst & src address and
1235	//locate the type/len field in the packet.
1236	chain = mt;
1237	remainingBytes = ETHER_ADDR_LEN*2;
1238	destptr = (char *)mbuf_data( newmb );
1239
1240	while(chain && remainingBytes)
1241	{
1242		copyBytes = remainingBytes > mbuf_len( chain ) ? mbuf_len( chain ): remainingBytes;
1243
1244		remainingBytes -= copyBytes;
1245		bcopy( mbuf_data( chain ), destptr, copyBytes);
1246		destptr += copyBytes;
1247		if (mbuf_len( chain ) == copyBytes) //we've completely drained this mbuf
1248		{
1249			chain = mbuf_next( chain );  //advance to next
1250			copyBytes = 0; //if we break out of loop now, make sure the offset is correct
1251		}
1252	}
1253
1254	// chain points to the mbuf that contains the packet data with type/len field
1255	// and copyBytes indicates the offset it's at.
1256	if(chain==0 || remainingBytes)
1257	{
1258		mbuf_freem( newmb );
1259		return; //if we can't munge the packet, just return
1260	}
1261
1262	//patch mbuf so its data points after the dst+src address
1263	mbuf_setdata(chain, (char *)mbuf_data( chain ) + copyBytes, mbuf_len( chain ) - copyBytes );
1264
1265	//finish setting up our head mbuf
1266	*(short *)(destptr) = htons(ETHERTYPE_VLAN); //vlan magic number
1267	*(short *)(destptr + 2) = htons( vlan_tag ); // and the tag's value
1268	mbuf_setnext( newmb, chain ); //stick it infront of the rest of the packet
1269
1270	// feed the tap
1271	if(inputPacket)
1272		super::feedPacketInputTap( newmb );
1273	else
1274		super::feedPacketOutputTap( newmb );
1275
1276	//release the fake header
1277	mbuf_setnext( newmb, NULL );
1278	mbuf_freem( newmb );
1279
1280	//and repair our old mbuf
1281	mbuf_setdata( chain, (char *)mbuf_data( chain ) - copyBytes, mbuf_len( chain ) + copyBytes );
1282}
1283
1284//we need to feed the taps the packets as they appear
1285//on the wire...but devices with hardware vlan stuffing/stripping
1286//put that info oob. so we must munge the packet with the
1287//vlan, feed the tap, then unmunge it.
1288
1289void IOEthernetInterface::feedPacketInputTap(mbuf_t mt)
1290{
1291	u_int16_t vlan;
1292
1293	if( mbuf_get_vlan_tag(mt, &vlan) == 0) //does this packet have oob vlan tag?
1294		_fixupVlanPacket(mt, vlan, 1);
1295	else
1296		super::feedPacketInputTap(mt);
1297}
1298
1299void IOEthernetInterface::feedPacketOutputTap(mbuf_t mt)
1300{
1301	u_int16_t vlan;
1302	if( mbuf_get_vlan_tag(mt, &vlan) == 0) //does this packet have oob vlan tag?
1303		_fixupVlanPacket(mt, vlan, 0);
1304	else
1305		super::feedPacketOutputTap(mt);
1306}
1307
1308//---------------------------------------------------------------------------
1309
1310bool IOEthernetInterface::inputEvent( UInt32 type, void * data )
1311{
1312    if ((type == kIONetworkEventTypeLinkUp)   ||
1313        (type == kIONetworkEventTypeLinkDown) ||
1314        (type == kIONetworkEventWakeOnLANSupportChanged))
1315    {
1316        IONetworkController * ctr = getController();
1317
1318        if (ctr && !ctr->isInactive())
1319        {
1320            // reportInterfaceWakeFlags() callout
1321            retain();
1322            ctr->retain();
1323            if (thread_call_enter( _inputEventThreadCall ) == TRUE)
1324            {
1325                release();
1326                ctr->release();
1327            }
1328        }
1329    }
1330
1331    if ((type == kIONetworkEventTypeLinkUp) ||
1332        (type == kIONetworkEventTypeLinkDown))
1333    {
1334        ifnet_t ifp = getIfnet();
1335        const IONetworkLinkEventData * linkData =
1336            (const IONetworkLinkEventData *) data;
1337
1338        if (ifp && linkData)
1339        {
1340            if ((IOMediumGetNetworkType(linkData->linkType) == kIOMediumEthernet))
1341            {
1342                // Ethernet drivers typically don't report link quality,
1343                // do it for them based on link status.
1344                if (type == kIONetworkEventTypeLinkUp)
1345                {
1346                    ifnet_set_link_quality(ifp, IFNET_LQM_THRESH_GOOD);
1347                }
1348                else
1349                {
1350                    ifnet_set_link_quality(ifp, IFNET_LQM_THRESH_OFF);
1351                }
1352            }
1353        }
1354    }
1355
1356    return super::inputEvent(type, data);
1357}
1358
1359void IOEthernetInterface::handleEthernetInputEvent(
1360    thread_call_param_t param0,
1361    thread_call_param_t /*param1 not used*/ )
1362{
1363    IOEthernetInterface * me = (IOEthernetInterface *) param0;
1364    IONetworkController * ctr;
1365
1366    if (me)
1367    {
1368        ctr = me->getController();
1369        if (ctr)
1370        {
1371            ctr->executeCommand(
1372            me,     /* client */
1373                    /* action */
1374            OSMemberFunctionCast(
1375                IONetworkController::Action, me,
1376                &IOEthernetInterface::reportInterfaceWakeFlags),
1377            me,     /* target */
1378            ctr );  /* param0 */
1379
1380            ctr->release();
1381        }
1382        me->release();
1383    }
1384}
1385
1386//---------------------------------------------------------------------------
1387
1388void IOEthernetInterface::reportInterfaceWakeFlags( IONetworkController * ctr )
1389{
1390    ifnet_t                 ifnet;
1391    OSNumber *              number;
1392    unsigned long           wakeSetting = 0;
1393    uint32_t                disabled    = 0;
1394    uint32_t                filters     = 0;
1395    uint32_t                linkStatus  = 0;
1396
1397    ifnet = getIfnet();
1398
1399    if (!ifnet || !ctr)
1400        return;
1401
1402    // Across system sleep/wake, link down is expected, this should
1403    // not trigger a wake flags changed.
1404
1405    if (_controllerLostPower)
1406    {
1407        DLOG("en%u: controllerLostPower\n", getUnitNumber());
1408        return;
1409    }
1410
1411    do {
1412        // Report negative if controller is disabled or does not support WOL.
1413
1414        if (!_ctrEnabled ||
1415            ((_supportedWakeFilters & kIOEthernetWakeOnMagicPacket) == 0))
1416        {
1417            DLOG("en%u: ctrEnabled = %x, WakeFilters = %x\n",
1418                getUnitNumber(), _ctrEnabled, _supportedWakeFilters);
1419            break;
1420        }
1421
1422        // Poll for disabled WOL filters, which is allowed to change
1423        // after every link and WOL changed event.
1424
1425        if (_disabledWakeFilters)
1426        {
1427            if ( ctr->getPacketFilters(
1428                    gIOEthernetDisabledWakeOnLANFilterGroup,
1429                    (UInt32 *) &disabled ) != kIOReturnSuccess )
1430            {
1431                disabled = 0;
1432            }
1433            _disabledWakeFilters->setValue( disabled );
1434        }
1435
1436        // Check if network wake option is enabled,
1437        // that also implies system is on AC power.
1438
1439        getAggressiveness(kPMEthernetWakeOnLANSettings, &wakeSetting);
1440        filters = wakeSetting & _supportedWakeFilters & ~disabled;
1441        DLOG("en%u: WakeSetting = %lx, WakeFilters = %x, disabled = %x\n",
1442            getUnitNumber(), wakeSetting, _supportedWakeFilters, disabled);
1443
1444        if ((kIOEthernetWakeOnMagicPacket & filters) == 0)
1445            break;
1446
1447        // Check driver is reporting valid link.
1448
1449        number = OSDynamicCast(OSNumber, ctr->getProperty(kIOLinkStatus));
1450        if (!number)
1451        {
1452            filters = 0;
1453            break;
1454        }
1455
1456        linkStatus = number->unsigned32BitValue();
1457        if ((linkStatus & (kIONetworkLinkValid | kIONetworkLinkActive)) ==
1458            kIONetworkLinkValid)
1459        {
1460            filters = 0;
1461        }
1462    }
1463    while (false);
1464
1465    filters &= IFNET_WAKE_ON_MAGIC_PACKET;
1466    if (filters != (ifnet_get_wake_flags(ifnet) & IFNET_WAKE_ON_MAGIC_PACKET))
1467    {
1468        ifnet_set_wake_flags(ifnet, filters, IFNET_WAKE_ON_MAGIC_PACKET);
1469        DLOG("en%u: ifnet_set_wake_flags = %x\n", getUnitNumber(), filters);
1470
1471        // Lazy create of kernel assertion
1472        if (kIOPMUndefinedDriverAssertionID == _wompEnabledAssertionID)
1473        {
1474            _wompEnabledAssertionID = getPMRootDomain()->createPMAssertion(
1475                kIOPMDriverAssertionMagicPacketWakeEnabledBit,
1476                (filters & IFNET_WAKE_ON_MAGIC_PACKET) ?
1477                    kIOPMDriverAssertionLevelOn : kIOPMDriverAssertionLevelOff,
1478                this, getName());
1479        }
1480        else
1481        {
1482            getPMRootDomain()->setPMAssertionLevel(_wompEnabledAssertionID,
1483                (filters & IFNET_WAKE_ON_MAGIC_PACKET) ?
1484                    kIOPMDriverAssertionLevelOn : kIOPMDriverAssertionLevelOff);
1485        }
1486    }
1487}
1488