@@ -672,65 +672,62 @@ static int rawv6_send_hdrinc(struct sock *sk, void *from, int length,
672
672
return err ;
673
673
}
674
674
675
- static int rawv6_probe_proto_opt (struct flowi6 * fl6 , struct msghdr * msg )
675
+ struct raw6_frag_vec {
676
+ struct msghdr * msg ;
677
+ int hlen ;
678
+ char c [4 ];
679
+ };
680
+
681
+ static int rawv6_probe_proto_opt (struct raw6_frag_vec * rfv , struct flowi6 * fl6 )
676
682
{
677
- struct iovec * iov ;
678
- u8 __user * type = NULL ;
679
- u8 __user * code = NULL ;
680
- u8 len = 0 ;
681
- int probed = 0 ;
682
- int i ;
683
-
684
- if (!msg -> msg_iov )
685
- return 0 ;
683
+ int err = 0 ;
684
+ switch (fl6 -> flowi6_proto ) {
685
+ case IPPROTO_ICMPV6 :
686
+ rfv -> hlen = 2 ;
687
+ err = memcpy_from_msg (rfv -> c , rfv -> msg , rfv -> hlen );
688
+ if (!err ) {
689
+ fl6 -> fl6_icmp_type = rfv -> c [0 ];
690
+ fl6 -> fl6_icmp_code = rfv -> c [1 ];
691
+ }
692
+ break ;
693
+ case IPPROTO_MH :
694
+ rfv -> hlen = 4 ;
695
+ err = memcpy_from_msg (rfv -> c , rfv -> msg , rfv -> hlen );
696
+ if (!err )
697
+ fl6 -> fl6_mh_type = rfv -> c [2 ];
698
+ }
699
+ return err ;
700
+ }
686
701
687
- for ( i = 0 ; i < msg -> msg_iovlen ; i ++ ) {
688
- iov = & msg -> msg_iov [ i ];
689
- if (! iov )
690
- continue ;
702
+ static int raw6_getfrag ( void * from , char * to , int offset , int len , int odd ,
703
+ struct sk_buff * skb )
704
+ {
705
+ struct raw6_frag_vec * rfv = from ;
691
706
692
- switch (fl6 -> flowi6_proto ) {
693
- case IPPROTO_ICMPV6 :
694
- /* check if one-byte field is readable or not. */
695
- if (iov -> iov_base && iov -> iov_len < 1 )
696
- break ;
697
-
698
- if (!type ) {
699
- type = iov -> iov_base ;
700
- /* check if code field is readable or not. */
701
- if (iov -> iov_len > 1 )
702
- code = type + 1 ;
703
- } else if (!code )
704
- code = iov -> iov_base ;
705
-
706
- if (type && code ) {
707
- if (get_user (fl6 -> fl6_icmp_type , type ) ||
708
- get_user (fl6 -> fl6_icmp_code , code ))
709
- return - EFAULT ;
710
- probed = 1 ;
711
- }
712
- break ;
713
- case IPPROTO_MH :
714
- if (iov -> iov_base && iov -> iov_len < 1 )
715
- break ;
716
- /* check if type field is readable or not. */
717
- if (iov -> iov_len > 2 - len ) {
718
- u8 __user * p = iov -> iov_base ;
719
- if (get_user (fl6 -> fl6_mh_type , & p [2 - len ]))
720
- return - EFAULT ;
721
- probed = 1 ;
722
- } else
723
- len += iov -> iov_len ;
707
+ if (offset < rfv -> hlen ) {
708
+ int copy = min (rfv -> hlen - offset , len );
724
709
725
- break ;
726
- default :
727
- probed = 1 ;
728
- break ;
729
- }
730
- if (probed )
731
- break ;
710
+ if (skb -> ip_summed == CHECKSUM_PARTIAL )
711
+ memcpy (to , rfv -> c + offset , copy );
712
+ else
713
+ skb -> csum = csum_block_add (
714
+ skb -> csum ,
715
+ csum_partial_copy_nocheck (rfv -> c + offset ,
716
+ to , copy , 0 ),
717
+ odd );
718
+
719
+ odd = 0 ;
720
+ offset += copy ;
721
+ to += copy ;
722
+ len -= copy ;
723
+
724
+ if (!len )
725
+ return 0 ;
732
726
}
733
- return 0 ;
727
+
728
+ offset -= rfv -> hlen ;
729
+
730
+ return ip_generic_getfrag (rfv -> msg -> msg_iov , to , offset , len , odd , skb );
734
731
}
735
732
736
733
static int rawv6_sendmsg (struct kiocb * iocb , struct sock * sk ,
@@ -745,6 +742,7 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk,
745
742
struct ipv6_txoptions * opt = NULL ;
746
743
struct ip6_flowlabel * flowlabel = NULL ;
747
744
struct dst_entry * dst = NULL ;
745
+ struct raw6_frag_vec rfv ;
748
746
struct flowi6 fl6 ;
749
747
int addr_len = msg -> msg_namelen ;
750
748
int hlimit = -1 ;
@@ -848,7 +846,9 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk,
848
846
opt = ipv6_fixup_options (& opt_space , opt );
849
847
850
848
fl6 .flowi6_proto = proto ;
851
- err = rawv6_probe_proto_opt (& fl6 , msg );
849
+ rfv .msg = msg ;
850
+ rfv .hlen = 0 ;
851
+ err = rawv6_probe_proto_opt (& rfv , & fl6 );
852
852
if (err )
853
853
goto out ;
854
854
@@ -889,7 +889,7 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk,
889
889
err = rawv6_send_hdrinc (sk , msg -> msg_iov , len , & fl6 , & dst , msg -> msg_flags );
890
890
else {
891
891
lock_sock (sk );
892
- err = ip6_append_data (sk , ip_generic_getfrag , msg -> msg_iov ,
892
+ err = ip6_append_data (sk , raw6_getfrag , & rfv ,
893
893
len , 0 , hlimit , tclass , opt , & fl6 , (struct rt6_info * )dst ,
894
894
msg -> msg_flags , dontfrag );
895
895
0 commit comments