diff options
-rw-r--r-- | net/core/skbuff.c | 140 |
1 files changed, 50 insertions, 90 deletions
diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 465a01c97c76..8b52dfc56c0e 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c | |||
@@ -3566,15 +3566,47 @@ static int skb_maybe_pull_tail(struct sk_buff *skb, unsigned int len, | |||
3566 | return 0; | 3566 | return 0; |
3567 | } | 3567 | } |
3568 | 3568 | ||
3569 | #define MAX_TCP_HDR_LEN (15 * 4) | ||
3570 | |||
3571 | static __sum16 *skb_checksum_setup_ip(struct sk_buff *skb, | ||
3572 | typeof(IPPROTO_IP) proto, | ||
3573 | unsigned int off) | ||
3574 | { | ||
3575 | switch (proto) { | ||
3576 | int err; | ||
3577 | |||
3578 | case IPPROTO_TCP: | ||
3579 | err = skb_maybe_pull_tail(skb, off + sizeof(struct tcphdr), | ||
3580 | off + MAX_TCP_HDR_LEN); | ||
3581 | if (!err && !skb_partial_csum_set(skb, off, | ||
3582 | offsetof(struct tcphdr, | ||
3583 | check))) | ||
3584 | err = -EPROTO; | ||
3585 | return err ? ERR_PTR(err) : &tcp_hdr(skb)->check; | ||
3586 | |||
3587 | case IPPROTO_UDP: | ||
3588 | err = skb_maybe_pull_tail(skb, off + sizeof(struct udphdr), | ||
3589 | off + sizeof(struct udphdr)); | ||
3590 | if (!err && !skb_partial_csum_set(skb, off, | ||
3591 | offsetof(struct udphdr, | ||
3592 | check))) | ||
3593 | err = -EPROTO; | ||
3594 | return err ? ERR_PTR(err) : &udp_hdr(skb)->check; | ||
3595 | } | ||
3596 | |||
3597 | return ERR_PTR(-EPROTO); | ||
3598 | } | ||
3599 | |||
3569 | /* This value should be large enough to cover a tagged ethernet header plus | 3600 | /* This value should be large enough to cover a tagged ethernet header plus |
3570 | * maximally sized IP and TCP or UDP headers. | 3601 | * maximally sized IP and TCP or UDP headers. |
3571 | */ | 3602 | */ |
3572 | #define MAX_IP_HDR_LEN 128 | 3603 | #define MAX_IP_HDR_LEN 128 |
3573 | 3604 | ||
3574 | static int skb_checksum_setup_ip(struct sk_buff *skb, bool recalculate) | 3605 | static int skb_checksum_setup_ipv4(struct sk_buff *skb, bool recalculate) |
3575 | { | 3606 | { |
3576 | unsigned int off; | 3607 | unsigned int off; |
3577 | bool fragment; | 3608 | bool fragment; |
3609 | __sum16 *csum; | ||
3578 | int err; | 3610 | int err; |
3579 | 3611 | ||
3580 | fragment = false; | 3612 | fragment = false; |
@@ -3595,51 +3627,15 @@ static int skb_checksum_setup_ip(struct sk_buff *skb, bool recalculate) | |||
3595 | if (fragment) | 3627 | if (fragment) |
3596 | goto out; | 3628 | goto out; |
3597 | 3629 | ||
3598 | switch (ip_hdr(skb)->protocol) { | 3630 | csum = skb_checksum_setup_ip(skb, ip_hdr(skb)->protocol, off); |
3599 | case IPPROTO_TCP: | 3631 | if (IS_ERR(csum)) |
3600 | err = skb_maybe_pull_tail(skb, | 3632 | return PTR_ERR(csum); |
3601 | off + sizeof(struct tcphdr), | ||
3602 | MAX_IP_HDR_LEN); | ||
3603 | if (err < 0) | ||
3604 | goto out; | ||
3605 | |||
3606 | if (!skb_partial_csum_set(skb, off, | ||
3607 | offsetof(struct tcphdr, check))) { | ||
3608 | err = -EPROTO; | ||
3609 | goto out; | ||
3610 | } | ||
3611 | |||
3612 | if (recalculate) | ||
3613 | tcp_hdr(skb)->check = | ||
3614 | ~csum_tcpudp_magic(ip_hdr(skb)->saddr, | ||
3615 | ip_hdr(skb)->daddr, | ||
3616 | skb->len - off, | ||
3617 | IPPROTO_TCP, 0); | ||
3618 | break; | ||
3619 | case IPPROTO_UDP: | ||
3620 | err = skb_maybe_pull_tail(skb, | ||
3621 | off + sizeof(struct udphdr), | ||
3622 | MAX_IP_HDR_LEN); | ||
3623 | if (err < 0) | ||
3624 | goto out; | ||
3625 | |||
3626 | if (!skb_partial_csum_set(skb, off, | ||
3627 | offsetof(struct udphdr, check))) { | ||
3628 | err = -EPROTO; | ||
3629 | goto out; | ||
3630 | } | ||
3631 | |||
3632 | if (recalculate) | ||
3633 | udp_hdr(skb)->check = | ||
3634 | ~csum_tcpudp_magic(ip_hdr(skb)->saddr, | ||
3635 | ip_hdr(skb)->daddr, | ||
3636 | skb->len - off, | ||
3637 | IPPROTO_UDP, 0); | ||
3638 | break; | ||
3639 | default: | ||
3640 | goto out; | ||
3641 | } | ||
3642 | 3633 | ||
3634 | if (recalculate) | ||
3635 | *csum = ~csum_tcpudp_magic(ip_hdr(skb)->saddr, | ||
3636 | ip_hdr(skb)->daddr, | ||
3637 | skb->len - off, | ||
3638 | ip_hdr(skb)->protocol, 0); | ||
3643 | err = 0; | 3639 | err = 0; |
3644 | 3640 | ||
3645 | out: | 3641 | out: |
@@ -3662,6 +3658,7 @@ static int skb_checksum_setup_ipv6(struct sk_buff *skb, bool recalculate) | |||
3662 | unsigned int len; | 3658 | unsigned int len; |
3663 | bool fragment; | 3659 | bool fragment; |
3664 | bool done; | 3660 | bool done; |
3661 | __sum16 *csum; | ||
3665 | 3662 | ||
3666 | fragment = false; | 3663 | fragment = false; |
3667 | done = false; | 3664 | done = false; |
@@ -3739,51 +3736,14 @@ static int skb_checksum_setup_ipv6(struct sk_buff *skb, bool recalculate) | |||
3739 | if (!done || fragment) | 3736 | if (!done || fragment) |
3740 | goto out; | 3737 | goto out; |
3741 | 3738 | ||
3742 | switch (nexthdr) { | 3739 | csum = skb_checksum_setup_ip(skb, nexthdr, off); |
3743 | case IPPROTO_TCP: | 3740 | if (IS_ERR(csum)) |
3744 | err = skb_maybe_pull_tail(skb, | 3741 | return PTR_ERR(csum); |
3745 | off + sizeof(struct tcphdr), | ||
3746 | MAX_IPV6_HDR_LEN); | ||
3747 | if (err < 0) | ||
3748 | goto out; | ||
3749 | |||
3750 | if (!skb_partial_csum_set(skb, off, | ||
3751 | offsetof(struct tcphdr, check))) { | ||
3752 | err = -EPROTO; | ||
3753 | goto out; | ||
3754 | } | ||
3755 | |||
3756 | if (recalculate) | ||
3757 | tcp_hdr(skb)->check = | ||
3758 | ~csum_ipv6_magic(&ipv6_hdr(skb)->saddr, | ||
3759 | &ipv6_hdr(skb)->daddr, | ||
3760 | skb->len - off, | ||
3761 | IPPROTO_TCP, 0); | ||
3762 | break; | ||
3763 | case IPPROTO_UDP: | ||
3764 | err = skb_maybe_pull_tail(skb, | ||
3765 | off + sizeof(struct udphdr), | ||
3766 | MAX_IPV6_HDR_LEN); | ||
3767 | if (err < 0) | ||
3768 | goto out; | ||
3769 | |||
3770 | if (!skb_partial_csum_set(skb, off, | ||
3771 | offsetof(struct udphdr, check))) { | ||
3772 | err = -EPROTO; | ||
3773 | goto out; | ||
3774 | } | ||
3775 | |||
3776 | if (recalculate) | ||
3777 | udp_hdr(skb)->check = | ||
3778 | ~csum_ipv6_magic(&ipv6_hdr(skb)->saddr, | ||
3779 | &ipv6_hdr(skb)->daddr, | ||
3780 | skb->len - off, | ||
3781 | IPPROTO_UDP, 0); | ||
3782 | break; | ||
3783 | default: | ||
3784 | goto out; | ||
3785 | } | ||
3786 | 3742 | ||
3743 | if (recalculate) | ||
3744 | *csum = ~csum_ipv6_magic(&ipv6_hdr(skb)->saddr, | ||
3745 | &ipv6_hdr(skb)->daddr, | ||
3746 | skb->len - off, nexthdr, 0); | ||
3787 | err = 0; | 3747 | err = 0; |
3788 | 3748 | ||
3789 | out: | 3749 | out: |
@@ -3801,7 +3761,7 @@ int skb_checksum_setup(struct sk_buff *skb, bool recalculate) | |||
3801 | 3761 | ||
3802 | switch (skb->protocol) { | 3762 | switch (skb->protocol) { |
3803 | case htons(ETH_P_IP): | 3763 | case htons(ETH_P_IP): |
3804 | err = skb_checksum_setup_ip(skb, recalculate); | 3764 | err = skb_checksum_setup_ipv4(skb, recalculate); |
3805 | break; | 3765 | break; |
3806 | 3766 | ||
3807 | case htons(ETH_P_IPV6): | 3767 | case htons(ETH_P_IPV6): |