|
|
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.