uip.c

来自「FreeRTOS is a portable, open source, min」· C语言 代码 · 共 2,234 行 · 第 1/5 页

C
2,234
字号
#define DEBUG_PRINTF( ... )		/*printf(__VA_ARGS__)*/

/**
 * \defgroup uip The uIP TCP/IP stack
 * @{
 *
 * uIP is an implementation of the TCP/IP protocol stack intended for
 * small 8-bit and 16-bit microcontrollers.
 *
 * uIP provides the necessary protocols for Internet communication,
 * with a very small code footprint and RAM requirements - the uIP
 * code size is on the order of a few kilobytes and RAM usage is on
 * the order of a few hundred bytes.
 */

/**
 * \file
 * The uIP TCP/IP stack code.
 * \author Adam Dunkels <adam@dunkels.com>
 */

/*
 * Copyright (c) 2001-2003, Adam Dunkels.
 * 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 uIP TCP/IP stack.
 *
 * $Id: uip.c,v 1.65 2006/06/11 21:46:39 adam Exp $
 *
 */

/*
 * uIP is a small implementation of the IP, UDP and TCP protocols (as
 * well as some basic ICMP stuff). The implementation couples the IP,
 * UDP, TCP and the application layers very tightly. To keep the size
 * of the compiled code down, this code frequently uses the goto
 * statement. While it would be possible to break the uip_process()
 * function into many smaller functions, this would increase the code
 * size because of the overhead of parameter passing and the fact that
 * the optimier would not be as efficient.
 *
 * The principle is that we have a small buffer, called the uip_buf,
 * in which the device driver puts an incoming packet. The TCP/IP
 * stack parses the headers in the packet, and calls the
 * application. If the remote host has sent data to the application,
 * this data is present in the uip_buf and the application read the
 * data from there. It is up to the application to put this data into
 * a byte stream if needed. The application will not be fed with data
 * that is out of sequence.
 *
 * If the application whishes to send data to the peer, it should put
 * its data into the uip_buf. The uip_appdata pointer points to the
 * first available byte. The TCP/IP stack will calculate the
 * checksums, and fill in the necessary header fields and finally send
 * the packet back to the peer.
*/
#include "uip.h"
#include "uipopt.h"
#include "uip_arch.h"
#include "uip_arp.h"
#include "FreeRTOS.h"

#if UIP_CONF_IPV6
	#include "uip-neighbor.h"
#endif /* UIP_CONF_IPV6 */

#include <string.h>

/*---------------------------------------------------------------------------*/

/* Variable definitions. */

/* The IP address of this host. If it is defined to be fixed (by
   setting UIP_FIXEDADDR to 1 in uipopt.h), the address is set
   here. Otherwise, the address */
#if UIP_FIXEDADDR > 0
const uip_ipaddr_t			uip_hostaddr = { HTONS( (UIP_IPADDR0 << 8) | UIP_IPADDR1 ), HTONS( (UIP_IPADDR2 << 8) | UIP_IPADDR3 ) };
const uip_ipaddr_t			uip_draddr = { HTONS( (UIP_DRIPADDR0 << 8) | UIP_DRIPADDR1 ), HTONS( (UIP_DRIPADDR2 << 8) | UIP_DRIPADDR3 ) };
const uip_ipaddr_t			uip_netmask = { HTONS( (UIP_NETMASK0 << 8) | UIP_NETMASK1 ), HTONS( (UIP_NETMASK2 << 8) | UIP_NETMASK3 ) };
#else
uip_ipaddr_t				uip_hostaddr, uip_draddr, uip_netmask;
#endif /* UIP_FIXEDADDR */

static const uip_ipaddr_t	all_ones_addr =
#if UIP_CONF_IPV6
{ 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff };
#else /* UIP_CONF_IPV6 */
{
	0xffff, 0xffff
};
#endif /* UIP_CONF_IPV6 */
static const uip_ipaddr_t	all_zeroes_addr =
#if UIP_CONF_IPV6
{ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 };
#else /* UIP_CONF_IPV6 */
{
	0x0000, 0x0000
};
#endif /* UIP_CONF_IPV6 */

#if UIP_FIXEDETHADDR
const struct uip_eth_addr	uip_ethaddr = { { UIP_ETHADDR0, UIP_ETHADDR1, UIP_ETHADDR2, UIP_ETHADDR3, UIP_ETHADDR4, UIP_ETHADDR5 } };
#else
struct uip_eth_addr			uip_ethaddr = { { 0, 0, 0, 0, 0, 0 } };
#endif
#ifndef UIP_CONF_EXTERNAL_BUFFER
	#ifdef __ICCARM__
		#pragma data_alignment = 4
u8_t uip_buf[UIP_BUFSIZE + 2];	/* The packet buffer that contains incoming packets. */
	#else
u8_t				uip_buf[UIP_BUFSIZE + 2] ALIGN_STRUCT_END;	/* The packet buffer that contains incoming packets. */
	#endif
#endif /* UIP_CONF_EXTERNAL_BUFFER */

void				*uip_appdata;				/* The uip_appdata pointer points to
				    application data. */
void				*uip_sappdata;				/* The uip_appdata pointer points to
				    the application data which is to
				    be sent. */
#if UIP_URGDATA > 0
void				*uip_urgdata;				/* The uip_urgdata pointer points to
   				    urgent data (out-of-band data), if
   				    present. */
u16_t				uip_urglen, uip_surglen;
#endif /* UIP_URGDATA > 0 */

u16_t				uip_len, uip_slen;

/* The uip_len is either 8 or 16 bits,
				depending on the maximum packet
				size. */
u8_t				uip_flags;					/* The uip_flags variable is used for
				communication between the TCP/IP stack
				and the application program. */
struct uip_conn		*uip_conn;					/* uip_conn always points to the current
				connection. */

struct uip_conn		uip_conns[UIP_CONNS];

/* The uip_conns array holds all TCP
				connections. */
u16_t				uip_listenports[UIP_LISTENPORTS];

/* The uip_listenports list all currently
				listning ports. */
#if UIP_UDP
struct uip_udp_conn *uip_udp_conn;
struct uip_udp_conn uip_udp_conns[UIP_UDP_CONNS];
#endif /* UIP_UDP */

static u16_t		ipid;						/* Ths ipid variable is an increasing
				number that is used for the IP ID
				field. */

void uip_setipid( u16_t id )
{
	ipid = id;
}

static u8_t		iss[4];							/* The iss variable is used for the TCP
				initial sequence number. */

#if UIP_ACTIVE_OPEN
static u16_t	lastport;						/* Keeps track of the last port used for
				a new connection. */
#endif /* UIP_ACTIVE_OPEN */

/* Temporary variables. */
u8_t			uip_acc32[4];
static u8_t		c, opt;
static u16_t	tmp16;

/* Structures and definitions. */
#define TCP_FIN								0x01
#define TCP_SYN								0x02
#define TCP_RST								0x04
#define TCP_PSH								0x08
#define TCP_ACK								0x10
#define TCP_URG								0x20
#define TCP_CTL								0x3f

#define TCP_OPT_END							0	/* End of TCP options list */
#define TCP_OPT_NOOP						1	/* "No-operation" TCP option */
#define TCP_OPT_MSS							2	/* Maximum segment size TCP option */

#define TCP_OPT_MSS_LEN						4	/* Length of TCP MSS option. */

#define ICMP_ECHO_REPLY						0
#define ICMP_ECHO							8

#define ICMP6_ECHO_REPLY					129
#define ICMP6_ECHO							128
#define ICMP6_NEIGHBOR_SOLICITATION			135
#define ICMP6_NEIGHBOR_ADVERTISEMENT		136

#define ICMP6_FLAG_S						( 1 << 6 )
#define ICMP6_OPTION_SOURCE_LINK_ADDRESS	1
#define ICMP6_OPTION_TARGET_LINK_ADDRESS	2

/* Macros. */
#define BUF		( ( struct uip_tcpip_hdr * ) &uip_buf[UIP_LLH_LEN] )
#define FBUF	( ( struct uip_tcpip_hdr * ) &uip_reassbuf[0] )
#define ICMPBUF ( ( struct uip_icmpip_hdr * ) &uip_buf[UIP_LLH_LEN] )
#define UDPBUF	( ( struct uip_udpip_hdr * ) &uip_buf[UIP_LLH_LEN] )
#if UIP_STATISTICS == 1
struct uip_stats	uip_stat;
	#define UIP_STAT( s )	s
#else
	#define UIP_STAT( s )
#endif /* UIP_STATISTICS == 1 */

#if UIP_LOGGING == 1
	#include <stdio.h>
void	uip_log( char *msg );
	#define UIP_LOG( m )	uip_log( m )
#else
	#define UIP_LOG( m )
#endif /* UIP_LOGGING == 1 */

#if !UIP_ARCH_ADD32
void uip_add32( u8_t *op32, u16_t op16 )
{
	uip_acc32[3] = op32[3] + ( op16 & 0xff );
	uip_acc32[2] = op32[2] + ( op16 >> 8 );
	uip_acc32[1] = op32[1];
	uip_acc32[0] = op32[0];

	if( uip_acc32[2] < (op16 >> 8) )
	{
		++uip_acc32[1];
		if( uip_acc32[1] == 0 )
		{
			++uip_acc32[0];
		}
	}

	if( uip_acc32[3] < (op16 & 0xff) )
	{
		++uip_acc32[2];
		if( uip_acc32[2] == 0 )
		{
			++uip_acc32[1];
			if( uip_acc32[1] == 0 )
			{
				++uip_acc32[0];
			}
		}
	}
}

#endif /* UIP_ARCH_ADD32 */

#if !UIP_ARCH_CHKSUM

/*---------------------------------------------------------------------------*/
static u16_t chksum( u16_t sum, const u8_t *data, u16_t len )
{
	u16_t		t;
	const u8_t	*dataptr;
	const u8_t	*last_byte;

	dataptr = data;
	last_byte = data + len - 1;

	while( dataptr < last_byte )
	{				/* At least two more bytes */
		t = ( dataptr[0] << 8 ) + dataptr[1];
		sum += t;
		if( sum < t )
		{
			sum++;	/* carry */
		}

		dataptr += 2;
	}

	if( dataptr == last_byte )
	{
		t = ( dataptr[0] << 8 ) + 0;
		sum += t;
		if( sum < t )
		{
			sum++;	/* carry */
		}
	}

	/* Return sum in host byte order. */
	return sum;
}

/*---------------------------------------------------------------------------*/
u16_t uip_chksum( u16_t *data, u16_t len )
{
	return htons( chksum(0, ( u8_t * ) data, len) );
}

/*---------------------------------------------------------------------------*/
	#ifndef UIP_ARCH_IPCHKSUM
u16_t uip_ipchksum( void )
{
	u16_t	sum;

	sum = chksum( 0, &uip_buf[UIP_LLH_LEN], UIP_IPH_LEN );
	DEBUG_PRINTF( "uip_ipchksum: sum 0x%04x\n", sum );
	return( sum == 0 ) ? 0xffff : htons( sum );
}

	#endif

/*---------------------------------------------------------------------------*/
static u16_t upper_layer_chksum( u8_t proto )
{
	u16_t	upper_layer_len;
	u16_t	sum;

		#if UIP_CONF_IPV6
	upper_layer_len = ( ((u16_t) (BUF->len[0]) << 8) + BUF->len[1] );
		#else /* UIP_CONF_IPV6 */
	upper_layer_len = ( ((u16_t) (BUF->len[0]) << 8) + BUF->len[1] ) - UIP_IPH_LEN;
		#endif /* UIP_CONF_IPV6 */

	/* First sum pseudoheader. */

	/* IP protocol and length fields. This addition cannot carry. */
	sum = upper_layer_len + proto;

	/* Sum IP source and destination addresses. */
	sum = chksum( sum, ( u8_t * ) &BUF->srcipaddr[0], 2 * sizeof(uip_ipaddr_t) );

	/* Sum TCP header and data. */
	sum = chksum( sum, &uip_buf[UIP_IPH_LEN + UIP_LLH_LEN], upper_layer_len );

	return( sum == 0 ) ? 0xffff : htons( sum );
}

/*---------------------------------------------------------------------------*/
	#if UIP_CONF_IPV6
u16_t uip_icmp6chksum( void )
{
	return upper_layer_chksum( UIP_PROTO_ICMP6 );
}

	#endif /* UIP_CONF_IPV6 */

/*---------------------------------------------------------------------------*/
u16_t uip_tcpchksum( void )
{
	return upper_layer_chksum( UIP_PROTO_TCP );
}

/*---------------------------------------------------------------------------*/
	#if UIP_UDP_CHECKSUMS
u16_t uip_udpchksum( void )
{
	return upper_layer_chksum( UIP_PROTO_UDP );
}

	#endif /* UIP_UDP_CHECKSUMS */
#endif /* UIP_ARCH_CHKSUM */

/*---------------------------------------------------------------------------*/
void uip_init( void )
{
	for( c = 0; c < UIP_LISTENPORTS; ++c )
	{
		uip_listenports[c] = 0;
	}

	for( c = 0; c < UIP_CONNS; ++c )
	{
		uip_conns[c].tcpstateflags = UIP_CLOSED;
	}

	#if UIP_ACTIVE_OPEN
	lastport = 1024;
	#endif /* UIP_ACTIVE_OPEN */

	#if UIP_UDP
	for( c = 0; c < UIP_UDP_CONNS; ++c )
	{
		uip_udp_conns[c].lport = 0;
	}

	#endif /* UIP_UDP */

	/* IPv4 initialization. */
	#if UIP_FIXEDADDR == 0

	/*  uip_hostaddr[0] = uip_hostaddr[1] = 0;*/
	#endif /* UIP_FIXEDADDR */
}

/*---------------------------------------------------------------------------*/
#if UIP_ACTIVE_OPEN
struct uip_conn *uip_connect( uip_ipaddr_t *ripaddr, u16_t rport )
{
	register struct uip_conn	*conn, *cconn;

	/* Find an unused local port. */
again:
	++lastport;

	if( lastport >= 32000 )
	{
		lastport = 4096;
	}

	/* Check if this port is already in use, and if so try to find
     another one. */
	for( c = 0; c < UIP_CONNS; ++c )
	{
		conn = &uip_conns[c];
		if( conn->tcpstateflags != UIP_CLOSED && conn->lport == htons(lastport) )
		{
			goto again;
		}
	}

	conn = 0;
	for( c = 0; c < UIP_CONNS; ++c )
	{
		cconn = &uip_conns[c];
		if( cconn->tcpstateflags == UIP_CLOSED )

⌨️ 快捷键说明

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