uip.c

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

C
2,234
字号
		{
			conn = cconn;
			break;
		}

		if( cconn->tcpstateflags == UIP_TIME_WAIT )
		{
			if( conn == 0 || cconn->timer > conn->timer )
			{
				conn = cconn;
			}
		}
	}

	if( conn == 0 )
	{
		return 0;
	}

	conn->tcpstateflags = UIP_SYN_SENT;

	conn->snd_nxt[0] = iss[0];
	conn->snd_nxt[1] = iss[1];
	conn->snd_nxt[2] = iss[2];
	conn->snd_nxt[3] = iss[3];

	conn->initialmss = conn->mss = UIP_TCP_MSS;

	conn->len = 1;		/* TCP length of the SYN is one. */
	conn->nrtx = 0;
	conn->timer = 1;	/* Send the SYN next time around. */
	conn->rto = UIP_RTO;
	conn->sa = 0;
	conn->sv = 16;		/* Initial value of the RTT variance. */
	conn->lport = htons( lastport );
	conn->rport = rport;
	uip_ipaddr_copy( &conn->ripaddr, ripaddr );

	return conn;
}

#endif /* UIP_ACTIVE_OPEN */

/*---------------------------------------------------------------------------*/
#if UIP_UDP
struct uip_udp_conn *uip_udp_new( uip_ipaddr_t *ripaddr, u16_t rport )
{
	register struct uip_udp_conn	*conn;

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

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

	for( c = 0; c < UIP_UDP_CONNS; ++c )
	{
		if( uip_udp_conns[c].lport == htons(lastport) )
		{
			goto again;
		}
	}

	conn = 0;
	for( c = 0; c < UIP_UDP_CONNS; ++c )
	{
		if( uip_udp_conns[c].lport == 0 )
		{
			conn = &uip_udp_conns[c];
			break;
		}
	}

	if( conn == 0 )
	{
		return 0;
	}

	conn->lport = HTONS( lastport );
	conn->rport = rport;
	if( ripaddr == NULL )
	{
		memset( conn->ripaddr, 0, sizeof(uip_ipaddr_t) );
	}
	else
	{
		uip_ipaddr_copy( &conn->ripaddr, ripaddr );
	}

	conn->ttl = UIP_TTL;

	return conn;
}

#endif /* UIP_UDP */

/*---------------------------------------------------------------------------*/
void uip_unlisten( u16_t port )
{
	for( c = 0; c < UIP_LISTENPORTS; ++c )
	{
		if( uip_listenports[c] == port )
		{
			uip_listenports[c] = 0;
			return;
		}
	}
}

/*---------------------------------------------------------------------------*/
void uip_listen( u16_t port )
{
	for( c = 0; c < UIP_LISTENPORTS; ++c )
	{
		if( uip_listenports[c] == 0 )
		{
			uip_listenports[c] = port;
			return;
		}
	}
}

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

/* XXX: IP fragment reassembly: not well-tested. */
#if UIP_REASSEMBLY && !UIP_CONF_IPV6
	#define UIP_REASS_BUFSIZE	( UIP_BUFSIZE - UIP_LLH_LEN )
static u8_t			uip_reassbuf[UIP_REASS_BUFSIZE];
static u8_t			uip_reassbitmap[UIP_REASS_BUFSIZE / ( 8 * 8 )];
static const u8_t	bitmap_bits[8] = { 0xff, 0x7f, 0x3f, 0x1f, 0x0f, 0x07, 0x03, 0x01 };
static u16_t		uip_reasslen;
static u8_t			uip_reassflags;
	#define UIP_REASS_FLAG_LASTFRAG 0x01
static u8_t			uip_reasstmr;

	#define IP_MF	0x20

static u8_t uip_reass( void )
{
	u16_t	offset, len;
	u16_t	i;

	/* If ip_reasstmr is zero, no packet is present in the buffer, so we
     write the IP header of the fragment into the reassembly
     buffer. The timer is updated with the maximum age. */
	if( uip_reasstmr == 0 )
	{
		memcpy( uip_reassbuf, &BUF->vhl, UIP_IPH_LEN );
		uip_reasstmr = UIP_REASS_MAXAGE;
		uip_reassflags = 0;

		/* Clear the bitmap. */
		memset( uip_reassbitmap, 0, sizeof(uip_reassbitmap) );
	}

	/* Check if the incoming fragment matches the one currently present
     in the reasembly buffer. If so, we proceed with copying the
     fragment into the buffer. */
	if
	(
		BUF->srcipaddr[0] == FBUF->srcipaddr[0] &&
		BUF->srcipaddr[1] == FBUF->srcipaddr[1] &&
		BUF->destipaddr[0] == FBUF->destipaddr[0] &&
		BUF->destipaddr[1] == FBUF->destipaddr[1] &&
		BUF->ipid[0] == FBUF->ipid[0] &&
		BUF->ipid[1] == FBUF->ipid[1]
	)
	{
		len = ( BUF->len[0] << 8 ) + BUF->len[1] - ( BUF->vhl & 0x0f ) * 4;
		offset = ( ((BUF->ipoffset[0] & 0x3f) << 8) + BUF->ipoffset[1] ) * 8;

		/* If the offset or the offset + fragment length overflows the
       reassembly buffer, we discard the entire packet. */
		if( offset > UIP_REASS_BUFSIZE || offset + len > UIP_REASS_BUFSIZE )
		{
			uip_reasstmr = 0;
			goto nullreturn;
		}

		/* Copy the fragment into the reassembly buffer, at the right
       offset. */
		memcpy( &uip_reassbuf[UIP_IPH_LEN + offset], ( char * ) BUF + ( int ) ((BUF->vhl & 0x0f) * 4), len );

		/* Update the bitmap. */
		if( offset / (8 * 8) == (offset + len) / (8 * 8) )
		{
			/* If the two endpoints are in the same byte, we only update
	 that byte. */
			uip_reassbitmap[offset / ( 8 * 8 )] |= bitmap_bits[( offset / 8 ) & 7] &~bitmap_bits[( (offset + len) / 8 ) & 7];
		}
		else
		{
			/* If the two endpoints are in different bytes, we update the
	 bytes in the endpoints and fill the stuff inbetween with
	 0xff. */
			uip_reassbitmap[offset / ( 8 * 8 )] |= bitmap_bits[( offset / 8 ) & 7];
			for( i = 1 + offset / (8 * 8); i < (offset + len) / (8 * 8); ++i )
			{
				uip_reassbitmap[i] = 0xff;
			}

			uip_reassbitmap[( offset + len ) / ( 8 * 8 )] |= ~bitmap_bits[( (offset + len) / 8 ) & 7];
		}

		/* If this fragment has the More Fragments flag set to zero, we
       know that this is the last fragment, so we can calculate the
       size of the entire packet. We also set the
       IP_REASS_FLAG_LASTFRAG flag to indicate that we have received
       the final fragment. */
		if( (BUF->ipoffset[0] & IP_MF) == 0 )
		{
			uip_reassflags |= UIP_REASS_FLAG_LASTFRAG;
			uip_reasslen = offset + len;
		}

		/* Finally, we check if we have a full packet in the buffer. We do
       this by checking if we have the last fragment and if all bits
       in the bitmap are set. */
		if( uip_reassflags & UIP_REASS_FLAG_LASTFRAG )
		{
			/* Check all bytes up to and including all but the last byte in
	 the bitmap. */
			for( i = 0; i < uip_reasslen / (8 * 8) - 1; ++i )
			{
				if( uip_reassbitmap[i] != 0xff )
				{
					goto nullreturn;
				}
			}

			/* Check the last byte in the bitmap. It should contain just the
	 right amount of bits. */
			if( uip_reassbitmap[uip_reasslen / (8 * 8)] != (u8_t)~bitmap_bits[uip_reasslen / 8 & 7] )
			{
				goto nullreturn;
			}

			/* If we have come this far, we have a full packet in the
	 buffer, so we allocate a pbuf and copy the packet into it. We
	 also reset the timer. */
			uip_reasstmr = 0;
			memcpy( BUF, FBUF, uip_reasslen );

			/* Pretend to be a "normal" (i.e., not fragmented) IP packet
	 from now on. */
			BUF->ipoffset[0] = BUF->ipoffset[1] = 0;
			BUF->len[0] = uip_reasslen >> 8;
			BUF->len[1] = uip_reasslen & 0xff;
			BUF->ipchksum = 0;
			BUF->ipchksum = ~( uip_ipchksum() );

			return uip_reasslen;
		}
	}

nullreturn:
	return 0;
}

#endif /* UIP_REASSEMBLY */

/*---------------------------------------------------------------------------*/
static void uip_add_rcv_nxt( u16_t n )
{
	uip_add32( uip_conn->rcv_nxt, n );
	uip_conn->rcv_nxt[0] = uip_acc32[0];
	uip_conn->rcv_nxt[1] = uip_acc32[1];
	uip_conn->rcv_nxt[2] = uip_acc32[2];
	uip_conn->rcv_nxt[3] = uip_acc32[3];
}

/*---------------------------------------------------------------------------*/
void uip_process( u8_t flag )
{
	register struct uip_conn	*uip_connr = uip_conn;

	#if UIP_UDP
	if( flag == UIP_UDP_SEND_CONN )
	{
		goto udp_send;
	}

	#endif /* UIP_UDP */

	uip_sappdata = uip_appdata = &uip_buf[UIP_IPTCPH_LEN + UIP_LLH_LEN];

	/* Check if we were invoked because of a poll request for a
     particular connection. */
	if( flag == UIP_POLL_REQUEST )
	{
		if( (uip_connr->tcpstateflags & UIP_TS_MASK) == UIP_ESTABLISHED && !uip_outstanding(uip_connr) )
		{
			uip_flags = UIP_POLL;
			UIP_APPCALL();
			goto appsend;
		}

		goto drop;

		/* Check if we were invoked because of the perodic timer fireing. */
	}
	else if( flag == UIP_TIMER )
	{
		#if UIP_REASSEMBLY
		if( uip_reasstmr != 0 )
		{
			--uip_reasstmr;
		}

		#endif /* UIP_REASSEMBLY */

		/* Increase the initial sequence number. */
		if( ++iss[3] == 0 )
		{
			if( ++iss[2] == 0 )
			{
				if( ++iss[1] == 0 )
				{
					++iss[0];
				}
			}
		}

		/* Reset the length variables. */
		uip_len = 0;
		uip_slen = 0;

		/* Check if the connection is in a state in which we simply wait
       for the connection to time out. If so, we increase the
       connection's timer and remove the connection if it times
       out. */
		if( uip_connr->tcpstateflags == UIP_TIME_WAIT || uip_connr->tcpstateflags == UIP_FIN_WAIT_2 )
		{
			++( uip_connr->timer );
			if( uip_connr->timer == UIP_TIME_WAIT_TIMEOUT )
			{
				uip_connr->tcpstateflags = UIP_CLOSED;
			}
		}
		else if( uip_connr->tcpstateflags != UIP_CLOSED )
		{
			/* If the connection has outstanding data, we increase the
	 connection's timer and see if it has reached the RTO value
	 in which case we retransmit. */
			if( uip_outstanding(uip_connr) )
			{
				uip_connr->timer = uip_connr->timer - 1;
				if( uip_connr->timer == 0 )
				{
					if
					(
						uip_connr->nrtx == UIP_MAXRTX ||
						(
							(uip_connr->tcpstateflags == UIP_SYN_SENT || uip_connr->tcpstateflags == UIP_SYN_RCVD) &&
							uip_connr->nrtx == UIP_MAXSYNRTX
						)
					)
					{
						uip_connr->tcpstateflags = UIP_CLOSED;

						/* We call UIP_APPCALL() with uip_flags set to
	       UIP_TIMEDOUT to inform the application that the
	       connection has timed out. */
						uip_flags = UIP_TIMEDOUT;
						UIP_APPCALL();

						/* We also send a reset packet to the remote host. */
						BUF->flags = TCP_RST | TCP_ACK;
						goto tcp_send_nodata;
					}

					/* Exponential backoff. */
					uip_connr->timer = UIP_RTO << ( uip_connr->nrtx > 4 ? 4 : uip_connr->nrtx );
					++( uip_connr->nrtx );

					/* Ok, so we need to retransmit. We do this differently
	     depending on which state we are in. In ESTABLISHED, we
	     call upon the application so that it may prepare the
	     data for the retransmit. In SYN_RCVD, we resend the
	     SYNACK that we sent earlier and in LAST_ACK we have to
	     retransmit our FINACK. */
					UIP_STAT( ++uip_stat.tcp.rexmit );
					switch( uip_connr->tcpstateflags & UIP_TS_MASK )
					{
						case UIP_SYN_RCVD:
							/* In the SYN_RCVD state, we should retransmit our
               SYNACK. */
							goto tcp_send_synack;

							#if UIP_ACTIVE_OPEN

						case UIP_SYN_SENT:
							/* In the SYN_SENT state, we retransmit out SYN. */
							BUF->flags = 0;
							goto tcp_send_syn;
							#endif /* UIP_ACTIVE_OPEN */

						case UIP_ESTABLISHED:
							/* In the ESTABLISHED state, we call upon the application
               to do the actual retransmit after which we jump into
               the code for sending out the packet (the apprexmit
               label). */
							uip_flags = UIP_REXMIT;
							UIP_APPCALL();
							goto apprexmit;

						case UIP_FIN_WAIT_1:
						case UIP_CLOSING:
						case UIP_LAST_ACK:
							/* In all these states we should retransmit a FINACK. */
							goto tcp_send_finack;
					}
				}
			}
			else if( (uip_connr->tcpstateflags & UIP_TS_MASK) == UIP_ESTABLISHED )
			{
				/* If there was no need for a retransmission, we poll the
           application for new data. */
				uip_flags = UIP_POLL;
				UIP_APPCALL();
				goto appsend;
			}
		}

		goto drop;
	}

	#if UIP_UDP
	if( flag == UIP_UDP_TIMER )
	{
		if( uip_udp_conn->lport != 0 )
		{
			uip_conn = NULL;
			uip_sappdata = uip_appdata = &uip_buf[UIP_LLH_LEN + UIP_IPUDPH_LEN];
			uip_len = uip_slen = 0;
			uip_flags = UIP_POLL;
			UIP_UDP_APPCALL();
			goto udp_send;
		}
		else
		{
			goto drop;
		}
	}

⌨️ 快捷键说明

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