@@ -659,18 +659,114 @@ void ip6_fraglist_prepare(struct sk_buff *skb,
659
659
}
660
660
EXPORT_SYMBOL (ip6_fraglist_prepare );
661
661
662
+ void ip6_frag_init (struct sk_buff * skb , unsigned int hlen , unsigned int mtu ,
663
+ unsigned short needed_tailroom , int hdr_room , u8 * prevhdr ,
664
+ u8 nexthdr , __be32 frag_id , struct ip6_frag_state * state )
665
+ {
666
+ state -> prevhdr = prevhdr ;
667
+ state -> nexthdr = nexthdr ;
668
+ state -> frag_id = frag_id ;
669
+
670
+ state -> hlen = hlen ;
671
+ state -> mtu = mtu ;
672
+
673
+ state -> left = skb -> len - hlen ; /* Space per frame */
674
+ state -> ptr = hlen ; /* Where to start from */
675
+
676
+ state -> hroom = hdr_room ;
677
+ state -> troom = needed_tailroom ;
678
+
679
+ state -> offset = 0 ;
680
+ }
681
+ EXPORT_SYMBOL (ip6_frag_init );
682
+
683
+ struct sk_buff * ip6_frag_next (struct sk_buff * skb , struct ip6_frag_state * state )
684
+ {
685
+ u8 * prevhdr = state -> prevhdr , * fragnexthdr_offset ;
686
+ struct sk_buff * frag ;
687
+ struct frag_hdr * fh ;
688
+ unsigned int len ;
689
+
690
+ len = state -> left ;
691
+ /* IF: it doesn't fit, use 'mtu' - the data space left */
692
+ if (len > state -> mtu )
693
+ len = state -> mtu ;
694
+ /* IF: we are not sending up to and including the packet end
695
+ then align the next start on an eight byte boundary */
696
+ if (len < state -> left )
697
+ len &= ~7 ;
698
+
699
+ /* Allocate buffer */
700
+ frag = alloc_skb (len + state -> hlen + sizeof (struct frag_hdr ) +
701
+ state -> hroom + state -> troom , GFP_ATOMIC );
702
+ if (!frag )
703
+ return ERR_PTR (- ENOMEM );
704
+
705
+ /*
706
+ * Set up data on packet
707
+ */
708
+
709
+ ip6_copy_metadata (frag , skb );
710
+ skb_reserve (frag , state -> hroom );
711
+ skb_put (frag , len + state -> hlen + sizeof (struct frag_hdr ));
712
+ skb_reset_network_header (frag );
713
+ fh = (struct frag_hdr * )(skb_network_header (frag ) + state -> hlen );
714
+ frag -> transport_header = (frag -> network_header + state -> hlen +
715
+ sizeof (struct frag_hdr ));
716
+
717
+ /*
718
+ * Charge the memory for the fragment to any owner
719
+ * it might possess
720
+ */
721
+ if (skb -> sk )
722
+ skb_set_owner_w (frag , skb -> sk );
723
+
724
+ /*
725
+ * Copy the packet header into the new buffer.
726
+ */
727
+ skb_copy_from_linear_data (skb , skb_network_header (frag ), state -> hlen );
728
+
729
+ fragnexthdr_offset = skb_network_header (frag );
730
+ fragnexthdr_offset += prevhdr - skb_network_header (skb );
731
+ * fragnexthdr_offset = NEXTHDR_FRAGMENT ;
732
+
733
+ /*
734
+ * Build fragment header.
735
+ */
736
+ fh -> nexthdr = state -> nexthdr ;
737
+ fh -> reserved = 0 ;
738
+ fh -> identification = state -> frag_id ;
739
+
740
+ /*
741
+ * Copy a block of the IP datagram.
742
+ */
743
+ BUG_ON (skb_copy_bits (skb , state -> ptr , skb_transport_header (frag ),
744
+ len ));
745
+ state -> left -= len ;
746
+
747
+ fh -> frag_off = htons (state -> offset );
748
+ if (state -> left > 0 )
749
+ fh -> frag_off |= htons (IP6_MF );
750
+ ipv6_hdr (frag )-> payload_len = htons (frag -> len - sizeof (struct ipv6hdr ));
751
+
752
+ state -> ptr += len ;
753
+ state -> offset += len ;
754
+
755
+ return frag ;
756
+ }
757
+ EXPORT_SYMBOL (ip6_frag_next );
758
+
662
759
int ip6_fragment (struct net * net , struct sock * sk , struct sk_buff * skb ,
663
760
int (* output )(struct net * , struct sock * , struct sk_buff * ))
664
761
{
665
762
struct sk_buff * frag ;
666
763
struct rt6_info * rt = (struct rt6_info * )skb_dst (skb );
667
764
struct ipv6_pinfo * np = skb -> sk && !dev_recursion_level () ?
668
765
inet6_sk (skb -> sk ) : NULL ;
669
- struct frag_hdr * fh ;
670
- unsigned int mtu , hlen , left , len , nexthdr_offset ;
671
- int hroom , troom ;
766
+ struct ip6_frag_state state ;
767
+ unsigned int mtu , hlen , nexthdr_offset ;
768
+ int hroom , err = 0 ;
672
769
__be32 frag_id ;
673
- int ptr , offset = 0 , err = 0 ;
674
770
u8 * prevhdr , nexthdr = 0 ;
675
771
676
772
err = ip6_find_1stfragopt (skb , & prevhdr );
@@ -792,90 +888,25 @@ int ip6_fragment(struct net *net, struct sock *sk, struct sk_buff *skb,
792
888
}
793
889
794
890
slow_path :
795
- left = skb -> len - hlen ; /* Space per frame */
796
- ptr = hlen ; /* Where to start from */
797
-
798
891
/*
799
892
* Fragment the datagram.
800
893
*/
801
894
802
- troom = rt -> dst .dev -> needed_tailroom ;
895
+ ip6_frag_init (skb , hlen , mtu , rt -> dst .dev -> needed_tailroom ,
896
+ LL_RESERVED_SPACE (rt -> dst .dev ), prevhdr , nexthdr , frag_id ,
897
+ & state );
803
898
804
899
/*
805
900
* Keep copying data until we run out.
806
901
*/
807
- while (left > 0 ) {
808
- u8 * fragnexthdr_offset ;
809
-
810
- len = left ;
811
- /* IF: it doesn't fit, use 'mtu' - the data space left */
812
- if (len > mtu )
813
- len = mtu ;
814
- /* IF: we are not sending up to and including the packet end
815
- then align the next start on an eight byte boundary */
816
- if (len < left ) {
817
- len &= ~7 ;
818
- }
819
902
820
- /* Allocate buffer */
821
- frag = alloc_skb (len + hlen + sizeof (struct frag_hdr ) +
822
- hroom + troom , GFP_ATOMIC );
823
- if (!frag ) {
824
- err = - ENOMEM ;
903
+ while (state .left > 0 ) {
904
+ frag = ip6_frag_next (skb , & state );
905
+ if (IS_ERR (frag )) {
906
+ err = PTR_ERR (frag );
825
907
goto fail ;
826
908
}
827
909
828
- /*
829
- * Set up data on packet
830
- */
831
-
832
- ip6_copy_metadata (frag , skb );
833
- skb_reserve (frag , hroom );
834
- skb_put (frag , len + hlen + sizeof (struct frag_hdr ));
835
- skb_reset_network_header (frag );
836
- fh = (struct frag_hdr * )(skb_network_header (frag ) + hlen );
837
- frag -> transport_header = (frag -> network_header + hlen +
838
- sizeof (struct frag_hdr ));
839
-
840
- /*
841
- * Charge the memory for the fragment to any owner
842
- * it might possess
843
- */
844
- if (skb -> sk )
845
- skb_set_owner_w (frag , skb -> sk );
846
-
847
- /*
848
- * Copy the packet header into the new buffer.
849
- */
850
- skb_copy_from_linear_data (skb , skb_network_header (frag ), hlen );
851
-
852
- fragnexthdr_offset = skb_network_header (frag );
853
- fragnexthdr_offset += prevhdr - skb_network_header (skb );
854
- * fragnexthdr_offset = NEXTHDR_FRAGMENT ;
855
-
856
- /*
857
- * Build fragment header.
858
- */
859
- fh -> nexthdr = nexthdr ;
860
- fh -> reserved = 0 ;
861
- fh -> identification = frag_id ;
862
-
863
- /*
864
- * Copy a block of the IP datagram.
865
- */
866
- BUG_ON (skb_copy_bits (skb , ptr , skb_transport_header (frag ),
867
- len ));
868
- left -= len ;
869
-
870
- fh -> frag_off = htons (offset );
871
- if (left > 0 )
872
- fh -> frag_off |= htons (IP6_MF );
873
- ipv6_hdr (frag )-> payload_len = htons (frag -> len -
874
- sizeof (struct ipv6hdr ));
875
-
876
- ptr += len ;
877
- offset += len ;
878
-
879
910
/*
880
911
* Put this fragment into the sending queue.
881
912
*/
0 commit comments