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 { ...@@ -167,8 +167,8 @@ struct rfcomm_session {
int initiator; int initiator;
/* Default DLC parameters */ /* Default DLC parameters */
int cfc;
uint mtu; uint mtu;
uint credits;
struct list_head dlcs; struct list_head dlcs;
}; };
...@@ -190,7 +190,7 @@ struct rfcomm_dlc { ...@@ -190,7 +190,7 @@ struct rfcomm_dlc {
u8 mscex; u8 mscex;
uint mtu; uint mtu;
uint credits; uint cfc;
uint rx_credits; uint rx_credits;
uint tx_credits; uint tx_credits;
...@@ -219,6 +219,11 @@ struct rfcomm_dlc { ...@@ -219,6 +219,11 @@ struct rfcomm_dlc {
#define RFCOMM_MSCEX_RX 2 #define RFCOMM_MSCEX_RX 2
#define RFCOMM_MSCEX_OK (RFCOMM_MSCEX_TX + RFCOMM_MSCEX_RX) #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 struct task_struct *rfcomm_thread;
extern unsigned long rfcomm_event; extern unsigned long rfcomm_event;
......
...@@ -52,7 +52,7 @@ ...@@ -52,7 +52,7 @@
#include <net/bluetooth/l2cap.h> #include <net/bluetooth/l2cap.h>
#include <net/bluetooth/rfcomm.h> #include <net/bluetooth/rfcomm.h>
#define VERSION "1.0" #define VERSION "1.1"
#ifndef CONFIG_BT_RFCOMM_DEBUG #ifndef CONFIG_BT_RFCOMM_DEBUG
#undef BT_DBG #undef BT_DBG
...@@ -207,7 +207,7 @@ static void rfcomm_dlc_clear_state(struct rfcomm_dlc *d) ...@@ -207,7 +207,7 @@ static void rfcomm_dlc_clear_state(struct rfcomm_dlc *d)
d->mtu = RFCOMM_DEFAULT_MTU; d->mtu = RFCOMM_DEFAULT_MTU;
d->v24_sig = RFCOMM_V24_RTC | RFCOMM_V24_RTR | RFCOMM_V24_DV; 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; 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, ...@@ -314,8 +314,8 @@ static int __rfcomm_dlc_open(struct rfcomm_dlc *d, bdaddr_t *src, bdaddr_t *dst,
d->state = BT_CONFIG; d->state = BT_CONFIG;
rfcomm_dlc_link(s, d); rfcomm_dlc_link(s, d);
d->mtu = s->mtu; d->mtu = s->mtu;
d->credits = s->credits; d->cfc = (s->cfc == RFCOMM_CFC_UNKNOWN) ? 0 : s->cfc;
if (s->state == BT_CONNECTED) if (s->state == BT_CONNECTED)
rfcomm_send_pn(s, 1, d); rfcomm_send_pn(s, 1, d);
...@@ -415,7 +415,7 @@ void __rfcomm_dlc_throttle(struct rfcomm_dlc *d) ...@@ -415,7 +415,7 @@ void __rfcomm_dlc_throttle(struct rfcomm_dlc *d)
{ {
BT_DBG("dlc %p state %ld", d, d->state); BT_DBG("dlc %p state %ld", d, d->state);
if (!d->credits) { if (!d->cfc) {
d->v24_sig |= RFCOMM_V24_FC; d->v24_sig |= RFCOMM_V24_FC;
set_bit(RFCOMM_MSC_PENDING, &d->flags); set_bit(RFCOMM_MSC_PENDING, &d->flags);
} }
...@@ -426,7 +426,7 @@ void __rfcomm_dlc_unthrottle(struct rfcomm_dlc *d) ...@@ -426,7 +426,7 @@ void __rfcomm_dlc_unthrottle(struct rfcomm_dlc *d)
{ {
BT_DBG("dlc %p state %ld", d, d->state); BT_DBG("dlc %p state %ld", d, d->state);
if (!d->credits) { if (!d->cfc) {
d->v24_sig &= ~RFCOMM_V24_FC; d->v24_sig &= ~RFCOMM_V24_FC;
set_bit(RFCOMM_MSC_PENDING, &d->flags); set_bit(RFCOMM_MSC_PENDING, &d->flags);
} }
...@@ -479,8 +479,8 @@ struct rfcomm_session *rfcomm_session_add(struct socket *sock, int state) ...@@ -479,8 +479,8 @@ struct rfcomm_session *rfcomm_session_add(struct socket *sock, int state)
s->state = state; s->state = state;
s->sock = sock; s->sock = sock;
s->mtu = RFCOMM_DEFAULT_MTU; s->mtu = RFCOMM_DEFAULT_MTU;
s->credits = RFCOMM_MAX_CREDITS; s->cfc = RFCOMM_CFC_UNKNOWN;
list_add(&s->list, &session_list); 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 ...@@ -752,7 +752,7 @@ static int rfcomm_send_pn(struct rfcomm_session *s, int cr, struct rfcomm_dlc *d
pn->ack_timer = 0; pn->ack_timer = 0;
pn->max_retrans = 0; pn->max_retrans = 0;
if (d->credits) { if (s->cfc) {
pn->flow_ctrl = cr ? 0xf0 : 0xe0; pn->flow_ctrl = cr ? 0xf0 : 0xe0;
pn->credits = RFCOMM_DEFAULT_CREDITS; pn->credits = RFCOMM_DEFAULT_CREDITS;
} else { } else {
...@@ -1142,28 +1142,22 @@ static int rfcomm_recv_sabm(struct rfcomm_session *s, u8 dlci) ...@@ -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) 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", 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); d, d->state, d->dlci, pn->mtu, pn->flow_ctrl, pn->credits);
if (cr) { if (pn->flow_ctrl == 0xf0 || pn->flow_ctrl == 0xe0) {
if (pn->flow_ctrl == 0xf0) { d->cfc = s->cfc = RFCOMM_CFC_ENABLED;
d->tx_credits = pn->credits; d->tx_credits = pn->credits;
} else {
set_bit(RFCOMM_TX_THROTTLED, &d->flags);
d->credits = 0;
}
} else { } else {
if (pn->flow_ctrl == 0xe0) { d->cfc = s->cfc = RFCOMM_CFC_DISABLED;
d->tx_credits = pn->credits; set_bit(RFCOMM_TX_THROTTLED, &d->flags);
} else {
set_bit(RFCOMM_TX_THROTTLED, &d->flags);
d->credits = 0;
}
} }
d->priority = pn->priority; d->priority = pn->priority;
d->mtu = btohs(pn->mtu); d->mtu = s->mtu = btohs(pn->mtu);
return 0; return 0;
} }
...@@ -1353,7 +1347,7 @@ static int rfcomm_recv_msc(struct rfcomm_session *s, int cr, struct sk_buff *skb ...@@ -1353,7 +1347,7 @@ static int rfcomm_recv_msc(struct rfcomm_session *s, int cr, struct sk_buff *skb
return 0; return 0;
if (cr) { 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); set_bit(RFCOMM_TX_THROTTLED, &d->flags);
else else
clear_bit(RFCOMM_TX_THROTTLED, &d->flags); 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 ...@@ -1444,7 +1438,7 @@ static int rfcomm_recv_data(struct rfcomm_session *s, u8 dlci, int pf, struct sk
goto drop; goto drop;
} }
if (pf && d->credits) { if (pf && d->cfc) {
u8 credits = *(u8 *) skb->data; skb_pull(skb, 1); u8 credits = *(u8 *) skb->data; skb_pull(skb, 1);
d->tx_credits += credits; d->tx_credits += credits;
...@@ -1549,20 +1543,20 @@ static inline int rfcomm_process_tx(struct rfcomm_dlc *d) ...@@ -1549,20 +1543,20 @@ static inline int rfcomm_process_tx(struct rfcomm_dlc *d)
struct sk_buff *skb; struct sk_buff *skb;
int err; int err;
BT_DBG("dlc %p state %ld credits %d rx_credits %d tx_credits %d", BT_DBG("dlc %p state %ld cfc %d rx_credits %d tx_credits %d",
d, d->state, d->credits, d->rx_credits, d->tx_credits); d, d->state, d->cfc, d->rx_credits, d->tx_credits);
/* Send pending MSC */ /* Send pending MSC */
if (test_and_clear_bit(RFCOMM_MSC_PENDING, &d->flags)) if (test_and_clear_bit(RFCOMM_MSC_PENDING, &d->flags))
rfcomm_send_msc(d->session, 1, d->dlci, d->v24_sig); rfcomm_send_msc(d->session, 1, d->dlci, d->v24_sig);
if (d->credits) { if (d->cfc) {
/* CFC enabled. /* CFC enabled.
* Give them some credits */ * Give them some credits */
if (!test_bit(RFCOMM_RX_THROTTLED, &d->flags) && if (!test_bit(RFCOMM_RX_THROTTLED, &d->flags) &&
d->rx_credits <= (d->credits >> 2)) { d->rx_credits <= (d->cfc >> 2)) {
rfcomm_send_credits(d->session, d->addr, d->credits - d->rx_credits); rfcomm_send_credits(d->session, d->addr, d->cfc - d->rx_credits);
d->rx_credits = d->credits; d->rx_credits = d->cfc;
} }
} else { } else {
/* CFC disabled. /* CFC disabled.
...@@ -1583,7 +1577,7 @@ static inline int rfcomm_process_tx(struct rfcomm_dlc *d) ...@@ -1583,7 +1577,7 @@ static inline int rfcomm_process_tx(struct rfcomm_dlc *d)
d->tx_credits--; d->tx_credits--;
} }
if (d->credits && !d->tx_credits) { if (d->cfc && !d->tx_credits) {
/* We're out of TX credits. /* We're out of TX credits.
* Set TX_THROTTLED flag to avoid unnesary wakeups by dlc_send. */ * Set TX_THROTTLED flag to avoid unnesary wakeups by dlc_send. */
set_bit(RFCOMM_TX_THROTTLED, &d->flags); 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