Commit f742aa8a authored by Alexey Orishko's avatar Alexey Orishko Committed by David S. Miller
Browse files

USB CDC NCM: tx_fixup() race condition fix



- 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: default avatarAlexey Orishko <alexey.orishko@stericsson.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 1956cc52
...@@ -54,7 +54,7 @@ ...@@ -54,7 +54,7 @@
#include <linux/usb/usbnet.h> #include <linux/usb/usbnet.h>
#include <linux/usb/cdc.h> #include <linux/usb/cdc.h>
#define DRIVER_VERSION "30-Nov-2010" #define DRIVER_VERSION "17-Jan-2011"
/* CDC NCM subclass 3.2.1 */ /* CDC NCM subclass 3.2.1 */
#define USB_CDC_NCM_NDP16_LENGTH_MIN 0x10 #define USB_CDC_NCM_NDP16_LENGTH_MIN 0x10
...@@ -868,15 +868,19 @@ static void cdc_ncm_tx_timeout(unsigned long arg) ...@@ -868,15 +868,19 @@ static void cdc_ncm_tx_timeout(unsigned long arg)
if (ctx->tx_timer_pending != 0) { if (ctx->tx_timer_pending != 0) {
ctx->tx_timer_pending--; ctx->tx_timer_pending--;
restart = 1; restart = 1;
} else } else {
restart = 0; restart = 0;
}
spin_unlock(&ctx->mtx); spin_unlock(&ctx->mtx);
if (restart) if (restart) {
spin_lock(&ctx->mtx);
cdc_ncm_tx_timeout_start(ctx); 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); usbnet_start_xmit(NULL, ctx->netdev);
}
} }
static struct sk_buff * static struct sk_buff *
...@@ -900,7 +904,6 @@ cdc_ncm_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags) ...@@ -900,7 +904,6 @@ cdc_ncm_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags)
skb_out = cdc_ncm_fill_tx_frame(ctx, skb); skb_out = cdc_ncm_fill_tx_frame(ctx, skb);
if (ctx->tx_curr_skb != NULL) if (ctx->tx_curr_skb != NULL)
need_timer = 1; need_timer = 1;
spin_unlock(&ctx->mtx);
/* Start timer, if there is a remaining skb */ /* Start timer, if there is a remaining skb */
if (need_timer) if (need_timer)
...@@ -908,6 +911,8 @@ cdc_ncm_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags) ...@@ -908,6 +911,8 @@ cdc_ncm_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags)
if (skb_out) if (skb_out)
dev->net->stats.tx_packets += ctx->tx_curr_frame_num; dev->net->stats.tx_packets += ctx->tx_curr_frame_num;
spin_unlock(&ctx->mtx);
return skb_out; return skb_out;
error: error:
...@@ -1020,8 +1025,8 @@ static int cdc_ncm_rx_fixup(struct usbnet *dev, struct sk_buff *skb_in) ...@@ -1020,8 +1025,8 @@ static int cdc_ncm_rx_fixup(struct usbnet *dev, struct sk_buff *skb_in)
if (((offset + temp) > actlen) || if (((offset + temp) > actlen) ||
(temp > CDC_NCM_MAX_DATAGRAM_SIZE) || (temp < ETH_HLEN)) { (temp > CDC_NCM_MAX_DATAGRAM_SIZE) || (temp < ETH_HLEN)) {
pr_debug("invalid frame detected (ignored)" pr_debug("invalid frame detected (ignored)"
"offset[%u]=%u, length=%u, skb=%p\n", "offset[%u]=%u, length=%u, skb=%p\n",
x, offset, temp, skb_in); x, offset, temp, skb_in);
if (!x) if (!x)
goto error; goto error;
break; break;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment