showgu 发表于 2012-2-16 19:11:30

最近研究以太网,注释一下我对 EncEthernet 的理解

EncEthernet 应该是最简单的以太网协议,我这里学习了一下,注释了一些,现在分享,看看是否对大家的理解有帮助
// TCP 协议中几个关系:
// ARP,即地址解析协议,实现通过IP地址得知其物理地址。
// 反向地址转换协议(RARP:Reverse Address Resolution Protocol) 反向地址转换协议(RARP)
//                  允许局域网的物理机器从网关服务器的 ARP 表或者缓存上请求其 IP 地址。


static uchar wwwport=80;
static uchar macaddr;
static uchar ipaddr;
static uint info_hdr_len=0;
static uint info_data_len=0;
static uchar seqnum=0xa; // my initial tcp sequence number
// IP 和校验只有在刚开始的时候在IP头部进行,同时IP的长度是
// 在开始计算之前,一定要设置IP和校验区域为 0 IP 的长度是 20.
// For UDP/TCP we do not make up the required pseudo header. Instead we
// 我们采用的是 ip.src 和 ip.dst 区域代替实际的数据包
// UDP的和校验程序从 ip.src 区域开始
// Ip.src=4bytes,Ip.dst=4 bytes,Udp header=8bytes + data length=16+len
// 换句话说,这里讨论的数据长度相对于你真正要校验的长度是8 + length
// 在计算前,你必须先将校验的区域清 0
// udp 的长度是: 8 + 8 + data length
// tcp 的长度是: 4+4 + 20 + option len + data length
//
// 更多的资料,可以从以下网址获取:
// http://www.netfor2.com/checksum.html
// http://www.msc.uky.edu/ken/cs471/notes/chap3.htm
// The RFC has also a C code example: http://www.faqs.org/rfcs/rfc1071.html
// IP、ICMP、UDP和TCP报文头部都有校验和字段,大小都是16bit,算法也基本一样:
/* 在发送数据时,为了计算数据包的校验和。应该按如下步骤:

  (1)把校验和字段置为0;
  (2)把需校验的数据看成以16位为单位的数字组成,依次进行二进制反码求和;
  (3)把得到的结果存入校验和字段中。

  在接收数据时,计算数据包的校验和相对简单,按如下步骤:
  (1)把首部看成以16位为单位的数字组成,依次进行二进制反码求和,包括校验和字段;
  (2)检查计算出的校验和的结果是否为0;
  (3)如果等于0,说明被整除,校验是和正确。否则,校验和就是错误的,协议栈要抛弃这个数据包。
虽然上面四种报文的校验和算法一样,但在作用范围存在不同:
IP校验和只校验20字节的IP报头;
而ICMP校验和覆盖整个报文(ICMP报头+ICMP数据);
UDP和TCP校验和不仅覆盖整个报文,而且还有12字节的IP伪首部,
IP伪首部: 包括源IP地址(4字节)、目的IP地址(4字节)、协议(2字节,第一字节补0)和TCP/UDP包长(2字节)。
另外UDP、TCP数据报的长度可以为奇数字节,所以在计算校验和时需要在最后增加填充字节0
(注意,填充字节只是为了计算校验和,可以不被传送)。
*/
uint checksum(uchar *buf, uint len,uchar type)//参数type是数据的类型,分为IP,UDP,TCP;1=udp;2=tcp
{
        ulong sum = 0;//cksum必须是32bit的unsigned long型,高16bit用于保存累加过程中的进位;
        uint *ibuf=(uint*)(buf);

        //if(type==0){
        //      // do not add anything
        //}
        if (type==1)//UDP协议的校验
        {
                sum+=IP_PROTO_UDP_V; // udp协议,这里IP_PROTO_UDP_V=17
                // the length here is the length of udp (data+header len)
                // =length given to this function - (IP.scr+IP.dst length)
                sum+=len-8; // = real tcp len
        }
        if (type==2)//TCP协议的校验
        {
                sum+=IP_PROTO_TCP_V; //IP_PROTO_TCP_V宏定义中定义为6
                // the length here is the length of tcp (data+header len)
                // =length given to this function - (IP.scr+IP.dst length)
                sum+=len-8; // = real tcp len
        }
        // 对数据按16bit累加求和 build the sum of 16bit words
        while (len >1)
        {
                sum += *ibuf;
                ibuf++;
                len-=2;
        }
        // if there is a byte left then add it (padded with zero)
        if (len){
                sum += (*ibuf) & 0xff00;
        }
        // 保证相加后cksum的高16位为0,
        sum = (sum >> 16) + (sum & 0xffff);
        sum += (sum >>16);
        return (uint)(~sum);
}

// 在使用其他函数之前,必须先调用本段函数:这是一个初始化的过程
// 本函数用于初始化 IP地址、MAC地址、以及端口
void init_ip_arp_udp_tcp(uchar *mymac,uchar *myip,uchar wwwp)
{
        uchar i=0;
        wwwport=wwwp;
        while (i<4){
                ipaddr=myip;
                i++;
        }
        i=0;
        while (i<6){
                macaddr=mymac;
                i++;
        }
}

// ARP,即地址解析协议,实现通过IP地址得知其物理地址。
// 这段代码就是ARP的实现
uchar eth_type_is_arp_and_my_ip(uchar *buf,uint len)
{
        uchar i=0;
        //
        if (len<41)            //如果长度不足 41 ,则返回,arp协议的长度是42字节
        {
                return(0);
        }
        if (buf != ETHTYPE_ARP_H_V ||buf != ETHTYPE_ARP_L_V)
        {
                return(0);//如果输入的buf,12和13,上层协议0806代表ARP协议,这段是帧类型,这个arp的协议
        }
        while (i<4)
        {
                if (buf != ipaddr)//从数据包的第0x26开始 =2*16+6=32
                {
                        return(0);
                }
                i++;
        }
        return(1);
}
// 判断是不是一个IP包
uchar eth_type_is_ip_and_my_ip(uchar *buf,uint len)
{
        uchar i=0;
        //eth+ip+udp header is 42
        //
        if (len<42){
                return(0);//按照定义IP数据包应该大于46,这个大于42? 20字节的包头
        }
        if (buf!=ETHTYPE_IP_H_V || buf!=ETHTYPE_IP_L_V)
        {
                return(0);//如果输入的buf,12和13,上层协议0800代表ARP协议
        }
        if (buf!=0x45)
        {
                // must be IP V4 and 20 byte header
                return(0);
        }
        while (i<4)
                {
                if (buf!=ipaddr){
                        return(0);
                }
                i++;
        }
        return(1);
}
// make a return eth header from a received eth packet
// 生成一个 eth的头部
// 这个过程很简单 先加上目的MAC地址,在加上本机MAC地址
// 目的在前,本机在后
void make_eth(uchar *buf)
{
        uchar i=0;
        //
        //copy the destination mac from the source and fill my mac into src
        while (i<6)
        {
                buf=buf;
                buf=macaddr;
                i++;
        }
}

void fill_ip_hdr_checksum(uchar *buf)
{
        uint ck;
        // 先将两字节的和校验的值清空,以备后面计算                                                          
        buf=0;        // buf=0
        buf=0;        // buf=0

        buf=0x40;   // don't fragment BUF=0X40
        buf=0;    // fragement offset       分段偏移(fragment offset):说明分段在当前数据报的什么位置
        buf=64;       // ttl          8位生存时间 TTL=0X40
       
        // 计算校验和的过程:                  
        ck=checksum(&buf, IP_HEADER_LEN,0);

        buf=ck>>8;                   //        高位
        buf=ck& 0xff;           //        低位
}

// 生成一个IP头
// IP的头部是20个字节 先本机IP"1A" 再目的IP "1E"
void make_ip(uchar *buf)
{
        uchar i=0;
        while (i<4){
                buf=buf;
                buf=ipaddr;
                i++;
        }
        fill_ip_hdr_checksum(buf);
}
更多部分,请参考详细的源文件ourdev_719429PH5BSL.rar(文件大小:7K) (原文件名:Net.rar)

get500wan 发表于 2012-2-16 22:28:10

mark

tyqhaha 发表于 2012-2-16 22:51:25

mark

winterv 发表于 2012-2-16 23:09:34

mark

yan.ch.ao 发表于 2012-2-18 20:25:55

mark

qianzeqi 发表于 2012-10-31 19:04:43

感谢lz{:lol:}

chenmojiazi123 发表于 2013-3-25 21:42:32

{:smile:}好贴

qqq_147258 发表于 2015-12-10 11:19:01

你好,这个我在其他地方见过不知道这个源地址是哪里?

308594151 发表于 2015-12-10 16:17:52

mark一下
页: [1]
查看完整版本: 最近研究以太网,注释一下我对 EncEthernet 的理解