Release 4.11 net/ipv6/udp.c
/*
* UDP over IPv6
* Linux INET6 implementation
*
* Authors:
* Pedro Roque <roque@di.fc.ul.pt>
*
* Based on linux/ipv4/udp.c
*
* Fixes:
* Hideaki YOSHIFUJI : sin6_scope_id support
* YOSHIFUJI Hideaki @USAGI and: Support IPV6_V6ONLY socket option, which
* Alexey Kuznetsov allow both IPv4 and IPv6 sockets to bind
* a single port at the same time.
* Kazunori MIYAZAWA @USAGI: change process style to use ip6_append_data
* YOSHIFUJI Hideaki @USAGI: convert /proc/net/udp6 to seq_file.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
#include <linux/sockios.h>
#include <linux/net.h>
#include <linux/in6.h>
#include <linux/netdevice.h>
#include <linux/if_arp.h>
#include <linux/ipv6.h>
#include <linux/icmpv6.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/skbuff.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <net/addrconf.h>
#include <net/ndisc.h>
#include <net/protocol.h>
#include <net/transp_v6.h>
#include <net/ip6_route.h>
#include <net/raw.h>
#include <net/tcp_states.h>
#include <net/ip6_checksum.h>
#include <net/xfrm.h>
#include <net/inet6_hashtables.h>
#include <net/busy_poll.h>
#include <net/sock_reuseport.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <trace/events/skb.h>
#include "udp_impl.h"
static bool udp6_lib_exact_dif_match(struct net *net, struct sk_buff *skb)
{
#if defined(CONFIG_NET_L3_MASTER_DEV)
if (!net->ipv4.sysctl_udp_l3mdev_accept &&
skb && ipv6_l3mdev_skb(IP6CB(skb)->flags))
return true;
#endif
return false;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Robert Shearman | 51 | 100.00% | 1 | 100.00% |
Total | 51 | 100.00% | 1 | 100.00% |
static u32 udp6_ehashfn(const struct net *net,
const struct in6_addr *laddr,
const u16 lport,
const struct in6_addr *faddr,
const __be16 fport)
{
static u32 udp6_ehash_secret __read_mostly;
static u32 udp_ipv6_hash_secret __read_mostly;
u32 lhash, fhash;
net_get_random_once(&udp6_ehash_secret,
sizeof(udp6_ehash_secret));
net_get_random_once(&udp_ipv6_hash_secret,
sizeof(udp_ipv6_hash_secret));
lhash = (__force u32)laddr->s6_addr32[3];
fhash = __ipv6_addr_jhash(faddr, udp_ipv6_hash_secret);
return __inet6_ehashfn(lhash, lport, fhash, fport,
udp_ipv6_hash_secret + net_hash_mix(net));
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Hannes Frederic Sowa | 107 | 97.27% | 2 | 50.00% |
Eric Dumazet | 2 | 1.82% | 1 | 25.00% |
Vladislav Yasevich | 1 | 0.91% | 1 | 25.00% |
Total | 110 | 100.00% | 4 | 100.00% |
static u32 udp6_portaddr_hash(const struct net *net,
const struct in6_addr *addr6,
unsigned int port)
{
unsigned int hash, mix = net_hash_mix(net);
if (ipv6_addr_any(addr6))
hash = jhash_1word(0, mix);
else if (ipv6_addr_v4mapped(addr6))
hash = jhash_1word((__force u32)addr6->s6_addr32[3], mix);
else
hash = jhash2((__force u32 *)addr6->s6_addr32, 4, mix);
return hash ^ port;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Eric Dumazet | 98 | 98.99% | 3 | 75.00% |
Brian Haley | 1 | 1.01% | 1 | 25.00% |
Total | 99 | 100.00% | 4 | 100.00% |
int udp_v6_get_port(struct sock *sk, unsigned short snum)
{
unsigned int hash2_nulladdr =
udp6_portaddr_hash(sock_net(sk), &in6addr_any, snum);
unsigned int hash2_partial =
udp6_portaddr_hash(sock_net(sk), &sk->sk_v6_rcv_saddr, 0);
/* precompute partial secondary hash */
udp_sk(sk)->udp_portaddr_hash = hash2_partial;
return udp_lib_get_port(sk, snum, hash2_nulladdr);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Eric Dumazet | 47 | 67.14% | 3 | 27.27% |
Linus Torvalds (pre-git) | 17 | 24.29% | 4 | 36.36% |
Arnaldo Carvalho de Melo | 4 | 5.71% | 2 | 18.18% |
Pavel Emelyanov | 1 | 1.43% | 1 | 9.09% |
Gerrit Renker | 1 | 1.43% | 1 | 9.09% |
Total | 70 | 100.00% | 11 | 100.00% |
static void udp_v6_rehash(struct sock *sk)
{
u16 new_hash = udp6_portaddr_hash(sock_net(sk),
&sk->sk_v6_rcv_saddr,
inet_sk(sk)->inet_num);
udp_lib_rehash(sk, new_hash);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Eric Dumazet | 41 | 100.00% | 2 | 100.00% |
Total | 41 | 100.00% | 2 | 100.00% |
static int compute_score(struct sock *sk, struct net *net,
const struct in6_addr *saddr, __be16 sport,
const struct in6_addr *daddr, unsigned short hnum,
int dif, bool exact_dif)
{
int score;
struct inet_sock *inet;
if (!net_eq(sock_net(sk), net) ||
udp_sk(sk)->udp_port_hash != hnum ||
sk->sk_family != PF_INET6)
return -1;
score = 0;
inet = inet_sk(sk);
if (inet->inet_dport) {
if (inet->inet_dport != sport)
return -1;
score++;
}
if (!ipv6_addr_any(&sk->sk_v6_rcv_saddr)) {
if (!ipv6_addr_equal(&sk->sk_v6_rcv_saddr, daddr))
return -1;
score++;
}
if (!ipv6_addr_any(&sk->sk_v6_daddr)) {
if (!ipv6_addr_equal(&sk->sk_v6_daddr, saddr))
return -1;
score++;
}
if (sk->sk_bound_dev_if || exact_dif) {
if (sk->sk_bound_dev_if != dif)
return -1;
score++;
}
if (sk->sk_incoming_cpu == raw_smp_processor_id())
score++;
return score;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Linus Torvalds (pre-git) | 109 | 49.32% | 4 | 19.05% |
Eric Dumazet | 58 | 26.24% | 6 | 28.57% |
Joe Perches | 19 | 8.60% | 1 | 4.76% |
Hideaki Yoshifuji / 吉藤英明 | 11 | 4.98% | 3 | 14.29% |
Pavel Emelyanov | 8 | 3.62% | 1 | 4.76% |
Robert Shearman | 5 | 2.26% | 1 | 4.76% |
Arnaldo Carvalho de Melo | 3 | 1.36% | 1 | 4.76% |
Xuemin Su | 3 | 1.36% | 1 | 4.76% |
Balazs Scheidler | 2 | 0.90% | 1 | 4.76% |
David S. Miller | 2 | 0.90% | 1 | 4.76% |
Gerrit Renker | 1 | 0.45% | 1 | 4.76% |
Total | 221 | 100.00% | 21 | 100.00% |
/* called with rcu_read_lock() */
static struct sock *udp6_lib_lookup2(struct net *net,
const struct in6_addr *saddr, __be16 sport,
const struct in6_addr *daddr, unsigned int hnum, int dif,
bool exact_dif, struct udp_hslot *hslot2,
struct sk_buff *skb)
{
struct sock *sk, *result;
int score, badness, matches = 0, reuseport = 0;
u32 hash = 0;
result = NULL;
badness = -1;
udp_portaddr_for_each_entry_rcu(sk, &hslot2->head) {
score = compute_score(sk, net, saddr, sport,
daddr, hnum, dif, exact_dif);
if (score > badness) {
reuseport = sk->sk_reuseport;
if (reuseport) {
hash = udp6_ehashfn(net, daddr, hnum,
saddr, sport);
result = reuseport_select_sock(sk, hash, skb,
sizeof(struct udphdr));
if (result)
return result;
matches = 1;
}
result = sk;
badness = score;
} else if (score == badness && reuseport) {
matches++;
if (reciprocal_scale(hash, matches) == 0)
result = sk;
hash = next_pseudo_random32(hash);
}
}
return result;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Eric Dumazet | 112 | 50.45% | 3 | 27.27% |
Tom Herbert | 73 | 32.88% | 1 | 9.09% |
Craig Gallek | 26 | 11.71% | 3 | 27.27% |
Robert Shearman | 5 | 2.25% | 1 | 9.09% |
Daniel Borkmann | 4 | 1.80% | 1 | 9.09% |
Xuemin Su | 1 | 0.45% | 1 | 9.09% |
Hannes Frederic Sowa | 1 | 0.45% | 1 | 9.09% |
Total | 222 | 100.00% | 11 | 100.00% |
/* rcu_read_lock() must be held */
struct sock *__udp6_lib_lookup(struct net *net,
const struct in6_addr *saddr, __be16 sport,
const struct in6_addr *daddr, __be16 dport,
int dif, struct udp_table *udptable,
struct sk_buff *skb)
{
struct sock *sk, *result;
unsigned short hnum = ntohs(dport);
unsigned int hash2, slot2, slot = udp_hashfn(net, hnum, udptable->mask);
struct udp_hslot *hslot2, *hslot = &udptable->hash[slot];
bool exact_dif = udp6_lib_exact_dif_match(net, skb);
int score, badness, matches = 0, reuseport = 0;
u32 hash = 0;
if (hslot->count > 10) {
hash2 = udp6_portaddr_hash(net, daddr, hnum);
slot2 = hash2 & udptable->mask;
hslot2 = &udptable->hash2[slot2];
if (hslot->count < hslot2->count)
goto begin;
result = udp6_lib_lookup2(net, saddr, sport,
daddr, hnum, dif, exact_dif,
hslot2, skb);
if (!result) {
unsigned int old_slot2 = slot2;
hash2 = udp6_portaddr_hash(net, &in6addr_any, hnum);
slot2 = hash2 & udptable->mask;
/* avoid searching the same slot again. */
if (unlikely(slot2 == old_slot2))
return result;
hslot2 = &udptable->hash2[slot2];
if (hslot->count < hslot2->count)
goto begin;
result = udp6_lib_lookup2(net, saddr, sport,
daddr, hnum, dif,
exact_dif, hslot2,
skb);
}
return result;
}
begin:
result = NULL;
badness = -1;
sk_for_each_rcu(sk, &hslot->head) {
score = compute_score(sk, net, saddr, sport, daddr, hnum, dif,
exact_dif);
if (score > badness) {
reuseport = sk->sk_reuseport;
if (reuseport) {
hash = udp6_ehashfn(net, daddr, hnum,
saddr, sport);
result = reuseport_select_sock(sk, hash, skb,
sizeof(struct udphdr));
if (result)
return result;
matches = 1;
}
result = sk;
badness = score;
} else if (score == badness && reuseport) {
matches++;
if (reciprocal_scale(hash, matches) == 0)
result = sk;
hash = next_pseudo_random32(hash);
}
}
return result;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Eric Dumazet | 279 | 62.98% | 6 | 35.29% |
Tom Herbert | 72 | 16.25% | 1 | 5.88% |
Craig Gallek | 29 | 6.55% | 3 | 17.65% |
Xuemin Su | 21 | 4.74% | 1 | 5.88% |
Linus Torvalds (pre-git) | 18 | 4.06% | 1 | 5.88% |
Robert Shearman | 16 | 3.61% | 1 | 5.88% |
Daniel Borkmann | 4 | 0.90% | 1 | 5.88% |
Balazs Scheidler | 2 | 0.45% | 1 | 5.88% |
Jorge Boncompte | 1 | 0.23% | 1 | 5.88% |
Hannes Frederic Sowa | 1 | 0.23% | 1 | 5.88% |
Total | 443 | 100.00% | 17 | 100.00% |
EXPORT_SYMBOL_GPL(__udp6_lib_lookup);
static struct sock *__udp6_lib_lookup_skb(struct sk_buff *skb,
__be16 sport, __be16 dport,
struct udp_table *udptable)
{
const struct ipv6hdr *iph = ipv6_hdr(skb);
struct sock *sk;
sk = skb_steal_sock(skb);
if (unlikely(sk))
return sk;
return __udp6_lib_lookup(dev_net(skb->dev), &iph->saddr, sport,
&iph->daddr, dport, inet6_iif(skb),
udptable, skb);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
KOVACS Krisztian | 75 | 82.42% | 2 | 28.57% |
Ian Morris | 6 | 6.59% | 1 | 14.29% |
Alexander Duyck | 5 | 5.49% | 1 | 14.29% |
Eric Dumazet | 3 | 3.30% | 2 | 28.57% |
Craig Gallek | 2 | 2.20% | 1 | 14.29% |
Total | 91 | 100.00% | 7 | 100.00% |
struct sock *udp6_lib_lookup_skb(struct sk_buff *skb,
__be16 sport, __be16 dport)
{
const struct ipv6hdr *iph = ipv6_hdr(skb);
return __udp6_lib_lookup(dev_net(skb->dev), &iph->saddr, sport,
&iph->daddr, dport, inet6_iif(skb),
&udp_table, skb);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Tom Herbert | 62 | 96.88% | 1 | 50.00% |
Alexander Duyck | 2 | 3.12% | 1 | 50.00% |
Total | 64 | 100.00% | 2 | 100.00% |
EXPORT_SYMBOL_GPL(udp6_lib_lookup_skb);
/* Must be called under rcu_read_lock().
* Does increment socket refcount.
*/
#if IS_ENABLED(CONFIG_NETFILTER_XT_MATCH_SOCKET) || \
IS_ENABLED(CONFIG_NETFILTER_XT_TARGET_TPROXY) || \
IS_ENABLED(CONFIG_NF_SOCKET_IPV6)
struct sock *udp6_lib_lookup(struct net *net, const struct in6_addr *saddr, __be16 sport,
const struct in6_addr *daddr, __be16 dport, int dif)
{
struct sock *sk;
sk = __udp6_lib_lookup(net, saddr, sport, daddr, dport,
dif, &udp_table, NULL);
if (sk && !atomic_inc_not_zero(&sk->sk_refcnt))
sk = NULL;
return sk;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Balazs Scheidler | 47 | 58.75% | 1 | 33.33% |
Eric Dumazet | 31 | 38.75% | 1 | 33.33% |
Craig Gallek | 2 | 2.50% | 1 | 33.33% |
Total | 80 | 100.00% | 3 | 100.00% |
EXPORT_SYMBOL_GPL(udp6_lib_lookup);
#endif
/*
* This should be easy, if there is something there we
* return it, otherwise we block.
*/
int udpv6_recvmsg(struct sock *sk, struct msghdr *msg, size_t len,
int noblock, int flags, int *addr_len)
{
struct ipv6_pinfo *np = inet6_sk(sk);
struct inet_sock *inet = inet_sk(sk);
struct sk_buff *skb;
unsigned int ulen, copied;
int peeked, peeking, off;
int err;
int is_udplite = IS_UDPLITE(sk);
bool checksum_valid = false;
int is_udp4;
if (flags & MSG_ERRQUEUE)
return ipv6_recv_error(sk, msg, len, addr_len);
if (np->rxpmtu && np->rxopt.bits.rxpmtu)
return ipv6_recv_rxpmtu(sk, msg, len, addr_len);
try_again:
peeking = off = sk_peek_offset(sk, flags);
skb = __skb_recv_udp(sk, flags, noblock, &peeked, &off, &err);
if (!skb)
return err;
ulen = skb->len;
copied = len;
if (copied > ulen - off)
copied = ulen - off;
else if (copied < ulen)
msg->msg_flags |= MSG_TRUNC;
is_udp4 = (skb->protocol == htons(ETH_P_IP));
/*
* If checksum is needed at all, try to do it while copying the
* data. If the data is truncated, or if we only want a partial
* coverage checksum (UDP-Lite), do it before the copy.
*/
if (copied < ulen || peeking ||
(is_udplite && UDP_SKB_CB(skb)->partial_cov)) {
checksum_valid = !udp_lib_checksum_complete(skb);
if (!checksum_valid)
goto csum_copy_err;
}
if (checksum_valid || skb_csum_unnecessary(skb))
err = skb_copy_datagram_msg(skb, off, msg, copied);
else {
err = skb_copy_and_csum_datagram_msg(skb, off, msg);
if (err == -EINVAL)
goto csum_copy_err;
}
if (unlikely(err)) {
if (!peeked) {
atomic_inc(&sk->sk_drops);
if (is_udp4)
UDP_INC_STATS(sock_net(sk), UDP_MIB_INERRORS,
is_udplite);
else
UDP6_INC_STATS(sock_net(sk), UDP_MIB_INERRORS,
is_udplite);
}
kfree_skb(skb);
return err;
}
if (!peeked) {
if (is_udp4)
UDP_INC_STATS(sock_net(sk), UDP_MIB_INDATAGRAMS,
is_udplite);
else
UDP6_INC_STATS(sock_net(sk), UDP_MIB_INDATAGRAMS,
is_udplite);
}
sock_recv_ts_and_drops(msg, sk, skb);
/* Copy the address. */
if (msg->msg_name) {
DECLARE_SOCKADDR(struct sockaddr_in6 *, sin6, msg->msg_name);
sin6->sin6_family = AF_INET6;
sin6->sin6_port = udp_hdr(skb)->source;
sin6->sin6_flowinfo = 0;
if (is_udp4) {
ipv6_addr_set_v4mapped(ip_hdr(skb)->saddr,
&sin6->sin6_addr);
sin6->sin6_scope_id = 0;
} else {
sin6->sin6_addr = ipv6_hdr(skb)->saddr;
sin6->sin6_scope_id =
ipv6_iface_scope_id(&sin6->sin6_addr,
inet6_iif(skb));
}
*addr_len = sizeof(*sin6);
}
if (np->rxopt.all)
ip6_datagram_recv_common_ctl(sk, msg, skb);
if (is_udp4) {
if (inet->cmsg_flags)
ip_cmsg_recv_offset(msg, sk, skb,
sizeof(struct udphdr), off);
} else {
if (np->rxopt.all)
ip6_datagram_recv_specific_ctl(sk, msg, skb);
}
err = copied;
if (flags & MSG_TRUNC)
err = ulen;
skb_consume_udp(sk, skb, peeking ? -err : err);
return err;
csum_copy_err:
if (!__sk_queue_drop_skb(sk, skb, flags, udp_skb_destructor)) {
if (is_udp4) {
UDP_INC_STATS(sock_net(sk),
UDP_MIB_CSUMERRORS, is_udplite);
UDP_INC_STATS(sock_net(sk),
UDP_MIB_INERRORS, is_udplite);
} else {
UDP6_INC_STATS(sock_net(sk),
UDP_MIB_CSUMERRORS, is_udplite);
UDP6_INC_STATS(sock_net(sk),
UDP_MIB_INERRORS, is_udplite);
}
}
kfree_skb(skb);
/* starting over for a new packet, but check if we need to yield */
cond_resched();
msg->msg_flags &= ~MSG_TRUNC;
goto try_again;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Linus Torvalds (pre-git) | 216 | 30.29% | 10 | 16.95% |
Eric Dumazet | 117 | 16.41% | 9 | 15.25% |
Wei Yongjun | 54 | 7.57% | 2 | 3.39% |
Herbert Xu | 49 | 6.87% | 5 | 8.47% |
Hideaki Yoshifuji / 吉藤英明 | 49 | 6.87% | 2 | 3.39% |
Hannes Frederic Sowa | 46 | 6.45% | 4 | 6.78% |
samanthakumar | 36 | 5.05% | 1 | 1.69% |
Brian Haley | 30 | 4.21% | 2 | 3.39% |
David S. Miller | 29 | 4.07% | 4 | 6.78% |
Pavel Emelyanov | 15 | 2.10% | 2 | 3.39% |
Gerrit Renker | 11 | 1.54% | 1 | 1.69% |
Paolo Abeni | 9 | 1.26% | 3 | 5.08% |
Arnaldo Carvalho de Melo | 9 | 1.26% | 3 | 5.08% |
Samuel Thibault | 9 | 1.26% | 1 | 1.69% |
Xufeng Zhang | 7 | 0.98% | 1 | 1.69% |
Wang Chen | 6 | 0.84% | 1 | 1.69% |
Steffen Hurrle | 6 | 0.84% | 1 | 1.69% |
Linus Torvalds | 5 | 0.70% | 1 | 1.69% |
Stephen Hemminger | 3 | 0.42% | 1 | 1.69% |
Hideo Aoki | 3 | 0.42% | 1 | 1.69% |
Duan Jiong | 1 | 0.14% | 1 | 1.69% |
Neil Horman | 1 | 0.14% | 1 | 1.69% |
Alexey Dobriyan | 1 | 0.14% | 1 | 1.69% |
Al Viro | 1 | 0.14% | 1 | 1.69% |
Total | 713 | 100.00% | 59 | 100.00% |
void __udp6_lib_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
u8 type, u8 code, int offset, __be32 info,
struct udp_table *udptable)
{
struct ipv6_pinfo *np;
const struct ipv6hdr *hdr = (const struct ipv6hdr *)skb->data;
const struct in6_addr *saddr = &hdr->saddr;
const struct in6_addr *daddr = &hdr->daddr;
struct udphdr *uh = (struct udphdr *)(skb->data+offset);
struct sock *sk;
int harderr;
int err;
struct net *net = dev_net(skb->dev);
sk = __udp6_lib_lookup(net, daddr, uh->dest, saddr, uh->source,
inet6_iif(skb), udptable, skb);
if (!sk) {
__ICMP6_INC_STATS(net, __in6_dev_get(skb->dev),
ICMP6_MIB_INERRORS);
return;
}
harderr = icmpv6_err_convert(type, code, &err);
np = inet6_sk(sk);
if (type == ICMPV6_PKT_TOOBIG) {
if (!ip6_sk_accept_pmtu(sk))
goto out;
ip6_sk_update_pmtu(skb, sk, info);
if (np->pmtudisc != IPV6_PMTUDISC_DONT)
harderr = 1;
}
if (type == NDISC_REDIRECT) {
ip6_sk_redirect(skb, sk);
goto out;
}
if (!np->recverr) {
if (!harderr || sk->sk_state != TCP_ESTABLISHED)
goto out;
} else {
ipv6_icmp_error(sk, skb, err, uh->dest, ntohl(info), (u8 *)(uh+1));
}
sk->sk_err = err;
sk->sk_error_report(sk);
out:
return;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Linus Torvalds (pre-git) | 126 | 40.26% | 7 | 25.00% |
Wei Wang | 42 | 13.42% | 1 | 3.57% |
David S. Miller | 34 | 10.86% | 3 | 10.71% |
Linus Torvalds | 33 | 10.54% | 1 | 3.57% |
Duan Jiong | 31 | 9.90% | 2 | 7.14% |
Hannes Frederic Sowa | 13 | 4.15% | 1 | 3.57% |
Eric Dumazet | 8 | 2.56% | 4 | 14.29% |
Hideaki Yoshifuji / 吉藤英明 | 7 | 2.24% | 2 | 7.14% |
Gerrit Renker | 6 | 1.92% | 1 | 3.57% |
Pavel Emelyanov | 4 | 1.28% | 1 | 3.57% |
Arnaldo Carvalho de Melo | 3 | 0.96% | 1 | 3.57% |
Brian Haley | 2 | 0.64% | 1 | 3.57% |
Craig Gallek | 2 | 0.64% | 1 | 3.57% |
Ian Morris | 1 | 0.32% | 1 | 3.57% |
Al Viro | 1 | 0.32% | 1 | 3.57% |
Total | 313 | 100.00% | 28 | 100.00% |
int __udpv6_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
{
int rc;
if (!ipv6_addr_any(&sk->sk_v6_daddr)) {
sock_rps_save_rxhash(sk, skb);
sk_mark_napi_id(sk, skb);
sk_incoming_cpu_update(sk);
} else {
sk_mark_napi_id_once(sk, skb);
}
rc = __udp_enqueue_schedule_skb(sk, skb);
if (rc < 0) {
int is_udplite = IS_UDPLITE(sk);
/* Note that an ENOMEM error is charged twice */
if (rc == -ENOMEM)
UDP6_INC_STATS(sock_net(sk),
UDP_MIB_RCVBUFERRORS, is_udplite);
UDP6_INC_STATS(sock_net(sk), UDP_MIB_INERRORS, is_udplite);
kfree_skb(skb);
return -1;
}
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Benjamin LaHaise | 101 | 78.29% | 1 | 14.29% |
Eric Dumazet | 18 | 13.95% | 4 | 57.14% |
Shawn Bohrer | 9 | 6.98% | 1 | 14.29% |
Paolo Abeni | 1 | 0.78% | 1 | 14.29% |
Total | 129 | 100.00% | 7 | 100.00% |
static __inline__ void udpv6_err(struct sk_buff *skb,
struct inet6_skb_parm *opt, u8 type,
u8 code, int offset, __be32 info)
{
__udp6_lib_err(skb, opt, type, code, offset, info, &udp_table);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Gerrit Renker | 40 | 85.11% | 1 | 16.67% |
Eric Dumazet | 2 | 4.26% | 1 | 16.67% |
Brian Haley | 2 | 4.26% | 1 | 16.67% |
Linus Torvalds (pre-git) | 1 | 2.13% | 1 | 16.67% |
Al Viro | 1 | 2.13% | 1 | 16.67% |
Hideaki Yoshifuji / 吉藤英明 | 1 | 2.13% | 1 | 16.67% |
Total | 47 | 100.00% | 6 | 100.00% |
static struct static_key udpv6_encap_needed __read_mostly;
void udpv6_encap_enable(void)
{
if (!static_key_enabled(&udpv6_encap_needed))
static_key_slow_inc(&udpv6_encap_needed);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Benjamin LaHaise | 22 | 100.00% | 1 | 100.00% |
Total | 22 | 100.00% | 1 | 100.00% |
EXPORT_SYMBOL(udpv6_encap_enable);
int udpv6_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
{
struct udp_sock *up = udp_sk(sk);
int is_udplite = IS_UDPLITE(sk);
if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb))
goto drop;
if (static_key_false(&udpv6_encap_needed) && up->encap_type) {
int (*encap_rcv)(struct sock *sk, struct sk_buff *skb);
/*
* This is an encapsulation socket so pass the skb to
* the socket's udp_encap_rcv() hook. Otherwise, just
* fall through and pass this up the UDP socket.
* up->encap_rcv() returns the following value:
* =0 if skb was successfully passed to the encap
* handler or was discarded by it.
* >0 if skb should be passed on to UDP.
* <0 if skb should be resubmitted as proto -N
*/
/* if we're overly short, let UDP handle it */
encap_rcv = ACCESS_ONCE(up->encap_rcv);
if (encap_rcv) {
int ret;
/* Verify checksum before giving to encap */
if (udp_lib_checksum_complete(skb))
goto csum_error;
ret = encap_rcv(sk, skb);
if (ret <= 0) {
__UDP_INC_STATS(sock_net(sk),
UDP_MIB_INDATAGRAMS,
is_udplite);
return -