📄 nifce_driver.c
字号:
/*
* Description:
* Contains process packet functionality
*/
#include "lwip/debug.h"
#include "lwip/opt.h"
#include "lwip/def.h"
#include "lwip/mem.h"
#include "lwip/pbuf.h"
#include "lwip/stats.h"
#include "lwip/sys.h"
#include "lwip/tcpip.h"
#include "netif/etharp.h"
#include <kernel_abs.h>
#include <sys/exception.h>
#include <services/services.h>
#include <drivers/adi_dev.h>
#include <services/adi_dcb.h>
#include <services/adi_dma.h>
#include <services/adi_int.h>
#include <services/adi_ebiu.h>
#include "netif/nifce_driver.h"
#include <ADI_ETHER.h>
// base of network interface identifiers
#define IFNAME0 'e'
#define IFNAME1 't'
// interface MTU size - max size of an ethernet frame
#define MTU 1518
void eth_input(struct pbuf* p, struct netif* netif);
void process_rcvd_packets(void *nifce);
void process_xmtd_packets(void *nifce);
/* declared in pkthandler.c */
extern ADI_ETHER_BUFFER *rcv_list,*xmt_list;
/* Trace function */
int (*Trace_Function)( unsigned char EventId, unsigned short NoOfBytes, const unsigned char *Data) = NULL;
// Set trace function
void SetTraceFunction( int (*Trace_Event) ( unsigned char EventId, unsigned short NoOfBytes, const unsigned char *Data))
{
Trace_Function = Trace_Event;
}
// Ethernet header as received from the wire
PACK_STRUCT_BEGIN
struct hw_eth_hdr
{
PACK_STRUCT_FIELD(struct eth_addr dest);
PACK_STRUCT_FIELD(struct eth_addr src);
PACK_STRUCT_FIELD(u16_t type);
}
PACK_STRUCT_STRUCT;
PACK_STRUCT_END
/*##########################################################################
*
* This function should be called regularly to service the lists of receive
* buffers that the hardware might have filled and transmit buffers that it
* may have emptied since the last call.
* This function is registered as tcp callback routine. see pkthandler.c
* currently the callback routines is called periodically and the period is
* configurable by the user.
*
*#########################################################################*/
void nifce_driver_poll(void* arg)
{
// lazy to check in critical region if it fails first time gets nextime
if(xmt_list)
process_xmtd_packets(arg); // TODO: directly process it in callback
if(rcv_list)
process_rcvd_packets(arg); // TODO: Check to process in callback
}
/*##########################################################################
*
* processes the transmitted packets by releasing the memory
*
*#########################################################################*/
void process_xmtd_packets(void *arg_nif)
{
struct netif* netif = (struct netif*)arg_nif;
struct nifce_info* nip = (struct nifce_info*)netif->state;
unsigned int *mangle_ptr;
void *handle = nip->handle;
int int_sts;
ADI_ETHER_BUFFER* buffers_to_reuse;
ADI_ETHER_BUFFER* buffers_to_process;
ADI_ETHER_BUFFER* recycle_list = 0;
ADI_ETHER_BUFFER* bp;
ADI_ETHER_BUFFER* nbp;
ADI_ETHER_BUFFER* lbp;
int_sts = ker_disable_interrupts(ker_kPriorityLevelAll);
buffers_to_reuse = xmt_list;
xmt_list = NULL;
ker_enable_interrupts(int_sts);
// add transmitted buffers to the available list after resetting length
lbp = bp = buffers_to_reuse;
while (bp != 0)
{
// this is a hack to use the num_rows and num_rows for the
// purpose of storing the buffer_info address.
// TODO: getrid of using reserved area
//
mangle_ptr = ((unsigned int*)&bp->Reserved)+4;
bp->ElementCount = ((struct buffer_info*)((*(unsigned int*)mangle_ptr)))->max_buf_len;
bp->CallbackParameter =bp;
bp->StatusWord = 0;
bp->PayLoad =0;
bp->ProcessedElementCount=0;
bp->ProcessedFlag =0;
lbp = bp;
bp = bp->pNext;
} //while
bp = buffers_to_reuse;
if (bp)
{
u32_t old_level;
old_level = sys_arch_protect();
lbp->pNext = nip->x;
nip->x = bp;
sys_arch_unprotect(old_level);
}
}
void process_rcvd_packets(void *arg_nif)
{
struct netif* netif = (struct netif*)arg_nif;
struct nifce_info* nip = (struct nifce_info*)netif->state;
unsigned int *mangle_ptr;
void *handle = nip->handle;
int int_sts;
ADI_ETHER_BUFFER* buffers_to_reuse;
ADI_ETHER_BUFFER* buffers_to_process;
ADI_ETHER_BUFFER* recycle_list = 0;
ADI_ETHER_BUFFER* bp;
ADI_ETHER_BUFFER* nbp;
ADI_ETHER_BUFFER* lbp;
// now check for received buffers
int_sts = ker_disable_interrupts(ker_kPriorityLevelAll);
buffers_to_process = rcv_list;
rcv_list = NULL;
ker_enable_interrupts(int_sts);
// create a pbuf for each received buffer and call eth_input to process it
bp = buffers_to_process;
while (bp != 0)
{
struct hw_eth_hdr* ethhdr = (struct hw_eth_hdr*)((char*)bp->Data+2);
u16_t length = bp->ProcessedElementCount - 6; // 2 + 4crc byte to store length
struct pbuf* p;
int unpack_arp = 0;
nbp = bp->pNext;
bp->pNext = 0;
// (char*)bp->Data + 2 contrain the actual data.
if (Trace_Function) Trace_Function('R',length,((unsigned char *)bp->Data+2));
// see whether we need two extra u16_t fields for alignment
if (length >= (sizeof(struct etharp_hdr) - 6) &&
htons(ethhdr->type) == ETHTYPE_ARP) {
length += 4; // need fields unused2 and unused3 in struct etharp_hdr
unpack_arp = 1;
}
length += 2;// for field unused1 in struct eth_hdr
p = pbuf_alloc(PBUF_RAW, length, PBUF_RAM);
if (p != NULL)
{
//u8_t* psrc = (u8_t*)bp->Data;
u8_t* psrc = (u8_t*)bp->Data+2;
u8_t* pdst = (u8_t*)p->payload;
// set field unused1 to 0
*(u16_t*)pdst = 0;
pdst += 2;
// copy in eth_hdr data
memcpy(pdst, psrc, 14);
pdst += 14;
psrc += 14;
if (unpack_arp)
{
// copy etharp frame into pbuf up to field unused2
memcpy(pdst, psrc, 14);
pdst += 14;
psrc += 14;
// set field unused2 to 0
*(u16_t*)pdst = 0;
pdst += 2;
// copy more of frame up to field unused3
memcpy(pdst, psrc, 10);
pdst += 10;
psrc += 10;
// set field unused3 to 0
*(u16_t*)pdst = 0;
pdst += 2;
// copy remainder of frame
memcpy(pdst, psrc, 4);
} else
{
// just copy the rest of the frame into the pbuf in one go
memcpy(pdst, psrc, length - 16);
}
#ifdef LINK_STATS
lwip_stats.link.recv++;
#endif
mangle_ptr = ((unsigned int*)&bp->Reserved)+4; // TODO: get-rid of Reserved.
eth_input(p, ((struct buffer_info*)(*((unsigned int*)mangle_ptr)))->netif);
} // p!=NULL
else
{
#ifdef LINK_STATS
lwip_stats.link.memerr++; // had to drop frame - no memory for pbuf
#endif
}
mangle_ptr = ((unsigned int*)&bp->Reserved)+4;
bp->ElementCount = ((struct buffer_info*)(*((unsigned int*)mangle_ptr)))->max_buf_len;
bp->CallbackParameter = bp;
bp->PayLoad =0;
bp->StatusWord =0;
bp->ProcessedElementCount=0;
bp->ProcessedFlag =0;
bp->pNext = recycle_list;
recycle_list = bp;
bp = nbp;
} // while
// return the buffers to the driver
if (recycle_list != 0)
adi_dev_Read(nip->handle,ADI_DEV_1D,(ADI_DEV_BUFFER*)recycle_list);
}
/*##########################################################################
*
* Output pbuf chain to hardware. It is assumed that there is a complete and
* correct ethernet frame in p. The only buffering in this system is in the
* list of tx ADI_ETHER_BUFFER's. If there is no room in it, then drop the frame.
*
*#########################################################################*/
static err_t
low_level_output(struct netif* netif, struct pbuf* p)
{
struct nifce_info* nip = (struct nifce_info*)netif->state;
ADI_ETHER_BUFFER* tx;
struct pbuf *q;
char* data;
unsigned short *ps;
struct hw_eth_hdr* ethhdr;
u32_t old_level;
int len;
if (p->tot_len > nip->tx_buff_datalen)
{
// frame too big for our buffers
#ifdef LINK_STATS
lwip_stats.link.memerr++;
#endif
return ERR_MEM;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -