mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-10-05 00:20:32 +00:00
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
1 changed files with 38 additions and 22 deletions
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue