aboutsummaryrefslogtreecommitdiffstats
path: root/net/core/skbuff.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/core/skbuff.c')
-rw-r--r--net/core/skbuff.c140
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
3571static __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
3574static int skb_checksum_setup_ip(struct sk_buff *skb, bool recalculate) 3605static 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
3645out: 3641out:
@@ -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
3789out: 3749out:
@@ -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):