www.pudn.com > uCOSII上实现的tcpip.rar > zarp.c



#include "./include/zarp.h"
#include "./include/zeth.h"


#define ARP_LIVING_TIME	100		/*100 seconds*/
#define ARP_ITEM_NUM	20


STRUCT_BEGIN
typedef struct _arp_header
{
	ethaddr_t 	dest_hwaddr;
	ethaddr_t	src_hwaddr;	
	u16_t		eth_type;
	u16_t		hwtype;
	u16_t		proto;
	u16_t		_hwlen_protolen;
	u16_t		opcode;
  	ethaddr_t	shwaddr;
	ipaddr_t	sipaddr;
	ethaddr_t	dhwaddr;
	ipaddr_t	dipaddr;
}arp_header_t;
STRUCT_END


typedef struct _arp_item
{
	ethaddr_t	hwaddr;
	ipaddr_t	ipaddr;	
	u16_t		ctime;
}arp_item_t;

static arp_item_t arp_table[ARP_ITEM_NUM];

#define NTOHS
#define HTONS
#define ARPH_HWLEN(hdr) (NTOHS((hdr)->_hwlen_protolen) >> 8)
#define ARPH_PROTOLEN(hdr) (NTOHS((hdr)->_hwlen_protolen) & 0xff)


#define ARPH_HWLEN_SET(hdr, len) (hdr)->_hwlen_protolen = HTONS(ARPH_PROTOLEN(hdr) | ((len) << 8))
#define ARPH_PROTOLEN_SET(hdr, len) (hdr)->_hwlen_protolen = HTONS((len) | (ARPH_HWLEN(hdr) << 8))


void add_arp_item(ipaddr_t *ipaddr, ethaddr_t *hwaddr)
{
	u8_t	i,j,olditem = 0;

	u16_t	oldtime = 0xffff;	/*MAX VALUE*/
	
	for ( i = 0; i < ARP_ITEM_NUM; i++)
	{
		
		if ( arp_table[i].ipaddr == *ipaddr)
		{
			for (j = 0; j < 6; j++)
				arp_table[i].hwaddr.addr[j] = hwaddr->addr[j];
			arp_table[i].ctime = sys_get_time() / 100;
			return;
		}

		if ( arp_table[i].ctime < oldtime)
		{
			oldtime =  arp_table[i].ctime;
			olditem = i;
		}
	}

	for (j = 0; j < 6; j++)
		arp_table[olditem].hwaddr.addr[j] = hwaddr->addr[j];
	arp_table[olditem].ipaddr = *ipaddr;
	arp_table[olditem].ctime = sys_get_time() / 100;
	
	return;
}

void arp_init(void)
{
	u8_t	i;
	for ( i = 0; i < ARP_ITEM_NUM; i++)
	{
		arp_table[i].ipaddr = IPADDRANY;
		arp_table[i].ctime = 0;
	}
	
}

zbuffer_t * arp_arp_input(znetif_t *pnetif, zbuffer_t *pbuffer)
{
	arp_header_t 	*pheader;
	u8_t	i;
	
	if ( pbuffer->tot_len < sizeof( arp_header_t ) ) 
	{
		return NULL;
	}

	pheader =(arp_header_t *) pbuffer->pdata;
	
	switch ( pheader->opcode )
	{
		case ARP_REQUEST:
			{
				if ( pheader->dipaddr  == pnetif->ipaddr ) 
				{
					pheader->opcode = ARP_REPLY;
					pheader->dipaddr = pheader->sipaddr;
					pheader->sipaddr = pnetif->ipaddr;
					for (i = 0; i < 6; i++)
					{
		  			  	pheader->dhwaddr.addr[i] = pheader->shwaddr.addr[i];
						pheader->shwaddr.addr[i] = pnetif->hwaddr.addr[i];
						pheader->dest_hwaddr.addr[i] = pheader->dhwaddr.addr[i];
						pheader->src_hwaddr.addr[i] = pnetif->hwaddr.addr[i];
					}
					pheader->hwtype = htons(HWTYPE_ETHERNET);
					ARPH_HWLEN_SET(pheader, 6);
					pheader->proto = ETHTYPE_IP;
					ARPH_PROTOLEN_SET(pheader, sizeof( ipaddr_t));
			        pheader->eth_type = htons(ETHTYPE_ARP);
					return pbuffer;
				}
				break;
			}
		case ARP_REPLY:
			{
				if (pheader->dipaddr == pnetif->ipaddr)
				{
					add_arp_item(&pheader->sipaddr, &pheader->shwaddr);
					return NULL;
				}
				break;
			}
		default:
			break;
	}
	return NULL;
}


u8_t arp_lookup(ethaddr_t *hwaddr, ipaddr_t *ipaddr)
{
	u8_t	i, j;
	u16_t	ctime;
	
	sys_enter_critical();
	for ( i = 0; i < ARP_ITEM_NUM; i++)
	{
		if ( arp_table[i].ipaddr == *ipaddr)
		{
			ctime = sys_get_time() / 100;
			
			if ( (ctime - arp_table[i].ctime ) >ARP_LIVING_TIME)
			{
				arp_table[i].ipaddr = IPADDRANY;		/*this must be refresh*/
				return -1;
			}
			
			for ( j = 0; j < 6; j++)
				hwaddr->addr[j] = arp_table[i].hwaddr.addr[j];
			sys_exit_critical();
			return 0;
		}
	}
	sys_exit_critical();
	return -1;
}



u8_t arp_query(ethaddr_t *hwaddr, ipaddr_t *ipaddr)
{
	zbuffer_t *pbuffer;
	arp_header_t *parpheader;
	u8_t	i;
	
	pbuffer = zbuffer_new(sizeof(arp_header_t));
	
	if ( pbuffer == NULL)
		return -1;

	parpheader = (arp_header_t *)pbuffer->pdata;
	

  	for(i = 0; i < 6; ++i) 
	{
		parpheader->dhwaddr.addr[i] = 0x00;
	    parpheader->shwaddr.addr[i] = default_netif.hwaddr.addr[i];
    }

	for(i = 0; i < 6; ++i) 
	{
		parpheader->dest_hwaddr.addr[i] = 0xff;
		parpheader->src_hwaddr.addr[i] = default_netif.hwaddr.addr[i];
	}

	parpheader->eth_type = ETHTYPE_ARP;
	parpheader->dipaddr = *ipaddr;
	parpheader->sipaddr = default_netif.ipaddr;
	parpheader->hwtype = HWTYPE_ETHERNET;
	ARPH_HWLEN_SET(parpheader, 6);
	parpheader->proto = ETHTYPE_IP;
	parpheader->opcode = ARP_REQUEST;
	ARPH_PROTOLEN_SET(parpheader, sizeof(ipaddr_t) );

	i = 0;
	while( i < 5)
	{
		default_netif.netif_tx(&default_netif, pbuffer);
		sys_delay(20);
		i++;
		if ( arp_lookup(hwaddr, ipaddr) == 0 )
		{
			zbuffer_delete(pbuffer);
			return 0;
		}
	}
	zbuffer_delete(pbuffer);
	
	return -1;	
}