📄 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_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 + -