summaryrefslogtreecommitdiff
path: root/drivers/isdn/gigaset/i4l.c
diff options
context:
space:
mode:
authorTilman Schmidt <tilman@imap.cc>2009-10-25 09:29:57 +0000
committerDavid S. Miller <davem@davemloft.net>2009-10-29 01:37:09 -0700
commit4dd8230acd20cb456cae02696b3da2986faad258 (patch)
treeded49543277fdd72784ac7d2dd14311d39b4e4c9 /drivers/isdn/gigaset/i4l.c
parent22077ebceb44f4097d4677e2a26bc1175143d647 (diff)
gigaset: fix bad assumptions about CAPI skbuffs
The CAPI interface incorrectly assumed that CAPI messages would always start at the beginning of the data buffer: fix by treating DATA_B3 messages as the link layer header to their payload data. This fix changes the way acknowledgement information is propagated through the hardware specific modules and thereby impacts the ISDN4Linux variant of the driver, too. Also some assumptions about methods not being called from interrupt context turned out to be unwarranted; fix by using dev_kfree_skb_any() wherever non-interrupt context isn't guaranteed. Impact: bugfix Signed-off-by: Tilman Schmidt <tilman@imap.cc> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/isdn/gigaset/i4l.c')
-rw-r--r--drivers/isdn/gigaset/i4l.c28
1 files changed, 20 insertions, 8 deletions
diff --git a/drivers/isdn/gigaset/i4l.c b/drivers/isdn/gigaset/i4l.c
index aca72a06184e..828824f905c4 100644
--- a/drivers/isdn/gigaset/i4l.c
+++ b/drivers/isdn/gigaset/i4l.c
@@ -41,8 +41,8 @@ static int writebuf_from_LL(int driverID, int channel, int ack,
{
struct cardstate *cs;
struct bc_state *bcs;
+ unsigned char *ack_header;
unsigned len;
- unsigned skblen;
if (!(cs = gigaset_get_cs_by_id(driverID))) {
pr_err("%s: invalid driver ID (%d)\n", __func__, driverID);
@@ -78,11 +78,23 @@ static int writebuf_from_LL(int driverID, int channel, int ack,
return -EINVAL;
}
- skblen = ack ? len : 0;
- skb->head[0] = skblen & 0xff;
- skb->head[1] = skblen >> 8;
- gig_dbg(DEBUG_MCMD, "skb: len=%u, skblen=%u: %02x %02x",
- len, skblen, (unsigned) skb->head[0], (unsigned) skb->head[1]);
+ /* set up acknowledgement header */
+ if (skb_headroom(skb) < HW_HDR_LEN) {
+ /* should never happen */
+ dev_err(cs->dev, "%s: insufficient skb headroom\n", __func__);
+ return -ENOMEM;
+ }
+ skb_set_mac_header(skb, -HW_HDR_LEN);
+ skb->mac_len = HW_HDR_LEN;
+ ack_header = skb_mac_header(skb);
+ if (ack) {
+ ack_header[0] = len & 0xff;
+ ack_header[1] = len >> 8;
+ } else {
+ ack_header[0] = ack_header[1] = 0;
+ }
+ gig_dbg(DEBUG_MCMD, "skb: len=%u, ack=%d: %02x %02x",
+ len, ack, ack_header[0], ack_header[1]);
/* pass to device-specific module */
return cs->ops->send_skb(bcs, skb);
@@ -99,6 +111,7 @@ static int writebuf_from_LL(int driverID, int channel, int ack,
void gigaset_skb_sent(struct bc_state *bcs, struct sk_buff *skb)
{
isdn_if *iif = bcs->cs->iif;
+ unsigned char *ack_header = skb_mac_header(skb);
unsigned len;
isdn_ctrl response;
@@ -108,8 +121,7 @@ void gigaset_skb_sent(struct bc_state *bcs, struct sk_buff *skb)
dev_warn(bcs->cs->dev, "%s: skb->len==%d\n",
__func__, skb->len);
- len = (unsigned char) skb->head[0] |
- (unsigned) (unsigned char) skb->head[1] << 8;
+ len = ack_header[0] + ((unsigned) ack_header[1] << 8);
if (len) {
gig_dbg(DEBUG_MCMD, "ACKing to LL (id: %d, ch: %d, sz: %u)",
bcs->cs->myid, bcs->channel, len);