static int rawv6_recvmsg ( struct kiocb * iocb , struct sock * sk , struct msghdr * msg , size_t len , int noblock , int flags , int * addr_len ) {
 struct ipv6_pinfo * np = inet6_sk ( sk ) ;
 struct sockaddr_in6 * sin6 = ( struct sockaddr_in6 * ) msg -> msg_name ;
 struct sk_buff * skb ;
 size_t copied ;
 int err ;
 if ( flags & MSG_OOB ) return - EOPNOTSUPP ;
 if ( addr_len ) * addr_len = sizeof ( * sin6 ) ;
 if ( flags & MSG_ERRQUEUE ) return ipv6_recv_error ( sk , msg , len ) ;
 if ( np -> rxpmtu && np -> rxopt . bits . rxpmtu ) return ipv6_recv_rxpmtu ( sk , msg , len ) ;
 skb = skb_recv_datagram ( sk , flags , noblock , & err ) ;
 if ( ! skb ) goto out ;
 copied = skb -> len ;
 if ( copied > len ) {
 copied = len ;
 msg -> msg_flags |= MSG_TRUNC ;
 }
 if ( skb_csum_unnecessary ( skb ) ) {
 err = skb_copy_datagram_iovec ( skb , 0 , msg -> msg_iov , copied ) ;
 }
 else if ( msg -> msg_flags & MSG_TRUNC ) {
 if ( __skb_checksum_complete ( skb ) ) goto csum_copy_err ;
 err = skb_copy_datagram_iovec ( skb , 0 , msg -> msg_iov , copied ) ;
 }
 else {
 err = skb_copy_and_csum_datagram_iovec ( skb , 0 , msg -> msg_iov ) ;
 if ( err == - EINVAL ) goto csum_copy_err ;
 }
 if ( err ) goto out_free ;
 if ( sin6 ) {
 sin6 -> sin6_family = AF_INET6 ;
 sin6 -> sin6_port = 0 ;
 ipv6_addr_copy ( & sin6 -> sin6_addr , & ipv6_hdr ( skb ) -> saddr ) ;
 sin6 -> sin6_flowinfo = 0 ;
 sin6 -> sin6_scope_id = 0 ;
 if ( ipv6_addr_type ( & sin6 -> sin6_addr ) & IPV6_ADDR_LINKLOCAL ) sin6 -> sin6_scope_id = IP6CB ( skb ) -> iif ;
 }
 sock_recv_ts_and_drops ( msg , sk , skb ) ;
 if ( np -> rxopt . all ) datagram_recv_ctl ( sk , msg , skb ) ;
 err = copied ;
 if ( flags & MSG_TRUNC ) err = skb -> len ;
 out_free : skb_free_datagram ( sk , skb ) ;
 out : return err ;
 csum_copy_err : skb_kill_datagram ( sk , skb , flags ) ;
 err = ( flags & MSG_DONTWAIT ) ? - EAGAIN : - EHOSTUNREACH ;
 goto out ;
 }
static int rawv6_recvmsg ( struct kiocb * iocb , struct sock * sk , struct msghdr * msg , size_t len , int noblock , int flags , int * addr_len ) {
 struct ipv6_pinfo * np = inet6_sk ( sk ) ;
 struct sockaddr_in6 * sin6 = ( struct sockaddr_in6 * ) msg -> msg_name ;
 struct sk_buff * skb ;
 size_t copied ;
 int err ;
 if ( flags & MSG_OOB ) return - EOPNOTSUPP ;
 if ( addr_len ) * addr_len = sizeof ( * sin6 ) ;
 if ( flags & MSG_ERRQUEUE ) return ipv6_recv_error ( sk , msg , len ) ;
 if ( np -> rxpmtu && np -> rxopt . bits . rxpmtu ) return ipv6_recv_rxpmtu ( sk , msg , len ) ;
 skb = skb_recv_datagram ( sk , flags , noblock , & err ) ;
 if ( ! skb ) goto out ;
 copied = skb -> len ;
 if ( copied > len ) {
 copied = len ;
 msg -> msg_flags |= MSG_TRUNC ;
 }
 if ( skb_csum_unnecessary ( skb ) ) {
 err = skb_copy_datagram_iovec ( skb , 0 , msg -> msg_iov , copied ) ;
 }
 else if ( msg -> msg_flags & MSG_TRUNC ) {
 if ( __skb_checksum_complete ( skb ) ) goto csum_copy_err ;
 err = skb_copy_datagram_iovec ( skb , 0 , msg -> msg_iov , copied ) ;
 }
 else {
 err = skb_copy_and_csum_datagram_iovec ( skb , 0 , msg -> msg_iov ) ;
 if ( err == - EINVAL ) goto csum_copy_err ;
 }
 if ( err ) goto out_free ;
 if ( sin6 ) {
 sin6 -> sin6_family = AF_INET6 ;
 sin6 -> sin6_port = 0 ;
 ipv6_addr_copy ( & sin6 -> sin6_addr , & ipv6_hdr ( skb ) -> saddr ) ;
 sin6 -> sin6_flowinfo = 0 ;
 sin6 -> sin6_scope_id = 0 ;
 if ( ipv6_addr_type ( & sin6 -> sin6_addr ) & IPV6_ADDR_LINKLOCAL ) sin6 -> sin6_scope_id = IP6CB ( skb ) -> iif ;
 }
 sock_recv_ts_and_drops ( msg , sk , skb ) ;
 if ( np -> rxopt . all ) datagram_recv_ctl ( sk , msg , skb ) ;
 err = copied ;
 if ( flags & MSG_TRUNC ) err = skb -> len ;
 out_free : skb_free_datagram ( sk , skb ) ;
 out : return err ;
 csum_copy_err : skb_kill_datagram ( sk , skb , flags ) ;
 err = ( flags & MSG_DONTWAIT ) ? - EAGAIN : - EHOSTUNREACH ;
 goto out ;
 }