⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ip.c

📁 cf8020+cp2200(网络)的驱动实现
💻 C
字号:
//-----------------------------------------------------------------------------
// Copyright (c) 2002 Jim Brady
// Do not use commercially without author's permission
// Last revised August 2002
// Net IP.C
//
// This module is the IP layer
// Refer to RFC 791, 1122, and RFC 815 (fragmentation)
//-----------------------------------------------------------------------------
#include "stdlib.h"
#include "net.h"
#include "cksum.h"
#include "arp.h"
#include "icmp.h"
#include "udp.h"
#include "eth.h"
#include "tcp.h"
#include "ip.h"
#include "utils.h"

extern UCHAR  debug;
extern ulong  my_ipaddr;
extern UCHAR   broadcast_hwaddr[];
WAIT volatile 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  * outbuf, ulong ipaddr, UCHAR proto_id, uint len)
{
	//UCHAR testadd[6]={0x00,0x19,0x21,0x5b,0xd8,0x3f};
   IP_HEADER  * ip;
   UCHAR  * hwaddr;
   static uint ip_ident = 0;
   
   ip = (IP_HEADER  *)(outbuf + 14);
   ip->ver_len = 0x45;             //版本(=$4) + 首部长度(= $5 * 4 =20): IPv4 with 20 byte header
   ip->type_of_service = 0;        //服务类型: 
   ip->total_length = 20 + len;    //总长度: 20 + len 
   ip->identifier = ip_ident++;    //标识号: sequential identifier
   ip->fragment_info = 0;          //标志:  本案为不能分片; not fragmented
   ip->time_to_live = 128;          //生存时间: 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 通过ARP表取得目的主机的MAC地址;
   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
#ifdef __LITTLEENDIAN__
//	hwaddr  = testadd;
#endif
    //没找到此IP地址对应MAC地址, 把欲发送的缓冲区信息和地址和端口等放入wait结构里,等找到时再发送 
	
	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
		if(ip->dest_ipaddr == 0xffffffff)
		{
			hwaddr = broadcast_hwaddr;
		}
		else
		{
			wait.buf = outbuf;
			wait.ipaddr = ip->dest_ipaddr;
			wait.proto_id = proto_id;
			wait.len = len;
			wait.timer = ARP_TIMEOUT; 
        	return;
		}
	}	
	
#ifdef __LITTLEENDIAN__
	ip->dest_ipaddr = ntohl(ip->dest_ipaddr);
	ip->source_ipaddr = ntohl(ip->source_ipaddr);
	ip->total_length = ntohs(ip->total_length);
	ip->identifier = ntohs(ip->identifier);
	ip->header_cksum = 0; 
	ip->header_cksum = ~cksum(outbuf + 14, 20);
	ip->header_cksum = ntohs(ip->header_cksum);
#endif
	
	eth_send(outbuf, hwaddr, IP_PACKET, 20 + len);
}



//------------------------------------------------------------------------
// This handles incoming IP datagrams from the Ethernet layer
// See "TCP/IP Illustrated, Volume 1" Sect 3.2
//------------------------------------------------------------------------
void ip_rcve(UCHAR  * inbuf)
{
	IP_HEADER  * ip;
	uint  header_len, payload_len;
		
	ip = (IP_HEADER  *)(inbuf + 14);

   // Make sure it is addressed to my IP address
   //目的IP地址不匹配, 返回
#ifdef __LITTLEENDIAN__
	ip->total_length = ntohs(ip->total_length);
	ip->dest_ipaddr = ntohl(ip->dest_ipaddr);
#endif
	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; //计算静负荷长度
#ifdef __LITTLEENDIAN__
	ip->total_length = ntohs(ip->total_length);
	ip->dest_ipaddr = ntohl(ip->dest_ipaddr);
#endif
	
	if (cksum(inbuf + 14, header_len) != 0xFFFF)  //计算首部校验和, 不等于0xFFFF就丢弃;
	{
	  	//if (debug) serial_send("IP:  Error, cksum bad\r");
	   return; 
   }
#ifdef __LITTLEENDIAN__
	ip->total_length = ntohs(ip->total_length);
	ip->fragment_info = ntohs(ip->fragment_info);
	ip->dest_ipaddr = ntohl(ip->dest_ipaddr);
	ip->source_ipaddr = ntohl(ip->source_ipaddr);
	ip->header_cksum = ntohs(ip->header_cksum);
#endif
	// Make sure incoming message is IP version 4
   if ((ip->ver_len >> 4) != 0x04)              //不支持非版本4
   {
	   //if (debug) serial_send("IP:  Error, not IPv4\r");
	   return;
   }

	// Make sure incoming message is not fragmented because
   // we cannot handle fragmented messages
   // 不支持分片IP包;
   if ((ip->fragment_info & 0x3FFF) != 0)
   {
      //if (debug) serial_send("IP:  Error, fragmented msg rcvd\r");
	   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

    //如果首部长度 > 20, 即存在可变部分, 把净负荷数据移到从固定部分20字节开始.
   if (header_len > 20)
   {
	   //if (debug) serial_send("IP: Rcvd header > 20 bytes\r");
	   
	   // Use memmove because of overlap
//	   memmove(inbuf + 34, inbuf + 14 + header_len, payload_len);
  	   memcpy(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) 
//		  serial_send("IP:  ICMP pkt rcvd\n");
		  icmp_rcve(inbuf, payload_len);
		  break;
		  
      case IGMP_TYPE:
		  // We cannot handle IGMP messages
		  //if (debug)
		//  serial_send("IP:  Error, IGMP pkt rcvd\n");
		  break;
		  
	  case UDP_TYPE:
		  //if (debug) 
#ifdef __LITTLEENDIAN__
		  ip->total_length = ntohs(ip->total_length);
		  ip->fragment_info = ntohs(ip->fragment_info);
		  ip->dest_ipaddr = ntohl(ip->dest_ipaddr);
		  ip->source_ipaddr = ntohl(ip->source_ipaddr);
		  ip->header_cksum = ntohs(ip->header_cksum);
#endif

//		  serial_send("IP:  UDP pkt rcvd\n");
		  udp_rcve(inbuf, payload_len);
		  break;
		  
	  case TCP_TYPE:   
//		  if (debug) 
//		    serial_send("IP:  TCP pkt rcvd\n");
#ifdef __LITTLEENDIAN__
		  ip->total_length = ntohs(ip->total_length);
		  ip->fragment_info = ntohs(ip->fragment_info);
		  ip->dest_ipaddr = ntohl(ip->dest_ipaddr);
		  ip->source_ipaddr = ntohl(ip->source_ipaddr);
		  ip->header_cksum = ntohs(ip->header_cksum);
#endif
		  tcp_rcve(inbuf, payload_len);
		  break;
		  
      default:
	//	  if (debug) serial_send("IP:  Unknown IP proto id rcvd\r");
      break;
   }
}



⌨️ 快捷键说明

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