]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - net/ipv4/udp.c
udp: preserve head state for IP_CMSG_PASSSEC
[karo-tx-linux.git] / net / ipv4 / udp.c
index b057653ceca9208d1e1765525e5492876c0b651e..d243772f6efc91eb2e975fec8f6ff3414b1c52cf 100644 (file)
@@ -1163,34 +1163,32 @@ out:
        return ret;
 }
 
-#if BITS_PER_LONG == 64
+#define UDP_SKB_IS_STATELESS 0x80000000
+
 static void udp_set_dev_scratch(struct sk_buff *skb)
 {
-       struct udp_dev_scratch *scratch;
+       struct udp_dev_scratch *scratch = udp_skb_scratch(skb);
 
        BUILD_BUG_ON(sizeof(struct udp_dev_scratch) > sizeof(long));
-       scratch = (struct udp_dev_scratch *)&skb->dev_scratch;
-       scratch->truesize = skb->truesize;
+       scratch->_tsize_state = skb->truesize;
+#if BITS_PER_LONG == 64
        scratch->len = skb->len;
        scratch->csum_unnecessary = !!skb_csum_unnecessary(skb);
        scratch->is_linear = !skb_is_nonlinear(skb);
+#endif
+       if (likely(!skb->_skb_refdst))
+               scratch->_tsize_state |= UDP_SKB_IS_STATELESS;
 }
 
 static int udp_skb_truesize(struct sk_buff *skb)
 {
-       return ((struct udp_dev_scratch *)&skb->dev_scratch)->truesize;
-}
-#else
-static void udp_set_dev_scratch(struct sk_buff *skb)
-{
-       skb->dev_scratch = skb->truesize;
+       return udp_skb_scratch(skb)->_tsize_state & ~UDP_SKB_IS_STATELESS;
 }
 
-static int udp_skb_truesize(struct sk_buff *skb)
+static bool udp_skb_has_head_state(struct sk_buff *skb)
 {
-       return skb->dev_scratch;
+       return !(udp_skb_scratch(skb)->_tsize_state & UDP_SKB_IS_STATELESS);
 }
-#endif
 
 /* fully reclaim rmem/fwd memory allocated for skb */
 static void udp_rmem_release(struct sock *sk, int size, int partial,
@@ -1388,10 +1386,10 @@ void skb_consume_udp(struct sock *sk, struct sk_buff *skb, int len)
                unlock_sock_fast(sk, slow);
        }
 
-       /* we cleared the head states previously only if the skb lacks any IP
-        * options, see __udp_queue_rcv_skb().
+       /* In the more common cases we cleared the head states previously,
+        * see __udp_queue_rcv_skb().
         */
-       if (unlikely(IPCB(skb)->opt.optlen > 0))
+       if (unlikely(udp_skb_has_head_state(skb)))
                skb_release_head_state(skb);
        consume_stateless_skb(skb);
 }
@@ -1784,11 +1782,11 @@ static int __udp_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
                sk_mark_napi_id_once(sk, skb);
        }
 
-       /* At recvmsg() time we need skb->dst to process IP options-related
-        * cmsg, elsewhere can we clear all pending head states while they are
-        * hot in the cache
+       /* At recvmsg() time we may access skb->dst or skb->sp depending on
+        * the IP options and the cmsg flags, elsewhere can we clear all
+        * pending head states while they are hot in the cache
         */
-       if (likely(IPCB(skb)->opt.optlen == 0))
+       if (likely(IPCB(skb)->opt.optlen == 0 && !skb->sp))
                skb_release_head_state(skb);
 
        rc = __udp_enqueue_schedule_skb(sk, skb);