]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - net/core/skbuff.c
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
[karo-tx-linux.git] / net / core / skbuff.c
index da1378a3e2c72e0f23e9e21581dfd2ece5491d09..a18dfb02d94492647a50a88797e47d0f698ad62b 100644 (file)
@@ -3491,32 +3491,53 @@ int sock_queue_err_skb(struct sock *sk, struct sk_buff *skb)
 }
 EXPORT_SYMBOL(sock_queue_err_skb);
 
-void __skb_tstamp_tx(struct sk_buff *orig_skb,
-                    struct skb_shared_hwtstamps *hwtstamps,
-                    struct sock *sk, int tstype)
+struct sk_buff *sock_dequeue_err_skb(struct sock *sk)
 {
-       struct sock_exterr_skb *serr;
-       struct sk_buff *skb;
-       int err;
+       struct sk_buff_head *q = &sk->sk_error_queue;
+       struct sk_buff *skb, *skb_next;
+       int err = 0;
 
-       if (!sk)
-               return;
+       spin_lock_bh(&q->lock);
+       skb = __skb_dequeue(q);
+       if (skb && (skb_next = skb_peek(q)))
+               err = SKB_EXT_ERR(skb_next)->ee.ee_errno;
+       spin_unlock_bh(&q->lock);
 
-       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();
+       sk->sk_err = err;
+       if (err)
+               sk->sk_error_report(sk);
+
+       return 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;
        }
 
-       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));
@@ -3534,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,