aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/net/can/dev.c15
-rw-r--r--drivers/net/can/janz-ican3.c18
-rw-r--r--drivers/net/can/vcan.c9
-rw-r--r--include/linux/can/skb.h38
-rw-r--r--net/can/af_can.c3
-rw-r--r--net/can/bcm.c4
6 files changed, 53 insertions, 34 deletions
diff --git a/drivers/net/can/dev.c b/drivers/net/can/dev.c
index 13a909822e25..fc59bc6f040b 100644
--- a/drivers/net/can/dev.c
+++ b/drivers/net/can/dev.c
@@ -323,19 +323,10 @@ void can_put_echo_skb(struct sk_buff *skb, struct net_device *dev,
323 } 323 }
324 324
325 if (!priv->echo_skb[idx]) { 325 if (!priv->echo_skb[idx]) {
326 struct sock *srcsk = skb->sk;
327 326
328 if (atomic_read(&skb->users) != 1) { 327 skb = can_create_echo_skb(skb);
329 struct sk_buff *old_skb = skb; 328 if (!skb)
330 329 return;
331 skb = skb_clone(old_skb, GFP_ATOMIC);
332 kfree_skb(old_skb);
333 if (!skb)
334 return;
335 } else
336 skb_orphan(skb);
337
338 skb->sk = srcsk;
339 330
340 /* make settings for echo to reduce code in irq context */ 331 /* make settings for echo to reduce code in irq context */
341 skb->protocol = htons(ETH_P_CAN); 332 skb->protocol = htons(ETH_P_CAN);
diff --git a/drivers/net/can/janz-ican3.c b/drivers/net/can/janz-ican3.c
index e24e6690d672..2124c6790687 100644
--- a/drivers/net/can/janz-ican3.c
+++ b/drivers/net/can/janz-ican3.c
@@ -18,6 +18,7 @@
18#include <linux/netdevice.h> 18#include <linux/netdevice.h>
19#include <linux/can.h> 19#include <linux/can.h>
20#include <linux/can/dev.h> 20#include <linux/can/dev.h>
21#include <linux/can/skb.h>
21#include <linux/can/error.h> 22#include <linux/can/error.h>
22 23
23#include <linux/mfd/janz.h> 24#include <linux/mfd/janz.h>
@@ -1133,20 +1134,9 @@ static void ican3_handle_message(struct ican3_dev *mod, struct ican3_msg *msg)
1133 */ 1134 */
1134static void ican3_put_echo_skb(struct ican3_dev *mod, struct sk_buff *skb) 1135static void ican3_put_echo_skb(struct ican3_dev *mod, struct sk_buff *skb)
1135{ 1136{
1136 struct sock *srcsk = skb->sk; 1137 skb = can_create_echo_skb(skb);
1137 1138 if (!skb)
1138 if (atomic_read(&skb->users) != 1) { 1139 return;
1139 struct sk_buff *old_skb = skb;
1140
1141 skb = skb_clone(old_skb, GFP_ATOMIC);
1142 kfree_skb(old_skb);
1143 if (!skb)
1144 return;
1145 } else {
1146 skb_orphan(skb);
1147 }
1148
1149 skb->sk = srcsk;
1150 1140
1151 /* save this skb for tx interrupt echo handling */ 1141 /* save this skb for tx interrupt echo handling */
1152 skb_queue_tail(&mod->echoq, skb); 1142 skb_queue_tail(&mod->echoq, skb);
diff --git a/drivers/net/can/vcan.c b/drivers/net/can/vcan.c
index 0a2a5ee79a17..4e94057ef5cf 100644
--- a/drivers/net/can/vcan.c
+++ b/drivers/net/can/vcan.c
@@ -46,6 +46,7 @@
46#include <linux/if_ether.h> 46#include <linux/if_ether.h>
47#include <linux/can.h> 47#include <linux/can.h>
48#include <linux/can/dev.h> 48#include <linux/can/dev.h>
49#include <linux/can/skb.h>
49#include <linux/slab.h> 50#include <linux/slab.h>
50#include <net/rtnetlink.h> 51#include <net/rtnetlink.h>
51 52
@@ -109,25 +110,23 @@ static netdev_tx_t vcan_tx(struct sk_buff *skb, struct net_device *dev)
109 stats->rx_packets++; 110 stats->rx_packets++;
110 stats->rx_bytes += cfd->len; 111 stats->rx_bytes += cfd->len;
111 } 112 }
112 kfree_skb(skb); 113 consume_skb(skb);
113 return NETDEV_TX_OK; 114 return NETDEV_TX_OK;
114 } 115 }
115 116
116 /* perform standard echo handling for CAN network interfaces */ 117 /* perform standard echo handling for CAN network interfaces */
117 118
118 if (loop) { 119 if (loop) {
119 struct sock *srcsk = skb->sk;
120 120
121 skb = skb_share_check(skb, GFP_ATOMIC); 121 skb = can_create_echo_skb(skb);
122 if (!skb) 122 if (!skb)
123 return NETDEV_TX_OK; 123 return NETDEV_TX_OK;
124 124
125 /* receive with packet counting */ 125 /* receive with packet counting */
126 skb->sk = srcsk;
127 vcan_rx(skb, dev); 126 vcan_rx(skb, dev);
128 } else { 127 } else {
129 /* no looped packets => no counting */ 128 /* no looped packets => no counting */
130 kfree_skb(skb); 129 consume_skb(skb);
131 } 130 }
132 return NETDEV_TX_OK; 131 return NETDEV_TX_OK;
133} 132}
diff --git a/include/linux/can/skb.h b/include/linux/can/skb.h
index 2f0543f7510c..f9bbbb472663 100644
--- a/include/linux/can/skb.h
+++ b/include/linux/can/skb.h
@@ -11,7 +11,9 @@
11#define CAN_SKB_H 11#define CAN_SKB_H
12 12
13#include <linux/types.h> 13#include <linux/types.h>
14#include <linux/skbuff.h>
14#include <linux/can.h> 15#include <linux/can.h>
16#include <net/sock.h>
15 17
16/* 18/*
17 * The struct can_skb_priv is used to transport additional information along 19 * The struct can_skb_priv is used to transport additional information along
@@ -42,4 +44,40 @@ static inline void can_skb_reserve(struct sk_buff *skb)
42 skb_reserve(skb, sizeof(struct can_skb_priv)); 44 skb_reserve(skb, sizeof(struct can_skb_priv));
43} 45}
44 46
47static inline void can_skb_destructor(struct sk_buff *skb)
48{
49 sock_put(skb->sk);
50}
51
52static inline void can_skb_set_owner(struct sk_buff *skb, struct sock *sk)
53{
54 if (sk) {
55 sock_hold(sk);
56 skb->destructor = can_skb_destructor;
57 skb->sk = sk;
58 }
59}
60
61/*
62 * returns an unshared skb owned by the original sock to be echo'ed back
63 */
64static inline struct sk_buff *can_create_echo_skb(struct sk_buff *skb)
65{
66 if (skb_shared(skb)) {
67 struct sk_buff *nskb = skb_clone(skb, GFP_ATOMIC);
68
69 if (likely(nskb)) {
70 can_skb_set_owner(nskb, skb->sk);
71 consume_skb(skb);
72 return nskb;
73 } else {
74 kfree_skb(skb);
75 return NULL;
76 }
77 }
78
79 /* we can assume to have an unshared skb with proper owner */
80 return skb;
81}
82
45#endif /* CAN_SKB_H */ 83#endif /* CAN_SKB_H */
diff --git a/net/can/af_can.c b/net/can/af_can.c
index d249874a366d..a27f8aad9e99 100644
--- a/net/can/af_can.c
+++ b/net/can/af_can.c
@@ -57,6 +57,7 @@
57#include <linux/skbuff.h> 57#include <linux/skbuff.h>
58#include <linux/can.h> 58#include <linux/can.h>
59#include <linux/can/core.h> 59#include <linux/can/core.h>
60#include <linux/can/skb.h>
60#include <linux/ratelimit.h> 61#include <linux/ratelimit.h>
61#include <net/net_namespace.h> 62#include <net/net_namespace.h>
62#include <net/sock.h> 63#include <net/sock.h>
@@ -290,7 +291,7 @@ int can_send(struct sk_buff *skb, int loop)
290 return -ENOMEM; 291 return -ENOMEM;
291 } 292 }
292 293
293 newskb->sk = skb->sk; 294 can_skb_set_owner(newskb, skb->sk);
294 newskb->ip_summed = CHECKSUM_UNNECESSARY; 295 newskb->ip_summed = CHECKSUM_UNNECESSARY;
295 newskb->pkt_type = PACKET_BROADCAST; 296 newskb->pkt_type = PACKET_BROADCAST;
296 } 297 }
diff --git a/net/can/bcm.c b/net/can/bcm.c
index 3fc737b214c7..dcb75c0e66c1 100644
--- a/net/can/bcm.c
+++ b/net/can/bcm.c
@@ -268,7 +268,7 @@ static void bcm_can_tx(struct bcm_op *op)
268 268
269 /* send with loopback */ 269 /* send with loopback */
270 skb->dev = dev; 270 skb->dev = dev;
271 skb->sk = op->sk; 271 can_skb_set_owner(skb, op->sk);
272 can_send(skb, 1); 272 can_send(skb, 1);
273 273
274 /* update statistics */ 274 /* update statistics */
@@ -1223,7 +1223,7 @@ static int bcm_tx_send(struct msghdr *msg, int ifindex, struct sock *sk)
1223 1223
1224 can_skb_prv(skb)->ifindex = dev->ifindex; 1224 can_skb_prv(skb)->ifindex = dev->ifindex;
1225 skb->dev = dev; 1225 skb->dev = dev;
1226 skb->sk = sk; 1226 can_skb_set_owner(skb, sk);
1227 err = can_send(skb, 1); /* send with loopback */ 1227 err = can_send(skb, 1); /* send with loopback */
1228 dev_put(dev); 1228 dev_put(dev);
1229 1229