|
@@ -3511,32 +3511,33 @@ struct sk_buff *sock_dequeue_err_skb(struct sock *sk)
|
|
|
}
|
|
|
EXPORT_SYMBOL(sock_dequeue_err_skb);
|
|
|
|
|
|
-void __skb_tstamp_tx(struct sk_buff *orig_skb,
|
|
|
- struct skb_shared_hwtstamps *hwtstamps,
|
|
|
- struct sock *sk, int tstype)
|
|
|
+struct sk_buff *skb_clone_sk(struct sk_buff *skb)
|
|
|
{
|
|
|
- struct sock_exterr_skb *serr;
|
|
|
- struct sk_buff *skb;
|
|
|
- int err;
|
|
|
+ struct sock *sk = skb->sk;
|
|
|
+ struct sk_buff *clone;
|
|
|
|
|
|
- if (!sk)
|
|
|
- return;
|
|
|
+ if (!sk || !atomic_inc_not_zero(&sk->sk_refcnt))
|
|
|
+ return NULL;
|
|
|
|
|
|
- if (hwtstamps) {
|
|
|
- *skb_hwtstamps(orig_skb) =
|
|
|
- *hwtstamps;
|
|
|
- } else {
|
|
|
- /*
|
|
|
- * no hardware time stamps available,
|
|
|
- * so keep the shared tx_flags and only
|
|
|
- * store software time stamp
|
|
|
- */
|
|
|
- orig_skb->tstamp = ktime_get_real();
|
|
|
+ clone = skb_clone(skb, GFP_ATOMIC);
|
|
|
+ if (!clone) {
|
|
|
+ sock_put(sk);
|
|
|
+ return NULL;
|
|
|
}
|
|
|
|
|
|
- skb = skb_clone(orig_skb, GFP_ATOMIC);
|
|
|
- if (!skb)
|
|
|
- return;
|
|
|
+ clone->sk = sk;
|
|
|
+ clone->destructor = sock_efree;
|
|
|
+
|
|
|
+ return clone;
|
|
|
+}
|
|
|
+EXPORT_SYMBOL(skb_clone_sk);
|
|
|
+
|
|
|
+static void __skb_complete_tx_timestamp(struct sk_buff *skb,
|
|
|
+ struct sock *sk,
|
|
|
+ int tstype)
|
|
|
+{
|
|
|
+ struct sock_exterr_skb *serr;
|
|
|
+ int err;
|
|
|
|
|
|
serr = SKB_EXT_ERR(skb);
|
|
|
memset(serr, 0, sizeof(*serr));
|
|
@@ -3554,6 +3555,42 @@ void __skb_tstamp_tx(struct sk_buff *orig_skb,
|
|
|
if (err)
|
|
|
kfree_skb(skb);
|
|
|
}
|
|
|
+
|
|
|
+void skb_complete_tx_timestamp(struct sk_buff *skb,
|
|
|
+ struct skb_shared_hwtstamps *hwtstamps)
|
|
|
+{
|
|
|
+ struct sock *sk = skb->sk;
|
|
|
+
|
|
|
+ /* take a reference to prevent skb_orphan() from freeing the socket */
|
|
|
+ sock_hold(sk);
|
|
|
+
|
|
|
+ *skb_hwtstamps(skb) = *hwtstamps;
|
|
|
+ __skb_complete_tx_timestamp(skb, sk, SCM_TSTAMP_SND);
|
|
|
+
|
|
|
+ sock_put(sk);
|
|
|
+}
|
|
|
+EXPORT_SYMBOL_GPL(skb_complete_tx_timestamp);
|
|
|
+
|
|
|
+void __skb_tstamp_tx(struct sk_buff *orig_skb,
|
|
|
+ struct skb_shared_hwtstamps *hwtstamps,
|
|
|
+ struct sock *sk, int tstype)
|
|
|
+{
|
|
|
+ struct sk_buff *skb;
|
|
|
+
|
|
|
+ if (!sk)
|
|
|
+ return;
|
|
|
+
|
|
|
+ if (hwtstamps)
|
|
|
+ *skb_hwtstamps(orig_skb) = *hwtstamps;
|
|
|
+ else
|
|
|
+ orig_skb->tstamp = ktime_get_real();
|
|
|
+
|
|
|
+ skb = skb_clone(orig_skb, GFP_ATOMIC);
|
|
|
+ if (!skb)
|
|
|
+ return;
|
|
|
+
|
|
|
+ __skb_complete_tx_timestamp(skb, sk, tstype);
|
|
|
+}
|
|
|
EXPORT_SYMBOL_GPL(__skb_tstamp_tx);
|
|
|
|
|
|
void skb_tstamp_tx(struct sk_buff *orig_skb,
|