|
@@ -3511,6 +3511,27 @@ struct sk_buff *sock_dequeue_err_skb(struct sock *sk)
|
|
}
|
|
}
|
|
EXPORT_SYMBOL(sock_dequeue_err_skb);
|
|
EXPORT_SYMBOL(sock_dequeue_err_skb);
|
|
|
|
|
|
|
|
+struct sk_buff *skb_clone_sk(struct sk_buff *skb)
|
|
|
|
+{
|
|
|
|
+ struct sock *sk = skb->sk;
|
|
|
|
+ struct sk_buff *clone;
|
|
|
|
+
|
|
|
|
+ if (!sk || !atomic_inc_not_zero(&sk->sk_refcnt))
|
|
|
|
+ return NULL;
|
|
|
|
+
|
|
|
|
+ clone = skb_clone(skb, GFP_ATOMIC);
|
|
|
|
+ if (!clone) {
|
|
|
|
+ sock_put(sk);
|
|
|
|
+ return NULL;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ clone->sk = sk;
|
|
|
|
+ clone->destructor = sock_efree;
|
|
|
|
+
|
|
|
|
+ return clone;
|
|
|
|
+}
|
|
|
|
+EXPORT_SYMBOL(skb_clone_sk);
|
|
|
|
+
|
|
static void __skb_complete_tx_timestamp(struct sk_buff *skb,
|
|
static void __skb_complete_tx_timestamp(struct sk_buff *skb,
|
|
struct sock *sk,
|
|
struct sock *sk,
|
|
int tstype)
|
|
int tstype)
|
|
@@ -3540,14 +3561,11 @@ void skb_complete_tx_timestamp(struct sk_buff *skb,
|
|
{
|
|
{
|
|
struct sock *sk = skb->sk;
|
|
struct sock *sk = skb->sk;
|
|
|
|
|
|
- skb->sk = NULL;
|
|
|
|
|
|
+ /* take a reference to prevent skb_orphan() from freeing the socket */
|
|
|
|
+ sock_hold(sk);
|
|
|
|
|
|
- if (hwtstamps) {
|
|
|
|
- *skb_hwtstamps(skb) = *hwtstamps;
|
|
|
|
- __skb_complete_tx_timestamp(skb, sk, SCM_TSTAMP_SND);
|
|
|
|
- } else {
|
|
|
|
- kfree_skb(skb);
|
|
|
|
- }
|
|
|
|
|
|
+ *skb_hwtstamps(skb) = *hwtstamps;
|
|
|
|
+ __skb_complete_tx_timestamp(skb, sk, SCM_TSTAMP_SND);
|
|
|
|
|
|
sock_put(sk);
|
|
sock_put(sk);
|
|
}
|
|
}
|