/* * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * * The contents of this file constitute Original Code as defined in and * are subject to the Apple Public Source License Version 1.1 (the * "License"). You may not use this file except in compliance with the * License. Please obtain a copy of the License at * http://www.apple.com/publicsource and read it before using this file. * * This Original Code and all software distributed under the License are * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the * License for the specific language governing rights and limitations * under the License. * * @APPLE_LICENSE_HEADER_END@ */ /* * MACE Device-dependent code (some still lives in if_en.c): * * MACE Multicast Address scheme - * Compute Enet CRC for each Mcast address; take high 6 bits of 32-bit * crc, giving a "bit index" into a 64-bit register. On packet receipt, * if corresponding bit is set, accept packet. * We keep track of requests in a per-hash-value table (16-bit counters * should be sufficient). Since we're hashing, we only care about the * hash value of each address. * * Apple Confidential * * (C) COPYRIGHT Apple Computer, Inc., 1994-1997 * All Rights Reserved * * Justin C. Walker */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "if_en.h" #include "mace.h" extern mace_t mace; #define ENET_CRCPOLY 0x04c11db7 /* Real fast bit-reversal algorithm, 6-bit values */ int reverse6[] = { 0x0,0x20,0x10,0x30,0x8,0x28,0x18,0x38, 0x4,0x24,0x14,0x34,0xc,0x2c,0x1c,0x3c, 0x2,0x22,0x12,0x32,0xa,0x2a,0x1a,0x3a, 0x6,0x26,0x16,0x36,0xe,0x2e,0x1e,0x3e, 0x1,0x21,0x11,0x31,0x9,0x29,0x19,0x39, 0x5,0x25,0x15,0x35,0xd,0x2d,0x1d,0x3d, 0x3,0x23,0x13,0x33,0xb,0x2b,0x1b,0x3b, 0x7,0x27,0x17,0x37,0xf,0x2f,0x1f,0x3f }; unsigned int crc416(current, nxtval) register unsigned int current; register unsigned short nxtval; { register unsigned int counter; register int highCRCBitSet, lowDataBitSet; /* Swap bytes */ nxtval = ((nxtval & 0x00FF) << 8) | (nxtval >> 8); /* Compute bit-by-bit */ for (counter = 0; counter != 16; ++counter) { /* is high CRC bit set? */ if ((current & 0x80000000) == NULL) highCRCBitSet = 0; else highCRCBitSet = 1; current = current << 1; if ((nxtval & 0x0001) == NULL) lowDataBitSet = 0; else lowDataBitSet = 1; nxtval = nxtval >> 1; /* do the XOR */ if (highCRCBitSet ^ lowDataBitSet) current = current ^ ENET_CRCPOLY; } return current; } unsigned int mace_crc(unsigned short *address) { register unsigned int newcrc; newcrc = crc416(0xffffffff, *address); /* address bits 47 - 32 */ newcrc = crc416(newcrc, address[1]); /* address bits 31 - 16 */ newcrc = crc416(newcrc, address[2]); /* address bits 15 - 0 */ return(newcrc); } /* * Add requested mcast addr to Mace's filter. Assume that the first * address in the arpcom ac_multiaddrs list is the one we're interested in. */ int mace_addmulti(register struct ifreq *ifr, register struct arpcom *ar) { register unsigned char *addr; unsigned int crc; unsigned char mask; addr = ar->ac_multiaddrs->enm_addrlo; crc = mace_crc((unsigned short *)addr)&0x3f; /* Big-endian alert! */ crc = reverse6[crc]; /* Hyperfast bit-reversing algorithm */ if (mace.multi_use[crc]++) return(0); /* This bit is already set */ mask = crc % 8; mask = (unsigned char)1 << mask; mace.multi_mask[crc/8] |= mask; return(1); } int mace_delmulti(register struct ifreq *ifr, register struct arpcom *ar, struct ether_addr * enaddr) { register unsigned char *addr; unsigned int crc; unsigned char mask; addr = (char *)enaddr; /* XXX assumes addrlo == addrhi */ /* Now, delete the address from the filter copy, as indicated */ crc = mace_crc((unsigned short *)addr)&0x3f; /* Big-endian alert! */ crc = reverse6[crc]; /* Hyperfast bit-reversing algorithm */ if (mace.multi_use[crc] == 0) return(EINVAL); /* That bit wasn't in use! */ if (--mace.multi_use[crc]) return(0); /* That bit is still in use */ mask = crc % 8; mask = ((unsigned char)1 << mask) ^ 0xff; /* To turn off bit */ mace.multi_mask[crc/8] &= mask; return(1); } /* * Sync the adapter with the software copy of the multicast mask * (logical address filter). * If we want all m-cast addresses, we just blast 1's into the filter. * When we reverse this, we can use the current state of the (software) * filter, which should have been kept up to date. */ void mace_sync_mcast(register struct ifnet * ifp) { register unsigned long temp, temp1; register int i; register char *p; register struct mace_board *ereg = mace.ereg; temp = ereg->maccc; /* * Have to deal with early rev of chip for updating LAF * Don't know if any MacOSX systems still run this rev. */ if (mace.chip_id == MACERevA2) { /* First, turn off receiver */ temp1 = temp&~MACCC_ENRCV; ereg->maccc = temp1; eieio(); /* Then, check FIFO - frame being received will complete */ temp1 = ereg->fifofc; mace.ereg->iac = IAC_LOGADDR; eieio(); } else { ereg->iac = IAC_ADDRCHG|IAC_LOGADDR; eieio(); while (temp1 = ereg->iac) { eieio(); if ((temp1&IAC_ADDRCHG) == 0) break; } } if (ifp->if_flags & IFF_ALLMULTI) /* Then want ALL m-cast pkts */ { /* set mask to all 1's */ for (i=0;i<8;i++) { ereg->ladrf = 0xff; eieio(); } } else { /* Assuming everything is big-endian */ for (i=0, p = &mace.multi_mask[0];i<8;i++) { ereg->ladrf = *p++; eieio(); } } ereg->maccc = temp; /* Reset config ctrlr */ eieio(); } void mace_sync_promisc(register struct ifnet *ifp) { register u_long o_maccc, n_maccc; register struct mace_board *ereg = mace.ereg; /* * Save current state and disable receive. */ o_maccc = ereg->maccc; n_maccc = o_maccc & ~MACCC_ENRCV; ereg->maccc = n_maccc; eieio(); /* * Calculate new desired state */ if (ifp->if_flags & IFF_PROMISC) { /* set PROMISC bit */ o_maccc |= MACCC_PROM; } else { /* clear PROMISC bit */ o_maccc &= ~MACCC_PROM; } /* * Note that the "old" mode includes the new promiscuous state now. */ ereg->maccc = o_maccc; eieio(); }