Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

net: Move rx skb_orphan call to where needed

In order to get the tun driver to account packets, we need to be
able to receive packets with destructors set. To be on the safe
side, I added an skb_orphan call for all protocols by default since
some of them (IP in particular) cannot handle receiving packets
destructors properly.

Now it seems that at least one protocol (CAN) expects to be able
to pass skb->sk through the rx path without getting clobbered.

So this patch attempts to fix this properly by moving the skb_orphan
call to where it's actually needed. In particular, I've added it
to skb_set_owner_[rw] which is what most users of skb->destructor
call.

This is actually an improvement for tun too since it means that
we only give back the amount charged to the socket when the skb
is passed to another socket that will also be charged accordingly.

Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Tested-by: Oliver Hartkopp <olver@hartkopp.net>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Herbert Xu and committed by
David S. Miller
d55d87fd d5fdd6ba

+5 -7
+1
include/net/sctp/sctp.h
··· 448 448 { 449 449 struct sctp_ulpevent *event = sctp_skb2event(skb); 450 450 451 + skb_orphan(skb); 451 452 skb->sk = sk; 452 453 skb->destructor = sctp_sock_rfree; 453 454 atomic_add(event->rmem_len, &sk->sk_rmem_alloc);
+2
include/net/sock.h
··· 1250 1250 1251 1251 static inline void skb_set_owner_w(struct sk_buff *skb, struct sock *sk) 1252 1252 { 1253 + skb_orphan(skb); 1253 1254 skb->sk = sk; 1254 1255 skb->destructor = sock_wfree; 1255 1256 /* ··· 1263 1262 1264 1263 static inline void skb_set_owner_r(struct sk_buff *skb, struct sock *sk) 1265 1264 { 1265 + skb_orphan(skb); 1266 1266 skb->sk = sk; 1267 1267 skb->destructor = sock_rfree; 1268 1268 atomic_add(skb->truesize, &sk->sk_rmem_alloc);
+1 -2
net/ax25/ax25_in.c
··· 437 437 int ax25_kiss_rcv(struct sk_buff *skb, struct net_device *dev, 438 438 struct packet_type *ptype, struct net_device *orig_dev) 439 439 { 440 - skb->sk = NULL; /* Initially we don't know who it's for */ 441 - skb->destructor = NULL; /* Who initializes this, dammit?! */ 440 + skb_orphan(skb); 442 441 443 442 if (!net_eq(dev_net(dev), &init_net)) { 444 443 kfree_skb(skb);
-2
net/core/dev.c
··· 2310 2310 if (!skb) 2311 2311 goto out; 2312 2312 2313 - skb_orphan(skb); 2314 - 2315 2313 type = skb->protocol; 2316 2314 list_for_each_entry_rcu(ptype, 2317 2315 &ptype_base[ntohs(type) & PTYPE_HASH_MASK], list) {
-3
net/irda/af_irda.c
··· 913 913 /* Clean up the original one to keep it in listen state */ 914 914 irttp_listen(self->tsap); 915 915 916 - /* Wow ! What is that ? Jean II */ 917 - skb->sk = NULL; 918 - skb->destructor = NULL; 919 916 kfree_skb(skb); 920 917 sk->sk_ack_backlog--; 921 918
+1
net/irda/ircomm/ircomm_lmp.c
··· 196 196 /* Don't forget to refcount it - see ircomm_tty_do_softint() */ 197 197 skb_get(skb); 198 198 199 + skb_orphan(skb); 199 200 skb->destructor = ircomm_lmp_flow_control; 200 201 201 202 if ((self->pkt_count++ > 7) && (self->flow_status == FLOW_START)) {