diff options
Diffstat (limited to 'net/ipv6/reassembly.c')
-rw-r--r-- | net/ipv6/reassembly.c | 62 |
1 files changed, 36 insertions, 26 deletions
diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c index 7034c54e5010..de795c04e34c 100644 --- a/net/ipv6/reassembly.c +++ b/net/ipv6/reassembly.c | |||
@@ -88,7 +88,7 @@ struct frag_queue | |||
88 | int len; | 88 | int len; |
89 | int meat; | 89 | int meat; |
90 | int iif; | 90 | int iif; |
91 | struct timeval stamp; | 91 | ktime_t stamp; |
92 | unsigned int csum; | 92 | unsigned int csum; |
93 | __u8 last_in; /* has first/last segment arrived? */ | 93 | __u8 last_in; /* has first/last segment arrived? */ |
94 | #define COMPLETE 4 | 94 | #define COMPLETE 4 |
@@ -430,19 +430,24 @@ static void ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb, | |||
430 | goto err; | 430 | goto err; |
431 | 431 | ||
432 | offset = ntohs(fhdr->frag_off) & ~0x7; | 432 | offset = ntohs(fhdr->frag_off) & ~0x7; |
433 | end = offset + (ntohs(skb->nh.ipv6h->payload_len) - | 433 | end = offset + (ntohs(ipv6_hdr(skb)->payload_len) - |
434 | ((u8 *) (fhdr + 1) - (u8 *) (skb->nh.ipv6h + 1))); | 434 | ((u8 *)(fhdr + 1) - (u8 *)(ipv6_hdr(skb) + 1))); |
435 | 435 | ||
436 | if ((unsigned int)end > IPV6_MAXPLEN) { | 436 | if ((unsigned int)end > IPV6_MAXPLEN) { |
437 | IP6_INC_STATS_BH(ip6_dst_idev(skb->dst), | 437 | IP6_INC_STATS_BH(ip6_dst_idev(skb->dst), |
438 | IPSTATS_MIB_INHDRERRORS); | 438 | IPSTATS_MIB_INHDRERRORS); |
439 | icmpv6_param_prob(skb,ICMPV6_HDR_FIELD, (u8*)&fhdr->frag_off - skb->nh.raw); | 439 | icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, |
440 | ((u8 *)&fhdr->frag_off - | ||
441 | skb_network_header(skb))); | ||
440 | return; | 442 | return; |
441 | } | 443 | } |
442 | 444 | ||
443 | if (skb->ip_summed == CHECKSUM_COMPLETE) | 445 | if (skb->ip_summed == CHECKSUM_COMPLETE) { |
446 | const unsigned char *nh = skb_network_header(skb); | ||
444 | skb->csum = csum_sub(skb->csum, | 447 | skb->csum = csum_sub(skb->csum, |
445 | csum_partial(skb->nh.raw, (u8*)(fhdr+1)-skb->nh.raw, 0)); | 448 | csum_partial(nh, (u8 *)(fhdr + 1) - nh, |
449 | 0)); | ||
450 | } | ||
446 | 451 | ||
447 | /* Is this the final fragment? */ | 452 | /* Is this the final fragment? */ |
448 | if (!(fhdr->frag_off & htons(IP6_MF))) { | 453 | if (!(fhdr->frag_off & htons(IP6_MF))) { |
@@ -562,7 +567,7 @@ static void ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb, | |||
562 | if (skb->dev) | 567 | if (skb->dev) |
563 | fq->iif = skb->dev->ifindex; | 568 | fq->iif = skb->dev->ifindex; |
564 | skb->dev = NULL; | 569 | skb->dev = NULL; |
565 | skb_get_timestamp(skb, &fq->stamp); | 570 | fq->stamp = skb->tstamp; |
566 | fq->meat += skb->len; | 571 | fq->meat += skb->len; |
567 | atomic_add(skb->truesize, &ip6_frag_mem); | 572 | atomic_add(skb->truesize, &ip6_frag_mem); |
568 | 573 | ||
@@ -605,7 +610,9 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff **skb_in, | |||
605 | BUG_TRAP(FRAG6_CB(head)->offset == 0); | 610 | BUG_TRAP(FRAG6_CB(head)->offset == 0); |
606 | 611 | ||
607 | /* Unfragmented part is taken from the first segment. */ | 612 | /* Unfragmented part is taken from the first segment. */ |
608 | payload_len = (head->data - head->nh.raw) - sizeof(struct ipv6hdr) + fq->len - sizeof(struct frag_hdr); | 613 | payload_len = ((head->data - skb_network_header(head)) - |
614 | sizeof(struct ipv6hdr) + fq->len - | ||
615 | sizeof(struct frag_hdr)); | ||
609 | if (payload_len > IPV6_MAXPLEN) | 616 | if (payload_len > IPV6_MAXPLEN) |
610 | goto out_oversize; | 617 | goto out_oversize; |
611 | 618 | ||
@@ -639,15 +646,15 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff **skb_in, | |||
639 | /* We have to remove fragment header from datagram and to relocate | 646 | /* We have to remove fragment header from datagram and to relocate |
640 | * header in order to calculate ICV correctly. */ | 647 | * header in order to calculate ICV correctly. */ |
641 | nhoff = fq->nhoffset; | 648 | nhoff = fq->nhoffset; |
642 | head->nh.raw[nhoff] = head->h.raw[0]; | 649 | skb_network_header(head)[nhoff] = skb_transport_header(head)[0]; |
643 | memmove(head->head + sizeof(struct frag_hdr), head->head, | 650 | memmove(head->head + sizeof(struct frag_hdr), head->head, |
644 | (head->data - head->head) - sizeof(struct frag_hdr)); | 651 | (head->data - head->head) - sizeof(struct frag_hdr)); |
645 | head->mac.raw += sizeof(struct frag_hdr); | 652 | head->mac_header += sizeof(struct frag_hdr); |
646 | head->nh.raw += sizeof(struct frag_hdr); | 653 | head->network_header += sizeof(struct frag_hdr); |
647 | 654 | ||
648 | skb_shinfo(head)->frag_list = head->next; | 655 | skb_shinfo(head)->frag_list = head->next; |
649 | head->h.raw = head->data; | 656 | skb_reset_transport_header(head); |
650 | skb_push(head, head->data - head->nh.raw); | 657 | skb_push(head, head->data - skb_network_header(head)); |
651 | atomic_sub(head->truesize, &ip6_frag_mem); | 658 | atomic_sub(head->truesize, &ip6_frag_mem); |
652 | 659 | ||
653 | for (fp=head->next; fp; fp = fp->next) { | 660 | for (fp=head->next; fp; fp = fp->next) { |
@@ -663,15 +670,17 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff **skb_in, | |||
663 | 670 | ||
664 | head->next = NULL; | 671 | head->next = NULL; |
665 | head->dev = dev; | 672 | head->dev = dev; |
666 | skb_set_timestamp(head, &fq->stamp); | 673 | head->tstamp = fq->stamp; |
667 | head->nh.ipv6h->payload_len = htons(payload_len); | 674 | ipv6_hdr(head)->payload_len = htons(payload_len); |
668 | IP6CB(head)->nhoff = nhoff; | 675 | IP6CB(head)->nhoff = nhoff; |
669 | 676 | ||
670 | *skb_in = head; | 677 | *skb_in = head; |
671 | 678 | ||
672 | /* Yes, and fold redundant checksum back. 8) */ | 679 | /* Yes, and fold redundant checksum back. 8) */ |
673 | if (head->ip_summed == CHECKSUM_COMPLETE) | 680 | if (head->ip_summed == CHECKSUM_COMPLETE) |
674 | head->csum = csum_partial(head->nh.raw, head->h.raw-head->nh.raw, head->csum); | 681 | head->csum = csum_partial(skb_network_header(head), |
682 | skb_network_header_len(head), | ||
683 | head->csum); | ||
675 | 684 | ||
676 | rcu_read_lock(); | 685 | rcu_read_lock(); |
677 | IP6_INC_STATS_BH(__in6_dev_get(dev), IPSTATS_MIB_REASMOKS); | 686 | IP6_INC_STATS_BH(__in6_dev_get(dev), IPSTATS_MIB_REASMOKS); |
@@ -699,33 +708,34 @@ static int ipv6_frag_rcv(struct sk_buff **skbp) | |||
699 | struct net_device *dev = skb->dev; | 708 | struct net_device *dev = skb->dev; |
700 | struct frag_hdr *fhdr; | 709 | struct frag_hdr *fhdr; |
701 | struct frag_queue *fq; | 710 | struct frag_queue *fq; |
702 | struct ipv6hdr *hdr; | 711 | struct ipv6hdr *hdr = ipv6_hdr(skb); |
703 | |||
704 | hdr = skb->nh.ipv6h; | ||
705 | 712 | ||
706 | IP6_INC_STATS_BH(ip6_dst_idev(skb->dst), IPSTATS_MIB_REASMREQDS); | 713 | IP6_INC_STATS_BH(ip6_dst_idev(skb->dst), IPSTATS_MIB_REASMREQDS); |
707 | 714 | ||
708 | /* Jumbo payload inhibits frag. header */ | 715 | /* Jumbo payload inhibits frag. header */ |
709 | if (hdr->payload_len==0) { | 716 | if (hdr->payload_len==0) { |
710 | IP6_INC_STATS(ip6_dst_idev(skb->dst), IPSTATS_MIB_INHDRERRORS); | 717 | IP6_INC_STATS(ip6_dst_idev(skb->dst), IPSTATS_MIB_INHDRERRORS); |
711 | icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, skb->h.raw-skb->nh.raw); | 718 | icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, |
719 | skb_network_header_len(skb)); | ||
712 | return -1; | 720 | return -1; |
713 | } | 721 | } |
714 | if (!pskb_may_pull(skb, (skb->h.raw-skb->data)+sizeof(struct frag_hdr))) { | 722 | if (!pskb_may_pull(skb, (skb_transport_offset(skb) + |
723 | sizeof(struct frag_hdr)))) { | ||
715 | IP6_INC_STATS(ip6_dst_idev(skb->dst), IPSTATS_MIB_INHDRERRORS); | 724 | IP6_INC_STATS(ip6_dst_idev(skb->dst), IPSTATS_MIB_INHDRERRORS); |
716 | icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, skb->h.raw-skb->nh.raw); | 725 | icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, |
726 | skb_network_header_len(skb)); | ||
717 | return -1; | 727 | return -1; |
718 | } | 728 | } |
719 | 729 | ||
720 | hdr = skb->nh.ipv6h; | 730 | hdr = ipv6_hdr(skb); |
721 | fhdr = (struct frag_hdr *)skb->h.raw; | 731 | fhdr = (struct frag_hdr *)skb_transport_header(skb); |
722 | 732 | ||
723 | if (!(fhdr->frag_off & htons(0xFFF9))) { | 733 | if (!(fhdr->frag_off & htons(0xFFF9))) { |
724 | /* It is not a fragmented frame */ | 734 | /* It is not a fragmented frame */ |
725 | skb->h.raw += sizeof(struct frag_hdr); | 735 | skb->transport_header += sizeof(struct frag_hdr); |
726 | IP6_INC_STATS_BH(ip6_dst_idev(skb->dst), IPSTATS_MIB_REASMOKS); | 736 | IP6_INC_STATS_BH(ip6_dst_idev(skb->dst), IPSTATS_MIB_REASMOKS); |
727 | 737 | ||
728 | IP6CB(skb)->nhoff = (u8*)fhdr - skb->nh.raw; | 738 | IP6CB(skb)->nhoff = (u8 *)fhdr - skb_network_header(skb); |
729 | return 1; | 739 | return 1; |
730 | } | 740 | } |
731 | 741 | ||