免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1742 | 回复: 0
打印 上一主题 下一主题

sk_buff的结构和操作: [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2009-06-18 15:20 |只看该作者 |倒序浏览
struct sk_buff {
unsigned char pad[2];
unsigned char buf[ETH_FRAME_LEN];//buffer,这里是帧存储的位置
unsigned int truesize;    /* Buffer size       */

unsigned char *data;    /* Data head pointer     */这个指针总是指向当前层协议头在buf中的位置或者当前层协议数据部分在buf中的位置。
unsigned int len;    /* Length of actual data    */指示从*data位置到帧尾的length
};

buf[ETH_FRAME_LEN] 就是一帧实体,也是一帧协议栈的栈的实体。*data 是栈的指针,len则相当栈的底部,但是它是变化的,意义是*data到*data+len部分是当前协议层的内容(接收),或者这部分是已经填好的上层协议内容(发送)。 对应的操作有skb_push,skb_pull。
skb_push 用于从上层协议向下封装数据包,相当于压栈。char *skb_pull(struct sk_buff *skb, unsigned int ln) 就是要向栈中写入len字节前,先把栈指针*data-=ln, 而栈长len+=ln,返回当前*data指针,数据或者协议头(长度一定是ln)就可以往*data处填充了。很明显这是个向下生长的满栈 (FD) 。
skb_pull 用于从帧开始向上逐次解析协议。相当于弹栈的过程, char *skb_pull(struct sk_buff *skb, unsigned int ln)就是从栈中弹出ln个字节,*data+=ln, 栈长len-=ln,返回当前*data。弹出的ln字节就是下层协议已经处理过的协议头,返回值指向本层协议头,用它就可以开始解析本层协议了。

2、接收包的流程
1) 申请一个缓冲区sk_buf *skb, 以skb为参数调用以太网层的接收数据帧函数eth_rcv(skb)。eth_rcv(skb)调用board_eth_rcv(skb->data, &skb->len); board_eth_rcv调用CS8900 查询函数CS8900DBG_IsReceivedPacket()检查当前是否收到数据帧,如果收到调用RcvPkt((BYTE *)data, 1532);接收帧。 这样一帧数据就缓存到skb->buff中了。此时栈指针*data=buff,len=帧长。

2)处理以太网帧头,弹栈skb_pull(skb, ETH_HLEN)。以太网的帧头protocol解析上层协议是IP还是ARP,分别调用ip_rcv_packet(skb);(见4)或者arp_rcv_packet(skb);(见3)

3)如果是ARP报文,arp_rcv_packet(skb)处理ARP协议。判断ARP头的目标IP是否为本地IP,不是丢弃。是则判断ARP操作码是否为ARP请求,是发送ARP reply。缓存对方MAC IP 至ARP cache.当前帧的处理结束。

4)如果IP报文 ,ip_rcv_packet(skb); 处理IP层协议头,检查目的IP是否是本地IP,不是直接丢弃,是则根据IP头的上层协议是UDP还是ICMP,分别调用udp_rcv_packet(skb);或者icmp_rcv_packet(skb);

5)如果是ICMP数据包,icmp_rcv_packet(skb); 处理ICMP报文,如果ICMP头的类型是8,即请求回显,则发送一个回显ICMP报文。当前帧的处理结束。

6)如果是UDP数据包,udp_rcv_packet(skb)处理UDP协议头,检查目的端口是否为TFTP端口。由于程序只有TFTP作为UDP的上层协议。 如果是则弹栈后调用tftp_rcv_packet(skb);

7)如果是ftfp包,tftp_rcv_packet(skb);处理TFTP协议,限于功能,只处理WRQ和DATA两种请求,如果是WRQ请求,保存源IP和端口,发送一个ftfp应答block=0,开始block++计数并进入下载状态。
如果是DATA包,判断源IP和端口与上面保存的是否一致,当前tftp包的block号与block计数是否相等。相等则拷贝数据, 发送应答,block++,判断数据长是否小于512,是则表明block接收结束。当前tftp包的block号

3、发送包过程
1)sk_buff结构的另外两个操作,skb_put操作和skb_reserve(预留)操作:申请一个缓冲示进行任何操作的时候,*data=buff, len=0. 每层协议都有一个相对于下层协议头的偏移,这个偏移是一定的。skb_reserve(skb,len)操作是把skb->data+=len。每层协议都实现对应的reserve操作,它调用下层reserve,再把自己协议头的长度len添加到预留空间skb_reserve(skb,len)。
skb_put(skb,len)操作则是实现内容填充之后,skb->len+=len.
这两个操作和skb_push在发送数据包中起重要作用。如发送TFTP包,申请缓冲区,调用udp_skb_reserve(skb);把UDP头到以太网帧头的所有协议头的位置预留出来。再向*data处添加TFTP头和数据。
2)TFTP包发送过程
      发送TFTP应答,tftp_send_ack :申请缓冲,预留所有下层协议(UDP,IP,ETH)协议头空间,填写TFTP头和数据。调用udp_send(skb, client_ip, TFTP, client_port); 参数告诉下层相对的协议头怎么填。如TFTP,client_port 是给UDP协议层的,指定了本地端口和目标端口;client_ip则是给IP层的,给定目标IP。
      udp_send(skb, client_ip, TFTP, client_port); UDP层压栈后填写自己UDP协议头。调用ip_send(skb, ip, UDP); 指定目标IP和上层协议是UDP协议。
      IP层ip_send(skb, ip, UDP); 填写协议头,在这里注意校验和的计算。在ARP缓存中查找目标IP对应的MAC地址,查找成功然后调用下层eth_send(skb, dest_eth_addr, ETH_P_IP);查找失败发送ARP查询请求。
      ETH层 填充以太网帧头,调用底层驱动函数:board_eth_send(skb->data, skb->len);由CS8900芯片完成帧发送。


本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u2/82249/showart_1968795.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP