在接收数据时,在ip_local_deliver_finish函数中会先调用raw_local_deliver,将数据包提交到raw socket中去,下面就是提交过程:
[ net/ipv4/raw.c ]
int raw_local_deliver(struct sk_buff *skb, int protocol)
{
int hash;
struct sock *raw_sk;
/* 所有的raw socket都挂在全局数组raw_v4_hashinfo上
* 每种协议都有一个列表
*/
hash = protocol & (RAW_HTABLE_SIZE - 1); // 通过协议得到数组下标
raw_sk = sk_head(&raw_v4_hashinfo.ht[hash]);
/* If there maybe a raw socket we must check - if not we
* don't care less
*/
if (raw_sk && !raw_v4_input(skb, ip_hdr(skb), hash))
raw_sk = NULL;
return raw_sk != NULL;
}
当中调用的函数:
[ net/ipv4/raw.c ]
/* IP input processing comes here for RAW socket delivery.
* Caller owns SKB, so we must make clones.
*
* RFC 1122: SHOULD pass TOS value up to the transport layer.
* -> It does. And not only TOS, but all IP header.
*/
static int raw_v4_input(struct sk_buff *skb, const struct iphdr *iph, int hash)
{
struct sock *sk;
struct hlist_head *head;
int delivered = 0;
struct net *net;
read_lock(&raw_v4_hashinfo.lock);
head = &raw_v4_hashinfo.ht[hash]; // hash由skb的协议决定。得到协议对应的row socket
if (hlist_empty(head))
goto out;
net = dev_net(skb->dev); // 网络
/* 得到关联的socket
* 根据IP层的上层协议,目的和源地址,接收数据的设备号
*/
sk = __raw_v4_lookup(net, __sk_head(head), iph->protocol,
iph->saddr, iph->daddr,
skb->dev->ifindex);
while (sk) {
delivered = 1;
/* 协议不是ICMP
* 数据包不是ICMP要过滤的数据包
*/
if (iph->protocol !&