.getname = packet_getname, .poll = packet_poll, .ioctl = packet_ioctl, .listen = sock_no_listen, .shutdown = sock_no_shutdown, .setsockopt = packet_setsockopt, .getsockopt = packet_getsockopt, .sendmsg = packet_sendmsg,
.recvmsg = packet_recvmsg, //socket收包的时候调这个 .mmap = packet_mmap, .sendpage = sock_no_sendpage, };
static struct net_proto_family packet_family_ops = { .family = PF_PACKET,
.create = packet_create, //创建socket的时候调这个 .owner = THIS_MODULE, };
至于系统调用 socket、recv、close是如何调到这些内核钩子函数的,以后再讲。这里只关注packet_type
4.1 系统调用socket
libpcap系统调用socket,内核最终调用 packet_create
static int packet_create(struct net *net, struct socket *sock, int protocol){ po->prot_hook.func = packet_rcv; //初始化钩子函数指针 po->prot_hook.af_packet_priv = sk; if (protocol) {
po->prot_hook.type = protocol; //类型是系统调用socket形参指定的 dev_add_pack(&po->prot_hook);//关键!! sock_hold(sk); po->running = 1; } return(0); }
4.2 钩子函数 packet_rcv 将skb放入到接收队列
文件 linux_2_6_24/net/packet/af_packet.c
简单来说,packet_rcv中,skb越过了整个协议栈,直接进入队列
4.3 系统调用recv
系统调用recv、read、recvmsg,内核最终会调用packet_recvmsg 从接收队列中取出skb,将数据包内容skb->data拷贝到用户空间
4.4 系统调用close
内核最终会调用packet_release
static int packet_release(struct socket *sock){ struct sock *sk = sock->sk; struct packet_sock *po; if (!sk) return 0; po = pkt_sk(sk);
write_lock_bh(&packet_sklist_lock); sk_del_node_init(sk);
write_unlock_bh(&packet_sklist_lock); // Unhook packet receive handler. if (po->running) {
dev_remove_pack(&po->prot_hook); //就是这句!!把packet_type从链表中删除 po->running = 0; po->num = 0; __sock_put(sk); }
packet_flush_mclist(sk);
// Now the socket is dead. No more input will appear. sock_orphan(sk); sock->sk = NULL; /* Purge queues */
skb_queue_purge(&sk->sk_receive_queue); sk_refcnt_debug_release(sk); sock_put(sk);
return 0; }
----------------------------------------------------------------------------------------------
搜一下内核源代码,二层协议还真是多。。。
drivers/net/wan/hdlc.c: dev_add_pack(&hdlc_packet_type); //ETH_P_HDLC hdlc_rcv drivers/net/wan/lapbether.c:
dev_add_pack(&lapbeth_packet_type); //ETH_P_DEC lapbeth_rcv drivers/net/wan/syncppp.c:
dev_add_pack(&sppp_packet_type); //ETH_P_WAN_PPP sppp_rcv drivers/net/bonding/bond_alb.c: dev_add_pack(pk_type); //ETH_P_ARP rlb_arp_recv
drivers/net/bonding/bond_main.c:dev_add_pack(pk_type); //PKT_TYPE_LACPDU bond_3ad_lacpdu_recv drivers/net/bonding/bond_main.c:dev_add_pack(pt); //ETH_P_ARP bond_arp_rcv drivers/net/pppoe.c: dev_add_pack(&pppoes_ptype); //ETH_P_PPP_SES pppoe_rcv drivers/net/pppoe.c: dev_add_pack(&pppoed_ptype); //ETH_P_PPP_DISC pppoe_disc_rcv drivers/net/hamradio/bpqether.c:
dev_add_pack(&bpq_packet_type); //ETH_P_BPQ bpq_rcv net/ipv4/af_inet.c: dev_add_pack(&ip_packet_type); //ETH_P_IP ip_rcv net/ipv4/arp.c: dev_add_pack(&arp_packet_type); //ETH_P_ARP arp_rcv net/ipv4/ipconfig.c: dev_add_pack(&rarp_packet_type); //ETH_P_RARP ic_rarp_recv net/ipv4/ipconfig.c: dev_add_pack(&bootp_packet_type); //ETH_P_IP ic_bootp_recv net/llc/llc_core.c: dev_add_pack(&llc_packet_type); //ETH_P_802_2 llc_rcv net/llc/llc_core.c: dev_add_pack(&llc_tr_packet_type); //ETH_P_TR_802_2 llc_rcv
net/x25/af_x25.c: dev_add_pack(&x25_packet_type); //ETH_P_X25 x25_lapb_receive_frame net/8021q/vlan.c: dev_add_pack(&vlan_packet_type); //ETH_P_8021Q vlan_skb_recv
这些不同协议的packet_type,有些是linux系统启动时挂上去的 比如处理ip协议的pakcet_type,就是在 inet_init()时挂上去的 还有些驱动模块加载的时候才加上去的。
百度搜索“77cn”或“免费范文网”即可找到本站免费阅读全部范文。收藏本站方便下次阅读,免费范文网,提供经典小说综合文库网络数据包收发流程(一):从驱动到协议栈(6)在线全文阅读。
相关推荐: