|
|
1.1 root 1: /*
2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7: * Reserved. This file contains Original Code and/or Modifications of
8: * Original Code as defined in and that are subject to the Apple Public
9: * Source License Version 1.1 (the "License"). You may not use this file
10: * except in compliance with the License. Please obtain a copy of the
11: * License at http://www.apple.com/publicsource and read it before using
12: * this file.
13: *
14: * The Original Code and all software distributed under the License are
15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18: * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. Please see the
19: * License for the specific language governing rights and limitations
20: * under the License.
21: *
22: * @APPLE_LICENSE_HEADER_END@
23: */
24: /*
25: * Copyright (c) 1992 NeXT Computer, Inc.
26: *
27: * Device independent abstract superclass for Ethernet.
28: *
29: * HISTORY
30: *
31: * 25 September 1992 David E. Bohman at NeXT
32: * Created.
33: *
34: * 4 April 1993 Joel D. Greenblatt at NeXT
35: * Integrated multicast & promiscuous mode support.
36: */
37:
38: #define MACH_USER_API 1
39:
40: #import <mach/mach_types.h>
41: #import <mach/message.h>
42:
43: #import <machkit/NXLock.h>
44:
45: #import <driverkit/generalFuncs.h>
46: #import <driverkit/interruptMsg.h>
47:
48: #import <sys/errno.h>
49: #import <sys/socket.h>
50: #ifndef NEXT
51: #define NEXT 1
52: #endif
53: #import <sys/sockio.h>
54:
55: #import <driverkit/IOEthernet.h>
56: #import <driverkit/IOEthernetPrivate.h>
57: #import <netinet/in_var.h>
58: #import <netinet/if_ether.h>
59:
60: #import <net/bpf.h>
61:
62: #define min(a, b) (((a) < (b)) ? (a) : (b))
63:
64: /*
65: * Allowable values for _net_buf_type
66: */
67: enum {
68: _NET_BUF_TYPE_NETBUF, // netbuf
69: _NET_BUF_TYPE_MBUF, // mbuf
70: };
71:
72: static void
73: IOEthernetTimeout(IOEthernet *device);
74:
75: static char IOEthernetDeviceName[] = "en",
76: IOEthernetDeviceType[] = "Ethernet";
77: static int IOEthernetDeviceCount = 0;
78:
79:
80: @interface DriverCmd:Object
81: {
82: @private
83: port_t _driverPort_kern;
84: id _interLock;
85: #define DONE 1
86: #define BUSY 2
87: #define IDLE 3
88: int _oper;
89: #define RESET_ON 1
90: #define RESET_OFF 2
91: #define TERMINATE 4
92: #define PROMISC_ENABLE 5
93: #define PROMISC_DISABLE 6
94: #define MULTICAST_ENABLE 7
95: #define MULTICAST_DISABLE 8
96: int _ret;
97: void * _param;
98: }
99: @end
100:
101: @implementation DriverCmd
102:
103: - initPort:(port_t)port
104: {
105: [super init];
106:
107: _interLock = [[NXConditionLock alloc] initWith:IDLE];
108:
109: _driverPort_kern = IOGetKernPort(port);
110:
111: return self;
112: }
113:
114: - free
115: {
116: [_interLock free];
117:
118: port_release(_driverPort_kern);
119:
120: return [super free];
121: }
122:
123: - (int)oper
124: {
125: return (_oper);
126: }
127:
128: - (void *)param
129: {
130: return (_param);
131: }
132:
133: - (void)done:(int)ret
134: {
135: if ([_interLock condition] == BUSY) {
136: [_interLock lock];
137: _ret = ret;
138: [_interLock unlockWith:DONE];
139: }
140: }
141:
142: - (int)send:(int)oper withParam:(void *)param
143:
144: {
145: msg_header_t msg = { 0 };
146: int result;
147:
148: [_interLock lockWhen:IDLE];
149:
150: _oper = oper;
151: _param = param;
152:
153: msg.msg_size = sizeof (msg);
154: msg.msg_remote_port = _driverPort_kern;
155: msg.msg_id = IO_COMMAND_MSG;
156:
157: [_interLock unlockWith:BUSY];
158:
159: result = msg_send_from_kernel(&msg, MSG_OPTION_NONE, 0);
160: if (result == SEND_SUCCESS) {
161: [_interLock lockWhen:DONE];
162: result = _ret;
163: }
164: else
165: [_interLock lock];
166:
167: [_interLock unlockWith:IDLE];
168:
169: return (result);
170: }
171:
172: - (int)send:(int)oper
173: {
174: return( [self send:oper withParam:0]);
175: }
176:
177: @end
178:
179: @implementation IOEthernet
180:
181: - initFromDeviceDescription:(IODeviceDescription *)devDesc
182: {
183: char devName[8];
184: int unit;
185:
186: if ([super initFromDeviceDescription:devDesc] == nil)
187: return nil;
188:
189: if ([self startIOThread] != IO_R_SUCCESS) {
190: [self free];
191: return nil;
192: }
193:
194: if( (en_arpcom = IOMalloc( sizeof( *en_arpcom))) == NULL) {
195: [self free];
196: return nil;
197: }
198: bzero( en_arpcom, sizeof( *en_arpcom));
199:
200: _driverCmd = [[DriverCmd alloc] initPort:[self interruptPort]];
201:
202: queue_init(&_multicastQueue);
203:
204: if ([self respondsTo:@selector(mbufsPlease)]) {
205: _net_buf_type = _NET_BUF_TYPE_MBUF;
206: printf("IOEthernet: driver registered to use mbufs\n");
207: }
208: else {
209: _net_buf_type = _NET_BUF_TYPE_NETBUF;
210: }
211:
212: unit = IOEthernetDeviceCount++;
213:
214: sprintf(devName, "%s%d", IOEthernetDeviceName,unit);
215: [self setName:devName];
216: [self setDeviceKind:IOEthernetDeviceType];
217: [self setUnit:unit];
218:
219: [self registerDevice];
220:
221: return self;
222: }
223:
224: - free
225: {
226: enetMulti_t *multiAddr;
227:
228: [self clearTimeout];
229: if (_driverCmd) {
230: [_driverCmd send:TERMINATE];
231: [_driverCmd free];
232: }
233: if (_netif)
234: [_netif free];
235:
236: if( en_arpcom)
237: IOFree( en_arpcom, sizeof( *en_arpcom));
238:
239: return [super free];
240: }
241:
242: - (BOOL)isRunning
243: {
244: return (_isRunning);
245: }
246:
247: - (void)setRunning:(BOOL)running
248: {
249: _isRunning = running;
250: }
251:
252: /*
253: * Implement driver timeouts.
254: */
255: - (unsigned int)relativeTimeout
256: {
257: ns_time_t timestamp;
258:
259: if (_absTimeout == 0)
260: return (0);
261:
262: IOGetTimestamp(×tamp);
263:
264: if (_absTimeout <= timestamp) {
265: _absTimeout = 0; return (0);
266: }
267:
268: return ((unsigned int) ((_absTimeout - timestamp) / (1000 * 1000)));
269: }
270:
271: - (void)setRelativeTimeout:(unsigned int)timeout
272: {
273: if (_absTimeout > 0)
274: (void)ns_untimeout((func)IOEthernetTimeout, self);
275:
276: IOGetTimestamp(&_absTimeout);
277:
278: _absTimeout += ((ns_time_t)timeout * (1000 * 1000));
279:
280: ns_abstimeout(
281: (func)IOEthernetTimeout, self, _absTimeout, CALLOUT_PRI_THREAD);
282: }
283:
284: - (void)clearTimeout
285: {
286: if (_absTimeout > 0) {
287: (void)ns_untimeout((func)IOEthernetTimeout, self);
288: _absTimeout = 0;
289: }
290: }
291:
292: //
293: // Multicast Methods
294: //
295:
296: /*
297: * Determine if specified packet passes thru multicast filter. Returns
298: * YES if packet should be dropped (because it is an unregistered multicast
299: * packet), else returns NO.
300: * Must be called from command thread.
301: */
302: - (BOOL)isUnwantedMulticastPacket:(ether_header_t *)header
303: {
304: int i;
305: enetMulti_t *multi;
306: BOOL isBroadcastPacket = YES;
307:
308: if ((header->ether_dhost[EA_GROUP_BYTE] & EA_GROUP_BIT) &&
309: !_promiscEnabled) {
310:
311:
312: for (i = 0 ; i < NUM_EN_ADDR_BYTES ; ++i) {
313: if (header->ether_dhost[i] != 0xff) {
314: isBroadcastPacket = NO;
315: break;
316: }
317: }
318:
319: /*
320: * Always accept the all-ones broadcast.
321: */
322: if (isBroadcastPacket)
323: return NO;
324:
325: /*
326: * Is this address registered as a multicast address?
327: *
328: * CAREFUL - this assumes that the bytes in
329: * the packet are in the same format as the
330: * bytes in an enet_addr_t...
331: */
332: multi = [self searchMulti:(enet_addr_t *)&header->ether_dhost];
333: if (multi == NULL) {
334: /*
335: * We don't want this.
336: */
337: return YES;
338: }
339: }
340:
341: /*
342: * Not a group packet (or is a registered multicast pckt),
343: * must be for us.
344: */
345: return NO;
346: }
347:
348:
349: /*
350: * Determine if the outgoing packet should be received by the current
351: * interface (either because it's a broadcast packet or a multicast
352: * packet for which we are enabled); if so, send a copy of the packet
353: * up the pipe.
354: */
355: /*
356: * DWS 7/25/97
357: *
358: * In BSD 4.4, the layer above already takes care of looping back packets:
359: * see bsd/net/if_ethersubr.c.
360: */
361: - (void)performLoopback : (netbuf_t)pkt
362: {
363: }
364:
365: #import <sys/param.h>
366: #import <sys/mbuf.h>
367:
368: //
369: // Implement the IONetworkDeviceMethods protocol.
370: //
371: // NOTE: Stop the unneeded copies and proc calls.
372: // Also: we want to "guarantee" that the media header is still
373: // in the mbuf; the new code makes it clear.
374: //
375: -(int) inputPacket: (netbuf_t)pkt extra:(void *)extra
376: {
377: struct ether_header *eh;
378: struct ifnet *ifp;
379: struct mbuf *m;
380:
381: ifp = (struct ifnet *)&en_arpcom->ac_if;
382: ifp->if_ipackets += 1;
383: m = (struct mbuf *)pkt;
384: m->m_pkthdr.rcvif = ifp;
385:
386: if (ifp->if_bpf)
387: BPF_MTAP(ifp->if_bpf, m);
388:
389: eh = (struct ether_header *)m->m_data;
390: m->m_len -= sizeof (struct ether_header);
391: m->m_data += sizeof (struct ether_header);
392:
393: if (_net_buf_type == _NET_BUF_TYPE_NETBUF) {
394: /* guaranteed one-piece packet */
395: m->m_pkthdr.len = m->m_len;
396: }
397: else {
398: m->m_pkthdr.len -= sizeof(struct ether_header);
399: }
400:
401: ether_input(ifp, eh, (struct mbuf *)pkt);
402:
403: return 0;
404: }
405:
406: - (int)finishInitialization
407: {
408: return [_driverCmd send:RESET_ON];
409: }
410:
411: - (int)outputPacket:(netbuf_t)pkt address:(void *)addrs
412: {
413: ether_header_t *header;
414: enet_addr_t *ea;
415: int length;
416:
417: if (!_isRunning) {
418: nb_free(pkt);
419: return 0;
420: }
421:
422: /*
423: * Setup the Ethernet header
424: */
425: header = (ether_header_t *)nb_map(pkt);
426:
427: /*
428: * Insert the destination address
429: */
430: ea = (enet_addr_t *)header->ether_dhost;
431: *ea = *(enet_addr_t *)addrs;
432:
433: /*
434: * Insert our source address
435: */
436: ea = (enet_addr_t *)header->ether_shost;
437: *ea = _ethernetAddress;
438:
439: /*
440: * Insure that the packet meets minimum length requirements
441: */
442: length = nb_size(pkt);
443: if (length < (ETHERMINPACKET - ETHERCRC))
444: nb_grow_bot(pkt, ETHERMINPACKET - ETHERCRC - length);
445:
446: [self transmit:pkt];
447:
448: return (0);
449: }
450:
451: - (netbuf_t)allocateNetbuf
452: {
453: return (nb_alloc(ETHERMAXPACKET));
454: }
455:
456:
457: - (int)performCommand:(const char *)command data:(void *)data
458: {
459: return (0);
460: }
461: - (id)getDriverCmd
462: {
463: return(_driverCmd);
464: }
465:
466: - (struct ifnet *)allocateIfnet
467: {
468: return(&en_arpcom->ac_if);
469: }
470:
471: //
472: // Methods which implement the
473: // IOEthernet(DriverInterface) category.
474: //
475: - (BOOL)resetAndEnable:(BOOL)enable
476: {
477: return (TRUE);
478: }
479:
480: IOEthernet_ioctl(struct ifnet * ifp,u_long cmd, caddr_t data)
481: {
482: struct arpcom * ar;
483: id device = ifp->if_private;
484: id dcmd;
485: unsigned error = 0;
486: struct ifaddr * ifa = (struct ifaddr *)data;
487: struct ifreq * ifr = (struct ifreq *)data;
488: unsigned ioctl_command;
489: void * ioctl_data;
490: int s;
491: // R E M E M B E R
492: // sockaddr_in comes from bsd/netinet/in.h
493: struct sockaddr_in * sin;
494:
495: sin = (struct sockaddr_in *)(&((struct ifreq *)data)->ifr_addr);
496:
497: ar = (struct arpcom *)ifp;
498:
499: dcmd = [device getDriverCmd];
500: switch (cmd) {
501: case SIOCAUTOADDR:
502: error = in_bootp(ifp, sin,
503: &((struct IOEthernet *)device)->_ethernetAddress);
504: break;
505:
506: case SIOCSIFADDR:
507: #if NeXT
508: ifp->if_flags |= (IFF_UP | IFF_RUNNING);
509: #else
510: ifp->if_flags |= IFF_UP;
511: #endif
512: switch (ifa->ifa_addr->sa_family) {
513: case AF_INET:
514: [dcmd send:RESET_ON];
515: /*
516: * See if another station has *our* IP address.
517: * i.e.: There is an address conflict! If a
518: * conflict exists, a message is sent to the
519: * console.
520: */
521: if (IA_SIN(ifa)->sin_addr.s_addr != 0) { /* don't bother for 0.0.0.0 */
522: ar->ac_ipaddr = IA_SIN(ifa)->sin_addr;
523: arpwhohas(ar, &IA_SIN(ifa)->sin_addr);
524: }
525: break;
526: default:
527: [dcmd send:RESET_ON];
528: break;
529: }
530: break;
531:
532: case SIOCSIFFLAGS:
533: /*
534: * If interface is marked down and it is running, then stop it
535: */
536: if ((ifp->if_flags & IFF_UP) == 0 &&
537: (ifp->if_flags & IFF_RUNNING) != 0) {
538: /*
539: * If interface is marked down and it is running, then
540: * stop it.
541: */
542: ifp->if_flags &= ~IFF_RUNNING;
543: } else if ((ifp->if_flags & IFF_UP) != 0 &&
544: (ifp->if_flags & IFF_RUNNING) == 0) {
545: /*
546: * If interface is marked up and it is stopped, then
547: * start it.
548: */
549: [dcmd send:RESET_ON];
550: ifp->if_flags |= IFF_RUNNING;
551: } else {
552: /*
553: * Reset the interface to pick up changes in any other
554: * flags that affect hardware registers.
555: */
556: [dcmd send:RESET_ON];
557: }
558: /*
559: * Set or clear promiscuous mode as appropriate
560: */
561: if (ifp->if_flags & IFF_RUNNING) {
562: BOOL isProm = ((struct IOEthernet *)device)->_promiscEnabled;
563: if (isProm && !(ifp->if_flags & IFF_PROMISC))
564: [dcmd send:PROMISC_DISABLE];
565: else if (!isProm && (ifp->if_flags & IFF_PROMISC))
566: [dcmd send:PROMISC_ENABLE];
567:
568: }
569: break;
570:
571: case SIOCADDMULTI:
572: error = ether_addmulti(ifr, ar);
573: if (error == ENETRESET) {
574: error = 0;
575: [device enableMulticast:
576: (enet_addr_t *)ar->ac_multiaddrs->enm_addrlo];
577: }
578: break;
579: case SIOCDELMULTI:
580: {
581: struct ether_addr enaddr[2]; /* 0 - addrlo, 1 - addrhi */
582:
583: error = ether_delmulti(ifr, ar, enaddr);
584: if (error == ENETRESET) {
585: error = 0;
586: [device disableMulticast:enaddr]; /* XXX assume addrlo == addrhi */
587: }
588: }
589: break;
590:
591: default:
592: error = EINVAL;
593: break;
594: }
595: return (error);
596: // return [device performCommand:cmd data:data];
597:
598:
599: }
600:
601: #include <sys/mbuf.h>
602:
603: static int
604: IOEthernet_transmitPacket(
605: struct ifnet *ifp
606: )
607: {
608: void *buf_p;
609: id device = ifp->if_private;
610: IOEthernet *eth = (IOEthernet *)device;
611: struct mbuf *m, *mp;
612: int mLen;
613: netbuf_t pkt;
614: int pktSize;
615:
616: if (device == nil) {
617: return -1;
618: }
619:
620: IF_DEQUEUE(&(ifp->if_snd), m);
621:
622: if (m == 0)
623: return 0;
624:
625: if ((m->m_flags & M_PKTHDR) == 0) {
626: IOLog("IOEthernet: M_PKTHDR flag not set (%04x)\n", m->m_flags);
627: m_freem(m);
628: return -1;
629: }
630:
631: if (ifp->if_bpf)
632: BPF_MTAP(ifp->if_bpf, m);
633:
634: if (eth->_net_buf_type == _NET_BUF_TYPE_MBUF)
635: [device transmit:(netbuf_t)m];
636: else {
637: /* old compat interface uses netbufs */
638: pkt = [device allocateNetbuf]; /* call the driver's allocation routine */
639: if (pkt == 0) {
640: m_freem(m);
641: return 0;
642: }
643:
644: mLen = m->m_pkthdr.len;
645: buf_p = nb_map(pkt);
646: pktSize = nb_size(pkt);
647: if (pktSize < mLen) {
648: IOLog("IOEthernet: %s driver packet size too small (%d < %d)\n",
649: [device name], pktSize, mLen);
650: m_freem(m);
651: nb_free(pkt);
652: return 0;
653: }
654:
655: { /* copy the mbuf to the netbuf */
656: int len = mLen;
657: struct mbuf * m_pkt;
658:
659: for (mp = m; mp; mp = mp->m_next) {
660: if (mp->m_len == 0)
661: continue;
662: bcopy(mtod(mp, caddr_t), buf_p, min(len, mp->m_len));
663: buf_p += mp->m_len;
664: len -= mp->m_len;
665: }
666: m_pkt = (struct mbuf *)pkt;
667: m_pkt->m_len = mLen;
668: m_pkt->m_pkthdr.len = mLen;
669: }
670: m_freem(m);
671: [device transmit:pkt];
672: }
673:
674: return 0;
675: }
676:
677:
678: static void
679: null_func()
680: {
681: }
682:
683: - (IONetwork *)attachToNetworkWithAddress:(enet_addr_t)addrs
684: {
685: struct ifnet *ifp;
686:
687: _ethernetAddress = addrs;
688: bcopy(&addrs,en_arpcom->ac_enaddr,6);
689:
690: _netif = [[IONetwork alloc] initForNetworkDevice:self
691: name:IOEthernetDeviceName unit:[self unit]
692: type:IFTYPE_ETHERNET
693: maxTransferUnit:ETHERMTU
694: flags:0];
695: ifp = [_netif getIONetworkIfnet];
696: ifp->if_unit = [self unit];
697: ifp->if_name = "en";
698:
699: /*
700: *
701: * Fix the start and WD functions
702: */
703: ifp->if_output = ether_output;
704: ifp->if_ioctl = IOEthernet_ioctl;
705: ifp->if_start = IOEthernet_transmitPacket;
706: ifp->if_watchdog = (void *) null_func;
707:
708: ifp->if_flags =
709: IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS | IFF_MULTICAST;
710: bpfattach(&ifp->if_bpf, ifp, DLT_EN10MB, sizeof(struct ether_header));
711: if_attach(ifp);
712: ether_ifattach(ifp);
713:
714: [self registerAsDebuggerDevice];
715:
716: IOLog("%s: Ethernet address %02x:%02x:%02x:%02x:%02x:%02x\n",
717: [self name],
718: _ethernetAddress.ether_addr_octet[0],
719: _ethernetAddress.ether_addr_octet[1],
720: _ethernetAddress.ether_addr_octet[2],
721: _ethernetAddress.ether_addr_octet[3],
722: _ethernetAddress.ether_addr_octet[4],
723: _ethernetAddress.ether_addr_octet[5]);
724:
725: return _netif;
726: }
727:
728: - (void)transmit:(netbuf_t)pkt
729: {
730: nb_free(pkt);
731: }
732:
733: - (void)receivePacket:(void *)pkt
734: length:(unsigned int *)pkt_len
735: timeout:(unsigned int)timeout
736: {
737: *pkt_len = 0;
738: }
739:
740: - (void)sendPacket:(void *)pkt
741: length:(unsigned int)pkt_len
742: {
743: }
744:
745: - (BOOL)enablePromiscuousMode
746: {
747: return YES;
748: }
749:
750: - (void)disablePromiscuousMode
751: {
752: }
753:
754: - (void)addMulticastAddress:(enet_addr_t *)addr
755: {
756: }
757:
758: - (void)removeMulticastAddress:(enet_addr_t *)addr
759: {
760:
761: }
762:
763: - (BOOL)enableMulticastMode
764: {
765: return YES;
766: }
767: - (void)disableMulticastMode
768: {
769: }
770:
771: - property_IODeviceClass:(char *)classes length:(unsigned int *)maxLen
772: {
773: [_netif property_IODeviceClass:classes length:maxLen];
774: strcat( classes, " "IOClassEthernet);
775: return( self);
776: }
777:
778: @end
779:
780: @implementation IOEthernet(PrivateMethods)
781:
782: //
783: // Used to handle a synchronous
784: // command sent by another thread
785: // to the driver thread.
786: //
787: - (void)commandRequestOccurred
788: {
789: int oper = [_driverCmd oper];
790: int result = 0;
791: enet_addr_t * multiAddr;
792:
793: switch (oper) {
794:
795: case RESET_ON:
796: if (!_isRunning) {
797: if (![self resetAndEnable:TRUE])
798: result = EIO;
799: }
800: [_driverCmd done:result];
801: break;
802:
803: case RESET_OFF:
804: [self resetAndEnable:FALSE];
805: [_driverCmd done:result];
806: break;
807:
808: case TERMINATE:
809: while (!queue_empty(&_multicastQueue)) {
810: enetMulti_t *multiAddr;
811: queue_remove_first(&_multicastQueue,multiAddr,enetMulti_t *,link);
812: IOFree(multiAddr,sizeof(*multiAddr));
813: }
814: [_driverCmd done:result];
815: IOExitThread();
816: break;
817:
818: case PROMISC_ENABLE:
819: if ([self enablePromiscuousMode])
820: _promiscEnabled = TRUE;
821: else {
822: _promiscEnabled = FALSE;
823: result = 1;
824: }
825: [_driverCmd done:result];
826: break;
827:
828: case PROMISC_DISABLE:
829: [self disablePromiscuousMode];
830: _promiscEnabled = FALSE;
831: [_driverCmd done:result];
832: break;
833:
834: case MULTICAST_ENABLE:
835: multiAddr = (enet_addr_t *) [_driverCmd param];
836: #ifdef DEBUG
837: printf("%s: enabling multicast address %x:%x:%x:%x:%x:%x\n",
838: [self name],
839: multiAddr->ether_addr_octet[0],
840: multiAddr->ether_addr_octet[1],
841: multiAddr->ether_addr_octet[2],
842: multiAddr->ether_addr_octet[3],
843: multiAddr->ether_addr_octet[4],
844: multiAddr->ether_addr_octet[5]);
845: #endif DEBUG
846: [self enqueueMulticast:multiAddr];
847: [self addMulticastAddress:multiAddr];
848: [self enableMulticastMode];
849: [_driverCmd done:result];
850: break;
851:
852: case MULTICAST_DISABLE:
853: multiAddr = (enet_addr_t *) [_driverCmd param];
854: #ifdef DEBUG
855: printf("%s: removing multicast address %x:%x:%x:%x:%x:%x\n",
856: [self name],
857: multiAddr->ether_addr_octet[0],
858: multiAddr->ether_addr_octet[1],
859: multiAddr->ether_addr_octet[2],
860: multiAddr->ether_addr_octet[3],
861: multiAddr->ether_addr_octet[4],
862: multiAddr->ether_addr_octet[5]);
863: #endif DEBUG
864: [self dequeueMulticast:multiAddr];
865: [self removeMulticastAddress:multiAddr];
866: if (queue_empty(&_multicastQueue)) {
867: [self disableMulticastMode];
868: }
869: [_driverCmd done:result];
870: break;
871: }
872:
873: }
874:
875: - (queue_head_t *)multicastQueue
876: {
877: return &_multicastQueue;
878: }
879:
880: /*
881: * Add a multicast address to the class queue.
882: * Invoked from our i/o thread
883: */
884: - (void)enqueueMulticast:(enet_addr_t *)addrs
885: {
886: enetMulti_t *multi;
887:
888: /*
889: * Paranoia check to make sure group bit is on.
890: */
891: if (!(addrs->ether_addr_octet[EA_GROUP_BYTE] & EA_GROUP_BIT)) {
892: return;
893: }
894:
895: multi = [self searchMulti:addrs];
896: if (multi) {
897: /*
898: * Just bump the reference count since the hardware should
899: * already be configured.
900: */
901: if (++multi->refCount < 0)
902: multi->refCount--;
903: return;
904: }
905:
906: /*
907: * New entry, so queue it
908: */
909: multi = IOMalloc(sizeof(*multi));
910: multi->address = *addrs;
911: multi->refCount = 1;
912: queue_enter(&_multicastQueue, multi, enetMulti_t *, link);
913: }
914:
915: /*
916: * Pass multicast address to the command thread.
917: */
918:
919: - (void)enableMulticast:(enet_addr_t *)addrs
920: {
921: [_driverCmd send:MULTICAST_ENABLE withParam:addrs];
922: }
923:
924: /*
925: * Disable a multicast address.
926: */
927: - (void)dequeueMulticast:(enet_addr_t *)addrs
928: {
929: enetMulti_t *multi;
930:
931: multi = [self searchMulti:addrs];
932: if (multi) {
933: /*
934: * Found it, now remove it if there are no remaining
935: * references.
936: */
937: if (multi->refCount > 0)
938: multi->refCount--;
939: if (multi->refCount <= 0) {
940: queue_remove(&_multicastQueue, multi, enetMulti_t *, link);
941: IOFree(multi, sizeof(*multi));
942: }
943: }
944: }
945:
946: - (void)disableMulticast:(enet_addr_t *)addrs
947: {
948: [_driverCmd send:MULTICAST_DISABLE withParam:addrs];
949: }
950:
951: /*
952: * See if a given enet_addr_t is present in _multicastQueue. If so, return
953: * the enetMulti_t of the entry in _multicastQueue; else return NULL.
954: * Must be called from command thread.
955: */
956: - (enetMulti_t *)searchMulti : (enet_addr_t *)addrs
957: {
958: enetMulti_t *multi;
959: int i;
960:
961: queue_iterate(&_multicastQueue,multi,enetMulti_t *,link) {
962:
963: if (memcmp(&multi->address.ether_addr_octet[0],
964: &addrs->ether_addr_octet[0], NUM_EN_ADDR_BYTES) == 0)
965: return multi;
966: }
967:
968: return NULL;
969: }
970:
971: @end
972:
973: static void
974: IOEthernetTimeout(IOEthernet *device)
975: {
976: msg_header_t msg = { 0 };
977:
978: if (device->_absTimeout > 0) {
979: device->_absTimeout = 0;
980:
981:
982: msg.msg_size = sizeof (msg);
983: msg.msg_remote_port = IOGetKernPort([device interruptPort]);
984: msg.msg_id = IO_TIMEOUT_MSG;
985:
986: msg_send_from_kernel(&msg, MSG_OPTION_NONE, 0);
987: }
988: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.