net-timestamp: allow reading recv cmsg on errqueue with origin tstamp
[cascardo/linux.git] / net / ipv6 / datagram.c
index 2cdc383..2464a00 100644 (file)
@@ -325,6 +325,16 @@ void ipv6_local_rxpmtu(struct sock *sk, struct flowi6 *fl6, u32 mtu)
        kfree_skb(skb);
 }
 
+static void ip6_datagram_prepare_pktinfo_errqueue(struct sk_buff *skb)
+{
+       int ifindex = skb->dev ? skb->dev->ifindex : -1;
+
+       if (skb->protocol == htons(ETH_P_IPV6))
+               IP6CB(skb)->iif = ifindex;
+       else
+               PKTINFO_SKB_CB(skb)->ipi_ifindex = ifindex;
+}
+
 /*
  *     Handle MSG_ERRQUEUE
  */
@@ -351,7 +361,7 @@ int ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len, int *addr_len)
                msg->msg_flags |= MSG_TRUNC;
                copied = len;
        }
-       err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
+       err = skb_copy_datagram_msg(skb, 0, msg, copied);
        if (err)
                goto out_free_skb;
 
@@ -388,8 +398,12 @@ int ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len, int *addr_len)
                sin->sin6_family = AF_INET6;
                sin->sin6_flowinfo = 0;
                sin->sin6_port = 0;
-               if (np->rxopt.all)
+               if (np->rxopt.all) {
+                       if (serr->ee.ee_origin != SO_EE_ORIGIN_ICMP &&
+                           serr->ee.ee_origin != SO_EE_ORIGIN_ICMP6)
+                               ip6_datagram_prepare_pktinfo_errqueue(skb);
                        ip6_datagram_recv_common_ctl(sk, msg, skb);
+               }
                if (skb->protocol == htons(ETH_P_IPV6)) {
                        sin->sin6_addr = ipv6_hdr(skb)->saddr;
                        if (np->rxopt.all)
@@ -445,7 +459,7 @@ int ipv6_recv_rxpmtu(struct sock *sk, struct msghdr *msg, int len,
                msg->msg_flags |= MSG_TRUNC;
                copied = len;
        }
-       err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
+       err = skb_copy_datagram_msg(skb, 0, msg, copied);
        if (err)
                goto out_free_skb;
 
@@ -491,7 +505,10 @@ void ip6_datagram_recv_common_ctl(struct sock *sk, struct msghdr *msg,
                        ipv6_addr_set_v4mapped(ip_hdr(skb)->daddr,
                                               &src_info.ipi6_addr);
                }
-               put_cmsg(msg, SOL_IPV6, IPV6_PKTINFO, sizeof(src_info), &src_info);
+
+               if (src_info.ipi6_ifindex >= 0)
+                       put_cmsg(msg, SOL_IPV6, IPV6_PKTINFO,
+                                sizeof(src_info), &src_info);
        }
 }
 
@@ -893,8 +910,8 @@ int ip6_datagram_send_ctl(struct net *net, struct sock *sk,
                        break;
                    }
                default:
-                       LIMIT_NETDEBUG(KERN_DEBUG "invalid cmsg type: %d\n",
-                                      cmsg->cmsg_type);
+                       net_dbg_ratelimited("invalid cmsg type: %d\n",
+                                           cmsg->cmsg_type);
                        err = -EINVAL;
                        goto exit_f;
                }