www.pudn.com > tcpip5151.rar > Ip.c


//----------------------------------------------------------------------------- 
// Net IP.C 
// This module is the IP layer 
// Refer to RFC 791, 1122, and RFC 815 (fragmentation) 
//----------------------------------------------------------------------------- 
#include  
#include  
#include  
#include "net.h" 
#include "cksum.h" 
#include "arp.h" 
#include "eth.h" 
#include "icmp.h" 
#include "udp.h" 
#include "serial.h" 
#include "tcp.h" 
#include "ip.h" 
 
extern UCHAR idata debug; 
extern ULONG code my_ipaddr; 
WAIT xdata wait; 
 
 
//------------------------------------------------------------------------ 
// This handles outgoing IP datagrams.  It adds the 20 byte IP header 
// and checksum then forwards the IP datagram to the Ethernet layer 
// for sending. See "TCP/IP Illustrated, Volume 1" Sect 3.2 
//------------------------------------------------------------------------ 
void ip_send(UCHAR xdata * outbuf, ULONG ipaddr, UCHAR proto_id, UINT len) 
{ 
   IP_HEADER xdata * ip; 
   UCHAR xdata * hwaddr; 
   static UINT ip_ident = 0; 
    
   ip = (IP_HEADER xdata *)(outbuf + 14); 
   ip->ver_len = 0x45;          // IPv4 with 20 byte header 
   ip->type_of_service = 0; 
   ip->total_length = 20 + len; 
   ip->identifier = ip_ident++;     // sequential identifier 
   ip->fragment_info = 0;           // not fragmented 
   ip->time_to_live = 32;           // max hops 
   ip->protocol_id = proto_id;      // type of payload 
   ip->header_cksum = 0; 
   ip->source_ipaddr = my_ipaddr; 
    
   // Outgoing IP address 
   ip->dest_ipaddr = ipaddr; 
 
   // Compute and insert complement of checksum of ip header 
   // Outgoing ip header length is always 20 bytes 
   ip->header_cksum = ~cksum(outbuf + 14, 20); 
    
   // Use ARP to get hardware address to send this to 
   hwaddr = arp_resolve(ip->dest_ipaddr); 
	 
	// Null means that the ARP resolver did not find the IP address 
	// in its cache so had to send an ARP request 
	if (hwaddr == NULL) 
	{ 
		// Fill in the destination information so ehrn the ARP response 
		// arrives we can identify it and know what to do when we get it 
      wait.buf = outbuf; 
		wait.ipaddr = ip->dest_ipaddr; 
		wait.proto_id = proto_id; 
		wait.len = len; 
		wait.timer = ARP_TIMEOUT;  
      return; 
	}	 
	 
	eth_send(outbuf, hwaddr, IP_PACKET, 20 + len); 
		printf("IP:send  IP packet.\n"); 
} 
 
 
 
//------------------------------------------------------------------------ 
// This handles incoming IP datagrams from the Ethernet layer 
// See "TCP/IP Illustrated, Volume 1" Sect 3.2 
//------------------------------------------------------------------------ 
void ip_rcve(UCHAR xdata * inbuf) 
{ 
	IP_HEADER xdata * ip; 
	UINT idata header_len, payload_len; 
		 
   ip = (IP_HEADER xdata *)(inbuf + 14); 
             
   // Make sure it is addressed to my IP address 
   if (ip->dest_ipaddr != my_ipaddr) return; 
 
   // Validate checksum of ip header 
	header_len = 4 * (0x0F & ip->ver_len); 
	payload_len = ip->total_length - header_len; 
   if (cksum(inbuf + 14, header_len) != 0xFFFF) 
	{ 
	  	if (debug) printf("IP:  Error, cksum bad\n"); 
	   return;  
   } 
	 
	// Make sure incoming message is IP version 4 
	if ((ip->ver_len >> 4) != 0x04) 
	{ 
		if (debug) printf("IP:  Error, not IPv4\n"); 
   	return; 
	} 
 
	// Make sure incoming message is not fragmented because 
   // we cannot handle fragmented messages 
   if ((ip->fragment_info & 0x3FFF) != 0) 
   { 
      if (debug) printf("IP:  Error, fragmented msg rcvd\n"); 
	   return;  
   } 
 
   // At this point we have received a valid IP datagram addressed 
   // to me.  We do not use header options, and do not forward 
   // messages, so in the unlikely event there are header options, 
   // delete them and shift the data down. The advantage is that 
   // layers such as UDP and TCP know where their data starts 
	if (header_len > 20) 
	{ 
		if (debug) printf("IP: Rcvd header > 20 bytes\n"); 
   			 
      // Use memmove because of overlap 
      memmove(inbuf + 34, inbuf + 14 + header_len, payload_len); 
 
		// Adjust info to reflect the move 
		header_len = 20; 
		ip->ver_len = 0x45; 
		ip->total_length = 20 + payload_len; 
	} 
	 
	 
	// Look at protocol ID byte and call the appropriate 
   // function to handle the received message.  See  
   // "TCP/IP Illustrated, Volume 1" Sect 1.7 and RFC 791 
   // for values for various protocols 
   switch (ip->protocol_id) 
	{ 
	   case ICMP_TYPE: 
      if (debug) printf("IP:  ICMP pkt rcvd\n"); 
      icmp_rcve(inbuf, payload_len); 
		break; 
 
      case IGMP_TYPE: 
		// We cannot handle IGMP messages 
		if (debug) printf("IP:  Error, IGMP pkt rcvd\n"); 
		break; 
		   
		case UDP_TYPE: 
		if (debug) printf("IP:  UDP pkt rcvd\n"); 
      udp_rcve(inbuf, payload_len); 
		break; 
 
		case TCP_TYPE:    
		if (debug) printf("IP:  TCP pkt rcvd\n"); 
      tcp_rcve(inbuf, payload_len); 
		break; 
 
      default: 
      if (debug) printf("IP:  Unknown IP proto id rcvd\n"); 
      break; 
   } 
}