From 347fbbb117e30818447a85bbecf18e8a2dbbbedb Mon Sep 17 00:00:00 2001 From: Jeff Hugo Date: Tue, 15 Nov 2011 16:39:20 -0700 Subject: [PATCH] msm: rmnet_bam: fix xmit statistics The skb being transmitted can be freed at any point after handing it off to the transport. Thus the statistics must be determined in the callback to prevent accessing data that is already freed. Also, statistics should always be calculated when in IP mode. CRs-Fixed: 318747 Change-Id: I3a2a081291fc657ca64aff47a3370017c5b6f7ca Signed-off-by: Jeffrey Hugo --- drivers/net/msm_rmnet_bam.c | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/drivers/net/msm_rmnet_bam.c b/drivers/net/msm_rmnet_bam.c index 3b3758e00d3..bb20a3fc87e 100644 --- a/drivers/net/msm_rmnet_bam.c +++ b/drivers/net/msm_rmnet_bam.c @@ -308,6 +308,7 @@ static int _rmnet_xmit(struct sk_buff *skb, struct net_device *dev) } dev->trans_start = jiffies; + /* if write() succeeds, skb access is unsafe in this process */ bam_ret = msm_bam_dmux_write(p->ch_id, skb); if (bam_ret != 0) { @@ -316,16 +317,6 @@ static int _rmnet_xmit(struct sk_buff *skb, struct net_device *dev) goto xmit_out; } - if (count_this_packet(skb->data, skb->len)) { - p->stats.tx_packets++; - p->stats.tx_bytes += skb->len; -#ifdef CONFIG_MSM_RMNET_DEBUG - p->wakeups_xmit += rmnet_cause_wakeup(p); -#endif - } - DBG1("[%s] Tx packet #%lu len=%d mark=0x%x\n", - dev->name, p->stats.tx_packets, skb->len, skb->mark); - return 0; xmit_out: /* data xmited, safe to release skb */ @@ -335,7 +326,21 @@ xmit_out: static void bam_write_done(void *dev, struct sk_buff *skb) { + struct rmnet_private *p = netdev_priv(dev); + u32 opmode = p->operation_mode; + DBG1("%s: write complete\n", __func__); + if (RMNET_IS_MODE_IP(opmode) || + count_this_packet(skb->data, skb->len)) { + p->stats.tx_packets++; + p->stats.tx_bytes += skb->len; +#ifdef CONFIG_MSM_RMNET_DEBUG + p->wakeups_xmit += rmnet_cause_wakeup(p); +#endif + } + DBG1("[%s] Tx packet #%lu len=%d mark=0x%x\n", + ((struct net_device *)(dev))->name, p->stats.tx_packets, + skb->len, skb->mark); dev_kfree_skb_any(skb); netif_wake_queue(dev); }