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: Jan Kiszka <jan.kiszka@web.de> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
b75b2eedcb
commit
a11ef7be8e
@ -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)
|
||||
{
|
||||
unsigned int datalen = skb->len - CAPIMSG_LEN(skb->data);
|
||||
struct tty_struct *tty;
|
||||
struct sk_buff *nskb;
|
||||
int datalen;
|
||||
u16 errcode, datahandle;
|
||||
struct tty_ldisc *ld;
|
||||
int ret = -1;
|
||||
|
||||
datalen = skb->len - CAPIMSG_LEN(skb->data);
|
||||
|
||||
tty = tty_port_tty_get(&mp->port);
|
||||
if (!tty) {
|
||||
#ifdef _DEBUG_DATAFLOW
|
||||
@ -454,50 +452,68 @@ static int handle_recv_skb(struct capiminor *mp, struct sk_buff *skb)
|
||||
}
|
||||
|
||||
ld = tty_ldisc_ref(tty);
|
||||
if (!ld)
|
||||
goto out1;
|
||||
if (!ld) {
|
||||
/* fatal error, do not requeue */
|
||||
ret = 0;
|
||||
kfree_skb(skb);
|
||||
goto deref_tty;
|
||||
}
|
||||
|
||||
if (ld->ops->receive_buf == NULL) {
|
||||
#if defined(_DEBUG_DATAFLOW) || defined(_DEBUG_TTYFUNCS)
|
||||
printk(KERN_DEBUG "capi: ldisc has no receive_buf function\n");
|
||||
#endif
|
||||
goto out2;
|
||||
/* fatal error, do not requeue */
|
||||
goto free_skb;
|
||||
}
|
||||
if (mp->ttyinstop) {
|
||||
#if defined(_DEBUG_DATAFLOW) || defined(_DEBUG_TTYFUNCS)
|
||||
printk(KERN_DEBUG "capi: recv tty throttled\n");
|
||||
#endif
|
||||
goto out2;
|
||||
goto deref_ldisc;
|
||||
}
|
||||
|
||||
if (tty->receive_room < datalen) {
|
||||
#if defined(_DEBUG_DATAFLOW) || defined(_DEBUG_TTYFUNCS)
|
||||
printk(KERN_DEBUG "capi: no room in tty\n");
|
||||
#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");
|
||||
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);
|
||||
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",
|
||||
errcode);
|
||||
kfree_skb(nskb);
|
||||
goto out2;
|
||||
|
||||
if (errcode == CAPI_SENDQUEUEFULL)
|
||||
goto deref_ldisc;
|
||||
}
|
||||
(void)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);
|
||||
kfree_skb(skb);
|
||||
|
||||
free_skb:
|
||||
ret = 0;
|
||||
out2:
|
||||
kfree_skb(skb);
|
||||
|
||||
deref_ldisc:
|
||||
tty_ldisc_deref(ld);
|
||||
out1:
|
||||
|
||||
deref_tty:
|
||||
tty_kref_put(tty);
|
||||
return ret;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user