patch-2.4.23 linux-2.4.23/net/bluetooth/rfcomm/core.c

Next file: linux-2.4.23/net/bridge/br_forward.c
Previous file: linux-2.4.23/net/atm/svc.c
Back to the patch index
Back to the overall index

diff -urN linux-2.4.22/net/bluetooth/rfcomm/core.c linux-2.4.23/net/bluetooth/rfcomm/core.c
@@ -51,7 +51,7 @@
 #include <net/bluetooth/l2cap.h>
 #include <net/bluetooth/rfcomm.h>
 
-#define VERSION "1.0"
+#define VERSION "1.1"
 
 #ifndef CONFIG_BLUEZ_RFCOMM_DEBUG
 #undef  BT_DBG
@@ -202,7 +202,7 @@
 	d->mtu        = RFCOMM_DEFAULT_MTU;
 	d->v24_sig    = RFCOMM_V24_RTC | RFCOMM_V24_RTR | RFCOMM_V24_DV;
 
-	d->credits    = RFCOMM_MAX_CREDITS;
+	d->cfc        = RFCOMM_CFC_DISABLED;
 	d->rx_credits = RFCOMM_DEFAULT_CREDITS;
 }
 
@@ -309,8 +309,8 @@
 	d->state    = BT_CONFIG;
 	rfcomm_dlc_link(s, d);
 
-	d->mtu     = s->mtu;
-	d->credits = s->credits;
+	d->mtu = s->mtu;
+	d->cfc = (s->cfc == RFCOMM_CFC_UNKNOWN) ? 0 : s->cfc;
 
 	if (s->state == BT_CONNECTED)
 		rfcomm_send_pn(s, 1, d);
@@ -410,7 +410,7 @@
 {
 	BT_DBG("dlc %p state %ld", d, d->state);
 
-	if (!d->credits) {
+	if (!d->cfc) {
 		d->v24_sig |= RFCOMM_V24_FC;
 		set_bit(RFCOMM_MSC_PENDING, &d->flags);
 	}
@@ -421,7 +421,7 @@
 {
 	BT_DBG("dlc %p state %ld", d, d->state);
 
-	if (!d->credits) {
+	if (!d->cfc) {
 		d->v24_sig &= ~RFCOMM_V24_FC;
 		set_bit(RFCOMM_MSC_PENDING, &d->flags);
 	}
@@ -474,8 +474,8 @@
 	s->state = state;
 	s->sock  = sock;
 
-	s->mtu     = RFCOMM_DEFAULT_MTU;
-	s->credits = RFCOMM_MAX_CREDITS;
+	s->mtu   = RFCOMM_DEFAULT_MTU;
+	s->cfc   = RFCOMM_CFC_UNKNOWN;
 	
 	list_add(&s->list, &session_list);
 
@@ -746,7 +746,7 @@
 	pn->ack_timer   = 0;
 	pn->max_retrans = 0;
 
-	if (d->credits) {
+	if (s->cfc) {
 		pn->flow_ctrl = cr ? 0xf0 : 0xe0;
 		pn->credits = RFCOMM_DEFAULT_CREDITS;
 	} else {
@@ -853,6 +853,50 @@
 	return rfcomm_send_frame(s, buf, ptr - buf);
 }
 
+static int rfcomm_send_fcoff(struct rfcomm_session *s, int cr)
+{
+	struct rfcomm_hdr *hdr;
+	struct rfcomm_mcc *mcc;
+	u8 buf[16], *ptr = buf;
+
+	BT_DBG("%p cr %d", s, cr);
+
+	hdr = (void *) ptr; ptr += sizeof(*hdr);
+	hdr->addr = __addr(s->initiator, 0);
+	hdr->ctrl = __ctrl(RFCOMM_UIH, 0);
+	hdr->len  = __len8(sizeof(*mcc));
+
+	mcc = (void *) ptr; ptr += sizeof(*mcc);
+	mcc->type = __mcc_type(cr, RFCOMM_FCOFF);
+	mcc->len  = __len8(0);
+
+	*ptr = __fcs(buf); ptr++;
+
+	return rfcomm_send_frame(s, buf, ptr - buf);
+}
+
+static int rfcomm_send_fcon(struct rfcomm_session *s, int cr)
+{
+	struct rfcomm_hdr *hdr;
+	struct rfcomm_mcc *mcc;
+	u8 buf[16], *ptr = buf;
+
+	BT_DBG("%p cr %d", s, cr);
+
+	hdr = (void *) ptr; ptr += sizeof(*hdr);
+	hdr->addr = __addr(s->initiator, 0);
+	hdr->ctrl = __ctrl(RFCOMM_UIH, 0);
+	hdr->len  = __len8(sizeof(*mcc));
+
+	mcc = (void *) ptr; ptr += sizeof(*mcc);
+	mcc->type = __mcc_type(cr, RFCOMM_FCON);
+	mcc->len  = __len8(0);
+
+	*ptr = __fcs(buf); ptr++;
+
+	return rfcomm_send_frame(s, buf, ptr - buf);
+}
+
 static int rfcomm_send_test(struct rfcomm_session *s, int cr, u8 *pattern, int len)
 {
 	struct socket *sock = s->sock;
@@ -1091,28 +1135,22 @@
 
 static int rfcomm_apply_pn(struct rfcomm_dlc *d, int cr, struct rfcomm_pn *pn)
 {
+	struct rfcomm_session *s = d->session;
+
 	BT_DBG("dlc %p state %ld dlci %d mtu %d fc 0x%x credits %d", 
 			d, d->state, d->dlci, pn->mtu, pn->flow_ctrl, pn->credits);
 
-	if (cr) {
-		if (pn->flow_ctrl == 0xf0) {
-			d->tx_credits = pn->credits;
-		} else {
-			set_bit(RFCOMM_TX_THROTTLED, &d->flags);
-			d->credits = 0;
-		}
+	if (pn->flow_ctrl == 0xf0 || pn->flow_ctrl == 0xe0) {
+		d->cfc = s->cfc = RFCOMM_CFC_ENABLED;
+		d->tx_credits = pn->credits;
 	} else {
-		if (pn->flow_ctrl == 0xe0) {
-			d->tx_credits = pn->credits;
-		} else {
-			set_bit(RFCOMM_TX_THROTTLED, &d->flags);
-			d->credits = 0;
-		}
+		d->cfc = s->cfc = RFCOMM_CFC_DISABLED;
+		set_bit(RFCOMM_TX_THROTTLED, &d->flags);
 	}
 
 	d->priority = pn->priority;
 
-	d->mtu = btohs(pn->mtu);
+	d->mtu = s->mtu = btohs(pn->mtu);
 
 	return 0;
 }
@@ -1302,7 +1340,7 @@
 		return 0;
 
 	if (cr) {
-		if (msc->v24_sig & RFCOMM_V24_FC && !d->credits)
+		if (msc->v24_sig & RFCOMM_V24_FC && !d->cfc)
 			set_bit(RFCOMM_TX_THROTTLED, &d->flags);
 		else
 			clear_bit(RFCOMM_TX_THROTTLED, &d->flags);
@@ -1351,6 +1389,20 @@
 		rfcomm_recv_msc(s, cr, skb);
 		break;
 
+	case RFCOMM_FCOFF:
+		if (cr) {
+			set_bit(RFCOMM_TX_THROTTLED, &s->flags);
+			rfcomm_send_fcoff(s, 0);
+		}
+		break;
+
+	case RFCOMM_FCON:
+		if (cr) {
+			clear_bit(RFCOMM_TX_THROTTLED, &s->flags);
+			rfcomm_send_fcon(s, 0);
+		}
+		break;
+
 	case RFCOMM_TEST:
 		if (cr)
 			rfcomm_send_test(s, 0, skb->data, skb->len);
@@ -1379,7 +1431,7 @@
 		goto drop;
 	}
 
-	if (pf && d->credits) {
+	if (pf && d->cfc) {
 		u8 credits = *(u8 *) skb->data; skb_pull(skb, 1);
 
 		d->tx_credits += credits;
@@ -1484,20 +1536,20 @@
 	struct sk_buff *skb;
 	int err;
 
-	BT_DBG("dlc %p state %ld credits %d rx_credits %d tx_credits %d", 
-			d, d->state, d->credits, d->rx_credits, d->tx_credits);
+	BT_DBG("dlc %p state %ld cfc %d rx_credits %d tx_credits %d", 
+			d, d->state, d->cfc, d->rx_credits, d->tx_credits);
 
 	/* Send pending MSC */
 	if (test_and_clear_bit(RFCOMM_MSC_PENDING, &d->flags))
 		rfcomm_send_msc(d->session, 1, d->dlci, d->v24_sig);
 	
-	if (d->credits) {
+	if (d->cfc) {
 		/* CFC enabled. 
 		 * Give them some credits */
 		if (!test_bit(RFCOMM_RX_THROTTLED, &d->flags) &&
-			       	d->rx_credits <= (d->credits >> 2)) {
-			rfcomm_send_credits(d->session, d->addr, d->credits - d->rx_credits);
-			d->rx_credits = d->credits;
+			       	d->rx_credits <= (d->cfc >> 2)) {
+			rfcomm_send_credits(d->session, d->addr, d->cfc - d->rx_credits);
+			d->rx_credits = d->cfc;
 		}
 	} else {
 		/* CFC disabled. 
@@ -1518,7 +1570,7 @@
 		d->tx_credits--;
 	}
 
-	if (d->credits && !d->tx_credits) {
+	if (d->cfc && !d->tx_credits) {
 		/* We're out of TX credits.
 		 * Set TX_THROTTLED flag to avoid unnesary wakeups by dlc_send. */
 		set_bit(RFCOMM_TX_THROTTLED, &d->flags);
@@ -1541,6 +1593,9 @@
 			continue;
 		}
 
+		if (test_bit(RFCOMM_TX_THROTTLED, &s->flags))
+			continue;
+
 		if ((d->state == BT_CONNECTED || d->state == BT_DISCONN) &&
 				d->mscex == RFCOMM_MSCEX_OK)
 			rfcomm_process_tx(d);

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)