[PATCH v2 32/41] CAPI: Rework capiminor RX handler

Jan Kiszka <[email protected]>
Newsgroups gmane.linux.network,gmane.linux.kernel,gmane.linux.isdn.i4l.devel,gmane.linux.isdn.i4l.user
Message-ID <986a5c803a1c55bd0d7d721024a471fbe43953c9.1265659936.git.jan.kiszka@web.de>
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 <[email protected]>
---
 drivers/isdn/capi/capi.c |   60 +++++++++++++++++++++++++++++-----------------
 1 files changed, 38 insertions(+), 22 deletions(-)

diff --git a/drivers/isdn/capi/capi.c b/drivers/isdn/capi/capi.c
index 554fa1b..c5c54fa 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)
 
 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;
 }
-- 
1.6.0.2

--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.