Commit 73a88814 authored by Tilman Schmidt's avatar Tilman Schmidt Committed by Linus Torvalds

[PATCH] isdn4linux: Siemens Gigaset base driver: fix disconnect handling

Fix a possible Oops in the Siemens Gigaset base driver when the device is
unplugged while an ISDN connection is still active, and makes sure that the
isdn4linux link level (LL) is properly informed if a connection is broken
by the USB cable being unplugged.

- Avoid unsafe checks of URB status fields outside the URB completion
  handlers, keep track of in-use URBs myself instead.

- If an isochronous transfer URB completes with status==0, also check the
  status of the frame descriptors.

- Verify length of interrupt messages received from the device.

- Align the length limit on transmitted AT commands with the device
  documentation.

- In case of AT response receive overrun, keep newly arrived instead of old
  unread data.

- Remove redundant check of device ID in the USB probe function.

- Correct and improve some comments and formatting.
Signed-off-by: default avatarTilman Schmidt <tilman@imap.cc>
Acked-by: default avatarHansjoerg Lipp <hjlipp@web.de>
Cc: Karsten Keil <kkeil@suse.de>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent f4ffaa45
This diff is collapsed.
...@@ -781,8 +781,7 @@ error: if (cs) ...@@ -781,8 +781,7 @@ error: if (cs)
} }
EXPORT_SYMBOL_GPL(gigaset_initcs); EXPORT_SYMBOL_GPL(gigaset_initcs);
/* ReInitialize the b-channel structure */ /* ReInitialize the b-channel structure on hangup */
/* e.g. called on hangup, disconnect */
void gigaset_bcs_reinit(struct bc_state *bcs) void gigaset_bcs_reinit(struct bc_state *bcs)
{ {
struct sk_buff *skb; struct sk_buff *skb;
......
...@@ -373,6 +373,9 @@ struct reply_t gigaset_tab_cid_m10x[] = /* for M10x */ ...@@ -373,6 +373,9 @@ struct reply_t gigaset_tab_cid_m10x[] = /* for M10x */
{EV_TIMEOUT, 750,750, -1, 0, 0, {ACT_CONNTIMEOUT}}, {EV_TIMEOUT, 750,750, -1, 0, 0, {ACT_CONNTIMEOUT}},
/* B channel closed (general case) */
{EV_BC_CLOSED, -1, -1, -1, -1,-1, {ACT_NOTIFY_BC_DOWN}}, //FIXME
/* misc. */ /* misc. */
{EV_PROTO_L2, -1, -1, -1, -1,-1, {ACT_PROTO_L2}}, //FIXME {EV_PROTO_L2, -1, -1, -1, -1,-1, {ACT_PROTO_L2}}, //FIXME
......
...@@ -75,7 +75,7 @@ extern int gigaset_debuglevel; /* "needs" cast to (enum debuglevel) */ ...@@ -75,7 +75,7 @@ extern int gigaset_debuglevel; /* "needs" cast to (enum debuglevel) */
* e.g. 'insmod usb_gigaset.o debug=0x2c' will set DEBUG_OPEN, DEBUG_CMD and * e.g. 'insmod usb_gigaset.o debug=0x2c' will set DEBUG_OPEN, DEBUG_CMD and
* DEBUG_INTR. * DEBUG_INTR.
*/ */
enum debuglevel { /* up to 24 bits (atomic_t) */ enum debuglevel {
DEBUG_REG = 0x0002, /* serial port I/O register operations */ DEBUG_REG = 0x0002, /* serial port I/O register operations */
DEBUG_OPEN = 0x0004, /* open/close serial port */ DEBUG_OPEN = 0x0004, /* open/close serial port */
DEBUG_INTR = 0x0008, /* interrupt processing */ DEBUG_INTR = 0x0008, /* interrupt processing */
...@@ -141,7 +141,7 @@ enum debuglevel { /* up to 24 bits (atomic_t) */ ...@@ -141,7 +141,7 @@ enum debuglevel { /* up to 24 bits (atomic_t) */
printk(KERN_DEBUG KBUILD_MODNAME ": " format "\n", \ printk(KERN_DEBUG KBUILD_MODNAME ": " format "\n", \
## arg); \ ## arg); \
} while (0) } while (0)
#define DEBUG_DEFAULT (DEBUG_INIT | DEBUG_TRANSCMD | DEBUG_CMD | DEBUG_USBREQ) #define DEBUG_DEFAULT (DEBUG_TRANSCMD | DEBUG_CMD | DEBUG_USBREQ)
#else #else
...@@ -627,8 +627,7 @@ struct gigaset_ops { ...@@ -627,8 +627,7 @@ struct gigaset_ops {
/* Called by gigaset_freecs() for freeing bcs->hw.xxx */ /* Called by gigaset_freecs() for freeing bcs->hw.xxx */
int (*freebcshw)(struct bc_state *bcs); int (*freebcshw)(struct bc_state *bcs);
/* Called by gigaset_stop() or gigaset_bchannel_down() for resetting /* Called by gigaset_bchannel_down() for resetting bcs->hw.xxx */
bcs->hw.xxx */
void (*reinitbcshw)(struct bc_state *bcs); void (*reinitbcshw)(struct bc_state *bcs);
/* Called by gigaset_initcs() for setting up cs->hw.xxx */ /* Called by gigaset_initcs() for setting up cs->hw.xxx */
......
...@@ -73,7 +73,7 @@ static int writebuf_from_LL(int driverID, int channel, int ack, ...@@ -73,7 +73,7 @@ static int writebuf_from_LL(int driverID, int channel, int ack,
len, skblen, (unsigned) skb->head[0], (unsigned) skb->head[1]); len, skblen, (unsigned) skb->head[0], (unsigned) skb->head[1]);
/* pass to device-specific module */ /* pass to device-specific module */
return cs->ops->send_skb(bcs, skb); //FIXME cs->ops->send_skb() must handle !cs->connected correctly return cs->ops->send_skb(bcs, skb);
} }
void gigaset_skb_sent(struct bc_state *bcs, struct sk_buff *skb) void gigaset_skb_sent(struct bc_state *bcs, struct sk_buff *skb)
......
...@@ -992,14 +992,18 @@ int gigaset_isoc_send_skb(struct bc_state *bcs, struct sk_buff *skb) ...@@ -992,14 +992,18 @@ int gigaset_isoc_send_skb(struct bc_state *bcs, struct sk_buff *skb)
int len = skb->len; int len = skb->len;
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&bcs->cs->lock, flags);
if (!bcs->cs->connected) {
spin_unlock_irqrestore(&bcs->cs->lock, flags);
return -ENODEV;
}
skb_queue_tail(&bcs->squeue, skb); skb_queue_tail(&bcs->squeue, skb);
gig_dbg(DEBUG_ISO, "%s: skb queued, qlen=%d", gig_dbg(DEBUG_ISO, "%s: skb queued, qlen=%d",
__func__, skb_queue_len(&bcs->squeue)); __func__, skb_queue_len(&bcs->squeue));
/* tasklet submits URB if necessary */ /* tasklet submits URB if necessary */
spin_lock_irqsave(&bcs->cs->lock, flags); tasklet_schedule(&bcs->hw.bas->sent_tasklet);
if (bcs->cs->connected)
tasklet_schedule(&bcs->hw.bas->sent_tasklet);
spin_unlock_irqrestore(&bcs->cs->lock, flags); spin_unlock_irqrestore(&bcs->cs->lock, flags);
return len; /* ok so far */ return len; /* ok so far */
......
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