]>
Commit | Line | Data |
---|---|---|
1c79356b A |
1 | /* |
2 | * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. | |
3 | * | |
4 | * @APPLE_LICENSE_HEADER_START@ | |
5 | * | |
6 | * The contents of this file constitute Original Code as defined in and | |
7 | * are subject to the Apple Public Source License Version 1.1 (the | |
8 | * "License"). You may not use this file except in compliance with the | |
9 | * License. Please obtain a copy of the License at | |
10 | * http://www.apple.com/publicsource and read it before using this file. | |
11 | * | |
12 | * This Original Code and all software distributed under the License are | |
13 | * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
14 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, | |
15 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
16 | * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the | |
17 | * License for the specific language governing rights and limitations | |
18 | * under the License. | |
19 | * | |
20 | * @APPLE_LICENSE_HEADER_END@ | |
21 | */ | |
22 | /* | |
23 | * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. | |
24 | * | |
25 | * 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 | } |