注册 登录  
 加关注
查看详情
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

蒙奇D小豌豆的博客

蒙奇D小豌豆的学习记录

 
 
 

日志

 
 

socket 之PF_PACKET 实现  

2012-03-22 00:12:20|  分类: network |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

1Introduction

Sockets in the PF_PACKET family get direct link-level access to the underlying hardware (i.e. Ethernet or similar). They are usually used to implement packet capturing, or sending of specially-constructed packets or to implement protocols the underlying kernel does not recognise.

 

int socket(int domain, int type, int protocol);

 

domain: PF_PACKET

type:       SOCK_RAW, SOCK_DGRAM , SOCK_PACKET

protocol:  3L protocol such as htons(ETH_P_IP)(0x0800) which is describe by ether_type in  the mac heads.

  

2 Kernel analyse

pf_packet kernel code is net/packet/af_packet.c

 

static int __init packet_init(void)

{

      int rc = proto_register(&packet_proto, 0);  //register the new proto

      if (rc != 0)

           goto out;

 

      sock_register(&packet_family_ops);//register the new sock

      register_pernet_subsys(&packet_net_ops);

      register_netdevice_notifier(&packet_netdev_notifier);

out:

      return rc;

}


Packet_proto: in the inet domain it describe a L4 protocol such as udp or tcp . in the pf_packet domain it  only affords the  obj_size(struct packet_sock) which contant the sock structure  to alloc a sock  later

 

static struct proto packet_proto = {

      .name     = "PACKET",

      .owner   = THIS_MODULE,

      .obj_size = sizeof(struct packet_sock),

};

 

packet_family_ops: describe a domain of a socket

 

static const struct net_proto_family packet_family_ops = {

      .family =    PF_PACKET,

      .create =    packet_create,

      .owner =   THIS_MODULE,

};

 

When user create a socket(PF_PACKET, SOCK_RAW, htons(ETH_P_IP)), it finally calls the packet_create.

socket->sys_socket ->socket_creat->packet_family_ops->create;

static int packet_create(struct net *net, struct socket *sock, int protocol, int kern)

{

      sk = sk_alloc(net, PF_PACKET, GFP_KERNEL, &packet_proto);

/*分配sk结构体 sk->sk_prot = packet_proto;  packet_proto->obj_size 决定了分配的大小struct packet_sock第一个成员就是sk所以有(struct packet_sock*)sk就成了一个struct packet_sock*/

     

      sock->ops = &packet_ops;/*struct proto_ops  packet_ops;*/

 

      packet_sock->prot_hook.func = packet_rcv;

/*struct packet_type  packet_sock->prot_hook;作为packet_sock的成员*/

 

packet_sock->prot_hook.type = protocol;

/*protocol is L3 protocol from the user create socket htons(ETH_P_IP)*/

     

      packet_sock->prot_hook.af_packet_priv = sk

/*sk传给包类型方便接收到包后找到相应的sock*/

 

      dev_add_pack(&po->prot_hook);

/*packet_type加入相应的type或者全局接收列表中*/

}

 

struct proto_ops is used for L4  ops through the user ops. In the inet domain is sub a structure of struct proto present a udp or tcp . both of the domains  assigned the proto_ops to  socket ->ops.

 

bindsys_bindpacket_bind(socket->proto_ops->bind)

sendmsgsys_sendmsgpacket_sendmsg(socket->proto_ops->sendmsgt)

rcvmsg()sys_rcvmsgpacket_revmsg()(socket->proto_ops->revmsg)

........

 

static const struct proto_ops packet_ops = {

      .family =    PF_PACKET,

      .owner =    THIS_MODULE,

      .release =   packet_release,

      .bind =      packet_bind,

      .setsockopt =   packet_setsockopt,

      .getsockopt =  packet_getsockopt,

      .sendmsg =      packet_sendmsg,

      .recvmsg = packet_recvmsg,

      …….

};

 

struct packet_type: 包接收类型,指定接收特定typeL3 protocol类型(对应于socket第三个参数)init domain中会为所有的ip packet 注册一个struct packet_type ip_packet_typefuncip_rcv的接收函数。在af_packet domain中每个socket 都分配一个指定的 packet_type 直接从L2层获取packet

Packet_type 存放于不同的type链表中,当相应type的包到来,NIC驱动奖该包分发给指定的链表的每个func,在af_packte domain packet_rcv为其func

struct packet_type {

      __be16      type;    /* This is really htons(ether_type). */

      struct net_device    *dev;   /* NULL is wildcarded here      */

      int             (*func) (struct sk_buff *,

                             struct net_device *,

                             struct packet_type *,

                             struct net_device *);

      struct sk_buff         *(*gso_segment)(struct sk_buff *skb,

                                  u32 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;

};

 

Packet rcv

网卡驱动--->netif_rx()--->netif_receive_skb()->deliver_skb()->packet_type.func->packet_rcv;

static int packet_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev)

{

      sk = pt->af_packet_priv;//获取sk

    struct packet_sock *po = (struct packet_sock*)sk//获取packet_sock

      res = run_filter(skb, sk, snaplen);//根据过滤规则过滤

      __skb_queue_tail(&sk->sk_receive_queue, skb);//包传到skqueue

}


3Diagram

 socket 之PF_PACKET 实现 - CR7 - CR7的博客

  评论这张
 
阅读(2797)| 评论(0)

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2018