aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/isdn/gigaset/i4l.c
diff options
context:
space:
mode:
authorTilman Schmidt <tilman@imap.cc>2009-10-25 05:29:57 -0400
committerDavid S. Miller <davem@davemloft.net>2009-10-29 04:37:09 -0400
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,
41{ 41{
42 struct cardstate *cs; 42 struct cardstate *cs;
43 struct bc_state *bcs; 43 struct bc_state *bcs;
44 unsigned char *ack_header;
44 unsigned len; 45 unsigned len;
45 unsigned skblen;
46 46
47 if (!(cs = gigaset_get_cs_by_id(driverID))) { 47 if (!(cs = gigaset_get_cs_by_id(driverID))) {
48 pr_err("%s: invalid driver ID (%d)\n", __func__, driverID); 48 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,
78 return -EINVAL; 78 return -EINVAL;
79 } 79 }
80 80
81 skblen = ack ? len : 0; 81 /* set up acknowledgement header */
82 skb->head[0] = skblen & 0xff; 82 if (skb_headroom(skb) < HW_HDR_LEN) {
83 skb->head[1] = skblen >> 8; 83 /* should never happen */
84 gig_dbg(DEBUG_MCMD, "skb: len=%u, skblen=%u: %02x %02x", 84 dev_err(cs->dev, "%s: insufficient skb headroom\n", __func__);
85 len, skblen, (unsigned) skb->head[0], (unsigned) skb->head[1]); 85 return -ENOMEM;
86 }
87 skb_set_mac_header(skb, -HW_HDR_LEN);
88 skb->mac_len = HW_HDR_LEN;
89 ack_header = skb_mac_header(skb);
90 if (ack) {
91 ack_header[0] = len & 0xff;
92 ack_header[1] = len >> 8;
93 } else {
94 ack_header[0] = ack_header[1] = 0;
95 }
96 gig_dbg(DEBUG_MCMD, "skb: len=%u, ack=%d: %02x %02x",
97 len, ack, ack_header[0], ack_header[1]);
86 98
87 /* pass to device-specific module */ 99 /* pass to device-specific module */
88 return cs->ops->send_skb(bcs, skb); 100 return cs->ops->send_skb(bcs, skb);
@@ -99,6 +111,7 @@ static int writebuf_from_LL(int driverID, int channel, int ack,
99void gigaset_skb_sent(struct bc_state *bcs, struct sk_buff *skb) 111void gigaset_skb_sent(struct bc_state *bcs, struct sk_buff *skb)
100{ 112{
101 isdn_if *iif = bcs->cs->iif; 113 isdn_if *iif = bcs->cs->iif;
114 unsigned char *ack_header = skb_mac_header(skb);
102 unsigned len; 115 unsigned len;
103 isdn_ctrl response; 116 isdn_ctrl response;
104 117
@@ -108,8 +121,7 @@ void gigaset_skb_sent(struct bc_state *bcs, struct sk_buff *skb)
108 dev_warn(bcs->cs->dev, "%s: skb->len==%d\n", 121 dev_warn(bcs->cs->dev, "%s: skb->len==%d\n",
109 __func__, skb->len); 122 __func__, skb->len);
110 123
111 len = (unsigned char) skb->head[0] | 124 len = ack_header[0] + ((unsigned) ack_header[1] << 8);
112 (unsigned) (unsigned char) skb->head[1] << 8;
113 if (len) { 125 if (len) {
114 gig_dbg(DEBUG_MCMD, "ACKing to LL (id: %d, ch: %d, sz: %u)", 126 gig_dbg(DEBUG_MCMD, "ACKing to LL (id: %d, ch: %d, sz: %u)",
115 bcs->cs->myid, bcs->channel, len); 127 bcs->cs->myid, bcs->channel, len);