diff options
Diffstat (limited to 'net/ipv6/udp.c')
-rw-r--r-- | net/ipv6/udp.c | 24 |
1 files changed, 23 insertions, 1 deletions
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 4c79dc5329bc..c55698d19d68 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c | |||
@@ -554,7 +554,7 @@ void udpv6_encap_enable(void) | |||
554 | } | 554 | } |
555 | EXPORT_SYMBOL(udpv6_encap_enable); | 555 | EXPORT_SYMBOL(udpv6_encap_enable); |
556 | 556 | ||
557 | static int udpv6_queue_rcv_skb(struct sock *sk, struct sk_buff *skb) | 557 | static int udpv6_queue_rcv_one_skb(struct sock *sk, struct sk_buff *skb) |
558 | { | 558 | { |
559 | struct udp_sock *up = udp_sk(sk); | 559 | struct udp_sock *up = udp_sk(sk); |
560 | int is_udplite = IS_UDPLITE(sk); | 560 | int is_udplite = IS_UDPLITE(sk); |
@@ -637,6 +637,28 @@ drop: | |||
637 | return -1; | 637 | return -1; |
638 | } | 638 | } |
639 | 639 | ||
640 | static int udpv6_queue_rcv_skb(struct sock *sk, struct sk_buff *skb) | ||
641 | { | ||
642 | struct sk_buff *next, *segs; | ||
643 | int ret; | ||
644 | |||
645 | if (likely(!udp_unexpected_gso(sk, skb))) | ||
646 | return udpv6_queue_rcv_one_skb(sk, skb); | ||
647 | |||
648 | __skb_push(skb, -skb_mac_offset(skb)); | ||
649 | segs = udp_rcv_segment(sk, skb, false); | ||
650 | for (skb = segs; skb; skb = next) { | ||
651 | next = skb->next; | ||
652 | __skb_pull(skb, skb_transport_offset(skb)); | ||
653 | |||
654 | ret = udpv6_queue_rcv_one_skb(sk, skb); | ||
655 | if (ret > 0) | ||
656 | ip6_protocol_deliver_rcu(dev_net(skb->dev), skb, ret, | ||
657 | true); | ||
658 | } | ||
659 | return 0; | ||
660 | } | ||
661 | |||
640 | static bool __udp_v6_is_mcast_sock(struct net *net, struct sock *sk, | 662 | static bool __udp_v6_is_mcast_sock(struct net *net, struct sock *sk, |
641 | __be16 loc_port, const struct in6_addr *loc_addr, | 663 | __be16 loc_port, const struct in6_addr *loc_addr, |
642 | __be16 rmt_port, const struct in6_addr *rmt_addr, | 664 | __be16 rmt_port, const struct in6_addr *rmt_addr, |