📄 eth_drv.c
字号:
//==========================================================================//// ecos/eth_drv.c//// Hardware independent ethernet driver////==========================================================================//####COPYRIGHTBEGIN####// // ------------------------------------------- // The contents of this file are subject to the Red Hat eCos Public License // Version 1.1 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at // http://www.redhat.com/ // // Software distributed under the License is distributed on an "AS IS" // basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the // License for the specific language governing rights and limitations under // the License. // // The Original Code is eCos - Embedded Configurable Operating System, // released September 30, 1998. // // The Initial Developer of the Original Code is Red Hat. // Portions created by Red Hat are // Copyright (C) 1998, 1999, 2000 Red Hat, Inc. // All Rights Reserved. // ------------------------------------------- // //####COPYRIGHTEND####//####BSDCOPYRIGHTBEGIN####//// -------------------------------------------//// Portions of this software may have been derived from OpenBSD or other sources,// and are covered by the appropriate copyright disclaimers included herein.//// -------------------------------------------////####BSDCOPYRIGHTEND####//==========================================================================//#####DESCRIPTIONBEGIN####//// Author(s): gthomas// Contributors: gthomas// Date: 2000-01-10// Purpose: Hardware independent ethernet driver// Description: // ////####DESCRIPTIONEND####////==========================================================================// High-level ethernet driver#include <sys/param.h>#include <sys/errno.h>#include <sys/ioctl.h>#include <sys/mbuf.h>#include <sys/socket.h>#include <net/if.h>#include <net/if_dl.h>#include <net/if_types.h>#include <net/netisr.h>#ifdef INET#include <netinet/in.h>#include <netinet/in_systm.h>#include <netinet/in_var.h>#include <netinet/ip.h>#include <netinet/if_ether.h>#endif#if NBPFILTER > 0#include <net/bpf.h>#include <net/bpfdesc.h>#endif#include <cyg/infra/cyg_ass.h>#include <cyg/hal/drv_api.h>#include <pkgconf/hal.h>#include <cyg/hal/hal_if.h>#include <pkgconf/io_eth_drivers.h> // module configury; SIMULATED_FAILURES#include <eth_drv.h>#include <netdev.h>// ------------------------------------------------------------------------#ifdef CYGPKG_IO_ETH_DRIVERS_SIMULATED_FAILURES#define noLOG_RANDOM 32 // so you can tell this is really being random#ifdef LOG_RANDOMstatic struct { unsigned int *which; unsigned int random; unsigned int r100;} random_log[LOG_RANDOM];static int random_index = 0;#endifstatic unsigned intrandomize( unsigned int *p ){ unsigned int r100; HAL_CLOCK_READ( &r100 ); r100 ^= *p; *p = (r100 * 1103515245) + 12345; r100 &= 127; if ( r100 >= 100 ) // spread the overflow around evenly r100 = 4 * (r100 - 100); if ( r100 >= 100 ) // and again - (125,126,127=>100,104,108) r100 = 12 * (r100 - 100); // =>(0,48,96)#ifdef LOG_RANDOM random_log[random_index].which = p; random_log[random_index].random = *p; random_log[random_index].r100 = r100; random_index++; random_index &= (LOG_RANDOM-1);#endif return r100;}#define SIMULATE_FAIL_SEND 1#define SIMULATE_FAIL_RECV 2#define SIMULATE_FAIL_CORRUPT 3static struct simulated_failure_state { struct eth_drv_sc *sc; unsigned int r_tx_fail; unsigned int r_rx_fail; unsigned int r_rx_corrupt; cyg_tick_count_t droptime; cyg_tick_count_t passtime;} simulated_failure_states[2] = {{0},{0}};static intsimulate_fail( struct eth_drv_sc *sc, int which ){ struct simulated_failure_state *s; for ( s = &simulated_failure_states[0]; s < &simulated_failure_states[2]; s++ ) { if ( 0 == s->sc ) { s->sc = sc; s->r_tx_fail = (unsigned int)sc; s->r_rx_fail = (unsigned int)sc ^ 0x01234567; s->r_rx_corrupt = (unsigned int)sc ^ 0xdeadbeef; s->droptime = 0; s->passtime = 0; } if ( sc == s->sc ) break; } if ( &simulated_failure_states[2] == s ) { CYG_FAIL( "No free slot in simulated_failure_states[]" ); return 1; // always fail }#ifdef CYGPKG_IO_ETH_DRIVERS_SIMULATE_LINE_CUT // Regardless of the question, we say "yes" during the period of // unpluggedness... { cyg_tick_count_t now = cyg_current_time(); if ( now > s->droptime && 0 == s->passtime ) { // [initial condition] s->droptime = 0; // go into a passing phase (void)randomize( &s->r_tx_fail ); (void)randomize( &s->r_rx_fail ); (void)randomize( &s->r_rx_corrupt ); s->passtime = s->r_tx_fail + s->r_rx_fail + s->r_rx_corrupt; s->passtime &= 0x3fff; // 16k cS is up to 160S, about 2.5 minutes s->passtime += now; } else if ( now > s->passtime && 0 == s->droptime ) { s->passtime = 0; // go into a dropping phase (void)randomize( &s->r_tx_fail ); (void)randomize( &s->r_rx_fail ); (void)randomize( &s->r_rx_corrupt ); s->droptime = s->r_tx_fail + s->r_rx_fail + s->r_rx_corrupt; s->droptime &= 0x0fff; // 4k cS is up to 40S, about 1/2 a minute s->droptime += now; } if ( now < s->droptime ) return 1; // Say "no" }#endif switch ( which ) {#ifdef CYGPKG_IO_ETH_DRIVERS_SIMULATE_DROP_TX case SIMULATE_FAIL_SEND: { unsigned int z = randomize( &s->r_tx_fail ); return z < CYGPKG_IO_ETH_DRIVERS_SIMULATE_DROP_TX; }#endif#ifdef CYGPKG_IO_ETH_DRIVERS_SIMULATE_DROP_RX case SIMULATE_FAIL_RECV: { unsigned int z = randomize( &s->r_rx_fail ); return z < CYGPKG_IO_ETH_DRIVERS_SIMULATE_DROP_RX; }#endif#ifdef CYGPKG_IO_ETH_DRIVERS_SIMULATE_CORRUPT_RX case SIMULATE_FAIL_CORRUPT: { unsigned int z = randomize( &s->r_rx_corrupt ); return z < CYGPKG_IO_ETH_DRIVERS_SIMULATE_CORRUPT_RX; }#endif default: // do nothing - for when options above are not enabled. } return 0;}#define noLOG_CORRUPTION 32 // so you can tell this is really being random#ifdef LOG_CORRUPTIONstatic struct { int len; int thislen; int off; unsigned char xor; unsigned char idx;} corruption_log[LOG_CORRUPTION];static int corruption_index = 0;#endifstatic voidsimulate_fail_corrupt_sglist( struct eth_drv_sg *sg_list, int sg_len ){ unsigned int z, len, i, off; HAL_CLOCK_READ( &z ); z += simulated_failure_states[0].r_rx_corrupt; z += simulated_failure_states[1].r_rx_corrupt; CYG_ASSERT( MAX_ETH_DRV_SG >= sg_len, "sg_len overflow in corrupt" ); for ( i = 0, len = 0; i < sg_len && sg_list[i].buf && sg_list[i].len; i++ ) len =+ sg_list[i].len; CYG_ASSERT( 1500 >= len, "sg...len > ether MTU" ); if ( 14 >= len ) // normal ether header return; off = z & 2047; // next (2^N-1) > MTU while ( off > len ) off -= len; for ( i = 0; i < sg_len && sg_list[i].buf && sg_list[i].len; i++ ) { if ( off < sg_list[i].len ) { // corrupt this one unsigned char *p = (unsigned char *)sg_list[i].buf; p[off] ^= (0xff & (z >> 11));#ifdef LOG_CORRUPTION corruption_log[corruption_index].len = len; corruption_log[corruption_index].thislen = sg_list[i].len; corruption_log[corruption_index].off = off; corruption_log[corruption_index].xor = (0xff & (z >> 11)); corruption_log[corruption_index].idx = i; corruption_index++; corruption_index &= (LOG_CORRUPTION-1);#endif return; } off -= sg_list[i].len; } CYG_FAIL( "Didn't corrupt anything" );}#endif // CYGPKG_IO_ETH_DRIVERS_SIMULATED_FAILURES// ------------------------------------------------------------------------static int eth_drv_ioctl(struct ifnet *, u_long, caddr_t);static void eth_drv_send(struct ifnet *);extern int net_debug; // FIXME// Interfaces exported to driversstatic void eth_drv_init(struct eth_drv_sc *sc, unsigned char *enaddr);static void eth_drv_recv(struct eth_drv_sc *sc, int total_len);static void eth_drv_tx_done(struct eth_drv_sc *sc, CYG_ADDRESS key, int status);struct eth_drv_funs eth_drv_funs = {eth_drv_init, eth_drv_recv, eth_drv_tx_done};//// This function is called during system initialization to register a// network interface with the system.//static voideth_drv_init(struct eth_drv_sc *sc, unsigned char *enaddr){ struct ifnet *ifp = &sc->sc_arpcom.ac_if; // Set up hardware address bcopy(enaddr, &sc->sc_arpcom.ac_enaddr, ETHER_ADDR_LEN); // Initialize ifnet structure bcopy((void *)sc->dev_name, ifp->if_xname, IFNAMSIZ); ifp->if_softc = sc; ifp->if_start = eth_drv_send; ifp->if_ioctl = eth_drv_ioctl; ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS | IFF_MULTICAST; sc->state = 0; // Attach the interface if_attach(ifp); ether_ifattach(ifp);#ifdef CYGSEM_HAL_VIRTUAL_VECTOR_DIAG// Set up interfaces so debug environment can share this device { void *dbg = CYGACC_CALL_IF_DBG_DATA(); if (!dbg) { CYGACC_CALL_IF_DBG_DATA_SET((void *)sc); } }#endif}//// This [internal] function will be called to stop activity on an interface.//static voideth_drv_stop(struct eth_drv_sc *sc){ (sc->funs->stop)(sc); sc->state &= ~ETH_DRV_STATE_ACTIVE;}//// This [internal] function will be called to start activity on an interface.//static voideth_drv_start(struct eth_drv_sc *sc){ struct ifnet *ifp = &sc->sc_arpcom.ac_if; // Perform any hardware initialization (sc->funs->start)(sc, (unsigned char *)&sc->sc_arpcom.ac_enaddr, 0); // Set 'running' flag, and clear output active flag. ifp->if_flags |= IFF_RUNNING; ifp->if_flags &= ~IFF_OACTIVE; sc->state |= ETH_DRV_STATE_ACTIVE; eth_drv_send(ifp); // Try and start up transmit}//// This function supports "I/O control" operations on an interface.//static int eth_drv_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data){ struct eth_drv_sc *sc = ifp->if_softc; struct ifaddr *ifa = (struct ifaddr *) data; struct ifreq *ifr = (struct ifreq *)data; int s, error = 0; s = splnet(); if ((error = ether_ioctl(ifp, &sc->sc_arpcom, cmd, data)) > 0) { splx(s); return error; } switch (cmd) { case SIOCSIFADDR: ifp->if_flags |= IFF_UP; switch (ifa->ifa_addr->sa_family) {#ifdef INET case AF_INET: eth_drv_start(sc); arp_ifinit(&sc->sc_arpcom, ifa); break;#endif default: eth_drv_start(sc); break; } break; case SIOCGIFHWADDR: // Get hardware (MAC) address ifr->ifr_hwaddr.sa_family = AF_INET;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -