aboutsummaryrefslogtreecommitdiffstats
path: root/net/can
diff options
context:
space:
mode:
authorOliver Hartkopp <oliver@hartkopp.net>2008-05-08 05:49:55 -0400
committerDavid S. Miller <davem@davemloft.net>2008-05-08 05:49:55 -0400
commitc2ab7ac225e29006b7117d6a9fe8f3be8d98b0c2 (patch)
tree6e327f59003db8e1de548623b08f4b8bb14c308f /net/can
parent33f9936b2b73dba6c8685994c441c4fd30b04814 (diff)
can: Fix can_send() handling on dev_queue_xmit() failures
The tx packet counting and the local loopback of CAN frames should only happen in the case that the CAN frame has been enqueued to the netdevice tx queue successfully. Thanks to Andre Naujoks <nautsch@gmail.com> for reporting this issue. Signed-off-by: Oliver Hartkopp <oliver@hartkopp.net> Signed-off-by: Urs Thuermann <urs@isnogud.escape.de> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/can')
-rw-r--r--net/can/af_can.c16
1 files changed, 12 insertions, 4 deletions
diff --git a/net/can/af_can.c b/net/can/af_can.c
index 2759b76f731c..7e8ca2836452 100644
--- a/net/can/af_can.c
+++ b/net/can/af_can.c
@@ -208,6 +208,7 @@ static int can_create(struct net *net, struct socket *sock, int protocol)
208 */ 208 */
209int can_send(struct sk_buff *skb, int loop) 209int can_send(struct sk_buff *skb, int loop)
210{ 210{
211 struct sk_buff *newskb = NULL;
211 int err; 212 int err;
212 213
213 if (skb->dev->type != ARPHRD_CAN) { 214 if (skb->dev->type != ARPHRD_CAN) {
@@ -244,8 +245,7 @@ int can_send(struct sk_buff *skb, int loop)
244 * If the interface is not capable to do loopback 245 * If the interface is not capable to do loopback
245 * itself, we do it here. 246 * itself, we do it here.
246 */ 247 */
247 struct sk_buff *newskb = skb_clone(skb, GFP_ATOMIC); 248 newskb = skb_clone(skb, GFP_ATOMIC);
248
249 if (!newskb) { 249 if (!newskb) {
250 kfree_skb(skb); 250 kfree_skb(skb);
251 return -ENOMEM; 251 return -ENOMEM;
@@ -254,7 +254,6 @@ int can_send(struct sk_buff *skb, int loop)
254 newskb->sk = skb->sk; 254 newskb->sk = skb->sk;
255 newskb->ip_summed = CHECKSUM_UNNECESSARY; 255 newskb->ip_summed = CHECKSUM_UNNECESSARY;
256 newskb->pkt_type = PACKET_BROADCAST; 256 newskb->pkt_type = PACKET_BROADCAST;
257 netif_rx(newskb);
258 } 257 }
259 } else { 258 } else {
260 /* indication for the CAN driver: no loopback required */ 259 /* indication for the CAN driver: no loopback required */
@@ -266,11 +265,20 @@ int can_send(struct sk_buff *skb, int loop)
266 if (err > 0) 265 if (err > 0)
267 err = net_xmit_errno(err); 266 err = net_xmit_errno(err);
268 267
268 if (err) {
269 if (newskb)
270 kfree_skb(newskb);
271 return err;
272 }
273
274 if (newskb)
275 netif_rx(newskb);
276
269 /* update statistics */ 277 /* update statistics */
270 can_stats.tx_frames++; 278 can_stats.tx_frames++;
271 can_stats.tx_frames_delta++; 279 can_stats.tx_frames_delta++;
272 280
273 return err; 281 return 0;
274} 282}
275EXPORT_SYMBOL(can_send); 283EXPORT_SYMBOL(can_send);
276 284