Commit 1b206f44 authored by Marcel Holtmann's avatar Marcel Holtmann

[Bluetooth] Disable credit based flow control by default

The credit based flow control must be disabled by default for compatibility
with Bluetooth 1.0b devices. This patch makes CFC a session attribute,
introduces CFC states and cleans up the CFC logic.
parent 67e9bb60
......@@ -167,8 +167,8 @@ struct rfcomm_session {
int initiator;
/* Default DLC parameters */
int cfc;
uint mtu;
uint credits;
struct list_head dlcs;
};
......@@ -190,7 +190,7 @@ struct rfcomm_dlc {
u8 mscex;
uint mtu;
uint credits;
uint cfc;
uint rx_credits;
uint tx_credits;
......@@ -219,6 +219,11 @@ struct rfcomm_dlc {
#define RFCOMM_MSCEX_RX 2
#define RFCOMM_MSCEX_OK (RFCOMM_MSCEX_TX + RFCOMM_MSCEX_RX)
/* CFC states */
#define RFCOMM_CFC_UNKNOWN -1
#define RFCOMM_CFC_DISABLED 0
#define RFCOMM_CFC_ENABLED RFCOMM_MAX_CREDITS
extern struct task_struct *rfcomm_thread;
extern unsigned long rfcomm_event;
......
......@@ -52,7 +52,7 @@
#include <net/bluetooth/l2cap.h>
#include <net/bluetooth/rfcomm.h>
#define VERSION "1.0"
#define VERSION "1.1"
#ifndef CONFIG_BT_RFCOMM_DEBUG
#undef BT_DBG
......@@ -207,7 +207,7 @@ static void rfcomm_dlc_clear_state(struct rfcomm_dlc *d)
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;
}
......@@ -314,8 +314,8 @@ static int __rfcomm_dlc_open(struct rfcomm_dlc *d, bdaddr_t *src, bdaddr_t *dst,
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);
......@@ -415,7 +415,7 @@ void __rfcomm_dlc_throttle(struct rfcomm_dlc *d)
{
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);
}
......@@ -426,7 +426,7 @@ void __rfcomm_dlc_unthrottle(struct rfcomm_dlc *d)
{
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);
}
......@@ -479,8 +479,8 @@ struct rfcomm_session *rfcomm_session_add(struct socket *sock, int state)
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);
......@@ -752,7 +752,7 @@ static int rfcomm_send_pn(struct rfcomm_session *s, int cr, struct rfcomm_dlc *d
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 {
......@@ -1142,28 +1142,22 @@ static int rfcomm_recv_sabm(struct rfcomm_session *s, u8 dlci)
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;
}
......@@ -1353,7 +1347,7 @@ static int rfcomm_recv_msc(struct rfcomm_session *s, int cr, struct sk_buff *skb
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);
......@@ -1444,7 +1438,7 @@ static int rfcomm_recv_data(struct rfcomm_session *s, u8 dlci, int pf, struct sk
goto drop;
}
if (pf && d->credits) {
if (pf && d->cfc) {
u8 credits = *(u8 *) skb->data; skb_pull(skb, 1);
d->tx_credits += credits;
......@@ -1549,20 +1543,20 @@ static inline int rfcomm_process_tx(struct rfcomm_dlc *d)
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.
......@@ -1583,7 +1577,7 @@ static inline int rfcomm_process_tx(struct rfcomm_dlc *d)
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);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment