Commit a11ef7be authored by Jan Kiszka's avatar Jan Kiszka Committed by David S. Miller

CAPI: Rework capiminor RX handler

Avoid re-queuing skbs unless the error detected in handle_recv_skb is
expected to be recoverable such as lacking memory, a full CAPI queue, a
full TTY input buffer, or a not yet existing TTY.
Signed-off-by: default avatarJan Kiszka <jan.kiszka@web.de>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent b75b2eed
...@@ -436,15 +436,13 @@ gen_data_b3_resp_for(struct capiminor *mp, struct sk_buff *skb) ...@@ -436,15 +436,13 @@ gen_data_b3_resp_for(struct capiminor *mp, struct sk_buff *skb)
static int handle_recv_skb(struct capiminor *mp, struct sk_buff *skb) static int handle_recv_skb(struct capiminor *mp, struct sk_buff *skb)
{ {
unsigned int datalen = skb->len - CAPIMSG_LEN(skb->data);
struct tty_struct *tty; struct tty_struct *tty;
struct sk_buff *nskb; struct sk_buff *nskb;
int datalen;
u16 errcode, datahandle; u16 errcode, datahandle;
struct tty_ldisc *ld; struct tty_ldisc *ld;
int ret = -1; int ret = -1;
datalen = skb->len - CAPIMSG_LEN(skb->data);
tty = tty_port_tty_get(&mp->port); tty = tty_port_tty_get(&mp->port);
if (!tty) { if (!tty) {
#ifdef _DEBUG_DATAFLOW #ifdef _DEBUG_DATAFLOW
...@@ -454,50 +452,68 @@ static int handle_recv_skb(struct capiminor *mp, struct sk_buff *skb) ...@@ -454,50 +452,68 @@ static int handle_recv_skb(struct capiminor *mp, struct sk_buff *skb)
} }
ld = tty_ldisc_ref(tty); ld = tty_ldisc_ref(tty);
if (!ld) if (!ld) {
goto out1; /* fatal error, do not requeue */
ret = 0;
kfree_skb(skb);
goto deref_tty;
}
if (ld->ops->receive_buf == NULL) { if (ld->ops->receive_buf == NULL) {
#if defined(_DEBUG_DATAFLOW) || defined(_DEBUG_TTYFUNCS) #if defined(_DEBUG_DATAFLOW) || defined(_DEBUG_TTYFUNCS)
printk(KERN_DEBUG "capi: ldisc has no receive_buf function\n"); printk(KERN_DEBUG "capi: ldisc has no receive_buf function\n");
#endif #endif
goto out2; /* fatal error, do not requeue */
goto free_skb;
} }
if (mp->ttyinstop) { if (mp->ttyinstop) {
#if defined(_DEBUG_DATAFLOW) || defined(_DEBUG_TTYFUNCS) #if defined(_DEBUG_DATAFLOW) || defined(_DEBUG_TTYFUNCS)
printk(KERN_DEBUG "capi: recv tty throttled\n"); printk(KERN_DEBUG "capi: recv tty throttled\n");
#endif #endif
goto out2; goto deref_ldisc;
} }
if (tty->receive_room < datalen) { if (tty->receive_room < datalen) {
#if defined(_DEBUG_DATAFLOW) || defined(_DEBUG_TTYFUNCS) #if defined(_DEBUG_DATAFLOW) || defined(_DEBUG_TTYFUNCS)
printk(KERN_DEBUG "capi: no room in tty\n"); printk(KERN_DEBUG "capi: no room in tty\n");
#endif #endif
goto out2; goto deref_ldisc;
} }
if ((nskb = gen_data_b3_resp_for(mp, skb)) == NULL) {
nskb = gen_data_b3_resp_for(mp, skb);
if (!nskb) {
printk(KERN_ERR "capi: gen_data_b3_resp failed\n"); printk(KERN_ERR "capi: gen_data_b3_resp failed\n");
goto out2; goto deref_ldisc;
} }
datahandle = CAPIMSG_U16(skb->data,CAPIMSG_BASELEN+4);
datahandle = CAPIMSG_U16(skb->data, CAPIMSG_BASELEN + 4);
errcode = capi20_put_message(mp->ap, nskb); errcode = capi20_put_message(mp->ap, nskb);
if (errcode != CAPI_NOERROR) {
if (errcode == CAPI_NOERROR) {
skb_pull(skb, CAPIMSG_LEN(skb->data));
#ifdef _DEBUG_DATAFLOW
printk(KERN_DEBUG "capi: DATA_B3_RESP %u len=%d => ldisc\n",
datahandle, skb->len);
#endif
ld->ops->receive_buf(tty, skb->data, NULL, skb->len);
} else {
printk(KERN_ERR "capi: send DATA_B3_RESP failed=%x\n", printk(KERN_ERR "capi: send DATA_B3_RESP failed=%x\n",
errcode); errcode);
kfree_skb(nskb); kfree_skb(nskb);
goto out2;
if (errcode == CAPI_SENDQUEUEFULL)
goto deref_ldisc;
} }
(void)skb_pull(skb, CAPIMSG_LEN(skb->data));
#ifdef _DEBUG_DATAFLOW free_skb:
printk(KERN_DEBUG "capi: DATA_B3_RESP %u len=%d => ldisc\n",
datahandle, skb->len);
#endif
ld->ops->receive_buf(tty, skb->data, NULL, skb->len);
kfree_skb(skb);
ret = 0; ret = 0;
out2: kfree_skb(skb);
deref_ldisc:
tty_ldisc_deref(ld); tty_ldisc_deref(ld);
out1:
deref_tty:
tty_kref_put(tty); tty_kref_put(tty);
return ret; return ret;
} }
......
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