Linux内核packet_rcv代码分析

上码分析:

static int packet_rcv(struct sk_buff *skb, struct net_device *dev,

     struct packet_type *pt, struct net_device *orig_dev)
{
struct sock *sk;
struct sockaddr_ll *sll;
struct packet_sock *po;
u8 *skb_head = skb->data;
int skb_len = skb->len;
unsigned int snaplen, res;

/*

skb->pkt_type表示帧的类型,分类是由L2的目的地址来决定的,可能的取值都在if_packet.h中定义,对于以太网设备来说,这个变量由eth_type_trans函数初始化。

PACKET_HOST 包的目的地址与收到它的网络设备的L2地址相等,即这个包是发给本机的

PACKET_MULTICAST 包的目的地址是一个多播地址,而这个多播地址时收到这个包的网络设备所注册的多播地址

PACKET_BROADCAST 包的目的地址是一个广播地址,而这个广播地址也是收到这个包的网络设备的广播地址

PACKET_OTHERHOST 包的目的地址与收到它的网络设备地址完全不同,因此,如果本机的转发功能没有启动,这个包会被丢弃。

PACKET_OUTGOING 这个包将被发出。用稿这个标记的功能包括Decnet协议,或者是为每个网络tap都复制一份发出包的函数。

PACKET_LOOPBACK 这个包发向loopback设备。由于有这个标记,在处理loopback设备室,内核可以跳过一些真实设备才需要的操作。

PACKET_FASTROUTE 这个包有快速路由代码查找路由。快速路由功能在2.6内核中已经去掉了。

*/


if (skb->pkt_type == PACKET_LOOPBACK)
goto drop;


sk = pt->af_packet_priv;
po = pkt_sk(sk);


if (!net_eq(dev_net(dev), sock_net(sk)))
goto drop;


skb->dev = dev;


if (dev->header_ops) {
/* The device has an explicit notion of ll header,
* exported to higher levels.
*
* Otherwise, the device hides details of its frame
* structure, so that corresponding packet head is
* never delivered to user.

*/

/*

if (sk->sk_type != SOCK_DGRAM) 这个负责区分应用层SOCK_RAW和SOCK_DGRAM,SOCK_RAW包含L2的数据头,运行此packet_rcv函数时,skb->data指向L3层头,所以如果是SOCK_RAW需要重设skb->data

*/

if (sk->sk_type != SOCK_DGRAM)
skb_push(skb, skb->data - skb_mac_header(skb));
else if (skb->pkt_type == PACKET_OUTGOING) {
/* Special case: outgoing packets have ll header at head */
skb_pull(skb, skb_network_offset(skb));
}
}


snaplen = skb->len;

/*

过滤规则,BPF数据包过滤(BSD PACKET Filter)

*/

res = run_filter(skb, sk, snaplen);
if (!res)
goto drop_n_restore;
if (snaplen > res)
snaplen = res;


if (atomic_read(&sk->sk_rmem_alloc) + skb->truesize >=
   (unsigned)sk->sk_rcvbuf)
goto drop_n_acct;


if (skb_shared(skb)) {
struct sk_buff *nskb = skb_clone(skb, GFP_ATOMIC);
if (nskb == NULL)
goto drop_n_acct;


if (skb_head != skb->data) {
skb->data = skb_head;
skb->len = skb_len;
}
kfree_skb(skb);
skb = nskb;
}


BUILD_BUG_ON(sizeof(*PACKET_SKB_CB(skb)) + MAX_ADDR_LEN - 8 >
    sizeof(skb->cb));


sll = &PACKET_SKB_CB(skb)->sa.ll;
sll->sll_family = AF_PACKET;
sll->sll_hatype = dev->type;
sll->sll_protocol = skb->protocol;
sll->sll_pkttype = skb->pkt_type;
if (unlikely(po->origdev))
sll->sll_ifindex = orig_dev->ifindex;
else
sll->sll_ifindex = dev->ifindex;


sll->sll_halen = dev_parse_header(skb, sll->sll_addr);


PACKET_SKB_CB(skb)->origlen = skb->len;


if (pskb_trim(skb, snaplen))
goto drop_n_acct;


skb_set_owner_r(skb, sk);
skb->dev = NULL;
skb_dst_drop(skb);


/* drop conntrack reference */
nf_reset(skb);


spin_lock(&sk->sk_receive_queue.lock);
po->stats.tp_packets++;
skb->dropcount = atomic_read(&sk->sk_drops);
__skb_queue_tail(&sk->sk_receive_queue, skb);//把数据包放到接收队列中,等待应用层recv操作。
spin_unlock(&sk->sk_receive_queue.lock);
sk->sk_data_ready(sk, skb->len);
return 0;


drop_n_acct:
spin_lock(&sk->sk_receive_queue.lock);
po->stats.tp_drops++;
atomic_inc(&sk->sk_drops);
spin_unlock(&sk->sk_receive_queue.lock);


drop_n_restore:
if (skb_head != skb->data && skb_shared(skb)) {
skb->data = skb_head;
skb->len = skb_len;
}
drop:
consume_skb(skb);
return 0;

}


分析暂时到此,大概了解一下,以后有新的发现再更新。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值