uip.c

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

C
2,234
字号

	#endif

	/* This is where the input processing starts. */
	UIP_STAT( ++uip_stat.ip.recv );

	/* Start of IP input header processing code. */
	#if UIP_CONF_IPV6

	/* Check validity of the IP header. */
	if( (BUF->vtc & 0xf0) != 0x60 )
	{					/* IP version and header length. */
		UIP_STAT( ++uip_stat.ip.drop );
		UIP_STAT( ++uip_stat.ip.vhlerr );
		UIP_LOG( "ipv6: invalid version." );
		goto drop;
	}

	#else /* UIP_CONF_IPV6 */

	/* Check validity of the IP header. */
	if( BUF->vhl != 0x45 )
	{					/* IP version and header length. */
		UIP_STAT( ++uip_stat.ip.drop );
		UIP_STAT( ++uip_stat.ip.vhlerr );
		UIP_LOG( "ip: invalid version or header length." );
		goto drop;
	}

	#endif /* UIP_CONF_IPV6 */

	/* Check the size of the packet. If the size reported to us in
     uip_len is smaller the size reported in the IP header, we assume
     that the packet has been corrupted in transit. If the size of
     uip_len is larger than the size reported in the IP packet header,
     the packet has been padded and we set uip_len to the correct
     value.. */
	if( (BUF->len[0] << 8) + BUF->len[1] <= uip_len )
	{
		uip_len = ( BUF->len[0] << 8 ) + BUF->len[1];
		#if UIP_CONF_IPV6
		uip_len += 40;	/* The length reported in the IPv6 header is the
		      length of the payload that follows the
		      header. However, uIP uses the uip_len variable
		      for holding the size of the entire packet,
		      including the IP header. For IPv4 this is not a
		      problem as the length field in the IPv4 header
		      contains the length of the entire packet. But
		      for IPv6 we need to add the size of the IPv6
		      header (40 bytes). */
		#endif /* UIP_CONF_IPV6 */
	}
	else
	{
		UIP_LOG( "ip: packet shorter than reported in IP header." );
		goto drop;
	}

	#if !UIP_CONF_IPV6

	/* Check the fragment flag. */
	if( (BUF->ipoffset[0] & 0x3f) != 0 || BUF->ipoffset[1] != 0 )
	{
			#if UIP_REASSEMBLY
		uip_len = uip_reass();
		if( uip_len == 0 )
		{
			goto drop;
		}

			#else /* UIP_REASSEMBLY */
		UIP_STAT( ++uip_stat.ip.drop );
		UIP_STAT( ++uip_stat.ip.fragerr );
		UIP_LOG( "ip: fragment dropped." );
		goto drop;
			#endif /* UIP_REASSEMBLY */
	}

	#endif /* UIP_CONF_IPV6 */

	if( uip_ipaddr_cmp(uip_hostaddr, all_zeroes_addr) )
	{
		/* If we are configured to use ping IP address configuration and
       hasn't been assigned an IP address yet, we accept all ICMP
       packets. */
		#if UIP_PINGADDRCONF && !UIP_CONF_IPV6
		if( BUF->proto == UIP_PROTO_ICMP )
		{
			UIP_LOG( "ip: possible ping config packet received." );
			goto icmp_input;
		}
		else
		{
			UIP_LOG( "ip: packet dropped since no address assigned." );
			goto drop;
		}

		#endif /* UIP_PINGADDRCONF */
	}
	else
	{
		/* If IP broadcast support is configured, we check for a broadcast
       UDP packet, which may be destined to us. */
		#if UIP_BROADCAST
		DEBUG_PRINTF( "UDP IP checksum 0x%04x\n", uip_ipchksum() );
		if( BUF->proto == UIP_PROTO_UDP && uip_ipaddr_cmp(BUF->destipaddr, all_ones_addr) /*&&
	 uip_ipchksum() == 0xffff*/ )
		{
			goto udp_input;
		}

		#endif /* UIP_BROADCAST */

		/* Check if the packet is destined for our IP address. */
		#if !UIP_CONF_IPV6
		if( !uip_ipaddr_cmp(BUF->destipaddr, uip_hostaddr) )
		{
			UIP_STAT( ++uip_stat.ip.drop );
			goto drop;
		}

		#else /* UIP_CONF_IPV6 */

		/* For IPv6, packet reception is a little trickier as we need to
       make sure that we listen to certain multicast addresses (all
       hosts multicast address, and the solicited-node multicast
       address) as well. However, we will cheat here and accept all
       multicast packets that are sent to the ff02::/16 addresses. */
		if( !uip_ipaddr_cmp(BUF->destipaddr, uip_hostaddr) && BUF->destipaddr[0] != HTONS(0xff02) )
		{
			UIP_STAT( ++uip_stat.ip.drop );
			goto drop;
		}

		#endif /* UIP_CONF_IPV6 */
	}

	#if !UIP_CONF_IPV6
	if( uip_ipchksum() != 0xffff )
	{					/* Compute and check the IP header
				    checksum. */
		UIP_STAT( ++uip_stat.ip.drop );
		UIP_STAT( ++uip_stat.ip.chkerr );
		UIP_LOG( "ip: bad checksum." );
		goto drop;
	}

	#endif /* UIP_CONF_IPV6 */

	if( BUF->proto == UIP_PROTO_TCP )
	{					/* Check for TCP packet. If so,
				       proceed with TCP input
				       processing. */
		goto tcp_input;
	}

	#if UIP_UDP
	if( BUF->proto == UIP_PROTO_UDP )
	{
		goto udp_input;
	}

	#endif /* UIP_UDP */

	#if !UIP_CONF_IPV6

	/* ICMPv4 processing code follows. */
	if( BUF->proto != UIP_PROTO_ICMP )
	{					/* We only allow ICMP packets from
					here. */
		UIP_STAT( ++uip_stat.ip.drop );
		UIP_STAT( ++uip_stat.ip.protoerr );
		UIP_LOG( "ip: neither tcp nor icmp." );
		goto drop;
	}

		#if UIP_PINGADDRCONF
	icmp_input :
		#endif /* UIP_PINGADDRCONF */
	UIP_STAT( ++uip_stat.icmp.recv );

	/* ICMP echo (i.e., ping) processing. This is simple, we only change
     the ICMP type from ECHO to ECHO_REPLY and adjust the ICMP
     checksum before we return the packet. */
	if( ICMPBUF->type != ICMP_ECHO )
	{
		UIP_STAT( ++uip_stat.icmp.drop );
		UIP_STAT( ++uip_stat.icmp.typeerr );
		UIP_LOG( "icmp: not icmp echo." );
		goto drop;
	}

	/* If we are configured to use ping IP address assignment, we use
     the destination IP address of this ping packet and assign it to
     ourself. */
		#if UIP_PINGADDRCONF
	if( (uip_hostaddr[0] | uip_hostaddr[1]) == 0 )
	{
		uip_hostaddr[0] = BUF->destipaddr[0];
		uip_hostaddr[1] = BUF->destipaddr[1];
	}

		#endif /* UIP_PINGADDRCONF */

	ICMPBUF->type = ICMP_ECHO_REPLY;

	if( ICMPBUF->icmpchksum >= HTONS(0xffff - (ICMP_ECHO << 8)) )
	{
		ICMPBUF->icmpchksum += HTONS( ICMP_ECHO << 8 ) + 1;
	}
	else
	{
		ICMPBUF->icmpchksum += HTONS( ICMP_ECHO << 8 );
	}

	/* Swap IP addresses. */
	uip_ipaddr_copy( BUF->destipaddr, BUF->srcipaddr );
	uip_ipaddr_copy( BUF->srcipaddr, uip_hostaddr );

	UIP_STAT( ++uip_stat.icmp.sent );
	goto send;

	/* End of IPv4 input header processing code. */
	#else /* !UIP_CONF_IPV6 */

	/* This is IPv6 ICMPv6 processing code. */
	DEBUG_PRINTF( "icmp6_input: length %d\n", uip_len );

	if( BUF->proto != UIP_PROTO_ICMP6 )
	{					/* We only allow ICMPv6 packets from
					 here. */
		UIP_STAT( ++uip_stat.ip.drop );
		UIP_STAT( ++uip_stat.ip.protoerr );
		UIP_LOG( "ip: neither tcp nor icmp6." );
		goto drop;
	}

	UIP_STAT( ++uip_stat.icmp.recv );

	/* If we get a neighbor solicitation for our address we should send
     a neighbor advertisement message back. */
	if( ICMPBUF->type == ICMP6_NEIGHBOR_SOLICITATION )
	{
		if( uip_ipaddr_cmp(ICMPBUF->icmp6data, uip_hostaddr) )
		{
			if( ICMPBUF->options[0] == ICMP6_OPTION_SOURCE_LINK_ADDRESS )
			{
				/* Save the sender's address in our neighbor list. */
				uip_neighbor_add( ICMPBUF->srcipaddr, &(ICMPBUF->options[2]) );
			}

			/* We should now send a neighbor advertisement back to where the
	 neighbor solicication came from. */
			ICMPBUF->type = ICMP6_NEIGHBOR_ADVERTISEMENT;
			ICMPBUF->flags = ICMP6_FLAG_S;	/* Solicited flag. */

			ICMPBUF->reserved1 = ICMPBUF->reserved2 = ICMPBUF->reserved3 = 0;

			uip_ipaddr_copy( ICMPBUF->destipaddr, ICMPBUF->srcipaddr );
			uip_ipaddr_copy( ICMPBUF->srcipaddr, uip_hostaddr );
			ICMPBUF->options[0] = ICMP6_OPTION_TARGET_LINK_ADDRESS;
			ICMPBUF->options[1] = 1;		/* Options length, 1 = 8 bytes. */
			memcpy( &(ICMPBUF->options[2]), &uip_ethaddr, sizeof(uip_ethaddr) );
			ICMPBUF->icmpchksum = 0;
			ICMPBUF->icmpchksum = ~uip_icmp6chksum();
			goto send;
		}

		goto drop;
	}
	else if( ICMPBUF->type == ICMP6_ECHO )
	{
		/* ICMP echo (i.e., ping) processing. This is simple, we only
       change the ICMP type from ECHO to ECHO_REPLY and update the
       ICMP checksum before we return the packet. */
		ICMPBUF->type = ICMP6_ECHO_REPLY;

		uip_ipaddr_copy( BUF->destipaddr, BUF->srcipaddr );
		uip_ipaddr_copy( BUF->srcipaddr, uip_hostaddr );
		ICMPBUF->icmpchksum = 0;
		ICMPBUF->icmpchksum = ~uip_icmp6chksum();

		UIP_STAT( ++uip_stat.icmp.sent );
		goto send;
	}
	else
	{
		DEBUG_PRINTF( "Unknown icmp6 message type %d\n", ICMPBUF->type );
		UIP_STAT( ++uip_stat.icmp.drop );
		UIP_STAT( ++uip_stat.icmp.typeerr );
		UIP_LOG( "icmp: unknown ICMP message." );
		goto drop;
	}

	/* End of IPv6 ICMP processing. */
	#endif /* !UIP_CONF_IPV6 */

	#if UIP_UDP

	/* UDP input processing. */
	udp_input :
	/* UDP processing is really just a hack. We don't do anything to the
     UDP/IP headers, but let the UDP application do all the hard
     work. If the application sets uip_slen, it has a packet to
     send. */
		#if UIP_UDP_CHECKSUMS
	uip_len = uip_len - UIP_IPUDPH_LEN;
	uip_appdata = &uip_buf[UIP_LLH_LEN + UIP_IPUDPH_LEN];
	if( UDPBUF->udpchksum != 0 && uip_udpchksum() != 0xffff )
	{
		UIP_STAT( ++uip_stat.udp.drop );
		UIP_STAT( ++uip_stat.udp.chkerr );
		UIP_LOG( "udp: bad checksum." );
		goto drop;
	}

		#else /* UIP_UDP_CHECKSUMS */
	uip_len = uip_len - UIP_IPUDPH_LEN;
		#endif /* UIP_UDP_CHECKSUMS */

	/* Demultiplex this UDP packet between the UDP "connections". */
	for( uip_udp_conn = &uip_udp_conns[0]; uip_udp_conn < &uip_udp_conns[UIP_UDP_CONNS]; ++uip_udp_conn )
	{
		/* If the local UDP port is non-zero, the connection is considered
       to be used. If so, the local port number is checked against the
       destination port number in the received packet. If the two port
       numbers match, the remote port number is checked if the
       connection is bound to a remote port. Finally, if the
       connection is bound to a remote IP address, the source IP
       address of the packet is checked. */
		if
		(
			uip_udp_conn->lport != 0 &&
			UDPBUF->destport == uip_udp_conn->lport &&
			(uip_udp_conn->rport == 0 || UDPBUF->srcport == uip_udp_conn->rport) &&
			(
				uip_ipaddr_cmp(uip_udp_conn->ripaddr, all_zeroes_addr) ||
				uip_ipaddr_cmp(uip_udp_conn->ripaddr, all_ones_addr) ||
				uip_ipaddr_cmp(BUF->srcipaddr, uip_udp_conn->ripaddr)
			)
		)
		{
			goto udp_found;
		}
	}

	UIP_LOG( "udp: no matching connection found" );
	goto drop;

udp_found:
	UIP_STAT( ++uip_stat.udp.recv );
	uip_conn = NULL;
	uip_flags = UIP_NEWDATA;
	uip_sappdata = uip_appdata = &uip_buf[UIP_LLH_LEN + UIP_IPUDPH_LEN];
	uip_slen = 0;
	UIP_UDP_APPCALL();
udp_send:
	if( uip_slen == 0 )
	{
		goto drop;
	}

	uip_len = uip_slen + UIP_IPUDPH_LEN;

		#if UIP_CONF_IPV6

	/* For IPv6, the IP length field does not include the IPv6 IP header
     length. */
	BUF->len[0] = ( (uip_len - UIP_IPH_LEN) >> 8 );
	BUF->len[1] = ( (uip_len - UIP_IPH_LEN) & 0xff );
		#else /* UIP_CONF_IPV6 */
	BUF->len[0] = ( uip_len >> 8 );
	BUF->len[1] = ( uip_len & 0xff );
		#endif /* UIP_CONF_IPV6 */

	BUF->ttl = uip_udp_conn->ttl;
	BUF->proto = UIP_PROTO_UDP;

	UDPBUF->udplen = HTONS( uip_slen + UIP_UDPH_LEN );
	UDPBUF->udpchksum = 0;

	BUF->srcport = uip_udp_conn->lport;
	BUF->destport = uip_udp_conn->rport;

	uip_ipaddr_copy( BUF->srcipaddr, uip_hostaddr );
	uip_ipaddr_copy( BUF->destipaddr, uip_udp_conn->ripaddr );

	uip_appdata = &uip_buf[UIP_LLH_LEN + UIP_IPTCPH_LEN];

		#if UIP_UDP_CHECKSUMS

	/* Calculate UDP checksum. */
	UDPBUF->udpchksum = ~( uip_udpchksum() );
	if( UDPBUF->udpchksum == 0 )
	{
		UDPBUF->udpchksum = 0xffff;
	}

		#endif /* UIP_UDP_CHECKSUMS */
	UIP_STAT( ++uip_stat.udp.sent );
	goto ip_send_nolen;
	#endif /* UIP_UDP */

	/* TCP input processing. */
	tcp_input : UIP_STAT( ++uip_stat.tcp.recv );

	/* Start of TCP input header processing code. */
	if( uip_tcpchksum() != 0xffff )
	{	/* Compute and check the TCP
				       checksum. */
		UIP_STAT( ++uip_stat.tcp.drop );
		UIP_STAT( ++uip_stat.tcp.chkerr );
		UIP_LOG( "tcp: bad checksum." );
		goto drop;
	}

	/* Demultiplex this segment. */

	/* First check any active connections. */
	for( uip_connr = &uip_conns[0]; uip_connr <= &uip_conns[UIP_CONNS - 1]; ++uip_connr )
	{
		if
		(
			uip_connr->tcpstateflags != UIP_CLOSED &&
			BUF->destport == uip_connr->lport &&
			BUF->srcport == uip_connr->rport &&
			uip_ipaddr_cmp(BUF->srcipaddr, uip_connr->ripaddr)
		)
		{
			goto found;
		}
	}

	/* If we didn't find and active connection that expected the packet,
     either this packet is an old duplicate, or this is a SYN packet
     destined for a connection in LISTEN. If the SYN flag isn't set,
     it is an old packet and we send a RST. */
	if( (BUF->flags & TCP_CTL) != TCP_SYN )
	{
		goto reset;
	}

	tmp16 = BUF->destport;

	/* Next, check listening connections. */
	for( c = 0; c < UIP_LISTENPORTS; ++c )
	{

⌨️ 快捷键说明

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