//==========================================================================
|
//==========================================================================
|
//
|
//
|
// net/enet.c
|
// net/enet.c
|
//
|
//
|
// Stand-alone ethernet [link-layer] support for RedBoot
|
// Stand-alone ethernet [link-layer] support for RedBoot
|
//
|
//
|
//==========================================================================
|
//==========================================================================
|
//####ECOSGPLCOPYRIGHTBEGIN####
|
//####ECOSGPLCOPYRIGHTBEGIN####
|
// -------------------------------------------
|
// -------------------------------------------
|
// This file is part of eCos, the Embedded Configurable Operating System.
|
// This file is part of eCos, the Embedded Configurable Operating System.
|
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
|
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
|
//
|
//
|
// eCos is free software; you can redistribute it and/or modify it under
|
// eCos is free software; you can redistribute it and/or modify it under
|
// the terms of the GNU General Public License as published by the Free
|
// the terms of the GNU General Public License as published by the Free
|
// Software Foundation; either version 2 or (at your option) any later version.
|
// Software Foundation; either version 2 or (at your option) any later version.
|
//
|
//
|
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
|
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
|
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
// for more details.
|
// for more details.
|
//
|
//
|
// You should have received a copy of the GNU General Public License along
|
// You should have received a copy of the GNU General Public License along
|
// with eCos; if not, write to the Free Software Foundation, Inc.,
|
// with eCos; if not, write to the Free Software Foundation, Inc.,
|
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
|
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
|
//
|
//
|
// As a special exception, if other files instantiate templates or use macros
|
// As a special exception, if other files instantiate templates or use macros
|
// or inline functions from this file, or you compile this file and link it
|
// or inline functions from this file, or you compile this file and link it
|
// with other works to produce a work based on this file, this file does not
|
// with other works to produce a work based on this file, this file does not
|
// by itself cause the resulting work to be covered by the GNU General Public
|
// by itself cause the resulting work to be covered by the GNU General Public
|
// License. However the source code for this file must still be made available
|
// License. However the source code for this file must still be made available
|
// in accordance with section (3) of the GNU General Public License.
|
// in accordance with section (3) of the GNU General Public License.
|
//
|
//
|
// This exception does not invalidate any other reasons why a work based on
|
// This exception does not invalidate any other reasons why a work based on
|
// this file might be covered by the GNU General Public License.
|
// this file might be covered by the GNU General Public License.
|
//
|
//
|
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
|
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
|
// at http://sources.redhat.com/ecos/ecos-license/
|
// at http://sources.redhat.com/ecos/ecos-license/
|
// -------------------------------------------
|
// -------------------------------------------
|
//####ECOSGPLCOPYRIGHTEND####
|
//####ECOSGPLCOPYRIGHTEND####
|
//==========================================================================
|
//==========================================================================
|
//#####DESCRIPTIONBEGIN####
|
//#####DESCRIPTIONBEGIN####
|
//
|
//
|
// Author(s): gthomas
|
// Author(s): gthomas
|
// Contributors: gthomas
|
// Contributors: gthomas
|
// Date: 2000-07-14
|
// Date: 2000-07-14
|
// Purpose:
|
// Purpose:
|
// Description:
|
// Description:
|
//
|
//
|
// This code is part of RedBoot (tm).
|
// This code is part of RedBoot (tm).
|
//
|
//
|
//####DESCRIPTIONEND####
|
//####DESCRIPTIONEND####
|
//
|
//
|
//==========================================================================
|
//==========================================================================
|
|
|
#include <redboot.h>
|
#include <redboot.h>
|
#include <net/net.h>
|
#include <net/net.h>
|
#include <cyg/io/eth/eth_drv.h> // Logical driver interfaces
|
#include <cyg/io/eth/eth_drv.h> // Logical driver interfaces
|
|
|
//#define ENET_STATS 1
|
//#define ENET_STATS 1
|
|
|
#ifdef ENET_STATS
|
#ifdef ENET_STATS
|
static int num_ip = 0;
|
static int num_ip = 0;
|
static int num_arp = 0;
|
static int num_arp = 0;
|
#ifdef NET_SUPPORT_RARP
|
#ifdef NET_SUPPORT_RARP
|
static int num_rarp = 0;
|
static int num_rarp = 0;
|
#endif
|
#endif
|
static int num_received = 0;
|
static int num_received = 0;
|
static int num_transmitted = 0;
|
static int num_transmitted = 0;
|
#endif
|
#endif
|
|
|
//
|
//
|
// Support for user handlers of additional ethernet packets (nonIP)
|
// Support for user handlers of additional ethernet packets (nonIP)
|
//
|
//
|
|
|
#define NUM_EXTRA_HANDLERS 4
|
#define NUM_EXTRA_HANDLERS 4
|
static struct {
|
static struct {
|
int type;
|
int type;
|
pkt_handler_t handler;
|
pkt_handler_t handler;
|
} eth_handlers[NUM_EXTRA_HANDLERS];
|
} eth_handlers[NUM_EXTRA_HANDLERS];
|
|
|
pkt_handler_t
|
pkt_handler_t
|
__eth_install_listener(int eth_type, pkt_handler_t handler)
|
__eth_install_listener(int eth_type, pkt_handler_t handler)
|
{
|
{
|
int i, empty;
|
int i, empty;
|
pkt_handler_t old;
|
pkt_handler_t old;
|
|
|
if (eth_type > 0x800 || handler != (pkt_handler_t)0) {
|
if (eth_type > 0x800 || handler != (pkt_handler_t)0) {
|
empty = -1;
|
empty = -1;
|
for (i = 0; i < NUM_EXTRA_HANDLERS; i++) {
|
for (i = 0; i < NUM_EXTRA_HANDLERS; i++) {
|
if (eth_handlers[i].type == eth_type) {
|
if (eth_handlers[i].type == eth_type) {
|
// Replace existing handler
|
// Replace existing handler
|
old = eth_handlers[i].handler;
|
old = eth_handlers[i].handler;
|
eth_handlers[i].handler = handler;
|
eth_handlers[i].handler = handler;
|
return old;
|
return old;
|
}
|
}
|
if (eth_handlers[i].type == 0) {
|
if (eth_handlers[i].type == 0) {
|
empty = i;
|
empty = i;
|
}
|
}
|
}
|
}
|
if (empty >= 0) {
|
if (empty >= 0) {
|
// Found a free slot
|
// Found a free slot
|
eth_handlers[empty].type = eth_type;
|
eth_handlers[empty].type = eth_type;
|
eth_handlers[empty].handler = handler;
|
eth_handlers[empty].handler = handler;
|
return (pkt_handler_t)0;
|
return (pkt_handler_t)0;
|
}
|
}
|
}
|
}
|
diag_printf("** Warning: can't install listener for ethernet type 0x%02x\n", eth_type);
|
diag_printf("** Warning: can't install listener for ethernet type 0x%02x\n", eth_type);
|
return (pkt_handler_t)0;
|
return (pkt_handler_t)0;
|
}
|
}
|
|
|
void
|
void
|
__eth_remove_listener(int eth_type)
|
__eth_remove_listener(int eth_type)
|
{
|
{
|
int i;
|
int i;
|
|
|
for (i = 0; i < NUM_EXTRA_HANDLERS; i++) {
|
for (i = 0; i < NUM_EXTRA_HANDLERS; i++) {
|
if (eth_handlers[i].type == eth_type) {
|
if (eth_handlers[i].type == eth_type) {
|
eth_handlers[i].type = 0;
|
eth_handlers[i].type = 0;
|
}
|
}
|
}
|
}
|
}
|
}
|
|
|
/*
|
/*
|
* Non-blocking poll of ethernet link. Process packets until no more
|
* Non-blocking poll of ethernet link. Process packets until no more
|
* are available.
|
* are available.
|
*/
|
*/
|
void
|
void
|
__enet_poll(void)
|
__enet_poll(void)
|
{
|
{
|
pktbuf_t *pkt;
|
pktbuf_t *pkt;
|
eth_header_t eth_hdr;
|
eth_header_t eth_hdr;
|
int i, type;
|
int i, type;
|
#ifdef DEBUG_PKT_EXHAUSTION
|
#ifdef DEBUG_PKT_EXHAUSTION
|
static bool was_exhausted = false;
|
static bool was_exhausted = false;
|
#endif
|
#endif
|
|
|
while (true) {
|
while (true) {
|
/*
|
/*
|
* Try to get a free pktbuf and return if none
|
* Try to get a free pktbuf and return if none
|
* are available.
|
* are available.
|
*/
|
*/
|
if ((pkt = __pktbuf_alloc(ETH_MAX_PKTLEN)) == NULL) {
|
if ((pkt = __pktbuf_alloc(ETH_MAX_PKTLEN)) == NULL) {
|
#ifdef DEBUG_PKT_EXHAUSTION
|
#ifdef DEBUG_PKT_EXHAUSTION
|
if (!was_exhausted) {
|
if (!was_exhausted) {
|
int old = start_console(); // Force output to standard port
|
int old = start_console(); // Force output to standard port
|
diag_printf("__enet_poll: no more buffers\n");
|
diag_printf("__enet_poll: no more buffers\n");
|
__pktbuf_dump();
|
__pktbuf_dump();
|
was_exhausted = true;
|
was_exhausted = true;
|
end_console(old);
|
end_console(old);
|
}
|
}
|
#endif
|
#endif
|
return;
|
return;
|
}
|
}
|
#ifdef DEBUG_PKT_EXHAUSTION
|
#ifdef DEBUG_PKT_EXHAUSTION
|
was_exhausted = false; // Report the next time we're out of buffers
|
was_exhausted = false; // Report the next time we're out of buffers
|
#endif
|
#endif
|
|
|
if ((pkt->pkt_bytes = eth_drv_read((char *)ð_hdr, (char *)pkt->buf,
|
if ((pkt->pkt_bytes = eth_drv_read((char *)ð_hdr, (char *)pkt->buf,
|
ETH_MAX_PKTLEN)) > 0) {
|
ETH_MAX_PKTLEN)) > 0) {
|
#ifdef ENET_STATS
|
#ifdef ENET_STATS
|
++num_received;
|
++num_received;
|
#endif
|
#endif
|
switch (type = ntohs(eth_hdr.type)) {
|
switch (type = ntohs(eth_hdr.type)) {
|
|
|
case ETH_TYPE_IP:
|
case ETH_TYPE_IP:
|
#ifdef ENET_STATS
|
#ifdef ENET_STATS
|
++num_ip;
|
++num_ip;
|
#endif
|
#endif
|
pkt->ip_hdr = (ip_header_t *)pkt->buf;
|
pkt->ip_hdr = (ip_header_t *)pkt->buf;
|
__ip_handler(pkt, ð_hdr.source);
|
__ip_handler(pkt, ð_hdr.source);
|
break;
|
break;
|
|
|
case ETH_TYPE_ARP:
|
case ETH_TYPE_ARP:
|
#ifdef ENET_STATS
|
#ifdef ENET_STATS
|
++num_arp;
|
++num_arp;
|
#endif
|
#endif
|
pkt->arp_hdr = (arp_header_t *)pkt->buf;
|
pkt->arp_hdr = (arp_header_t *)pkt->buf;
|
__arp_handler(pkt);
|
__arp_handler(pkt);
|
break;
|
break;
|
|
|
#ifdef NET_SUPPORT_RARP
|
#ifdef NET_SUPPORT_RARP
|
case ETH_TYPE_RARP:
|
case ETH_TYPE_RARP:
|
#ifdef ENET_STATS
|
#ifdef ENET_STATS
|
++num_rarp;
|
++num_rarp;
|
#endif
|
#endif
|
pkt->arp_hdr = (arp_header_t *)pkt->buf;
|
pkt->arp_hdr = (arp_header_t *)pkt->buf;
|
__rarp_handler(pkt);
|
__rarp_handler(pkt);
|
break;
|
break;
|
#endif
|
#endif
|
|
|
default:
|
default:
|
if (type > 0x800) {
|
if (type > 0x800) {
|
for (i = 0; i < NUM_EXTRA_HANDLERS; i++) {
|
for (i = 0; i < NUM_EXTRA_HANDLERS; i++) {
|
if (eth_handlers[i].type == type) {
|
if (eth_handlers[i].type == type) {
|
(eth_handlers[i].handler)(pkt, ð_hdr);
|
(eth_handlers[i].handler)(pkt, ð_hdr);
|
}
|
}
|
}
|
}
|
}
|
}
|
__pktbuf_free(pkt);
|
__pktbuf_free(pkt);
|
break;
|
break;
|
}
|
}
|
} else {
|
} else {
|
__pktbuf_free(pkt);
|
__pktbuf_free(pkt);
|
break;
|
break;
|
}
|
}
|
}
|
}
|
}
|
}
|
|
|
|
|
|
|
/*
|
/*
|
* Send an ethernet packet.
|
* Send an ethernet packet.
|
*/
|
*/
|
void
|
void
|
__enet_send(pktbuf_t *pkt, enet_addr_t *dest, int eth_type)
|
__enet_send(pktbuf_t *pkt, enet_addr_t *dest, int eth_type)
|
{
|
{
|
eth_header_t eth_hdr;
|
eth_header_t eth_hdr;
|
|
|
// Set up ethernet header
|
// Set up ethernet header
|
memcpy(ð_hdr.destination, dest, sizeof(enet_addr_t));
|
memcpy(ð_hdr.destination, dest, sizeof(enet_addr_t));
|
memcpy(ð_hdr.source, __local_enet_addr, sizeof(enet_addr_t));
|
memcpy(ð_hdr.source, __local_enet_addr, sizeof(enet_addr_t));
|
eth_hdr.type = htons(eth_type);
|
eth_hdr.type = htons(eth_type);
|
|
|
eth_drv_write((char *)ð_hdr, (char *)pkt->buf, pkt->pkt_bytes);
|
eth_drv_write((char *)ð_hdr, (char *)pkt->buf, pkt->pkt_bytes);
|
#ifdef ENET_STATS
|
#ifdef ENET_STATS
|
++num_transmitted;
|
++num_transmitted;
|
#endif
|
#endif
|
}
|
}
|
|
|
#ifdef __LITTLE_ENDIAN__
|
#ifdef __LITTLE_ENDIAN__
|
|
|
unsigned long
|
unsigned long
|
ntohl(unsigned long x)
|
ntohl(unsigned long x)
|
{
|
{
|
return (((x & 0x000000FF) << 24) |
|
return (((x & 0x000000FF) << 24) |
|
((x & 0x0000FF00) << 8) |
|
((x & 0x0000FF00) << 8) |
|
((x & 0x00FF0000) >> 8) |
|
((x & 0x00FF0000) >> 8) |
|
((x & 0xFF000000) >> 24));
|
((x & 0xFF000000) >> 24));
|
}
|
}
|
|
|
unsigned long
|
unsigned long
|
ntohs(unsigned short x)
|
ntohs(unsigned short x)
|
{
|
{
|
return (((x & 0x00FF) << 8) |
|
return (((x & 0x00FF) << 8) |
|
((x & 0xFF00) >> 8));
|
((x & 0xFF00) >> 8));
|
}
|
}
|
|
|
#endif
|
#endif
|
|
|