|
|
1.1 root 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 <net/if_dl.h>
43: #include <net/if_types.h>
44: #include <sys/sockio.h>
45: #include <netinet/in_var.h>
46: #include <sys/malloc.h>
47: void arpwhohas(struct arpcom * ac, struct in_addr * addr);
48: }
49:
50: //---------------------------------------------------------------------------
51:
52: #define super IONetworkInterface
53:
54: OSDefineMetaClassAndStructors( IOEthernetInterface, IONetworkInterface )
55:
56: // The name prefix for all BSD Ethernet interfaces.
57: //
58: #define kIOEthernetInterfaceNamePrefix "en"
59:
60: //---------------------------------------------------------------------------
61: // Macros
62:
63: #define CTLR_SYNC_REQ(ctlr, action, ret, args...) \
64: ctlr->syncRequest(this, this, (IONetworkAction) action, \
65: (UInt32 *) ret, ## args)
66:
67: #ifdef DEBUG
68: #define DLOG(fmt, args...) IOLog(fmt, ## args)
69: #else
70: #define DLOG
71: #endif
72:
73: //---------------------------------------------------------------------------
74: // Initialize an IOEthernetInterface instance. Instance variables are
75: // initialized, and an arpcom structure is allocated.
76:
77: bool IOEthernetInterface::init(OSDictionary * properties = 0)
78: {
79: // Initialize instance variables.
80: //
81: _arpcom = 0; // arpcom structure.
82: _mcAddrCount = 0; // number of multicast addresses.
83: _features = 0; // controller's family specific features.
84: _activeFilters = 0; // active packet filters.
85: _availableFilters = 0; // available packet filters.
86: _controllerEnabled = false;
87:
88: // Allocate an arpcom structure, clear it, then call super::init().
89: // We expect our superclass to call getIfnet() during its init()
90: // method. So we have to create arpcom before calling super::init().
91:
92: if ((_arpcom = (struct arpcom *) IOMalloc(sizeof(*_arpcom))) == 0)
93: {
94: DLOG("IOEthernetInterface: arpcom allocation failed\n");
95: return false;
96: }
97:
98: bzero(_arpcom, sizeof(*_arpcom));
99:
100: // Pass the init() call to our superclass.
101: //
102: if (!super::init(properties))
103: return false;
104:
105: // Add an IONetworkData with room to hold an IOEthernetStats structure.
106: // This class does not reference the data object created, and no harm
107: // is done if the data object is released.
108:
109: IONetworkData * data = IONetworkData::withName(kIOEthernetStatsKey,
110: sizeof(IOEthernetStats));
111: if (data) {
112: addNetworkData(data);
113: data->release();
114: }
115:
116: return true;
117: }
118:
119: //---------------------------------------------------------------------------
120: // Initialize the ifnet structure. The argument specified is
121: // a pointer to an ifnet structure obtained through getIfnet().
122: // IOEthernetInterface will initialize this structure in a manner that
123: // is appropriate for Ethernet interfaces.
124: //
125: // ifp: Pointer to the ifnet structure to be initialized.
126: //
127: // Returns true if successful, false otherwise.
128:
129: bool IOEthernetInterface::initIfnet(struct ifnet * ifp)
130: {
131: struct arpcom * ac = (struct arpcom *) ifp;
132:
133: assert(ac);
134:
135: lock(); // lock interface state
136:
137: bzero(ac, sizeof(*ac));
138:
139: // Set defaults suitable for Ethernet interfaces.
140:
141: setInterfaceType(IFT_ETHER);
142: setMaxTransferUnit(ETHERMTU);
143: setMediaAddressLength(NUM_EN_ADDR_BYTES);
144: setMediaHeaderLength(ETHERHDRSIZE);
145: setFlags(IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS);
146:
147: unlock(); // unlock interface state
148:
149: return super::initIfnet(ifp);
150: }
151:
152: //---------------------------------------------------------------------------
153: // Free the IOEthernetInterface instance. The memory allocated
154: // for the arpcom structure is released.
155:
156: void IOEthernetInterface::free()
157: {
158: if (_arpcom) IOFree(_arpcom, sizeof(*_arpcom));
159:
160: super::free();
161: }
162:
163: //---------------------------------------------------------------------------
164: // This method returns a pointer to an ifnet structure
165: // maintained by the family specific interface. IOEthernetInterface
166: // allocates an arpcom structure during initialization, and returns
167: // a pointer to this structure when this method is called.
168: //
169: // Returns a pointer to an ifnet structure.
170:
171: struct ifnet * IOEthernetInterface::getIfnet() const
172: {
173: return (&(_arpcom->ac_if));
174: }
175:
176: //---------------------------------------------------------------------------
177: // The name of the interface advertised to the network layer
178: // is generated by concatenating the string returned by this method,
179: // and an unit number.
180: //
181: // Returns a pointer to a constant string "en". Thus Ethernet interfaces
182: // will be registered as en0, en1, etc.
183:
184: const char * IOEthernetInterface::getNamePrefix() const
185: {
186: return kIOEthernetInterfaceNamePrefix;
187: }
188:
189: //---------------------------------------------------------------------------
190: // Update the packet filter property. This property contains the set of
191: // packet filters needed by the interface. It may not represent the set
192: // of packet filters that are actually in use and enabled.
193: //
194: // Returns true if the newFilter provided is different from the previously
195: // cached value.
196:
197: bool IOEthernetInterface::_setActiveFilters(UInt32 newFilters)
198: {
199: if (newFilters == _activeFilters)
200: return false;
201:
202: _activeFilters = newFilters;
203: setProperty(kIOPacketFilters, _activeFilters, 32);
204: return true;
205: }
206:
207: //---------------------------------------------------------------------------
208: // Prepare the controller after it has been opened.
209: // This method will be called by our superclass after a
210: // network controller has accepted an open from this interface.
211: // IOEthernetInterface uses this method to inspect the controller
212: // and to cache certain controller properties, such as its hardware
213: // address, and its set of supported packet filters.
214: //
215: // controller: The controller object that was opened.
216: //
217: // Returns true if the controller was accepted, false otherwise
218: // (which will cause the controller to be closed).
219:
220: bool IOEthernetInterface::controllerDidOpen(IONetworkController * inController)
221: {
222: bool ret = false;
223: IOEthernetController * controller = OSDynamicCast(IOEthernetController,
224: inController);
225:
226: do {
227: IOReturn r;
228:
229: if (!controller)
230: break;
231:
232: // Call the superclass' controllerDidOpen().
233: //
234: if (!super::controllerDidOpen(controller))
235: break;
236:
237: // Cache the controller's family feature set.
238: //
239: _features = controller->getFamilyFeatureSet();
240:
241: // Get the controller's (supported) packet filters.
242: //
243: r = controller->doGetPacketFilters(this, &_availableFilters);
244:
245: if (r != kIOReturnSuccess)
246: {
247: DLOG("%s: doGetPacketFilters error %x\n", getName(), r);
248: break;
249: }
250:
251: // Controller must support Unicast and Broadcast filtering.
252: //
253: if ((_availableFilters &
254: (kIOPacketFilterUnicast | kIOPacketFilterBroadcast)) !=
255: (kIOPacketFilterUnicast | kIOPacketFilterBroadcast))
256: {
257: DLOG("%s: No Unicast/Broadcast packet filters %lx\n",
258: getName(), _availableFilters);
259: break;
260: }
261:
262: // If controller reports multicast or multicast-all capability,
263: // then update if_flags to include multicast support.
264: //
265: if (_availableFilters &
266: (kIOPacketFilterMulticast | kIOPacketFilterMulticastAll))
267: {
268: setFlagsInt(IFF_MULTICAST);
269: }
270:
271: // Even though the network stack will not explicitly request the
272: // interface to enable Unicast and Broadcast filtering. It is
273: // implicit. Therefore, we will always activate both of those
274: // filter types.
275:
276: _setActiveFilters(kIOPacketFilterUnicast | kIOPacketFilterBroadcast);
277:
278: r = controller->doEnablePacketFilters(this, _activeFilters);
279:
280: if (r != kIOReturnSuccess)
281: {
282: DLOG("%s: Failed to enable Unicast/Broadcast filters %x\n",
283: getName(), r);
284: break;
285: }
286:
287: // Read and save the controller's MAC address.
288: //
289: r = ((IOEthernetController *)
290: controller)->doGetHardwareAddress(this, &_macAddr);
291: if (r != kIOReturnSuccess)
292: {
293: DLOG("%s: kRequestGetHardwareAddress error %x\n", getName(), r);
294: break;
295: }
296:
297: #if 1 // Print the MAC address
298: IOLog("%s: Ethernet address %02x:%02x:%02x:%02x:%02x:%02x\n",
299: getName(),
300: _macAddr.ether_addr_octet[0],
301: _macAddr.ether_addr_octet[1],
302: _macAddr.ether_addr_octet[2],
303: _macAddr.ether_addr_octet[3],
304: _macAddr.ether_addr_octet[4],
305: _macAddr.ether_addr_octet[5]);
306: #endif
307:
308: // Copy the hardware address we obtained from the controller
309: // to the arpcom structure.
310: //
311: bcopy(&_macAddr, _arpcom->ac_enaddr, NUM_EN_ADDR_BYTES);
312:
313: // Store MAC address in interface's propertyTable.
314: //
315: setProperty(kIOMACAddress, (void *) &_macAddr, NUM_EN_ADDR_BYTES);
316:
317: ret = true;
318: }
319: while (0);
320:
321: return ret;
322: }
323:
324: //---------------------------------------------------------------------------
325: // When the last close from our client is received, the
326: // interface object will close its controller. But before the controller
327: // is closed, this method will be called by our superclass to perform any
328: // final cleanup. IOEthernetInterface will ensure that the controller
329: // is disabled before it is closed.
330: //
331: // controller: The currently opened controller object.
332:
333: void IOEthernetInterface::controllerWillClose(IONetworkController * controller)
334: {
335: if (_controllerEnabled)
336: {
337: // Make sure the controller is disabled when we have lost all
338: // our clients, and is about to close the controller. It
339: // should be safe to update the _controllerEnabled variable
340: // shared with the ioctl handlers, which shouldn't run without
341: // an open client.
342:
343: controller->doDisable(this);
344: _controllerEnabled = false;
345: }
346:
347: super::controllerWillClose(controller);
348: }
349:
350: //---------------------------------------------------------------------------
351: // The handler for ioctl commands sent from the network layer.
352: // Commands not handled by this method are passed to our superclass.
353: //
354: // Argument convention is:
355: //
356: // arg0 - (struct ifnet *)
357: // arg1 - (void *)
358: //
359: // The commands handled by IOEthernetInterface are:
360: //
361: // SIOCSIFADDR
362: // SIOCSIFFLAGS
363: // SIOCADDMULTI
364: // SIOCDELMULTI
365: //
366: // Returns an error code defined in errno.h (BSD).
367:
368: SInt IOEthernetInterface::performCommand(IONetworkController * inController,
369: UInt32 cmd,
370: void * arg0,
371: void * arg1)
372: {
373: struct arpcom * ac = (struct arpcom *) _arpcom;
374: struct ifaddr * ifa = (struct ifaddr *) arg1;
375: SInt ret = EBUSY;
376: IOEthernetController * controller = (IOEthernetController *) inController;
377:
378: assert(arg0 == _arpcom);
379:
380: if (!controller) return EINVAL;
381:
382: switch (cmd)
383: {
384: case SIOCSIFADDR:
385: CTLR_SYNC_REQ(controller, &IOEthernetInterface::syncSIOCSIFADDR,
386: &ret, controller);
387: if (ret)
388: {
389: IOLog("IOEthernetInterface: SIOCSIFADDR returned %d\n", ret);
390: break;
391: }
392:
393: switch (ifa->ifa_addr->sa_family)
394: {
395: case AF_INET:
396: //
397: // See if another station has *our* IP address.
398: // i.e.: There is an address conflict! If a
399: // conflict exists, a message is sent to the
400: // console.
401: //
402: if (IA_SIN(ifa)->sin_addr.s_addr != 0)
403: {
404: /* don't bother for 0.0.0.0 */
405: ac->ac_ipaddr = IA_SIN(ifa)->sin_addr;
406: arpwhohas(ac, &IA_SIN(ifa)->sin_addr);
407: }
408: break;
409:
410: default:
411: break;
412: }
413: break;
414:
415: case SIOCSIFFLAGS:
416: CTLR_SYNC_REQ(controller, &IOEthernetInterface::syncSIOCSIFFLAGS,
417: &ret, controller);
418: break;
419:
420: case SIOCADDMULTI:
421: CTLR_SYNC_REQ(controller, &IOEthernetInterface::syncSIOCADDMULTI,
422: &ret, controller);
423: break;
424:
425: case SIOCDELMULTI:
426: CTLR_SYNC_REQ(controller, &IOEthernetInterface::syncSIOCDELMULTI,
427: &ret, controller);
428: break;
429:
430: default:
431: // Don't know what to do with this ioctl command, forward it
432: // to our superclass.
433: //
434: ret = super::performCommand(controller, cmd, arg0, arg1);
435: break;
436: }
437:
438: return ret;
439: }
440:
441: //---------------------------------------------------------------------------
442: // _enableController() is reponsible for calling the controller's enable()
443: // method and restoring the state of the controller. We assume that
444: // controllers can completely reset its state upon receiving a disable()
445: // method call. And when it is brought back up, the interface should
446: // assist in restoring the previous state of the Ethernet controller.
447:
448: IOReturn IOEthernetInterface::_enableController(IONetworkController * ctlr)
449: {
450: IOReturn ret;
451:
452: assert(ctlr);
453:
454: // Send the controller an enable request.
455: //
456: ret = ctlr->doEnable(this);
457: if (ret != kIOReturnSuccess)
458: return ret; // unable to bring up the controller.
459:
460: // Restore current filter settings.
461: //
462: ret = ctlr->doEnablePacketFilters(this, _activeFilters);
463: if (ret != kIOReturnSuccess)
464: goto error;
465:
466: // Update multicast address list.
467: //
468: if (_availableFilters & kIOPacketFilterMulticast)
469: {
470: ret = _loadMulticastList((IOEthernetController *) ctlr);
471: if (ret != kIOReturnSuccess)
472: goto error;
473: }
474:
475: _controllerEnabled = true;
476:
477: return kIOReturnSuccess;
478:
479: error:
480: // If the controller was enabled, make sure we disable it if an
481: // error occurred.
482: //
483: DLOG("%s: _enableController error %x\n", getName(), ret);
484:
485: ret = ctlr->doDisable(this);
486:
487: return ret;
488: }
489:
490: //---------------------------------------------------------------------------
491: // Handles SIOCSIFFLAGS ioctl command for Ethernet interfaces. The network
492: // stack has changed the if_flags field in ifnet. Our job is to go
493: // through if_flags and see what has changed, and act accordingly.
494: //
495: // The fact that if_flags contains both generic and Ethernet specific bits
496: // means that we cannot move some of the default flag processing to the
497: // superclass. Sigh...
498:
499: int IOEthernetInterface::syncSIOCSIFFLAGS(IOEthernetController * ctlr)
500: {
501: SInt r = 0;
502: UInt16 flags = getFlags();
503: IOReturn ret;
504: UInt32 newFilters = _activeFilters;
505:
506: if ( !(flags & IFF_UP) && (flags & IFF_RUNNING) )
507: {
508: // If interface is marked down and it is running,
509: // then stop it.
510:
511: ctlr->doDisable(this);
512: flags &= ~IFF_RUNNING;
513: _controllerEnabled = false;
514: }
515: else if ( (flags & IFF_UP) && !(flags & IFF_RUNNING) )
516: {
517: // If interface is marked up and it is stopped, then
518: // start it.
519:
520: if ((ret = _enableController(ctlr)) == kIOReturnSuccess)
521: flags |= IFF_RUNNING;
522: else
523: r = errnoFromReturn(ret);
524: }
525:
526: if (flags & IFF_RUNNING)
527: {
528: // Set/Clear promiscuous mode.
529: //
530: if (_availableFilters & kIOPacketFilterPromiscuous)
531: {
532: if (flags & IFF_PROMISC)
533: newFilters |= kIOPacketFilterPromiscuous;
534: else
535: newFilters &= ~kIOPacketFilterPromiscuous;
536: }
537:
538: // Set/Clear Multicast-All mode.
539: //
540: if (_availableFilters & kIOPacketFilterMulticastAll)
541: {
542: if (flags & IFF_ALLMULTI)
543: newFilters |= kIOPacketFilterMulticastAll;
544: else
545: newFilters &= ~kIOPacketFilterMulticastAll;
546: }
547: }
548:
549: if (_setActiveFilters(newFilters))
550: {
551: ret = ctlr->doEnablePacketFilters(this, newFilters);
552: if (ret != kIOReturnSuccess)
553: r = errnoFromReturn(ret);
554: }
555:
556: // Update the flags field to pick up any modifications. Also update the
557: // property table to reflect any flag changes.
558: //
559: setFlagsInt(flags, ~flags);
560:
561: return r;
562: }
563:
564: //---------------------------------------------------------------------------
565: // Handles SIOCSIFADDR ioctl command for Ethernet interfaces.
566:
567: SInt IOEthernetInterface::syncSIOCSIFADDR(IOEthernetController * ctlr)
568: {
569: SInt r = 0;
570: UInt16 flags = getFlags();
571:
572: flags |= IFF_UP;
573:
574: if (!(flags & IFF_RUNNING))
575: {
576: r = errnoFromReturn(_enableController(ctlr));
577: if (r == 0)
578: flags |= IFF_RUNNING;
579: }
580:
581: setFlagsInt(flags, ~flags);
582:
583: return r;
584: }
585:
586: //---------------------------------------------------------------------------
587: // This method is called by syncSIOCADDMULTI() and syncSIOCDELMULTI() to
588: // reload the hardware's multicast filter whenever the multicast address
589: // list is changed. A OSData is published in the property table containing
590: // the multicast addresses.
591:
592: IOReturn
593: IOEthernetInterface::_loadMulticastList(IOEthernetController * ctlr)
594: {
595: enet_addr_t * multiAddrs = 0;
596: UInt mcount;
597: OSData * mcData = 0;
598: struct ifnet * ifp = (struct ifnet *) _arpcom;
599: struct ifmultiaddr * ifma;
600: IOReturn ret;
601: bool ok;
602:
603: assert(ifp);
604:
605: // Update the multicast addresses count ivar.
606: //
607: mcount = 0;
608: for (ifma = ifp->if_multiaddrs.lh_first;
609: ifma != NULL;
610: ifma = ifma->ifma_link.le_next)
611: {
612: if ((ifma->ifma_addr->sa_family == AF_UNSPEC) ||
613: (ifma->ifma_addr->sa_family == AF_LINK))
614: mcount++;
615: }
616: _mcAddrCount = mcount;
617:
618: if (mcount)
619: {
620: char * addrp;
621:
622: mcData = OSData::withCapacity(mcount * NUM_EN_ADDR_BYTES);
623: if (!mcData)
624: {
625: DLOG("%s: multicast memory allocation failed\n", getName());
626: return kIOReturnNoMemory;
627: }
628:
629: // Loop through the linked multicast structures and write the
630: // address to the OSData.
631: //
632: for (ifma = ifp->if_multiaddrs.lh_first;
633: ifma != NULL;
634: ifma = ifma->ifma_link.le_next)
635: {
636: if (ifma->ifma_addr->sa_family == AF_UNSPEC)
637: addrp = &ifma->ifma_addr->sa_data[0];
638: else
639: if (ifma->ifma_addr->sa_family == AF_LINK)
640: addrp = LLADDR((struct sockaddr_dl *) ifma->ifma_addr);
641: else
642: continue;
643:
644: ok = mcData->appendBytes((const void *) addrp, NUM_EN_ADDR_BYTES);
645: assert(ok);
646: }
647:
648: multiAddrs = (enet_addr_t *) mcData->getBytesNoCopy();
649: assert(multiAddrs);
650: }
651:
652: // Call the controller's setMulticastList() method.
653: //
654: ret = ctlr->doSetMulticastList(this, multiAddrs, mcount);
655:
656: if (mcData)
657: {
658: if (ret == kIOReturnSuccess)
659: setProperty(kIOMulticastAddresses, mcData);
660: mcData->release();
661: }
662: else {
663: removeProperty(kIOMulticastAddresses);
664: }
665:
666: return ret;
667: }
668:
669: //---------------------------------------------------------------------------
670: // Handles SIOCADDMULTI ioctl command.
671:
672: SInt IOEthernetInterface::syncSIOCADDMULTI(IOEthernetController * ctlr)
673: {
674: IOReturn ret;
675: UInt32 activatedFilters;
676: SInt r = 0;
677:
678: if (_availableFilters & kIOPacketFilterMulticast)
679: {
680: _setActiveFilters(_activeFilters | kIOPacketFilterMulticast);
681:
682: // Make sure the multicast filter is active.
683: //
684: ret = ctlr->doEnablePacketFilters(this, _activeFilters,
685: &activatedFilters);
686:
687: // If the controller did not activate the multicast filter,
688: // report an error.
689: //
690: if ((activatedFilters & kIOPacketFilterMulticast) == 0)
691: {
692: assert(ret != kIOReturnSuccess);
693: r = errnoFromReturn(ret);
694: }
695:
696: // Do not load multicast list if the multicast filter
697: // did not become active.
698: //
699: if (r == 0)
700: r = errnoFromReturn(_loadMulticastList(ctlr));
701: }
702: else
703: r = EOPNOTSUPP; // no multicast support.
704:
705: return r;
706: }
707:
708: //---------------------------------------------------------------------------
709: // Handles SIOCDELMULTI ioctl command.
710:
711: SInt IOEthernetInterface::syncSIOCDELMULTI(IOEthernetController * ctlr)
712: {
713: IOReturn ret;
714: UInt32 activatedFilters;
715: SInt r = 0;
716:
717: if (_availableFilters & kIOPacketFilterMulticast)
718: {
719: r = errnoFromReturn(_loadMulticastList(ctlr));
720:
721: if (r == 0)
722: {
723: // If the multicast list is now empty, instruct the controller
724: // to turn off its multicast filter.
725:
726: if (_mcAddrCount == 0)
727: {
728: _setActiveFilters(_activeFilters & ~kIOPacketFilterMulticast);
729:
730: ret = ctlr->doEnablePacketFilters(this, _activeFilters,
731: &activatedFilters);
732:
733: if (activatedFilters & kIOPacketFilterMulticast)
734: {
735: assert(ret != kIOReturnSuccess);
736: r = errnoFromReturn(ret);
737: }
738: }
739: }
740: }
741: else
742: r = EOPNOTSUPP; // no multicast support.
743:
744: return r;
745: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.