/* * Note: called only from the BH handler context, * so we don't need to lock the hashes. */ static void udpv6_mcast_deliver(struct udphdr *uh, struct in6_addr *saddr, struct in6_addr *daddr, struct sk_buff *skb) { struct sock *sk, *sk2; struct sk_buff *buff; int dif; read_lock(&udp_hash_lock); sk = udp_hash[ntohs(uh->dest) & (UDP_HTABLE_SIZE - 1)]; dif = skb->dev->ifindex; sk = udp_v6_mcast_next(sk, uh->dest, daddr, uh->source, saddr, dif); if (!sk) goto free_skb; buff = NULL; sk2 = sk; while((sk2 = udp_v6_mcast_next(sk2->next, uh->dest, daddr, uh->source, saddr, dif))) { if (!buff) { buff = skb_clone(skb, GFP_ATOMIC); if (!buff) continue; } if (sock_queue_rcv_skb(sk2, buff) >= 0) buff = NULL; } if (buff) kfree_skb(buff); if (sock_queue_rcv_skb(sk, skb) < 0) { free_skb: kfree_skb(skb); } read_unlock(&udp_hash_lock); }
/* * Note: called only from the BH handler context, * so we don't need to lock the hashes. */ static void udpv6_mcast_deliver(struct udphdr *uh, struct in6_addr *saddr, struct in6_addr *daddr, struct sk_buff *skb) { struct sock *sk, *sk2; int dif; read_lock(&udp_hash_lock); sk = udp_hash[ntohs(uh->dest) & (UDP_HTABLE_SIZE - 1)]; dif = skb->dev->ifindex; sk = udp_v6_mcast_next(sk, uh->dest, daddr, uh->source, saddr, dif); if (!sk) { kfree_skb(skb); goto out; } sk2 = sk; while((sk2 = udp_v6_mcast_next(sk2->next, uh->dest, daddr, uh->source, saddr, dif))) { struct sk_buff *buff = skb_clone(skb, GFP_ATOMIC); if (buff) udpv6_queue_rcv_skb(sk2, buff); } udpv6_queue_rcv_skb(sk, skb); out: read_unlock(&udp_hash_lock); }