Chinaunix首页 | 论坛 | 博客
  • 博客访问: 393686
  • 博文数量: 105
  • 博客积分: 4100
  • 博客等级: 上校
  • 技术积分: 1040
  • 用 户 组: 普通用户
  • 注册时间: 2008-07-27 19:57
文章存档

2012年(1)

2011年(9)

2010年(4)

2009年(25)

2008年(66)

我的朋友

分类: 系统运维

2009-05-08 21:27:19

声明:由于CMX micronet的协议栈是需要付费的,此代码来源于网上,用来学习交流,用于其它的商业活动请联系
   最近在弄毕业设计,拿的是同事做好的一个51的串口转网口的板子,cpu c8051f340 ,比较高档的一个51单片机,silicon lab公司的,改进的cip-51内核,所有的外设配置都比较灵活,感觉不错。网卡也是 silicon labs cp2200,官方有两者应用的公板出售,并且提供协议栈,但是对协议栈封装成了库,看不到原代码,比较不爽,同事给我的代码用的不是库了,而是实实在在的代码,后来网上一查,这个协议栈是基于cmx micronet改过来的,此前对网络的这些底层实现基本为0,研究了几天,看明白了点点。
  目前的代友码主要实现了arp icmp ip tcp udp http,目前是一个webserver,通过html提交数据向串口发出数据。
 
主要的程序目录如下:
c8051f340.h------此单片机的一些sfr及地址的定义
cp220x.h---------cp220x的寄存器定义
cp220x.c---------将cp220x的寄存器映射到51的地址空间
net.h------------定义了一些各种协议的报文头格式及一些标志位,还有些预处理
arp.h------------arp协议的实现的所需函数的声明
arp.c------------arp协议实现所需函数的具体实现
icmp.h-----------icmp协议的实现的所需函数的声明
icmp.c-----------icmp协议实现所需函数的具体实现
tcp.h------------tcp协议的实现的所需函数的声明
tcp.c------------tcp协议实现所需函数的具体实现
udp.h------------udp协议的实现的所需函数的声明
udp.c------------udp协议实现所需函数的具体实现
http.h-----------http协议的实现的所需函数的声明
http.c-----------http协议实现所需函数的具体实现
cksum.h----------校验和所需函数的声明
cksum.c----------校验和所需函数的实现
先看net.h文件
 
 
注:我只是加了些中文注释
 

//-----------------------------------------------------------------------------

// NET.H

//一些网络相关的包,报文头,常量的数据结构

//-----------------------------------------------------------------------------



typedef unsigned char                 UCHAR;//1 byte

typedef unsigned int                 UINT;//2 bytes

typedef unsigned long                ULONG;//4 bytes

typedef unsigned long                LONG;
void eth_send(UCHAR xdata * outbuf, UCHAR * hwaddr, UINT ptype, UINT len);
// 常量定义

#define TRUE                     1
#define ON                            1
#define OK         1
#define FALSE                     0
#define OFF                            0
#define MATCH                        0
#define RET                             0x0D
#define LF                            0x0A
#define SPACE                         0x20

// 端口定义

#define ECHO_PORT                    7
#define DAYTIME_PORT                13
#define CHARGEN_PORT                19
#define TIME_PORT                    37
#define HTTP_PORT                     80


// 事件标志

#define EVENT_ETH_ARRIVED            0x0001 //有待处理的以太网帧事件

#define EVENT_AGE_ARP_CACHE            0x0002 //更新ARP缓存事件 60s更新一次

#define EVENT_TCP_RETRANSMIT        0x0004 //TCP重传事件

#define EVENT_TCP_INACTIVITY        0x0008 //关断不活动连接事件 (0.5s)

#define EVENT_ARP_RETRANSMIT        0x0010 //ARP请求数据包重传事件

#define EVENT_READ_ANALOG            0x0020
#define EVENT_RS232_ARRIVED            0x0040 //串口数据到达事件



// 以太网络帧的类型

#define IP_PACKET         0x0800
#define ARP_PACKET         0x0806
#define RARP_PACKET                    0x8035

// IP数据段中所采用的协议类型

#define ICMP_TYPE         1
#define IGMP_TYPE                    2
#define TCP_TYPE         6
#define UDP_TYPE         17

//ARP消息类型

#define ARP_REQUEST         1
#define ARP_RESPONSE         2
#define RARP_REQUEST         3
#define RARP_RESPONSE         4

// 在ARP报文中的硬件类型

#define DIX_ETHERNET         1
#define IEEE_ETHERNET         6


//ARP缓存

typedef struct
{
   ULONG ipaddr;
   UCHAR hwaddr[6];
   UCHAR timer;
} ARP_CACHE;

//ARP请求后的答复

typedef struct
{
    UCHAR xdata * buf;
    ULONG ipaddr;
    UCHAR proto_id;
    UINT len;
    UCHAR timer;
} WAIT;

//ARP报文头 28字节

typedef struct
{
   UINT hardware_type;//硬件类型2byte

   UINT protocol_type;//协议类型2byte

   UCHAR hwaddr_len;//MAC地址长度1byte

   UCHAR ipaddr_len;//IP地址长度1byte

   UINT message_type;//操作类型 arp应答、arp请求、rarp应答、rarp请求

   UCHAR source_hwaddr[6];//源MAC地址

   ULONG source_ipaddr;//源IP地址

   UCHAR dest_hwaddr[6];//目的MAC地址

   ULONG dest_ipaddr;//目的IP地址

} ARP_HEADER;

//以太网帧头部 14字节

typedef struct
{
  UCHAR dest_hwaddr[6]; //目的mac地址

  UCHAR source_hwaddr[6]; //源mac地址

  UINT frame_type; //协议类型

} ETH_HEADER;

//IP报文头 20字节

typedef struct
{
   UCHAR ver_len; //版本(4bit)与此报文头的长度(4bit)

   UCHAR type_of_service; //服务类型 8bit,用数值表示出报文的重要程度,此数大的报文优先

   UINT total_length; //总长度 16bit

   UINT identifier; //标识 16bit(假如多于一个报文,用来标识出报文位置)

   UINT fragment_info; //标志(3bit)片偏移(13bit)

   UCHAR time_to_live; //生存时间(8bit)

   UCHAR protocol_id; //处理此报文的上层协议(8bit)

   UINT header_cksum; //首部检验和(16bit)

   ULONG source_ipaddr; //源IP(32bit)

   ULONG dest_ipaddr; // 目的IP(32bit)

} IP_HEADER;

//ICMP PING回显请求报文结构

typedef struct
{
   UCHAR msg_type;//类型8bit

   UCHAR msg_code;//代码 8bit

   UINT checksum;//校验和16bit

   UINT identifier;//标识符16bit

   UINT sequence;//序号16bit

   UCHAR echo_data;//选项数据,必须回显

} PING_HEADER;

//ICMP差错报文结构(目的不可达报文)

typedef struct
{
   UCHAR msg_type; //类型8bit

   UCHAR msg_code; //代码 8bit

   UINT checksum; //校验和16bit

   ULONG msg_data; //消息数据32bit

   UCHAR echo_data; //回显数据8bit

} ICMP_ERR_HEADER;

//UDP数据包结构

typedef struct
{
   UINT source_port;
   UINT dest_port;
   UINT length;
   UINT checksum;
   UCHAR msg_data;
} UDP_HEADER;

//TCP报文头 21字节(不算选项的话21字节)

typedef struct
{
   UINT source_port;//源端口号 16bit

   UINT dest_port; //目的端口号 16bit

   ULONG sequence; //序号从TCP发端向TCP收端发送的数据字节流 32bit

   ULONG ack_number; //32bit 确认序号

   UINT flags; //首部长度及一些标志位

   UINT window; //窗口大小 16bit

   UINT checksum;//校验和 16bit

   UINT urgent_ptr;//紧急指针16bit

   UCHAR options;//选项

} TCP_HEADER;

//TCP连接的数据结构

typedef struct
{
  ULONG ipaddr;
  UINT port;
  ULONG his_sequence;
  ULONG my_sequence;
  ULONG old_sequence;
  ULONG his_ack;
  UCHAR timer;
  UCHAR inactivity;    
  UCHAR state;
  char query[20];
} CONNECTION;


 

 

再看一下arp协议所实现 的函数

 

 

 

//-----------------------------------------------------------------------------

//模块处理ARP消息和APR应求并且管理ARP缓存(ARP协议实现)

//-----------------------------------------------------------------------------

#include <string.h>
#include <stdio.h>
#include "C8051f340.h"
#include "net.h"
#include "ip.h"
#include "arp.h"



extern WAIT xdata wait;
extern UCHAR xdata my_hwaddr[];
extern UCHAR code broadcast_hwaddr[];
extern ULONG code my_ipaddr;
extern ULONG code my_subnet;
extern ULONG code gateway_ipaddr;
extern UCHAR idata debug;
ARP_CACHE xdata arp_cache[CACHESIZE];// 定义arp缓存为10个ARP_CACHE单位

UCHAR waiting_for_arp;

extern char xdata outbuf1[];

void init_arp(void)
{
      memset(arp_cache, 0, sizeof(arp_cache)); //初始化arp缓存全部为0

    memset(&wait, 0, sizeof(wait)); //初台化wait空间

    waiting_for_arp = FALSE; //无arp请求

}




//------------------------------------------------------------------------

//    This is called every 60 seconds to age the ARP cache

// If an entry times out then it is deleted from the cache

// See "TCP/IP Illustrated, Volume 1" Sect 4.3

// 函数作用:更新ARP缓存

//------------------------------------------------------------------------

void age_arp_cache(void)
{
     UCHAR i;
        
   for (i=0; i < CACHESIZE; i++)//查询arp缓存表
   {
      if ((arp_cache[i].ipaddr != 0) && (arp_cache[i].timer))
      {
         arp_cache[i].timer--;
            if (arp_cache[i].timer == 0)
         {
                // Timed out so clear out cache entry

                // Do not need to zero hwaddr
//时间到则进行清零
                arp_cache[i].ipaddr = 0;
         }
     }
   }
}




//------------------------------------------------------------------------

// This allocates memory for the entire outgoing message,

// including eth and ip headers, then builds an outgoing

// ARP response message

// See "TCP/IP Illustrated, Volume 1" Sect 4.4

// ARP请求广播

//------------------------------------------------------------------------

void arp_send(UCHAR * hwaddr, ULONG ipaddr, UCHAR msg_type)
{
    UCHAR xdata * outbuf;
    ARP_HEADER xdata * arp;
         
   
   // Allocate memory for entire outgoing message including

   // eth header. Always 42 bytes

   // outbuf = (UCHAR xdata *)malloc(42);

    outbuf = outbuf1;
     
   // Allow 14 bytes for the ethernet header//前14个字节为以太网帧头部

    arp = (ARP_HEADER xdata *)(outbuf + 14);
     
    arp->hardware_type = DIX_ETHERNET;
    arp->protocol_type = IP_PACKET;
    arp->hwaddr_len = 6;
    arp->ipaddr_len = 4;
    arp->message_type = (UINT)msg_type;
   
   // My hardware address and IP addresses

    memcpy(arp->source_hwaddr, my_hwaddr, 6);
    arp->source_ipaddr = my_ipaddr;
 
   // Destination hwaddr and dest IP addr

   if (msg_type == ARP_REQUEST) memset(arp->dest_hwaddr, 0, 6);
   else memcpy(arp->dest_hwaddr, hwaddr, 6);
   
   arp->dest_ipaddr = ipaddr;
      
   // If request then the message is a brodcast, if a response then

   // send to specified hwaddr

   // ARP payload size is always 28 bytes

    if (msg_type == ARP_REQUEST) eth_send(outbuf, broadcast_hwaddr, ARP_PACKET, 28);
   else eth_send(outbuf, hwaddr, ARP_PACKET, 28);
}



//------------------------------------------------------------------------

// This re-sends an ARP request if there was no response to

// the first one.     It is called every 0.5 seconds. If there

// is no response after 2 re-tries, the datagram that IP was

// trying to send is deleted

//ARP重新发送

//-----------------------------------------------------------------------

void arp_retransmit(void)
{
    static UCHAR idata retries = 0;
    
    if ((waiting_for_arp) && (wait.timer))
    {
        wait.timer--;
        if (wait.timer == 0)
        {
            retries++;
            if (retries <= 2)
            {
                 arp_send(NULL, wait.ipaddr, ARP_REQUEST);
                wait.timer = ARP_TIMEOUT;
            }
            else
            {    
                 wait.timer = 0;
                waiting_for_arp = 0;
//                free(wait.buf);

            }
        }
    }
}




//------------------------------------------------------------------------

// Find the ethernet hardware address for the given ip address

// If destination IP is on my subnet then we want the eth

// address    of destination, otherwise we want eth addr of gateway.

// Look in ARP cache first. If not found there, send ARP request.

// Return pointer to the hardware address or NULL if not found

// See "TCP/IP Illustrated, Volume 1" Sect 4.5

//ARP将IP地址解析为硬件地址的过程,返回mac 地址存储的首地址

//------------------------------------------------------------------------

UCHAR xdata * arp_resolve(ULONG dest_ipaddr)
{
   UCHAR i;
      
   // If destination IP is not on my subnet then we really want eth addr

    // of gateway, not destination IP

    if ((dest_ipaddr ^ my_ipaddr) & my_subnet)
    {
        if (gateway_ipaddr == 0)
        {
            return (NULL);    
         }
         else dest_ipaddr = gateway_ipaddr;
    }
    
    
   // See if IP addr of interest is in ARP cache

   for (i=0; i < CACHESIZE; i++)
   {
      if (arp_cache[i].ipaddr == dest_ipaddr)
         return (&arp_cache[i].hwaddr[0]);
   }

    // Not in cache so broadcast ARP request

      arp_send(NULL, dest_ipaddr, ARP_REQUEST);
         
   // Set a flag to indicate that an IP datagram is waiting

   // to be sent

   waiting_for_arp = TRUE;
                
   // Null means that we have sent an ARP request

   return (NULL);
}





//------------------------------------------------------------------------

// This handles incoming ARP messages

// See "TCP/IP Illustrated, Volume 1" Sect 4.4

// Todo: Resolve problem of trying to add to a full cache

// 接收ARP回复

//------------------------------------------------------------------------

void arp_rcve(UCHAR xdata * inbuf)
{
   UCHAR idata i, cached, oldest;
   UINT idata minimum;
   ARP_HEADER xdata * arp;
      
   arp = (ARP_HEADER xdata *)(inbuf + 14); //去除以太网帧的头信息

   cached = FALSE;
   
   // Print message

         
   // Validate incoming frame //表明是无效的帧

   if ((arp->hardware_type != DIX_ETHERNET) ||
       (arp->protocol_type != IP_PACKET)) return;

   // Search ARP cache for senders IP address

   // If found, update entry and restart timer

   for (i=0; i < CACHESIZE; i++)
   {
      if (arp_cache[i].ipaddr == arp->source_ipaddr)
      {
         memcpy(&arp_cache[i].hwaddr[0], &arp->source_hwaddr[0], 6);
         arp_cache[i].timer = CACHETIME;        
         cached = TRUE;
                  
         break;
      }
   }
   
   if (arp->dest_ipaddr != my_ipaddr) return;
   
   // At this point we know the the frame is addressed to me

   // If not already in cache then add entry and start timer

   if (cached == FALSE)
   {
      // Find first blank space and add entry

        // Blank entries are indicated by ip addr = 0

      for (i=0; i < CACHESIZE; i++)
      {
         if (arp_cache[i].ipaddr == 0)
         {
            arp_cache[i].ipaddr = arp->source_ipaddr;
            memcpy(&arp_cache[i].hwaddr[0], &arp->source_hwaddr[0], 6);
            arp_cache[i].timer = CACHETIME;
             break;
         }
      }

        // If no blank entries in arp cache    then sort cache

        // to find oldest entry and replace it

        if (i == CACHESIZE)
        {
            // Oldest entry is the one with lowest timer value            

            minimum = 0xFFFF;
            for (i=0; i < CACHESIZE; i++)
          {
                if (arp_cache[i].timer < minimum)
                {
                    minimum = arp_cache[i].timer;
                    oldest = i;
                }
            }
          
            // "oldest" is now index of oldest entry, so replace it

            arp_cache[oldest].ipaddr = arp->source_ipaddr;
         memcpy(&arp_cache[oldest].hwaddr[0], &arp->source_hwaddr[0], 6);
         arp_cache[oldest].timer = CACHETIME;
       }
    }

   
   // If we are waiting for an arp response and the arp response

      // that just came in is addressed to me and is from the host

      // we are waiting for, then send    the message-in-waiting

   if (arp->message_type == ARP_RESPONSE)
   {
       if ((waiting_for_arp) && (wait.ipaddr == arp->source_ipaddr))
       {
           waiting_for_arp = FALSE;
             ip_send(wait.buf, wait.ipaddr, wait.proto_id, wait.len);
        }
    }
    else if (arp->message_type == ARP_REQUEST)
   {
        // Send ARP response

        arp_send(arp->source_hwaddr, arp->source_ipaddr, ARP_RESPONSE);
    }
}


 

 

//-----------------------------------------------------------------------------

// ARP.H

//每条ARP缓存记录的生命周期为20分钟,2分钟内未用则删除。

//缓存容量满时,删除最老的记录

//-----------------------------------------------------------------------------



// Allow up to 10 entries in ARP cache

#define CACHESIZE        10 //ARP缓存大小


// ARP cache entry expiration time = 20 minutes

#define CACHETIME        20        // 60 second intervals


// Allow 2 seconds to receive an ARP reply

#define ARP_TIMEOUT         4     // 0.5 second intervals


void init_arp(void);
UCHAR xdata * arp_resolve(ULONG);
void arp_rcve(UCHAR xdata *);
void age_arp_cache(void);
void arp_retransmit(void);

 

程序注释得比较清晰了,具体过程需要参考tcp/ip 详解

 

再就是ip协议了,这个虽然经过精简后只有两个函数,看起来还是很抽像的

 

//-----------------------------------------------------------------------------

// 实现IP协议

// 参考 RFC 791, 1122, RFC 815

//-----------------------------------------------------------------------------

#include <string.h>
#include "C8051f340.h"
#include "net.h"
#include "cksum.h"
#include "arp.h"
#include "icmp.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

// 处理向外发送的IP报文

//------------------------------------------------------------------------

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); //14byte是以太网帧的报文头

   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);
}



//------------------------------------------------------------------------

// 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)
    {
     return;
    }
    
    // Make sure incoming message is IP version 4

    if ((ip->ver_len >> 4) != 0x04)
    {
       return;
    }

    // Make sure incoming message is not fragmented because

   // we cannot handle fragmented messages

   //确保收进来的IP报文头是没有分段的,分段报文无法处理

   if ((ip->fragment_info & 0x3FFF) != 0)
   {
     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的话,则需进行处理

    if (header_len > 20)
    {
               
      // 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:
      icmp_rcve(inbuf, payload_len);
        break;

      case IGMP_TYPE:
     ;
        // We cannot handle IGMP messages

        break;
        
     case UDP_TYPE:
      ;
   
        break;

     case TCP_TYPE:
      tcp_rcve(inbuf, payload_len);
        break;

      default:
      ;
        break;
   }
}



 

这个我也只是大致看明白了,其中有几个函数调用是网卡的驱动函数,应该能看出来。

再就是icmp协议了,这个同样对其精简了许多了,只处理了二种报文,这个代码我注释得比较详细,

 

 

//-----------------------------------------------------------------------------

// 处理ICMP消息(ICMP协议的实现)

// 具体细节参考 RFC 792, 896, 950, 1122, 1191

//-----------------------------------------------------------------------------

#include <string.h>
#include "C8051f340.h"
#include "net.h"
#include "cksum.h"
#include "ip.h"
#include "icmp.h"

extern UCHAR idata debug;
extern char xdata outbuf1[];

//------------------------------------------------------------------------

// 建立一个ping回显应答消息,为发整个需发送的信息分配内存,包括以太帧头与IP头

// 见TCP/IP详解 卷1 7.2

//------------------------------------------------------------------------

void ping_send(UCHAR xdata * inbuf, ULONG ipaddr, UINT len)
{
   PING_HEADER xdata * ping_in;
   PING_HEADER xdata * ping_out;
   UCHAR xdata * outbuf;

   //为接受到的ping回复加上以太网帧头(14byte)与IP头(20byte)

   ping_in = (PING_HEADER xdata *)(inbuf + 34);
   outbuf = outbuf1;

   // 为应答ping的消息加上以太网帧头(14byte)与IP头(20byte)

   ping_out = (PING_HEADER xdata *)(outbuf + 34);
   ping_out->msg_type = 0;
   ping_out->msg_code = 0;
   ping_out->checksum = 0;
   ping_out->identifier = ping_in->identifier;//标识原值信息返回

   ping_out->sequence = ping_in->sequence;//序号信息原值返回


    //回显数据原样返回

   memcpy(&ping_out->echo_data, &ping_in->echo_data, len - 8);
          
    //校验ICMP的报文头及插入的额外的数据

   ping_out->checksum = ~cksum(outbuf + 34, len);

    //通过IP数据报发磅

   ip_send(outbuf, ipaddr, ICMP_TYPE, len);
}



//------------------------------------------------------------------------

//目的不可达报文 类型3 代码3 表示目的不可达报文是由端口不可达

//处理方法是返回我们收到的原始的IP数据报文头,20byte以后的数据全部不收

//详见TCP/IP详解 卷1 6.5

//------------------------------------------------------------------------

void dest_unreach_send(UCHAR xdata * inbuf, ULONG ipaddr)
{
   UCHAR xdata * outbuf;
   ICMP_ERR_HEADER xdata * icmp;
   outbuf = outbuf1;
   icmp = (ICMP_ERR_HEADER xdata *)(outbuf + 34);
   
   // 填充ICMP出错报文的头

   icmp->msg_type = 3; // 目的不可达

   icmp->msg_code = 3; // 端口不可达

   icmp->checksum = 0;
      
   // 填充ICMP错误信息数据

   icmp->msg_data = 0;
           
   // 拷贝20字节的原始IP地址头

   // 及ICMP_ERR_HEADER的前8字节,

   //echo_data数据的地址用来存放前边提到的28字节

   memcpy(&icmp->echo_data, inbuf + 14, 28);
                               
    //校验36字节,ICMP_ERR_HEADER头的前8字节

    //及echo_data数据的地址用来存放前边提到的28字节

   icmp->checksum = ~cksum(outbuf + 34, 36);
      
   // 通过IP数据报发送

   ip_send(outbuf, ipaddr, ICMP_TYPE, 36);
}




//------------------------------------------------------------------------

// 处理收到ICMP请求

// 详见TCP/IP详解 卷1 6.2

//------------------------------------------------------------------------

void icmp_rcve(UCHAR xdata * inbuf, UINT len)
{
   IP_HEADER * ip;
   UCHAR idata msg_type;
   UINT idata temp;
   
   // 前边是以太网帧头的14个字节

   ip = (IP_HEADER *)(inbuf + 14);
        
   // IP 头在前边已将地址确定

   // 对有效的ICMP消息数据进行校验

    temp = cksum(inbuf + 34, len);
    
    if (temp != 0xFFFF)
    {
      return;
    }
      
   // 通过ICMP消息类型做出相应的处理

   msg_type = *(inbuf + 34);
   switch(msg_type)
   {
      case 3:
     ;
      break;

     case 8://请求回显(ping请求)//则用ping发送回显

      ping_send(inbuf, ip->source_ipaddr, len);
      break;

      default:
     ;
      break;
   }
}


 

还有过TCP协议的实现还没有彻底研究明白,研究后与http协议一起贴出来.

阅读(2483) | 评论(2) | 转发(1) |
给主人留下些什么吧!~~

inurl2013-02-22 12:25:06

呵呵 ,这个协议栈比较冷门啊, 楼主还在研究 ?

chinaunix网友2010-01-26 11:34:09

可以,等你后面的研究。