lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [day] [month] [year] [list]
Message-Id: <20120423170551.30CA59FB80@pingi6.linux-pingi.de>
Date:	Sat, 21 Apr 2012 17:39:50 +0200
From:	Karsten Keil <isdn@...ux-pingi.de>
To:	David Miller <davem@...emloft.net>
Cc:	netdev@...r.kernel.org, isdn4linux@...tserv.isdn4linux.de
Subject: [PATCH 22/28] mISDN: More support for MISDN_CTRL_FILL_EMPTY and MISDN_CTRL_RX_OFF

Add a common HW flag to support RX_OFF.
Implement MISDN_CTRL_FILL_EMPTY and MISDN_CTRL_RX_OFF for the avmfritz
driver.

Signed-off-by: Karsten Keil <kkeil@...ux-pingi.de>
---
 drivers/isdn/hardware/mISDN/avmfritz.c |  169 ++++++++++++++++++++++++--------
 drivers/isdn/mISDN/hwchannel.c         |    1 +
 include/linux/mISDNhw.h                |    4 +-
 include/linux/mISDNif.h                |   10 ++-
 4 files changed, 139 insertions(+), 45 deletions(-)

diff --git a/drivers/isdn/hardware/mISDN/avmfritz.c b/drivers/isdn/hardware/mISDN/avmfritz.c
index 9cee744..3781446 100644
--- a/drivers/isdn/hardware/mISDN/avmfritz.c
+++ b/drivers/isdn/hardware/mISDN/avmfritz.c
@@ -141,6 +141,8 @@ struct fritzcard {
 	struct isac_hw		isac;
 	struct hdlc_hw		hdlc[2];
 	struct bchannel		bch[2];
+	int			dropcnt[2];
+	u8			fill[2 * HDLC_FIFO_SIZE_V2];
 	char			log[LOG_SIZE + 1];
 };
 
@@ -402,35 +404,45 @@ static void
 hdlc_empty_fifo(struct bchannel *bch, int count)
 {
 	u32 *ptr;
-	u8 *p;
+	u8 *p, copy;
 	u32  val, addr;
 	int cnt;
 	struct fritzcard *fc = bch->hw;
 
 	pr_debug("%s: %s %d\n", fc->name, __func__, count);
-	if (!bch->rx_skb) {
-		if (test_bit(FLG_TRANSPARENT, &bch->Flags)) {
-			if (count >= bch->minlen)
-				cnt = count;
-			else
-				cnt = 2 * bch->minlen;
-		} else
-			cnt = bch->maxlen;
-		bch->rx_skb = mI_alloc_skb(cnt, GFP_ATOMIC);
+	if (test_bit(FLG_RX_OFF, &bch->Flags)) {
+		/* We drop the content, but need to read all bytes from FIFO */
+		copy = 0;
+		if (debug & DEBUG_HW_BFIFO)
+			printk(KERN_DEBUG "Dropped %d bytes - RX off\n", count);
+		val = (bch->nr - 1) & 1;
+		fc->dropcnt[val] += count;
+	} else {
+		copy = 1;
 		if (!bch->rx_skb) {
-			pr_info("%s: B receive out of memory\n",
-				fc->name);
+			if (test_bit(FLG_TRANSPARENT, &bch->Flags)) {
+				if (count >= bch->minlen)
+					cnt = count;
+				else
+					cnt = 2 * bch->minlen;
+			} else
+				cnt = bch->maxlen;
+			bch->rx_skb = mI_alloc_skb(cnt, GFP_ATOMIC);
+			if (!bch->rx_skb) {
+				pr_info("%s: B receive out of memory\n",
+					fc->name);
+				return;
+			}
+		} else
+			cnt = skb_tailroom(bch->rx_skb);
+		if (count > cnt) {
+			pr_debug("%s: overrun %d + %d free %d\n", fc->name,
+				bch->rx_skb->len, count, cnt);
 			return;
 		}
-	} else
-		cnt = skb_tailroom(bch->rx_skb);
-	if (count > cnt) {
-		pr_debug("%s: overrun %d + %d free %d\n", fc->name,
-			bch->rx_skb->len, count, cnt);
-		return;
+		p = skb_put(bch->rx_skb, count);
+		ptr = (u32 *)p;
 	}
-	p = skb_put(bch->rx_skb, count);
-	ptr = (u32 *)p;
 	if (AVM_FRITZ_PCIV2 == fc->type)
 		addr = fc->addr + (bch->nr == 2 ?
 				   AVM_HDLC_FIFO_2 : AVM_HDLC_FIFO_1);
@@ -441,11 +453,13 @@ hdlc_empty_fifo(struct bchannel *bch, int count)
 	cnt = 0;
 	while (cnt < count) {
 		val = le32_to_cpu(inl(addr));
-		put_unaligned(val, ptr);
-		ptr++;
+		if (copy) {
+			put_unaligned(val, ptr);
+			ptr++;
+		}
 		cnt += 4;
 	}
-	if (debug & DEBUG_HW_BFIFO) {
+	if (copy && (debug & DEBUG_HW_BFIFO)) {
 		snprintf(fc->log, LOG_SIZE, "B%1d-recv %s %d ",
 			 bch->nr, fc->name, count);
 		print_hex_dump_bytes(fc->log, DUMP_PREFIX_OFFSET, p, count);
@@ -457,19 +471,25 @@ hdlc_fill_fifo(struct bchannel *bch)
 {
 	struct fritzcard *fc = bch->hw;
 	struct hdlc_hw *hdlc;
-	int count, fs, cnt = 0;
+	int count, fs, cnt = 0, idx;
 	u8 *p;
 	u32 *ptr, val, addr;
 
-	hdlc = &fc->hdlc[(bch->nr - 1) & 1];
-	if (!bch->tx_skb)
-		return;
-	count = bch->tx_skb->len - bch->tx_idx;
-	if (count <= 0)
-		return;
+	idx = (bch->nr - 1) & 1;
+	hdlc = &fc->hdlc[idx];
 	fs = (fc->type == AVM_FRITZ_PCIV2) ?
 		HDLC_FIFO_SIZE_V2 : HDLC_FIFO_SIZE_V1;
-	p = bch->tx_skb->data + bch->tx_idx;
+	if (!bch->tx_skb) {
+		if (!test_bit(FLG_FILLEMPTY, &bch->Flags))
+			return;
+		count = fs;
+		p = fc->fill + (idx * HDLC_FIFO_SIZE_V2);
+	} else {
+		count = bch->tx_skb->len - bch->tx_idx;
+		if (count <= 0)
+			return;
+		p = bch->tx_skb->data + bch->tx_idx;
+	}
 	hdlc->ctrl.sr.cmd &= ~HDLC_CMD_XME;
 	if (count > fs) {
 		count = fs;
@@ -477,10 +497,13 @@ hdlc_fill_fifo(struct bchannel *bch)
 		if (test_bit(FLG_HDLC, &bch->Flags))
 			hdlc->ctrl.sr.cmd |= HDLC_CMD_XME;
 	}
-	pr_debug("%s: %s %d/%d/%d", fc->name, __func__, count,
-		 bch->tx_idx, bch->tx_skb->len);
 	ptr = (u32 *)p;
-	bch->tx_idx += count;
+	if (bch->tx_skb) {
+		pr_debug("%s: %s %d/%d/%d", fc->name, __func__, count,
+			bch->tx_idx, bch->tx_skb->len);
+		bch->tx_idx += count;
+	} else
+		 pr_debug("%s: %s fillempty %d\n", fc->name, __func__, count);
 	hdlc->ctrl.sr.xml = ((count == fs) ? 0 : count);
 	if (AVM_FRITZ_PCIV2 == fc->type) {
 		__write_ctrl_pciv2(fc, hdlc, bch->nr);
@@ -509,11 +532,10 @@ HDLC_irq_xpr(struct bchannel *bch)
 	if (bch->tx_skb && bch->tx_idx < bch->tx_skb->len)
 		hdlc_fill_fifo(bch);
 	else {
-		if (bch->tx_skb) {
-			/* send confirm, on trans, free on hdlc. */
+		if (bch->tx_skb)
 			dev_kfree_skb(bch->tx_skb);
-		}
-		if (get_next_bframe(bch))
+		if (get_next_bframe(bch) ||
+		    test_bit(FLG_FILLEMPTY, &bch->Flags))
 			hdlc_fill_fifo(bch);
 	}
 }
@@ -523,8 +545,9 @@ HDLC_irq(struct bchannel *bch, u32 stat)
 {
 	struct fritzcard *fc = bch->hw;
 	int		len, fs;
-	u32		rmlMask;
+	u32		rmlMask, err;
 	struct hdlc_hw	*hdlc;
+	struct sk_buff	*skb;
 
 	hdlc = &fc->hdlc[(bch->nr - 1) & 1];
 	pr_debug("%s: ch%d stat %#x\n", fc->name, bch->nr, stat);
@@ -546,6 +569,12 @@ HDLC_irq(struct bchannel *bch, u32 stat)
 			write_ctrl(bch, 1);
 			if (bch->rx_skb)
 				skb_trim(bch->rx_skb, 0);
+			if (test_bit(FLG_FIFO_STATUS, &bch->Flags)) {
+				skb = _alloc_mISDN_skb(PH_CONTROL_IND,
+					HW_FIFO_RDO, 0, NULL, GFP_KERNEL);
+				if (skb)
+					recv_Bchannel_skb(bch, skb);
+			}
 		} else {
 			len = (stat & rmlMask) >> 8;
 			if (!len)
@@ -575,13 +604,22 @@ handle_tx:
 		 */
 		pr_warning("%s: ch%d stat %x XDU %s\n", fc->name, bch->nr,
 			stat, bch->tx_skb ? "tx_skb" : "no tx_skb");
-		if (bch->tx_skb)
+		if (bch->tx_skb) {
 			pr_debug("%s: ch%d XDU len(%d) idx(%d) Flags(%lx)\n",
 				 fc->name, bch->nr, bch->tx_skb->len,
 				 bch->tx_idx, bch->Flags);
-		else
+			err = HW_FIFO_XDU_DATA;
+		} else {
 			pr_debug("%s: ch%d XDU no tx_skb Flags(%lx)\n",
 				 fc->name, bch->nr, bch->Flags);
+			err = HW_FIFO_XDU_NODATA;
+		}
+		if (test_bit(FLG_FIFO_STATUS, &bch->Flags)) {
+			skb = _alloc_mISDN_skb(PH_CONTROL_IND, err,
+				0, NULL, GFP_KERNEL);
+			if (skb)
+				recv_Bchannel_skb(bch, skb);
+		}
 		if (bch->tx_skb && bch->tx_skb->len) {
 			if (!test_bit(FLG_TRANSPARENT, &bch->Flags))
 				bch->tx_idx = 0;
@@ -721,6 +759,24 @@ avm_l2l1B(struct mISDNchannel *ch, struct sk_buff *skb)
 			    NULL, GFP_KERNEL);
 		ret = 0;
 		break;
+	case PH_CONTROL_REQ:
+		switch (hh->id) {
+		case HW_FIFO_STATUS_ON:
+			test_and_set_bit(FLG_FIFO_STATUS, &bch->Flags);
+			id = 0;
+			break;
+		case HW_FIFO_STATUS_OFF:
+			test_and_clear_bit(FLG_FIFO_STATUS, &bch->Flags);
+			id = 0;
+			break;
+		default:
+			pr_info("PH_CONTROL_REQ %x not supported\n", hh->id);
+			id = -EINVAL;
+			break;
+		}
+		_queue_data(ch, PH_CONTROL_CNF, id, 0, NULL, GFP_KERNEL);
+		ret = 0;
+		break;
 	}
 	if (!ret)
 		dev_kfree_skb(skb);
@@ -835,12 +891,39 @@ init_card(struct fritzcard *fc)
 static int
 channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq)
 {
-	int ret = 0, o1, o2;
+	int ret = 0, o1, o2, idx;
+	u8 *p;
 	struct fritzcard *fc = bch->hw;
 
+	idx = (bch->nr - 1) & 1;
 	switch (cq->op) {
 	case MISDN_CTRL_GETOP:
-		cq->op = MISDN_CTRL_RX_BUFFER;
+		cq->op = MISDN_CTRL_RX_BUFFER |
+			MISDN_CTRL_RX_OFF | MISDN_CTRL_FILL_EMPTY;
+		break;
+	case MISDN_CTRL_RX_OFF: /* turn off / on rx stream */
+		o1 = fc->dropcnt[idx];
+		if (cq->p1) {
+			test_and_set_bit(FLG_RX_OFF, &bch->Flags);
+			fc->dropcnt[idx] = 0;
+		} else
+			test_and_clear_bit(FLG_RX_OFF, &bch->Flags);
+		cq->p2 = o1;
+		if (debug & DEBUG_HW_BCHANNEL)
+			printk(KERN_DEBUG "Bch%d RX %s\n",
+			    bch->nr, cq->p1 ? "off" : "on");
+		break;
+	case MISDN_CTRL_FILL_EMPTY: /* fill fifo, if empty */
+		p = fc->fill + (idx * HDLC_FIFO_SIZE_V2);
+		if (cq->p1) {
+			test_and_set_bit(FLG_FILLEMPTY, &bch->Flags);
+			if (cq->p2 > -1)
+				memset(p, cq->p2 & 0xff, HDLC_FIFO_SIZE_V2);
+		} else
+			test_and_clear_bit(FLG_FILLEMPTY, &bch->Flags);
+		if (debug & DEBUG_HW_BCHANNEL)
+			printk(KERN_DEBUG "FILL_EMPTY Bch%d %s val %02x\n",
+				bch->nr, cq->p1 ? "on" : "off", *p);
 		break;
 	case MISDN_CTRL_RX_BUFFER:
 		/* We return the old values */
diff --git a/drivers/isdn/mISDN/hwchannel.c b/drivers/isdn/mISDN/hwchannel.c
index 467518c..84fbcf1 100644
--- a/drivers/isdn/mISDN/hwchannel.c
+++ b/drivers/isdn/mISDN/hwchannel.c
@@ -135,6 +135,7 @@ mISDN_clear_bchannel(struct bchannel *ch)
 	test_and_clear_bit(FLG_TX_BUSY, &ch->Flags);
 	test_and_clear_bit(FLG_TX_NEXT, &ch->Flags);
 	test_and_clear_bit(FLG_ACTIVE, &ch->Flags);
+	test_and_clear_bit(FLG_RX_OFF, &ch->Flags);
 }
 EXPORT_SYMBOL(mISDN_clear_bchannel);
 
diff --git a/include/linux/mISDNhw.h b/include/linux/mISDNhw.h
index 4f97bd3..9776edd 100644
--- a/include/linux/mISDNhw.h
+++ b/include/linux/mISDNhw.h
@@ -73,7 +73,9 @@
 #define FLG_LL_OK		24
 #define FLG_LL_CONN		25
 #define FLG_DTMFSEND		26
-
+/* stop sending received data upstream */
+#define FLG_RX_OFF		27
+#define FLG_FIFO_STATUS		28
 /* workq events */
 #define FLG_RECVQUEUE		30
 #define	FLG_PHCHANGE		31
diff --git a/include/linux/mISDNif.h b/include/linux/mISDNif.h
index b26de1a..89ce4ec 100644
--- a/include/linux/mISDNif.h
+++ b/include/linux/mISDNif.h
@@ -37,7 +37,7 @@
  */
 #define	MISDN_MAJOR_VERSION	1
 #define	MISDN_MINOR_VERSION	1
-#define MISDN_RELEASE		30
+#define MISDN_RELEASE		31
 
 /* primitives for information exchange
  * generell format
@@ -158,6 +158,7 @@
 #define HFC_VOL_CHANGE_RX	0x2602
 #define HFC_SPL_LOOP_ON		0x2603
 #define HFC_SPL_LOOP_OFF	0x2604
+
 /* for T30 FAX and analog modem */
 #define HW_MOD_FRM		0x4000
 #define HW_MOD_FRH		0x4001
@@ -171,6 +172,13 @@
 #define HW_MOD_READY		0x4014
 #define HW_MOD_LASTDATA		0x4015
 
+/* Debug and status via PH_CONTROL */
+#define HW_FIFO_STATUS_OFF	0x8000
+#define HW_FIFO_STATUS_ON	0x8001
+#define HW_FIFO_RDO		0x8002
+#define HW_FIFO_XDU_DATA	0x8003
+#define HW_FIFO_XDU_NODATA	0x8004
+
 /* DSP_TONE_PATT_ON parameter */
 #define TONE_OFF			0x0000
 #define TONE_GERMAN_DIALTONE		0x0001
-- 
1.7.3.4

--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ