aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/isdn/capi/capi.c
diff options
context:
space:
mode:
authorJan Kiszka <jan.kiszka@web.de>2010-02-08 05:12:36 -0500
committerDavid S. Miller <davem@davemloft.net>2010-02-16 19:01:32 -0500
commita11ef7be8e982426e9fbbfc84fa0c01d23ce05c3 (patch)
treeba8e293db3a4004100bc5f0608e5cfbf1e0bcfc5 /drivers/isdn/capi/capi.c
parentb75b2eedcbf6458c68713c772c2ade83ab7a55f0 (diff)
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>
Diffstat (limited to 'drivers/isdn/capi/capi.c')
-rw-r--r--drivers/isdn/capi/capi.c60
1 files changed, 38 insertions, 22 deletions
diff --git a/drivers/isdn/capi/capi.c b/drivers/isdn/capi/capi.c
index 554fa1b36d13..c5c54fab50eb 100644
--- a/drivers/isdn/capi/capi.c
+++ b/drivers/isdn/capi/capi.c
@@ -436,15 +436,13 @@ gen_data_b3_resp_for(struct capiminor *mp, struct sk_buff *skb)
436 436
437static int handle_recv_skb(struct capiminor *mp, struct sk_buff *skb) 437static int handle_recv_skb(struct capiminor *mp, struct sk_buff *skb)
438{ 438{
439 unsigned int datalen = skb->len - CAPIMSG_LEN(skb->data);
439 struct tty_struct *tty; 440 struct tty_struct *tty;
440 struct sk_buff *nskb; 441 struct sk_buff *nskb;
441 int datalen;
442 u16 errcode, datahandle; 442 u16 errcode, datahandle;
443 struct tty_ldisc *ld; 443 struct tty_ldisc *ld;
444 int ret = -1; 444 int ret = -1;
445 445
446 datalen = skb->len - CAPIMSG_LEN(skb->data);
447
448 tty = tty_port_tty_get(&mp->port); 446 tty = tty_port_tty_get(&mp->port);
449 if (!tty) { 447 if (!tty) {
450#ifdef _DEBUG_DATAFLOW 448#ifdef _DEBUG_DATAFLOW
@@ -454,50 +452,68 @@ static int handle_recv_skb(struct capiminor *mp, struct sk_buff *skb)
454 } 452 }
455 453
456 ld = tty_ldisc_ref(tty); 454 ld = tty_ldisc_ref(tty);
457 if (!ld) 455 if (!ld) {
458 goto out1; 456 /* fatal error, do not requeue */
457 ret = 0;
458 kfree_skb(skb);
459 goto deref_tty;
460 }
459 461
460 if (ld->ops->receive_buf == NULL) { 462 if (ld->ops->receive_buf == NULL) {
461#if defined(_DEBUG_DATAFLOW) || defined(_DEBUG_TTYFUNCS) 463#if defined(_DEBUG_DATAFLOW) || defined(_DEBUG_TTYFUNCS)
462 printk(KERN_DEBUG "capi: ldisc has no receive_buf function\n"); 464 printk(KERN_DEBUG "capi: ldisc has no receive_buf function\n");
463#endif 465#endif
464 goto out2; 466 /* fatal error, do not requeue */
467 goto free_skb;
465 } 468 }
466 if (mp->ttyinstop) { 469 if (mp->ttyinstop) {
467#if defined(_DEBUG_DATAFLOW) || defined(_DEBUG_TTYFUNCS) 470#if defined(_DEBUG_DATAFLOW) || defined(_DEBUG_TTYFUNCS)
468 printk(KERN_DEBUG "capi: recv tty throttled\n"); 471 printk(KERN_DEBUG "capi: recv tty throttled\n");
469#endif 472#endif
470 goto out2; 473 goto deref_ldisc;
471 } 474 }
475
472 if (tty->receive_room < datalen) { 476 if (tty->receive_room < datalen) {
473#if defined(_DEBUG_DATAFLOW) || defined(_DEBUG_TTYFUNCS) 477#if defined(_DEBUG_DATAFLOW) || defined(_DEBUG_TTYFUNCS)
474 printk(KERN_DEBUG "capi: no room in tty\n"); 478 printk(KERN_DEBUG "capi: no room in tty\n");
475#endif 479#endif
476 goto out2; 480 goto deref_ldisc;
477 } 481 }
478 if ((nskb = gen_data_b3_resp_for(mp, skb)) == NULL) { 482
483 nskb = gen_data_b3_resp_for(mp, skb);
484 if (!nskb) {
479 printk(KERN_ERR "capi: gen_data_b3_resp failed\n"); 485 printk(KERN_ERR "capi: gen_data_b3_resp failed\n");
480 goto out2; 486 goto deref_ldisc;
481 } 487 }
482 datahandle = CAPIMSG_U16(skb->data,CAPIMSG_BASELEN+4); 488
489 datahandle = CAPIMSG_U16(skb->data, CAPIMSG_BASELEN + 4);
490
483 errcode = capi20_put_message(mp->ap, nskb); 491 errcode = capi20_put_message(mp->ap, nskb);
484 if (errcode != CAPI_NOERROR) { 492
493 if (errcode == CAPI_NOERROR) {
494 skb_pull(skb, CAPIMSG_LEN(skb->data));
495#ifdef _DEBUG_DATAFLOW
496 printk(KERN_DEBUG "capi: DATA_B3_RESP %u len=%d => ldisc\n",
497 datahandle, skb->len);
498#endif
499 ld->ops->receive_buf(tty, skb->data, NULL, skb->len);
500 } else {
485 printk(KERN_ERR "capi: send DATA_B3_RESP failed=%x\n", 501 printk(KERN_ERR "capi: send DATA_B3_RESP failed=%x\n",
486 errcode); 502 errcode);
487 kfree_skb(nskb); 503 kfree_skb(nskb);
488 goto out2; 504
505 if (errcode == CAPI_SENDQUEUEFULL)
506 goto deref_ldisc;
489 } 507 }
490 (void)skb_pull(skb, CAPIMSG_LEN(skb->data)); 508
491#ifdef _DEBUG_DATAFLOW 509free_skb:
492 printk(KERN_DEBUG "capi: DATA_B3_RESP %u len=%d => ldisc\n",
493 datahandle, skb->len);
494#endif
495 ld->ops->receive_buf(tty, skb->data, NULL, skb->len);
496 kfree_skb(skb);
497 ret = 0; 510 ret = 0;
498out2: 511 kfree_skb(skb);
512
513deref_ldisc:
499 tty_ldisc_deref(ld); 514 tty_ldisc_deref(ld);
500out1: 515
516deref_tty:
501 tty_kref_put(tty); 517 tty_kref_put(tty);
502 return ret; 518 return ret;
503} 519}