Skip to content

Commit

Permalink
USB CDC NCM: tx_fixup() race condition fix
Browse files Browse the repository at this point in the history
- tx_fixup() can be called from either timer callback or from xmit()
  in usbnet, so spinlock is added to avoid concurrency-related problem.
- minor correction due to checkpatch warning for some line over 80
  chars after previous patch was applied.

Signed-off-by: Alexey Orishko <alexey.orishko@stericsson.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Alexey Orishko authored and David S. Miller committed Jan 19, 2011
1 parent 1956cc5 commit f742aa8
Showing 1 changed file with 12 additions and 7 deletions.
19 changes: 12 additions & 7 deletions drivers/net/usb/cdc_ncm.c
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@
#include <linux/usb/usbnet.h>
#include <linux/usb/cdc.h>

#define DRIVER_VERSION "30-Nov-2010"
#define DRIVER_VERSION "17-Jan-2011"

/* CDC NCM subclass 3.2.1 */
#define USB_CDC_NCM_NDP16_LENGTH_MIN 0x10
Expand Down Expand Up @@ -868,15 +868,19 @@ static void cdc_ncm_tx_timeout(unsigned long arg)
if (ctx->tx_timer_pending != 0) {
ctx->tx_timer_pending--;
restart = 1;
} else
} else {
restart = 0;
}

spin_unlock(&ctx->mtx);

if (restart)
if (restart) {
spin_lock(&ctx->mtx);
cdc_ncm_tx_timeout_start(ctx);
else if (ctx->netdev != NULL)
spin_unlock(&ctx->mtx);
} else if (ctx->netdev != NULL) {
usbnet_start_xmit(NULL, ctx->netdev);
}
}

static struct sk_buff *
Expand All @@ -900,14 +904,15 @@ cdc_ncm_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags)
skb_out = cdc_ncm_fill_tx_frame(ctx, skb);
if (ctx->tx_curr_skb != NULL)
need_timer = 1;
spin_unlock(&ctx->mtx);

/* Start timer, if there is a remaining skb */
if (need_timer)
cdc_ncm_tx_timeout_start(ctx);

if (skb_out)
dev->net->stats.tx_packets += ctx->tx_curr_frame_num;

spin_unlock(&ctx->mtx);
return skb_out;

error:
Expand Down Expand Up @@ -1020,8 +1025,8 @@ static int cdc_ncm_rx_fixup(struct usbnet *dev, struct sk_buff *skb_in)
if (((offset + temp) > actlen) ||
(temp > CDC_NCM_MAX_DATAGRAM_SIZE) || (temp < ETH_HLEN)) {
pr_debug("invalid frame detected (ignored)"
"offset[%u]=%u, length=%u, skb=%p\n",
x, offset, temp, skb_in);
"offset[%u]=%u, length=%u, skb=%p\n",
x, offset, temp, skb_in);
if (!x)
goto error;
break;
Expand Down

0 comments on commit f742aa8

Please sign in to comment.