网络帧在进入网络层时,需要区分不同的网络协议进行处理,这就需要涉及协议处理函数。
首先我们从驱动接收到一个数据帧,分析数据帧在协议栈中自下而上的传输流程。
设备驱动程序在接收到一个数据帧时,会将其保存在一个sk_buff缓冲区数据结构,并对其进行初始化。
struct sk_buff { ...... __be16 protocol:16; ...... }在这个缓冲区结构体中,有一个protocol字段,用于标识网络层的协议。
protocol的定义在include/linux/if_ether.h中,如下所示:
#define ETH_P_802_3 0x0001 /* Dummy type for 802.3 frames */ #define ETH_P_AX25 0x0002 /* Dummy protocol id for AX.25 */ #define ETH_P_ALL 0x0003 /* Every packet (be careful!!!) */ /*ETH_P_ALL不是真正的协议,而是作为通配符,主要用于sniff嗅探器等*/ #define ETH_P_802_2 0x0004 /* 802.2 frames */ #define ETH_P_SNAP 0x0005 /* Internal only */ #define ETH_P_DDCMP 0x0006 /* DEC DDCMP: Internal only */ #define ETH_P_WAN_PPP 0x0007 /* Dummy type for WAN PPP frames*/ #define ETH_P_PPP_MP 0x0008 /* Dummy type for PPP MP frames */ ......
struct packet_type { __be16 type; /* This is really htons(ether_type). */ //二层协议类型,ETH_P_IP、ETH_P_ARP等等 struct net_device *dev; /* NULL is wildcarded here */ //钩子函数了,如 ip_rcv()、arp_rcv()等等 int (*func) (struct sk_buff *, struct net_device *, struct packet_type *, struct net_device *); struct sk_buff *(*gso_segment)(struct sk_buff *skb, int features); int (*gso_send_check)(struct sk_buff *skb); struct sk_buff **(*gro_receive)(struct sk_buff **head, struct sk_buff *skb); int (*gro_complete)(struct sk_buff *skb); void *af_packet_priv; struct list_head list; };其中成员func即为各个协议的钩子函数(协议处理函数).
//注册协议:把packet_type结构挂在与type对应的list_head上面 void dev_add_pack(struct packet_type *pt) { int hash; spin_lock_bh(&ptype_lock); if (pt->type == htons(ETH_P_ALL)) //type为ETH_P_ALL时,挂在ptype_all上面 list_add_rcu(&pt->list, &ptype_all); else { //否则,挂在ptype_base[type&15]上面 hash = ntohs(pt->type) & PTYPE_HASH_MASK; list_add_rcu(&pt->list, &ptype_base[hash]); } spin_unlock_bh(&ptype_lock); } EXPORT_SYMBOL(dev_add_pack);
static struct packet_type ip_packet_type __read_mostly = { .type = cpu_to_be16(ETH_P_IP), .func = ip_rcv, //ipv4 的协议处理函数 ,在netif_receive_skb会使用 .gso_send_check = inet_gso_send_check, .gso_segment = inet_gso_segment, .gro_receive = inet_gro_receive, .gro_complete = inet_gro_complete, };
static int __init inet_init(void) { ...... dev_add_pack(&ip_packet_type); ...... }
原文地址:http://blog.csdn.net/windeal3203/article/details/44831133