ethernetif.c

来自「不带操作系统的LWIP栈」· C语言 代码 · 共 447 行

C
447
字号
/*
 * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
 * All rights reserved. 
 * 
 * Redistribution and use in source and binary forms, with or without modification, 
 * are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission. 
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 
 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 
 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 
 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 
 * OF SUCH DAMAGE.
 *
 * This file is part of the lwIP TCP/IP stack.
 * 
 * Author: Adam Dunkels <adam@sics.se>
 *
 */

/*
 * This file is a skeleton for developing Ethernet network interface
 * drivers for lwIP. Add code to the low_level functions and do a
 * search-and-replace for the word "ethernetif" to replace it with
 * something that better describes your network interface.
 */

#include "lwip/opt.h"
#include "lwip/def.h"
#include "lwip/mem.h"
#include "lwip/pbuf.h"
#include "lwip/sys.h"
#include "lwip/stats.h"
#include	"stoe.h"
#include	"dma.h"
#include "reg80390.h"
#include "netif/etharp.h"
#include "netif/ethernetif.h"

/* Define those to better describe your network interface. */
#define IFNAME0 'e'
#define IFNAME1 'n'

#define RECEIVE_THREAD_PRIO	11

#define PACKET_TYPE_POS		(MAC_TX_RX_HEADER+MAC_ADDRESS_LEN*2)

struct ethernetif	stoeif;

static const struct eth_addr ethbroadcast = {{0xff,0xff,0xff,0xff,0xff,0xff}};

extern const U8_T	ipaddr1, ipaddr2, ipaddr3, ipaddr4;

extern const U8_T	gateaddr1, gateaddr2, gateaddr3, gateaddr4;

extern const U8_T	submask1, submask2, submask3, submask4;

/* Forward declarations. */
u8_t  ethernetif_input(struct netif *netif) ;
static err_t ethernetif_output(struct netif *netif, struct pbuf *p,
             struct ip_addr *ipaddr)KCREENTRANT;
static void arp_timer(void *arg);
void ETH_RcvHandle(U8_T XDATA* pbuf, U16_T length, U8_T protocol);

static void
low_level_init(struct netif *netif)
{
  struct ethernetif *ethernetif = netif->state;
  
  /* set MAC hardware address length */
  netif->hwaddr_len = 6;

  /* set MAC hardware address */
	netif->hwaddr[0] = PNetStation->CurrStaAddr[0];
	netif->hwaddr[1] = PNetStation->CurrStaAddr[1];
	netif->hwaddr[2] = PNetStation->CurrStaAddr[2];
	netif->hwaddr[3] = PNetStation->CurrStaAddr[3];
	netif->hwaddr[4] = PNetStation->CurrStaAddr[4];
	netif->hwaddr[5] = PNetStation->CurrStaAddr[5];

  /* maximum transfer unit */
  netif->mtu = 1500;
  
  /* broadcast capability */
  netif->flags = NETIF_FLAG_BROADCAST;
 
  /* Do whatever else is needed to initialize interface. */  
}

/*
 * low_level_output():
 *
 * Should do the actual transmission of the packet. The packet is
 * contained in the pbuf that is passed to the function. This pbuf
 * might be chained.
 *
 */
static err_t
low_level_output(struct netif *netif, struct pbuf *p) KCREENTRANT
{
	struct ethernetif	*whateverif = netif->state;
	struct pbuf	*q;
	U8_T XDATA	*pBuf, *pdest;
	U16_T		length=0, leftlen;

	LWIP_PLATFORM_DIAG(("low_level_output ::Allocate buffer  %04d\n\r", p->tot_len + MAC_TX_RX_HEADER));

	/* allocate mac memory*/
	pBuf = STOE_AssignSendBuf(p->tot_len + MAC_TX_RX_HEADER);
	if (!pBuf) {
		if (P2 & 2)
			P2 &= ~2;
		else
			P2 |= 2;
		LWIP_PLATFORM_DIAG(("low_level_output ::Allocate buffer Failed %04d\n\r", p->tot_len + MAC_TX_RX_HEADER));
		return ERR_OK;
	}
	PBDP->STOE_TxInform.PBuf = pBuf;
	PBDP->STOE_TxInform.TotalLen = p->tot_len;

	LWIP_PLATFORM_DIAG(("low_level_output ::total leng = %04x\n\r", p->tot_len));

#if ETH_PAD_SIZE
	pbuf_header(p, -ETH_PAD_SIZE);			/* drop the padding word */
#endif

	pdest = pBuf + MAC_TX_RX_HEADER;
	leftlen = p->tot_len;
	q = p;
	while(leftlen > 0) {

		LWIP_ASSERT("low_level_output ::pbuf == NULL", q == NULL);
		length = q->len;
		if(length <=0) {
			goto again;
		}
		if (q->flags == PBUF_FLAG_ROM) {
			pdest = STOE_CopyCode2TPBR(pdest, q->payload, length);
		} else {
			pdest = DMA_GrantXdata(pdest, q->payload, length);
			if (!pdest) {
				LWIP_PLATFORM_DIAG(("low_level_output ::DMA Error occurred.!!\n\r"));
				return ERR_OK;
			}				
		}
		leftlen -= length;
again:
		q = q->next;
	} /* end of while(leftlen) */

#if (STOE_TRANSPARENT)
#	if (STOE_CHECKSUM_OFFLOAD)
		if ((*(pBuf + PACKET_TYPE_POS) == 8) && (*(pBuf + PACKET_TYPE_POS + 1) == 0)) {
			PBDP->STOE_TxInform.Protocol = *(pBuf + MAC_TX_RX_HEADER + 14 + 9);
		}
		else {
			PBDP->STOE_TxInform.Protocol = 0xff;
		}
#	else
			PBDP->STOE_TxInform.Protocol = 0xff;
#	endif
#else  /* (!STOE_TRANSPARENT) */ 
	PBDP->STOE_TxInform.Protocol = *(pBuf + MAC_TX_RX_HEADER + 9);
#endif /* (STOE_TRANSPARENT) */
	LWIP_PLATFORM_DIAG(("low_level_output ::send %04d\n\r",p->tot_len));

	STOE_Send(pBuf, PBDP->STOE_TxInform.TotalLen, PBDP->STOE_TxInform.Protocol);

#if ETH_PAD_SIZE
	pbuf_header(p, ETH_PAD_SIZE);			/* reclaim the padding word */
#endif
  
#if LINK_STATS
	lwip_stats.link.xmit++;
#endif /* LINK_STATS */   
   
	return ERR_OK;
}

/*
 * low_level_input():
 *
 * Should allocate a pbuf and transfer the bytes of the incoming
 * packet from the interface into the pbuf.
 *
 */
static
struct pbuf *low_level_input(struct netif *netif) 
{
	U8_T XDATA *pSour;
	struct ethernetif *whateverif = netif->state;
    struct pbuf *p, *q;
    u16_t len, left_len;
#if (!STOE_TRANSPARENT)
	u8_t  protocol;
#endif

    /* Obtain the size of the packet and put it into the "len" variable. */
	len = PBDP->STOE_RxInform.TotalLen;
	left_len = len;
	LWIP_PLATFORM_DIAG(("low_level_input ::total leng = %04d\n\r", left_len));
	pSour = PBDP->STOE_RxInform.PBuf;

#if ETH_PAD_SIZE
	len += ETH_PAD_SIZE;						/* allow room for Ethernet padding */
#endif

#if (STOE_TRANSPARENT)
    /* We allocate a pbuf chain of pbufs from the pool. */
    p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL);
#else
	protocol = PBDP->STOE_RxInform.Protocol;
	if (protocol == 0xff)
	{
	    /* We allocate a pbuf chain of pbufs from the pool. */
    	p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL);
	}
	else
	{
	    /* We allocate a pbuf chain of pbufs from the pool. */
    	p = pbuf_alloc(PBUF_RAW, len + sizeof(struct eth_hdr), PBUF_POOL);
	}
#endif	/* (STOE_TRANSPARENT) */

    if (p != NULL) {

#if ETH_PAD_SIZE
		pbuf_header(p, -ETH_PAD_SIZE);			/* drop the padding word */
#endif
		q = p;
#if (!STOE_TRANSPARENT)
		if (protocol != 0xff)
		    pbuf_header(p, -sizeof(struct eth_hdr));
#endif
	
		while (left_len)
		{
		    /* We iterate over the pbuf chain until we have read the entire
    		 * packet into the pbuf. */
			LWIP_PLATFORM_DIAG(("low_level_input ::left_len = %04d\n\r", left_len));
			if (left_len > q->len)
			{
				if(!DMA_GrantXdata((U8_T XDATA*)q->payload, pSour, q->len)) {
					LWIP_PLATFORM_DIAG(("DMA Error occurred.!!\n\r"));
					pbuf_free(p);
					p = NULL;
					return p;
				}
				left_len -= q->len;
				pSour += q->len;
			}
			else
			{
				if(!DMA_GrantXdata((U8_T XDATA*)q->payload, pSour, left_len)) {
					LWIP_PLATFORM_DIAG(("DMA Error occurred.!!\n\r"));
					pbuf_free(p);
					p = NULL;
					return p;
				}
				break;
			}
			q = q->next;
		}

#if ETH_PAD_SIZE
    	pbuf_header(p, ETH_PAD_SIZE);			/* reclaim the padding word */
#endif

#if LINK_STATS
    	lwip_stats.link.recv++;
#endif /* LINK_STATS */      

  } else {	/* (p == NULL) */
	LWIP_PLATFORM_DIAG(("pbuf_alloc failed!!!\n"));
#if LINK_STATS
    lwip_stats.link.memerr++;
    lwip_stats.link.drop++;
#endif /* LINK_STATS */      
  }	/* if (p != NULL) */

  return p;
}


/*
 * ethernetif_output():
 *
 * This function is called by the TCP/IP stack when an IP packet
 * should be sent. It calls the function called low_level_output() to
 * do the actual transmission of the packet.
 *
 */
static err_t
ethernetif_output(struct netif *netif, struct pbuf *p, struct ip_addr *ipaddr) KCREENTRANT
{
 /* resolve hardware address, then send (or queue) packet */
#if (STOE_TRANSPARENT)
  return etharp_output(netif, ipaddr, p);
#else
  return low_level_output(netif, p);
#endif
}

/*
 * ethernetif_input():
 *
 * This function should be called when a packet is ready to be read
 * from the interface. It uses the function low_level_input() that
 * should handle the actual reception of bytes from the network
 * interface.
 *
 */

u8_t
ethernetif_input(struct netif *netif) 
{
	struct ethernetif *ethernetif;
	struct eth_hdr *ethhdr;
	struct pbuf *p;
	ethernetif = netif->state;
 	LWIP_PLATFORM_DIAG(("ethernetif_input start...\n\r"));
	/* move received packet into a new pbuf */
	p = low_level_input(netif);
	/* no packet could be read, silently ignore this */
	if (p == NULL)
	{
		if (P2 & 0x40)
			P2 &= ~0x40;
		else
			P2 |= 0x40;
		LWIP_PLATFORM_DIAG(("p = NULL return!!\n\r"));
		return 0;
	}

	/* points to packet payload, which starts with an Ethernet header */
	ethhdr = p->payload;

	if (P2 & 0x20)
		P2 &= ~0x20;
	else
		P2 |= 0x20;
	LWIP_PLATFORM_DIAG(("ethernetif_input : Packet from low_level_input %d\n\r", p->tot_len));

#if LINK_STATS
  lwip_stats.link.recv++;
#endif /* LINK_STATS */

#if (STOE_TRANSPARENT)
	LWIP_PLATFORM_DIAG(("ethernet type : %x\n\r", ethhdr->type));
	switch (htons(ethhdr->type)) {
	/* IP packet? */
	case ETHTYPE_IP:
    /* update ARP table */
	    etharp_ip_input(netif, p);
    /* skip Ethernet header */
	    pbuf_header(p, -sizeof(struct eth_hdr));
    /* pass to network layer */
	    ip_input(p, netif);
		break;
    case ETHTYPE_ARP:
      /* pass p to ARP module  */	  	
		etharp_arp_input(netif, ethernetif->ethaddr, p);
		break;

    default:
		pbuf_free(p);
	    p = NULL;
		break;
	}
#else
	switch (PBDP->STOE_RxInform.Protocol) {
	case 0xff:
		LWIP_PLATFORM_DIAG(("ethernetif_input:: protocol %x\n\r", PBDP->STOE_RxInform.Protocol));
		pbuf_free(p);
	    p = NULL;
		break;
    default:
	    ip_input(p, netif);
		break;
	}
#endif
	return 1;
}

/*
 * ethernetif_init():
 *
 * Should be called at the beginning of the program to set up the
 * network interface. It calls the function low_level_init() to do the
 * actual setup of the hardware.
 *
 */
 
err_t
ethernetif_init(struct netif *netif)
{
	netif->state = &stoeif;
	netif->name[0] = 'e';
	netif->name[1] = 'n';
	netif->output = ethernetif_output;
	netif->linkoutput = low_level_output;


	stoeif.ethaddr = (struct eth_addr *)&(netif->hwaddr[0]);
	stoeif.netif = netif;
  
	STOE_Init(0);

	STOE_SetIPAddr(INT_TO_IPADDR(ipaddr1, ipaddr2, ipaddr3, ipaddr4));
	STOE_SetSubnetMask(INT_TO_IPADDR(submask1, submask2, submask3, submask4));
	STOE_SetGateway(INT_TO_IPADDR(gateaddr1, gateaddr2, gateaddr3, gateaddr4));

	low_level_init(netif);
	STOE_RcvCallback = ETH_RcvHandle;

	STOE_Start();
	return ERR_OK;
}

/*
 * ----------------------------------------------------------------------------
 * Function Name: ETH_RcvHandle
 * Purpose:
 * Params:
 * Returns:
 * Note:
 * ----------------------------------------------------------------------------
 */

void
ETH_RcvHandle(U8_T XDATA* pbuf, U16_T length, U8_T protocol)
{
	ethernetif_input(stoeif.netif);
} /* End of ETH_RcvHandle */

⌨️ 快捷键说明

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