⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 eth_drv.c

📁 基于ecos的redboot
💻 C
📖 第 1 页 / 共 2 页
字号:
//==========================================================================
//
//      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_RANDOM
static struct {
    unsigned int *which;
    unsigned int random;
    unsigned int r100;
} random_log[LOG_RANDOM];

static int random_index = 0;
#endif

static unsigned int
randomize( 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  3

static 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 int
simulate_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_CORRUPTION
static struct {
    int len;
    int thislen;
    int off;
    unsigned char xor;
    unsigned char idx;
} corruption_log[LOG_CORRUPTION];

static int corruption_index = 0;
#endif

static void
simulate_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 drivers

static 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 void
eth_drv_init(struct eth_drv_sc *sc, unsigned char *enaddr)
{
    struct ifnet *ifp = &sc->sc_arpcom.ac_if;

    // Set up hardware address
    if (NULL != enaddr)
        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 void
eth_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 void
eth_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;
        bcopy(&sc->sc_arpcom.ac_enaddr, &ifr->ifr_hwaddr.sa_data, ETHER_ADDR_LEN);
        break;

    case SIOCSIFHWADDR:
        // Set hardware (MAC) address

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -