956
技術社區[雲棲]
網絡子係統82_inet協議族-SOCK_RAW(三)
// 向raw sock傳遞skb // 步驟: // 1.根據協議號獲取監聽指定protocol的sock // 2.向raw sock傳遞skb 1.1 int raw_local_deliver(struct sk_buff *skb, int protocol) { int hash; struct sock *raw_sk; //獲取監聽指定協議的raw sock hash = protocol & (RAW_HTABLE_SIZE - 1); raw_sk = sk_head(&raw_v4_hashinfo.ht[hash]); //向raw socket傳遞 if (raw_sk && !raw_v4_input(skb, ip_hdr(skb), hash)) raw_sk = NULL; return raw_sk != NULL; } // 向raw sock傳遞skb // 步驟: // 1.獲取raw sock鏈表, 查找可接收此skb的sock // 1.1 如果raw sock指定了協議號,源地址,目的地址,設備號,則逐項匹配 // 2.向sock傳遞skb的拷貝 1.2 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]; if (hlist_empty(head)) goto out; net = dev_net(skb->dev); sk = __raw_v4_lookup(net, __sk_head(head), iph->protocol, iph->saddr, iph->daddr, skb->dev->ifindex); while (sk) { delivered = 1; //如果有注冊的sock raw,傳遞一份skb拷貝 struct sk_buff *clone = skb_clone(skb, GFP_ATOMIC); if (clone) raw_rcv(sk, clone); //匹配sock,協議號,源地址,目的地址,設備號 sk = __raw_v4_lookup(net, sk_next(sk), iph->protocol, iph->saddr, iph->daddr, skb->dev->ifindex); } out: read_unlock(&raw_v4_hashinfo.lock); return delivered; } // 添加skb到sock隊列 // 步驟: // 1.調整skb->data指向ip報頭 // 2.添加skb到struct sock的接收隊列 1.3 int raw_rcv(struct sock *sk, struct sk_buff *skb) { //調整skb->data指針指向ip報頭 skb_push(skb, skb->data - skb_network_header(skb)); //添加skb到struct sock隊列上 raw_rcv_skb(sk, skb); return 0; } // 添加skb到sock隊列 // 步驟: // 1.斷開skb與入口設備之間的聯係 // 2.將skb添加到sock->sk_receive_queue // 3.通知sock數據已經準備好 1.4 int sock_queue_rcv_skb(struct sock *sk, struct sk_buff *skb) { int err; int skb_len; unsigned long flags; struct sk_buff_head *list = &sk->sk_receive_queue; //接收緩存用完 if (atomic_read(&sk->sk_rmem_alloc) >= sk->sk_rcvbuf) { atomic_inc(&sk->sk_drops); trace_sock_rcvqueue_full(sk, skb); return -ENOMEM; } //清除skb的入口設備描述符 skb->dev = NULL; //skb由sock擁有 skb_set_owner_r(skb, sk); skb_len = skb->len; //接收隊列鎖 spin_lock_irqsave(&list->lock, flags); skb->dropcount = atomic_read(&sk->sk_drops); //將skb添加到sock->sk_receive_queue __skb_queue_tail(list, skb); spin_unlock_irqrestore(&list->lock, flags); //在sock_init_data中初始化為sock_def_readable sk->sk_data_ready(sk, skb_len); return 0; }
最後更新:2017-04-03 12:55:18