--- zzzz-none-000/linux-3.10.107/net/ipv6/udp.c 2017-06-27 09:49:32.000000000 +0000 +++ vr9-7490-729/linux-3.10.107/net/ipv6/udp.c 2021-11-10 11:53:56.000000000 +0000 @@ -52,6 +52,10 @@ #include #include "udp_impl.h" +#ifdef CONFIG_AVM_PA +#include +#endif + int ipv6_rcv_saddr_equal(const struct sock *sk, const struct sock *sk2) { const struct in6_addr *sk_rcv_saddr6 = &inet6_sk(sk)->rcv_saddr; @@ -341,9 +345,15 @@ if (unlikely(sk = skb_steal_sock(skb))) return sk; - return __udp6_lib_lookup(dev_net(skb_dst(skb)->dev), &iph->saddr, sport, + + sk = __udp6_lib_lookup(dev_net(skb_dst(skb)->dev), &iph->saddr, sport, &iph->daddr, dport, inet6_iif(skb), udptable); +#ifdef CONFIG_AVM_PA + if (sk) + avm_pa_add_local_session(skb, sk); +#endif + return sk; } struct sock *udp6_lib_lookup(struct net *net, const struct in6_addr *saddr, __be16 sport, @@ -911,9 +921,10 @@ { unsigned int offset; struct udphdr *uh = udp_hdr(skb); + struct sk_buff *frags = skb_shinfo(skb)->frag_list; __wsum csum = 0; - if (skb_queue_len(&sk->sk_write_queue) == 1) { + if (!frags) { /* Only one fragment on the socket. */ skb->csum_start = skb_transport_header(skb) - skb->head; skb->csum_offset = offsetof(struct udphdr, check); @@ -929,9 +940,9 @@ skb->ip_summed = CHECKSUM_NONE; - skb_queue_walk(&sk->sk_write_queue, skb) { - csum = csum_add(csum, skb->csum); - } + do { + csum = csum_add(csum, frags->csum); + } while ((frags = frags->next)); uh->check = csum_ipv6_magic(saddr, daddr, len, IPPROTO_UDP, csum); @@ -944,25 +955,15 @@ * Sending */ -static int udp_v6_push_pending_frames(struct sock *sk) +static int udp_v6_send_skb(struct sk_buff *skb, struct flowi6 *fl6) { - struct sk_buff *skb; + struct sock *sk = skb->sk; struct udphdr *uh; - struct udp_sock *up = udp_sk(sk); - struct inet_sock *inet = inet_sk(sk); - struct flowi6 *fl6; int err = 0; int is_udplite = IS_UDPLITE(sk); __wsum csum = 0; - - if (up->pending == AF_INET) - return udp_push_pending_frames(sk); - - fl6 = &inet->cork.fl.u.ip6; - - /* Grab the skbuff where UDP header space exists. */ - if ((skb = skb_peek(&sk->sk_write_queue)) == NULL) - goto out; + int offset = skb_transport_offset(skb); + int len = skb->len - offset; /* * Create a UDP header @@ -970,26 +971,25 @@ uh = udp_hdr(skb); uh->source = fl6->fl6_sport; uh->dest = fl6->fl6_dport; - uh->len = htons(up->len); + uh->len = htons(len); uh->check = 0; if (is_udplite) - csum = udplite_csum_outgoing(sk, skb); + csum = udplite_csum(skb); else if (skb->ip_summed == CHECKSUM_PARTIAL) { /* UDP hardware csum */ - udp6_hwcsum_outgoing(sk, skb, &fl6->saddr, &fl6->daddr, - up->len); + udp6_hwcsum_outgoing(sk, skb, &fl6->saddr, &fl6->daddr, len); goto send; } else - csum = udp_csum_outgoing(sk, skb); + csum = udp_csum(skb); /* add protocol-dependent pseudo-header */ uh->check = csum_ipv6_magic(&fl6->saddr, &fl6->daddr, - up->len, fl6->flowi6_proto, csum); + len, fl6->flowi6_proto, csum); if (uh->check == 0) uh->check = CSUM_MANGLED_0; send: - err = ip6_push_pending_frames(sk); + err = ip6_send_skb(skb); if (err) { if (err == -ENOBUFS && !inet6_sk(sk)->recverr) { UDP6_INC_STATS_USER(sock_net(sk), @@ -999,6 +999,30 @@ } else UDP6_INC_STATS_USER(sock_net(sk), UDP_MIB_OUTDATAGRAMS, is_udplite); + return err; +} + +static int udp_v6_push_pending_frames(struct sock *sk) +{ + struct sk_buff *skb; + struct udp_sock *up = udp_sk(sk); + struct flowi6 fl6; + int err = 0; + + if (up->pending == AF_INET) + return udp_push_pending_frames(sk); + + /* ip6_finish_skb will release the cork, so make a copy of + * fl6 here. + */ + fl6 = inet_sk(sk)->cork.fl.u.ip6; + + skb = ip6_finish_skb(sk); + if (!skb) + goto out; + + err = udp_v6_send_skb(skb, &fl6); + out: up->len = 0; up->pending = 0; @@ -1081,6 +1105,7 @@ if (len > INT_MAX - sizeof(struct udphdr)) return -EMSGSIZE; + getfrag = is_udplite ? udplite_getfrag : ip_generic_getfrag; if (up->pending) { /* * There are pending frames. @@ -1221,6 +1246,20 @@ goto do_confirm; back_from_confirm: + /* Lockless fast path for the non-corking case */ + if (!corkreq) { + struct sk_buff *skb; + + skb = ip6_make_skb(sk, getfrag, msg->msg_iov, ulen, + sizeof(struct udphdr), hlimit, tclass, opt, + &fl6, (struct rt6_info *)dst, + msg->msg_flags, dontfrag); + err = PTR_ERR(skb); + if (!IS_ERR_OR_NULL(skb)) + err = udp_v6_send_skb(skb, &fl6); + goto release_dst; + } + lock_sock(sk); if (unlikely(up->pending)) { /* The socket is already corked while preparing it. */ @@ -1236,7 +1275,6 @@ do_append_data: up->len += ulen; - getfrag = is_udplite ? udplite_getfrag : ip_generic_getfrag; err = ip6_append_data(sk, getfrag, msg->msg_iov, ulen, sizeof(struct udphdr), hlimit, tclass, opt, &fl6, (struct rt6_info*)dst, @@ -1248,6 +1286,11 @@ else if (unlikely(skb_queue_empty(&sk->sk_write_queue))) up->pending = 0; + if (err > 0) + err = np->recverr ? net_xmit_errno(err) : 0; + release_sock(sk); + +release_dst: if (dst) { if (connected) { ip6_dst_store(sk, dst, @@ -1264,9 +1307,6 @@ dst = NULL; } - if (err > 0) - err = np->recverr ? net_xmit_errno(err) : 0; - release_sock(sk); out: dst_release(dst); fl6_sock_release(flowlabel);