* [PATCH 4/7] Bluetooth: Add Kconfig option for L2CAP Extended Features
From: Gustavo F. Padovan @ 2010-04-14 19:41 UTC (permalink / raw)
To: linux-bluetooth; +Cc: marcel, gustavo, jprvita, ulisses
In-Reply-To: <1271274112-7806-4-git-send-email-padovan@profusion.mobi>
The L2CAP Extended Features are still unstable and under development,
so we are adding them under the EXPERIMENTAL flag to get more feedback
on them. L2CAP Extended Features includes the Enhanced Retransmission
and Streaming Modes, Frame Check Sequence (FCS), and Segmentation and
Reassemby (SAR).
Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi>
Reviewed-by: João Paulo Rechi Vita <jprvita@profusion.mobi>
---
net/bluetooth/Kconfig | 13 +++++++++++++
net/bluetooth/l2cap.c | 4 ++++
2 files changed, 17 insertions(+), 0 deletions(-)
diff --git a/net/bluetooth/Kconfig b/net/bluetooth/Kconfig
index ed37168..ee3b304 100644
--- a/net/bluetooth/Kconfig
+++ b/net/bluetooth/Kconfig
@@ -43,6 +43,19 @@ config BT_L2CAP
Say Y here to compile L2CAP support into the kernel or say M to
compile it as module (l2cap).
+config BT_L2CAP_EXT_FEATURES
+ bool "L2CAP Extended Features support (EXPERIMENTAL)"
+ depends on BT_L2CAP && EXPERIMENTAL
+ help
+ This option enables the L2CAP Extended Features support. These
+ new features include the Enhanced Retransmission and Streaming
+ Modes, the Frame Check Sequence (FCS), and Segmentation and
+ Reassembly (SAR) for L2CAP packets. They are a required for the
+ new Alternate MAC/PHY and the Bluetooth Medical Profile.
+
+ You should say N unless you know what you are doing. Note that
+ this is in an experimental state yet.
+
config BT_SCO
tristate "SCO links support"
depends on BT
diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c
index b653039..63248aa 100644
--- a/net/bluetooth/l2cap.c
+++ b/net/bluetooth/l2cap.c
@@ -55,7 +55,11 @@
#define VERSION "2.14"
+#ifdef CONFIG_BT_L2CAP_EXT_FEATURES
+static int enable_ertm = 1;
+#else
static int enable_ertm = 0;
+#endif
static int max_transmit = L2CAP_DEFAULT_MAX_TX;
static int tx_window = L2CAP_DEFAULT_TX_WINDOW;
--
1.6.4.4
^ permalink raw reply related
* [PATCH 5/7] Bluetooth: Add SOCK_STREAM support to L2CAP
From: Gustavo F. Padovan @ 2010-04-14 19:41 UTC (permalink / raw)
To: linux-bluetooth; +Cc: marcel, gustavo, jprvita, ulisses
In-Reply-To: <1271274112-7806-5-git-send-email-padovan@profusion.mobi>
if enable_ertm is true and we have SOCK_STREAM the default mode will be
ERTM, otherwise Basic Mode.
Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi>
Reviewed-by: João Paulo Rechi Vita <jprvita@profusion.mobi>
---
net/bluetooth/l2cap.c | 40 ++++++++++++++++++++++++++--------------
1 files changed, 26 insertions(+), 14 deletions(-)
diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c
index 63248aa..0e24ee3 100644
--- a/net/bluetooth/l2cap.c
+++ b/net/bluetooth/l2cap.c
@@ -224,7 +224,7 @@ static void __l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct so
l2cap_pi(sk)->conn = conn;
- if (sk->sk_type == SOCK_SEQPACKET) {
+ if (sk->sk_type == SOCK_SEQPACKET || sk->sk_type == SOCK_STREAM) {
/* Alloc CID for connection-oriented socket */
l2cap_pi(sk)->scid = l2cap_alloc_cid(l);
} else if (sk->sk_type == SOCK_DGRAM) {
@@ -452,7 +452,8 @@ static void l2cap_conn_start(struct l2cap_conn *conn)
for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) {
bh_lock_sock(sk);
- if (sk->sk_type != SOCK_SEQPACKET) {
+ if (sk->sk_type != SOCK_SEQPACKET &&
+ sk->sk_type != SOCK_STREAM) {
bh_unlock_sock(sk);
continue;
}
@@ -512,7 +513,8 @@ static void l2cap_conn_ready(struct l2cap_conn *conn)
for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) {
bh_lock_sock(sk);
- if (sk->sk_type != SOCK_SEQPACKET) {
+ if (sk->sk_type != SOCK_SEQPACKET &&
+ sk->sk_type != SOCK_STREAM) {
l2cap_sock_clear_timer(sk);
sk->sk_state = BT_CONNECTED;
sk->sk_state_change(sk);
@@ -721,7 +723,8 @@ static void __l2cap_sock_close(struct sock *sk, int reason)
case BT_CONNECTED:
case BT_CONFIG:
- if (sk->sk_type == SOCK_SEQPACKET) {
+ if (sk->sk_type == SOCK_SEQPACKET ||
+ sk->sk_type == SOCK_STREAM) {
struct l2cap_conn *conn = l2cap_pi(sk)->conn;
sk->sk_state = BT_DISCONN;
@@ -732,7 +735,8 @@ static void __l2cap_sock_close(struct sock *sk, int reason)
break;
case BT_CONNECT2:
- if (sk->sk_type == SOCK_SEQPACKET) {
+ if (sk->sk_type == SOCK_SEQPACKET ||
+ sk->sk_type == SOCK_STREAM) {
struct l2cap_conn *conn = l2cap_pi(sk)->conn;
struct l2cap_conn_rsp rsp;
__u16 result;
@@ -795,7 +799,10 @@ static void l2cap_sock_init(struct sock *sk, struct sock *parent)
} else {
pi->imtu = L2CAP_DEFAULT_MTU;
pi->omtu = 0;
- pi->mode = L2CAP_MODE_BASIC;
+ if (enable_ertm && sk->sk_type == SOCK_STREAM)
+ pi->mode = L2CAP_MODE_ERTM;
+ else
+ pi->mode = L2CAP_MODE_BASIC;
pi->max_tx = max_transmit;
pi->fcs = L2CAP_FCS_CRC16;
pi->tx_win = tx_window;
@@ -852,7 +859,7 @@ static int l2cap_sock_create(struct net *net, struct socket *sock, int protocol,
sock->state = SS_UNCONNECTED;
- if (sock->type != SOCK_SEQPACKET &&
+ if (sock->type != SOCK_SEQPACKET && sock->type != SOCK_STREAM &&
sock->type != SOCK_DGRAM && sock->type != SOCK_RAW)
return -ESOCKTNOSUPPORT;
@@ -1000,7 +1007,8 @@ static int l2cap_do_connect(struct sock *sk)
l2cap_sock_set_timer(sk, sk->sk_sndtimeo);
if (hcon->state == BT_CONNECTED) {
- if (sk->sk_type != SOCK_SEQPACKET) {
+ if (sk->sk_type != SOCK_SEQPACKET &&
+ sk->sk_type != SOCK_STREAM) {
l2cap_sock_clear_timer(sk);
sk->sk_state = BT_CONNECTED;
} else
@@ -1033,7 +1041,8 @@ static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int al
lock_sock(sk);
- if (sk->sk_type == SOCK_SEQPACKET && !la.l2_psm) {
+ if ((sk->sk_type == SOCK_SEQPACKET || sk->sk_type == SOCK_STREAM)
+ && !la.l2_psm) {
err = -EINVAL;
goto done;
}
@@ -1097,7 +1106,8 @@ static int l2cap_sock_listen(struct socket *sock, int backlog)
lock_sock(sk);
- if (sk->sk_state != BT_BOUND || sock->type != SOCK_SEQPACKET) {
+ if ((sock->type != SOCK_SEQPACKET && sock->type != SOCK_STREAM)
+ || sk->sk_state != BT_BOUND) {
err = -EBADFD;
goto done;
}
@@ -1832,7 +1842,8 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch
switch (optname) {
case BT_SECURITY:
- if (sk->sk_type != SOCK_SEQPACKET && sk->sk_type != SOCK_RAW) {
+ if (sk->sk_type != SOCK_SEQPACKET && sk->sk_type != SOCK_STREAM
+ && sk->sk_type != SOCK_RAW) {
err = -EINVAL;
break;
}
@@ -1982,7 +1993,8 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, ch
switch (optname) {
case BT_SECURITY:
- if (sk->sk_type != SOCK_SEQPACKET && sk->sk_type != SOCK_RAW) {
+ if (sk->sk_type != SOCK_SEQPACKET && sk->sk_type != SOCK_STREAM
+ && sk->sk_type != SOCK_RAW) {
err = -EINVAL;
break;
}
@@ -2289,7 +2301,7 @@ static int l2cap_build_conf_req(struct sock *sk, void *data)
{
struct l2cap_pinfo *pi = l2cap_pi(sk);
struct l2cap_conf_req *req = data;
- struct l2cap_conf_rfc rfc = { .mode = L2CAP_MODE_BASIC };
+ struct l2cap_conf_rfc rfc = { .mode = pi->mode };
void *ptr = req->data;
BT_DBG("sk %p", sk);
@@ -3979,7 +3991,7 @@ static int l2cap_disconn_cfm(struct hci_conn *hcon, u8 reason)
static inline void l2cap_check_encryption(struct sock *sk, u8 encrypt)
{
- if (sk->sk_type != SOCK_SEQPACKET)
+ if (sk->sk_type != SOCK_SEQPACKET && sk->sk_type != SOCK_STREAM)
return;
if (encrypt == 0x00) {
--
1.6.4.4
^ permalink raw reply related
* [PATCH 6/7] Bluetooth: Implement missing parts of the Invalid Frame Detection
From: Gustavo F. Padovan @ 2010-04-14 19:41 UTC (permalink / raw)
To: linux-bluetooth; +Cc: marcel, gustavo, jprvita, ulisses
In-Reply-To: <1271274112-7806-6-git-send-email-padovan@profusion.mobi>
There is a plenty of situation where ERTM shall close the channel, this
commit treats the cases regarding Invalid Frame Detection.
It create one reassembly SDU function for ERTM and other for Streaming
Mode to make the Invalid Frame Detection handling less complex.
Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi>
Reviewed-by: João Paulo Rechi Vita <jprvita@profusion.mobi>
---
net/bluetooth/l2cap.c | 119 ++++++++++++++++++++++++++++++++++++++++++++++---
1 files changed, 112 insertions(+), 7 deletions(-)
diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c
index 0e24ee3..1f66541 100644
--- a/net/bluetooth/l2cap.c
+++ b/net/bluetooth/l2cap.c
@@ -3317,12 +3317,111 @@ static void l2cap_add_to_srej_queue(struct sock *sk, struct sk_buff *skb, u8 tx_
__skb_queue_tail(SREJ_QUEUE(sk), skb);
}
-static int l2cap_sar_reassembly_sdu(struct sock *sk, struct sk_buff *skb, u16 control)
+static int l2cap_ertm_reassembly_sdu(struct sock *sk, struct sk_buff *skb, u16 control)
+{
+ struct l2cap_pinfo *pi = l2cap_pi(sk);
+ struct sk_buff *_skb;
+ int err = 0;
+
+ switch (control & L2CAP_CTRL_SAR) {
+ case L2CAP_SDU_UNSEGMENTED:
+ if (pi->conn_state & L2CAP_CONN_SAR_SDU)
+ goto drop;
+
+ err = sock_queue_rcv_skb(sk, skb);
+ if (!err)
+ return err;
+
+ break;
+
+ case L2CAP_SDU_START:
+ if (pi->conn_state & L2CAP_CONN_SAR_SDU)
+ goto drop;
+
+ pi->sdu_len = get_unaligned_le16(skb->data);
+ skb_pull(skb, 2);
+
+ if (pi->sdu_len > pi->imtu)
+ goto disconnect;
+
+ pi->sdu = bt_skb_alloc(pi->sdu_len, GFP_ATOMIC);
+ if (!pi->sdu) {
+ err = -ENOMEM;
+ break;
+ }
+
+ memcpy(skb_put(pi->sdu, skb->len), skb->data, skb->len);
+
+ pi->conn_state |= L2CAP_CONN_SAR_SDU;
+ pi->partial_sdu_len = skb->len;
+ break;
+
+ case L2CAP_SDU_CONTINUE:
+ if (!(pi->conn_state & L2CAP_CONN_SAR_SDU))
+ goto disconnect;
+
+ if (!pi->sdu)
+ goto disconnect;
+
+ memcpy(skb_put(pi->sdu, skb->len), skb->data, skb->len);
+
+ pi->partial_sdu_len += skb->len;
+ if (pi->partial_sdu_len > pi->sdu_len)
+ goto drop;
+
+ break;
+
+ case L2CAP_SDU_END:
+ if (!(pi->conn_state & L2CAP_CONN_SAR_SDU))
+ goto disconnect;
+
+ if (!pi->sdu)
+ goto disconnect;
+
+ memcpy(skb_put(pi->sdu, skb->len), skb->data, skb->len);
+
+ pi->conn_state &= ~L2CAP_CONN_SAR_SDU;
+ pi->partial_sdu_len += skb->len;
+
+ if (pi->partial_sdu_len > pi->imtu)
+ goto drop;
+
+ if (pi->partial_sdu_len != pi->sdu_len)
+ goto drop;
+
+ _skb = skb_clone(pi->sdu, GFP_ATOMIC);
+ err = sock_queue_rcv_skb(sk, _skb);
+ if (err < 0)
+ kfree_skb(_skb);
+
+ kfree_skb(pi->sdu);
+ break;
+ }
+
+ kfree_skb(skb);
+ return err;
+
+drop:
+ kfree_skb(pi->sdu);
+ pi->sdu = NULL;
+
+disconnect:
+ l2cap_send_disconn_req(pi->conn, sk);
+ kfree_skb(skb);
+ return 0;
+}
+
+static int l2cap_streaming_reassembly_sdu(struct sock *sk, struct sk_buff *skb, u16 control)
{
struct l2cap_pinfo *pi = l2cap_pi(sk);
struct sk_buff *_skb;
int err = -EINVAL;
+ /*
+ * TODO: We have to notify the userland if some data is lost with the
+ * Streaming Mode.
+ */
+
switch (control & L2CAP_CTRL_SAR) {
case L2CAP_SDU_UNSEGMENTED:
if (pi->conn_state & L2CAP_CONN_SAR_SDU) {
@@ -3417,7 +3516,7 @@ static void l2cap_check_srej_gap(struct sock *sk, u8 tx_seq)
skb = skb_dequeue(SREJ_QUEUE(sk));
control |= bt_cb(skb)->sar << L2CAP_CTRL_SAR_SHIFT;
- l2cap_sar_reassembly_sdu(sk, skb, control);
+ l2cap_ertm_reassembly_sdu(sk, skb, control);
l2cap_pi(sk)->buffer_seq_srej =
(l2cap_pi(sk)->buffer_seq_srej + 1) % 64;
tx_seq++;
@@ -3558,7 +3657,7 @@ expected:
pi->buffer_seq = (pi->buffer_seq + 1) % 64;
- err = l2cap_sar_reassembly_sdu(sk, skb, rx_control);
+ err = l2cap_ertm_reassembly_sdu(sk, skb, rx_control);
if (err < 0)
return err;
@@ -3786,20 +3885,26 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk
* Receiver will miss it and start proper recovery
* procedures and ask retransmission.
*/
- if (len > pi->mps)
+ if (len > pi->mps) {
+ l2cap_send_disconn_req(pi->conn, sk);
goto drop;
+ }
if (l2cap_check_fcs(pi, skb))
goto drop;
if (__is_iframe(control)) {
- if (len < 4)
+ if (len < 4){
+ l2cap_send_disconn_req(pi->conn, sk);
goto drop;
+ }
l2cap_data_channel_iframe(sk, control, skb);
} else {
- if (len != 0)
+ if (len != 0) {
+ l2cap_send_disconn_req(pi->conn, sk);
goto drop;
+ }
l2cap_data_channel_sframe(sk, control, skb);
}
@@ -3830,7 +3935,7 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk
else
pi->expected_tx_seq = (tx_seq + 1) % 64;
- l2cap_sar_reassembly_sdu(sk, skb, control);
+ l2cap_streaming_reassembly_sdu(sk, skb, control);
goto done;
--
1.6.4.4
^ permalink raw reply related
* [PATCH 7/7] Bluetooth: Implement Local Busy Condition handling
From: Gustavo F. Padovan @ 2010-04-14 19:41 UTC (permalink / raw)
To: linux-bluetooth; +Cc: marcel, gustavo, jprvita, ulisses
In-Reply-To: <1271274112-7806-7-git-send-email-padovan@profusion.mobi>
Supports Local Busy condition handling through a waitqueue that wake ups
each 200ms and try to push the packets to the upper layer. If it can
push all the queue then it leaves the Local Busy state.
The patch modifies the behaviour of l2cap_ertm_reassembly_sdu() to
support retry of the push operation.
Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi>
Reviewed-by: João Paulo Rechi Vita <jprvita@profusion.mobi>
---
include/net/bluetooth/l2cap.h | 6 ++
net/bluetooth/l2cap.c | 183 ++++++++++++++++++++++++++++++++++++-----
2 files changed, 169 insertions(+), 20 deletions(-)
diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index 15f6e55..fd0e4e4 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -35,6 +35,7 @@
#define L2CAP_DEFAULT_MONITOR_TO 12000 /* 12 seconds */
#define L2CAP_DEFAULT_MAX_PDU_SIZE 672
#define L2CAP_DEFAULT_ACK_TO 200
+#define L2CAP_LOCAL_BUSY_TRIES 12
#define L2CAP_CONN_TIMEOUT (40000) /* 40 seconds */
#define L2CAP_INFO_TIMEOUT (4000) /* 4 seconds */
@@ -294,6 +295,7 @@ struct l2cap_conn {
#define l2cap_pi(sk) ((struct l2cap_pinfo *) sk)
#define TX_QUEUE(sk) (&l2cap_pi(sk)->tx_queue)
#define SREJ_QUEUE(sk) (&l2cap_pi(sk)->srej_queue)
+#define BUSY_QUEUE(sk) (&l2cap_pi(sk)->busy_queue)
#define SREJ_LIST(sk) (&l2cap_pi(sk)->srej_l.list)
struct srej_list {
@@ -356,6 +358,8 @@ struct l2cap_pinfo {
struct timer_list ack_timer;
struct sk_buff_head tx_queue;
struct sk_buff_head srej_queue;
+ struct sk_buff_head busy_queue;
+ struct work_struct busy_work;
struct srej_list srej_l;
struct l2cap_conn *conn;
struct sock *next_c;
@@ -383,6 +387,8 @@ struct l2cap_pinfo {
#define L2CAP_CONN_LOCAL_BUSY 0x0040
#define L2CAP_CONN_REJ_ACT 0x0080
#define L2CAP_CONN_SEND_FBIT 0x0100
+#define L2CAP_CONN_RNR_SENT 0x0200
+#define L2CAP_CONN_SAR_RETRY 0x0400
#define __mod_retrans_timer() mod_timer(&l2cap_pi(sk)->retrans_timer, \
jiffies + msecs_to_jiffies(L2CAP_DEFAULT_RETRANS_TO));
diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c
index 1f66541..709dc03 100644
--- a/net/bluetooth/l2cap.c
+++ b/net/bluetooth/l2cap.c
@@ -68,10 +68,14 @@ static u8 l2cap_fixed_chan[8] = { 0x02, };
static const struct proto_ops l2cap_sock_ops;
+static struct workqueue_struct *_busy_wq;
+
static struct bt_sock_list l2cap_sk_list = {
.lock = __RW_LOCK_UNLOCKED(l2cap_sk_list.lock)
};
+static void l2cap_busy_work(struct work_struct *work);
+
static void __l2cap_sock_close(struct sock *sk, int reason);
static void l2cap_sock_close(struct sock *sk);
static void l2cap_sock_kill(struct sock *sk);
@@ -386,8 +390,10 @@ static inline void l2cap_send_sframe(struct l2cap_pinfo *pi, u16 control)
static inline void l2cap_send_rr_or_rnr(struct l2cap_pinfo *pi, u16 control)
{
- if (pi->conn_state & L2CAP_CONN_LOCAL_BUSY)
+ if (pi->conn_state & L2CAP_CONN_LOCAL_BUSY) {
control |= L2CAP_SUPER_RCV_NOT_READY;
+ pi->conn_state |= L2CAP_CONN_RNR_SENT;
+ }
else
control |= L2CAP_SUPER_RCV_READY;
@@ -816,6 +822,7 @@ static void l2cap_sock_init(struct sock *sk, struct sock *parent)
pi->flush_to = L2CAP_DEFAULT_FLUSH_TO;
skb_queue_head_init(TX_QUEUE(sk));
skb_queue_head_init(SREJ_QUEUE(sk));
+ skb_queue_head_init(BUSY_QUEUE(sk));
INIT_LIST_HEAD(SREJ_LIST(sk));
}
@@ -1440,6 +1447,7 @@ static void l2cap_send_ack(struct l2cap_pinfo *pi)
if (pi->conn_state & L2CAP_CONN_LOCAL_BUSY) {
control |= L2CAP_SUPER_RCV_NOT_READY;
+ pi->conn_state |= L2CAP_CONN_RNR_SENT;
l2cap_send_sframe(pi, control);
return;
} else if (l2cap_ertm_send(sk) == 0) {
@@ -2266,6 +2274,9 @@ static inline void l2cap_ertm_init(struct sock *sk)
l2cap_ack_timeout, (unsigned long) sk);
__skb_queue_head_init(SREJ_QUEUE(sk));
+ __skb_queue_head_init(BUSY_QUEUE(sk));
+
+ INIT_WORK(&l2cap_pi(sk)->busy_work, l2cap_busy_work);
}
static int l2cap_mode_supported(__u8 mode, __u32 feat_mask)
@@ -3033,6 +3044,7 @@ static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd
if (l2cap_pi(sk)->mode == L2CAP_MODE_ERTM) {
skb_queue_purge(SREJ_QUEUE(sk));
+ skb_queue_purge(BUSY_QUEUE(sk));
del_timer(&l2cap_pi(sk)->retrans_timer);
del_timer(&l2cap_pi(sk)->monitor_timer);
del_timer(&l2cap_pi(sk)->ack_timer);
@@ -3064,6 +3076,7 @@ static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, struct l2cap_cmd
if (l2cap_pi(sk)->mode == L2CAP_MODE_ERTM) {
skb_queue_purge(SREJ_QUEUE(sk));
+ skb_queue_purge(BUSY_QUEUE(sk));
del_timer(&l2cap_pi(sk)->retrans_timer);
del_timer(&l2cap_pi(sk)->monitor_timer);
del_timer(&l2cap_pi(sk)->ack_timer);
@@ -3274,6 +3287,7 @@ static inline void l2cap_send_i_or_rr_or_rnr(struct sock *sk)
if (pi->conn_state & L2CAP_CONN_LOCAL_BUSY) {
control |= L2CAP_SUPER_RCV_NOT_READY | L2CAP_CTRL_FINAL;
l2cap_send_sframe(pi, control);
+ pi->conn_state |= L2CAP_CONN_RNR_SENT;
pi->conn_state &= ~L2CAP_CONN_SEND_FBIT;
}
@@ -3321,7 +3335,7 @@ static int l2cap_ertm_reassembly_sdu(struct sock *sk, struct sk_buff *skb, u16 c
{
struct l2cap_pinfo *pi = l2cap_pi(sk);
struct sk_buff *_skb;
- int err = 0;
+ int err;
switch (control & L2CAP_CTRL_SAR) {
case L2CAP_SDU_UNSEGMENTED:
@@ -3339,16 +3353,18 @@ static int l2cap_ertm_reassembly_sdu(struct sock *sk, struct sk_buff *skb, u16 c
goto drop;
pi->sdu_len = get_unaligned_le16(skb->data);
- skb_pull(skb, 2);
if (pi->sdu_len > pi->imtu)
goto disconnect;
pi->sdu = bt_skb_alloc(pi->sdu_len, GFP_ATOMIC);
- if (!pi->sdu) {
- err = -ENOMEM;
- break;
- }
+ if (!pi->sdu)
+ return -ENOMEM;
+
+ /* pull sdu_len bytes only after alloc, because of Local Busy
+ * condition we have to be sure that this will be executed
+ * only once, i.e., when alloc does not fail */
+ skb_pull(skb, 2);
memcpy(skb_put(pi->sdu, skb->len), skb->data, skb->len);
@@ -3378,28 +3394,40 @@ static int l2cap_ertm_reassembly_sdu(struct sock *sk, struct sk_buff *skb, u16 c
if (!pi->sdu)
goto disconnect;
- memcpy(skb_put(pi->sdu, skb->len), skb->data, skb->len);
+ if (!(pi->conn_state & L2CAP_CONN_SAR_RETRY)) {
+ memcpy(skb_put(pi->sdu, skb->len), skb->data, skb->len);
- pi->conn_state &= ~L2CAP_CONN_SAR_SDU;
- pi->partial_sdu_len += skb->len;
+ pi->partial_sdu_len += skb->len;
- if (pi->partial_sdu_len > pi->imtu)
- goto drop;
+ if (pi->partial_sdu_len > pi->imtu)
+ goto drop;
- if (pi->partial_sdu_len != pi->sdu_len)
- goto drop;
+ if (pi->partial_sdu_len != pi->sdu_len)
+ goto drop;
+ }
_skb = skb_clone(pi->sdu, GFP_ATOMIC);
+ if (!_skb) {
+ pi->conn_state |= L2CAP_CONN_SAR_RETRY;
+ return -ENOMEM;
+ }
+
err = sock_queue_rcv_skb(sk, _skb);
- if (err < 0)
+ if (err < 0) {
kfree_skb(_skb);
+ pi->conn_state |= L2CAP_CONN_SAR_RETRY;
+ return err;
+ }
+
+ pi->conn_state &= ~L2CAP_CONN_SAR_RETRY;
+ pi->conn_state &= ~L2CAP_CONN_SAR_SDU;
kfree_skb(pi->sdu);
break;
}
kfree_skb(skb);
- return err;
+ return 0;
drop:
kfree_skb(pi->sdu);
@@ -3411,6 +3439,112 @@ disconnect:
return 0;
}
+static void l2cap_busy_work(struct work_struct *work)
+{
+ DECLARE_WAITQUEUE(wait, current);
+ struct l2cap_pinfo *pi =
+ container_of(work, struct l2cap_pinfo, busy_work);
+ struct sock *sk = (struct sock *)pi;
+ int n_tries = 0, timeo = HZ/5, err;
+ struct sk_buff *skb;
+ u16 control;
+
+ lock_sock(sk);
+
+ add_wait_queue(sk->sk_sleep, &wait);
+ while ((skb = skb_peek(BUSY_QUEUE(sk)))) {
+ set_current_state(TASK_INTERRUPTIBLE);
+
+ if (n_tries++ > L2CAP_LOCAL_BUSY_TRIES) {
+ err = -EBUSY;
+ l2cap_send_disconn_req(pi->conn, sk);
+ goto done;
+ }
+
+ if (!timeo)
+ timeo = HZ/5;
+
+ if (signal_pending(current)) {
+ err = sock_intr_errno(timeo);
+ goto done;
+ }
+
+ release_sock(sk);
+ timeo = schedule_timeout(timeo);
+ lock_sock(sk);
+
+ err = sock_error(sk);
+ if (err)
+ goto done;
+
+ while((skb = skb_peek(BUSY_QUEUE(sk)))) {
+ control = bt_cb(skb)->sar << L2CAP_CTRL_SAR_SHIFT;
+ err = l2cap_ertm_reassembly_sdu(sk, skb, control);
+ if (err < 0)
+ break;
+
+ skb_dequeue(BUSY_QUEUE(sk));
+
+ pi->buffer_seq = (pi->buffer_seq + 1) % 64;
+ }
+
+ if (!skb)
+ break;
+ }
+
+ if (!(pi->conn_state & L2CAP_CONN_RNR_SENT))
+ goto done;
+
+ control = pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
+ control |= L2CAP_SUPER_RCV_READY | L2CAP_CTRL_POLL;
+ l2cap_send_sframe(pi, control);
+
+ del_timer(&pi->retrans_timer);
+ __mod_monitor_timer();
+
+ pi->conn_state &= ~L2CAP_CONN_LOCAL_BUSY;
+ pi->conn_state &= ~L2CAP_CONN_RNR_SENT;
+
+done:
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(sk->sk_sleep, &wait);
+
+ release_sock(sk);
+}
+
+static int l2cap_push_rx_skb(struct sock *sk, struct sk_buff *skb, u16 control)
+{
+ struct l2cap_pinfo *pi = l2cap_pi(sk);
+ int sctrl, err;
+
+ if (pi->conn_state & L2CAP_CONN_LOCAL_BUSY) {
+ bt_cb(skb)->sar = control >> L2CAP_CTRL_SAR_SHIFT;
+ __skb_queue_tail(BUSY_QUEUE(sk), skb);
+ return -EBUSY;
+ }
+
+ err = l2cap_ertm_reassembly_sdu(sk, skb, control);
+ if (err >= 0) {
+ pi->buffer_seq = (pi->buffer_seq + 1) % 64;
+ return err;
+ }
+
+ /* Busy Condition */
+ pi->conn_state |= L2CAP_CONN_LOCAL_BUSY;
+ bt_cb(skb)->sar = control >> L2CAP_CTRL_SAR_SHIFT;
+ __skb_queue_tail(BUSY_QUEUE(sk), skb);
+
+ sctrl = pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
+ sctrl |= L2CAP_SUPER_RCV_NOT_READY;
+ l2cap_send_sframe(pi, sctrl);
+
+ pi->conn_state |= L2CAP_CONN_RNR_SENT;
+
+ queue_work(_busy_wq, &pi->busy_work);
+
+ return err;
+}
+
static int l2cap_streaming_reassembly_sdu(struct sock *sk, struct sk_buff *skb, u16 control)
{
struct l2cap_pinfo *pi = l2cap_pi(sk);
@@ -3585,6 +3719,9 @@ static inline int l2cap_data_channel_iframe(struct sock *sk, u16 rx_control, str
if (tx_seq == pi->expected_tx_seq)
goto expected;
+ if (pi->conn_state == L2CAP_CONN_LOCAL_BUSY)
+ return 0;
+
/* Check for duplicated tx_seq. This actually
* subtracts 1 from expected_tx_seq */
if (tx_seq == (pi->expected_tx_seq + 63) % 64) {
@@ -3628,6 +3765,7 @@ static inline int l2cap_data_channel_iframe(struct sock *sk, u16 rx_control, str
pi->buffer_seq_srej = pi->buffer_seq;
__skb_queue_head_init(SREJ_QUEUE(sk));
+ __skb_queue_head_init(BUSY_QUEUE(sk));
l2cap_add_to_srej_queue(sk, skb, tx_seq, sar);
pi->conn_state |= L2CAP_CONN_SEND_PBIT;
@@ -3655,11 +3793,9 @@ expected:
}
}
- pi->buffer_seq = (pi->buffer_seq + 1) % 64;
-
- err = l2cap_ertm_reassembly_sdu(sk, skb, rx_control);
+ err = l2cap_push_rx_skb(sk, skb, rx_control);
if (err < 0)
- return err;
+ return 0;
__mod_ack_timer();
@@ -4354,6 +4490,10 @@ static int __init l2cap_init(void)
if (err < 0)
return err;
+ _busy_wq = create_singlethread_workqueue("l2cap");
+ if (!_busy_wq)
+ goto error;
+
err = bt_sock_register(BTPROTO_L2CAP, &l2cap_sock_family_ops);
if (err < 0) {
BT_ERR("L2CAP socket registration failed");
@@ -4388,6 +4528,9 @@ static void __exit l2cap_exit(void)
{
debugfs_remove(l2cap_debugfs);
+ flush_workqueue(_busy_wq);
+ destroy_workqueue(_busy_wq);
+
if (bt_sock_unregister(BTPROTO_L2CAP) < 0)
BT_ERR("L2CAP socket unregistration failed");
--
1.6.4.4
^ permalink raw reply related
* RE: detecting dead link
From: Mike Tsai @ 2010-04-14 19:49 UTC (permalink / raw)
To: Luiz Augusto von Dentz; +Cc: linux-bluetooth@vger.kernel.org
In-Reply-To: <y2q2d5a2c101004141229gaf2dbac4u89e4e627004ddd95@mail.gmail.com>
-----Original Message-----
From: Luiz Augusto von Dentz [mailto:luiz.dentz@gmail.com]
Sent: Wednesday, April 14, 2010 12:30 PM
To: Mike Tsai
Cc: linux-bluetooth@vger.kernel.org
Subject: Re: detecting dead link
Hi,
On Wed, Apr 14, 2010 at 7:31 PM, Mike Tsai <Mike.Tsai@atheros.com> wrote:
> Hi Luiz,
> [MT] Page timeout is for creating ACL data link. In this case, ACL link is already created so page timeout is not involved. The 20 second timeout is the default link supervision timeout and the 35 second timeout is the LMP timeout (actually 30 seconds). I think if you have the sniff log for the LMP, it would appear that one of the LMP might be lost during SCO negotiation and it is quite possibly due to the existing sniff mode. A proper implementation of host stack shall probably exit sniff mode first before start the SCO link creation. So the log would look like this,
>
> HCI command: Exit Sniff Mode
> HCI event: Command status, Exit Sniff Mode
> HCI event: Mode changed
> HCI command: Setup Synchronous Connection
That exactly what Im arguing about, we have a 30 sec LMP timeout
compared to 5 sec of page timeout , if we are not willing to wait more
than 5 sec for a new ACL link why would we wait 30 sec? This is
completely disproportional and we should probably need to respond way
before that thus my suggestion to derive the LMP timeout for the page
timeout. This not only affect SCO connection but any attempt to
transfer data in the middle of the link loss.
>> I agree that 30 second LMP timeout is really too long, however it was defined in the spec. and is not changeable unless we go through errata process and get everyone in the Bluetooth CSWG to agree with it.
>> There is another way to shorten the timeout which is to change the link supervision timeout to less than that, for instance, 2 seconds. But based on the log, it would seem to me that the link supervision timeout was not detected prior to LMP timeout (because disconnect event didn't come at 20 seconds).
> I think the host was sending the commands out of order. It asks controller to set up SCO link before it asks controller to exit sniff mode. Note that both commands are async commands (meaning it will request controller to go through several state transition for those commands), so the controller might have hard time executing the host commands.
I guess it doesn't matter the order, as long as it detects the link
loss faster, things like PulseAudio cannot afford 30 sec of the stream
lost because the controller has lost the link, if the headset has been
moved away or shutdown in the middle of the playback we want to route
it back to the speaker as soon as possible.
>> Here I am just stating the fact that multiple async commands from host can cause difficulty on the controller side because there is only 1 physical link available and the media needs to be shared. I guess it matters if we want less frustration from end user and better connection quality. This is a common practice from many popular Bluetooth host stacks. I think that we won't loss the link if host does the command order as suggested. Because shorten the link disconnection timeout will just let user realize that the link establishment failed sooner, does not change the fact that it is still a failure and user can't get what they want,
--
Luiz Augusto von Dentz
Computer Engineer
^ permalink raw reply
* Re: detecting dead link
From: Luiz Augusto von Dentz @ 2010-04-14 20:34 UTC (permalink / raw)
To: Mike Tsai; +Cc: linux-bluetooth@vger.kernel.org
In-Reply-To: <35B17FE5076C7040809188FBE7913F983A1E128B32@SC1EXMB-MBCL.global.atheros.com>
Hi,
On Wed, Apr 14, 2010 at 10:49 PM, Mike Tsai <Mike.Tsai@atheros.com> wrote:
>>> I agree that 30 second LMP timeout is really too long, however it was defined in the spec. and is not changeable unless we go through errata process and get everyone in the Bluetooth CSWG to agree with it.
>
>>> There is another way to shorten the timeout which is to change the link supervision timeout to less than that, for instance, 2 seconds. But based on the log, it would seem to me that the link supervision timeout was not detected prior to LMP timeout (because disconnect event didn't come at 20 seconds).
Im not saying we have to change the LMP timeout, that is bellow hci
layer which I guess we have no control in BlueZ, obviously you are
misunderstanding me, there is no need to change the LMP timeout
whatsoever it is just that we don't need to wait for it.
> I guess it doesn't matter the order, as long as it detects the link
> loss faster, things like PulseAudio cannot afford 30 sec of the stream
> lost because the controller has lost the link, if the headset has been
> moved away or shutdown in the middle of the playback we want to route
> it back to the speaker as soon as possible.
>
>>> Here I am just stating the fact that multiple async commands from host can cause difficulty on the controller side because there is only 1 physical link available and the media needs to be shared. I guess it matters if we want less frustration from end user and better connection quality. This is a common practice from many popular Bluetooth host stacks. I think that we won't loss the link if host does the command order as suggested. Because shorten the link disconnection timeout will just let user realize that the link establishment failed sooner, does not change the fact that it is still a failure and user can't get what they want,
Sorry, again I guess you are misunderstanding me, the link is _lost_,
the device has being moved away or has been shutdown so I guess it
pretty impossible to give anything else but disconnect to the user, or
there is any way to maintain a link to an unreachable device?
Btw, the trace I gave here was from a carkit which when turned off
doesn't send any hci disconnect.
--
Luiz Augusto von Dentz
Computer Engineer
^ permalink raw reply
* RE: detecting dead link
From: Mike Tsai @ 2010-04-14 21:09 UTC (permalink / raw)
To: Luiz Augusto von Dentz; +Cc: linux-bluetooth@vger.kernel.org
In-Reply-To: <z2k2d5a2c101004141334kc91838fatc9bcce8d81e38740@mail.gmail.com>
-----Original Message-----
From: Luiz Augusto von Dentz [mailto:luiz.dentz@gmail.com]
Sent: Wednesday, April 14, 2010 1:34 PM
To: Mike Tsai
Cc: linux-bluetooth@vger.kernel.org
Subject: Re: detecting dead link
Hi,
On Wed, Apr 14, 2010 at 10:49 PM, Mike Tsai <Mike.Tsai@atheros.com> wrote:
>>> I agree that 30 second LMP timeout is really too long, however it was defined in the spec. and is not changeable unless we go through errata process and get everyone in the Bluetooth CSWG to agree with it.
>
>>> There is another way to shorten the timeout which is to change the link supervision timeout to less than that, for instance, 2 seconds. But based on the log, it would seem to me that the link supervision timeout was not detected prior to LMP timeout (because disconnect event didn't come at 20 seconds).
Im not saying we have to change the LMP timeout, that is bellow hci
layer which I guess we have no control in BlueZ, obviously you are
misunderstanding me, there is no need to change the LMP timeout
whatsoever it is just that we don't need to wait for it.
> I guess it doesn't matter the order, as long as it detects the link
> loss faster, things like PulseAudio cannot afford 30 sec of the stream
> lost because the controller has lost the link, if the headset has been
> moved away or shutdown in the middle of the playback we want to route
> it back to the speaker as soon as possible.
>
>>> Here I am just stating the fact that multiple async commands from host can cause difficulty on the controller side because there is only 1 physical link available and the media needs to be shared. I guess it matters if we want less frustration from end user and better connection quality. This is a common practice from many popular Bluetooth host stacks. I think that we won't loss the link if host does the command order as suggested. Because shorten the link disconnection timeout will just let user realize that the link establishment failed sooner, does not change the fact that it is still a failure and user can't get what they want,
Sorry, again I guess you are misunderstanding me, the link is _lost_,
the device has being moved away or has been shutdown so I guess it
pretty impossible to give anything else but disconnect to the user, or
there is any way to maintain a link to an unreachable device?
>>Ok, so I do miss understanding the situation. In that case, host can program link supervision timeout to a shorter time (like 3 or 4 seconds) as suggested. So the link supervision timeout shall kick in far ahead of LMP response timeout. The user will get disconnect notification sooner,
Btw, the trace I gave here was from a carkit which when turned off
doesn't send any hci disconnect.
--
Luiz Augusto von Dentz
Computer Engineer
^ permalink raw reply
* [PATCH] Set l2cap mode always
From: Gustavo F. Padovan @ 2010-04-14 22:03 UTC (permalink / raw)
To: linux-bluetooth; +Cc: marcel, gustavo
As ERTM can be the default mode with SOCK_STREAM we have to set
opts.mode always.
---
test/l2test.c | 3 +--
1 files changed, 1 insertions(+), 2 deletions(-)
diff --git a/test/l2test.c b/test/l2test.c
index 9413070..0bb46f3 100644
--- a/test/l2test.c
+++ b/test/l2test.c
@@ -228,8 +228,7 @@ static int do_connect(char *svr)
/* Set new options */
opts.omtu = omtu;
opts.imtu = imtu;
- if (rfcmode > 0)
- opts.mode = rfcmode;
+ opts.mode = rfcmode;
opts.fcs = fcs;
opts.txwin_size = txwin_size;
--
1.6.4.4
^ permalink raw reply related
* Re: detecting dead link
From: Andrei Emeltchenko @ 2010-04-15 7:54 UTC (permalink / raw)
To: Mike Tsai; +Cc: Luiz Augusto von Dentz, linux-bluetooth@vger.kernel.org
In-Reply-To: <35B17FE5076C7040809188FBE7913F983A1E128A57@SC1EXMB-MBCL.global.atheros.com>
Hi,
On Wed, Apr 14, 2010 at 7:31 PM, Mike Tsai <Mike.Tsai@atheros.com> wrote:
>
>
> -----Original Message-----
> From: linux-bluetooth-owner@vger.kernel.org [mailto:linux-bluetooth-owner@vger.kernel.org] On Behalf Of Luiz Augusto von Dentz
> Sent: Wednesday, April 14, 2010 1:11 AM
> To: linux-bluetooth@vger.kernel.org
> Subject: detecting dead link
>
> Hi,
>
> It seems that most of the chips take a lot of time to detect that a
> link in dead, due to out of range or power off (no hci disconnect),
> the most common problem regarding this is when we try to connect SCO:
>
> 2010-03-31 18:40:19.975128 < HCI Command: Setup Synchronous Connection
> (0x01|0x0028) plen 17
> handle 11 voice setting 0x0060
> 2010-03-31 18:40:19.981780 > HCI Event: Command Status (0x0f) plen 4
> Setup Synchronous Connection (0x01|0x0028) status 0x00 ncmd 1
> 2010-03-31 18:40:33.318023 < ACL data: handle 11 flags 0x02 dlen 22
> L2CAP(d): cid 0x0073 len 18 [psm 0]
> 0000: 69 ef 1d 0d 0a 2b 43 49 45 56 3a 20 32 2c 33 0d i....+CIEV: 2,3.
> 0010: 0a 3e .>
> 2010-03-31 18:40:33.318145 < HCI Command: Exit Sniff Mode (0x02|0x0004) plen 2
> handle 11
> 2010-03-31 18:40:33.324615 > HCI Event: Command Status (0x0f) plen 4
> Exit Sniff Mode (0x02|0x0004) status 0x00 ncmd 1
> 2010-03-31 18:40:51.207885 < ACL data: handle 11 flags 0x02 dlen 22
> L2CAP(d): cid 0x0073 len 18 [psm 0]
> 0000: 69 ef 1d 0d 0a 2b 43 49 45 56 3a 20 32 2c 32 0d i....+CIEV: 2,2.
> 0010: 0a 3e .>
> 2010-03-31 18:40:54.965362 > HCI Event: Max Slots Change (0x1b) plen 3
> handle 11 slots 5
> 2010-03-31 18:40:54.966094 > HCI Event: Synchronous Connect Complete (0x2c)
> plen 17
> status 0x08 handle 0 bdaddr 00:1E:DC:B3:40:9D type eSCO
> Error: Connection Timeout
> 2010-03-31 18:40:54.968353 > HCI Event: Number of Completed Packets (0x13) plen
> 5
> handle 11 packets 2
> 2010-03-31 18:40:54.968658 > HCI Event: Disconn Complete (0x05) plen 4
> status 0x00 handle 11 reason 0x08
> Reason: Connection Timeout
>
> It took 35 sec to timeout where connections attempt normally only take
> 5 sec due to page timeout (configurable in main.conf), it is probably
> due to being in sniff mode but even after exiting it takes another 20
> sec to timeout (probably lmp timeout).
>
> So I was wondering why this timeout is not derived from page timeout,
> to me it seems quite obvious that if the connection doesn't complete
> within page timeout there is something wrong since that is supposed to
> be much faster on an active link, also if that assumption is correct
> what would be the impact to have such a logic that takes page timeout
> as timeout for any connection attempt in active/dead links dropping
> them if the timeout is reached, of course this has to take into
> account the user authorization framework/defer setup so it only
> timeout if there is no activity in the link.
>
> Hi Luiz,
> [MT] Page timeout is for creating ACL data link. In this case, ACL link is already created so page timeout is not involved. The 20 second timeout is the default link supervision timeout and the 35 second timeout is the LMP timeout (actually 30 seconds). I think if you have the sniff log for the LMP, it would appear that one of the LMP might be lost during SCO negotiation and it is quite possibly due to the existing sniff mode. A proper implementation of host stack shall probably exit sniff mode first before start the SCO link creation. So the log would look like this,
>
> HCI command: Exit Sniff Mode
> HCI event: Command status, Exit Sniff Mode
> HCI event: Mode changed
> HCI command: Setup Synchronous Connection
>
> I think the host was sending the commands out of order. It asks controller to set up SCO link before it asks controller to exit sniff mode. Note that both commands are async commands (meaning it will request controller to go through several state transition for those commands), so the controller might have hard time executing the host commands.
>
I think we have recently applied the patch which makes this sequence correct:
http://git.kernel.org/?p=linux/kernel/git/holtmann/bluetooth-testing.git;a=commit;h=c390216b3e868b16d8154939f4b6f8c16dbd9a9f
Regards,
Andrei
^ permalink raw reply
* Re: Implement AVCTP passthrough commands + iPod Touch
From: Paolo Medici @ 2010-04-15 14:33 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <4BC1C340.50404@ce.unipr.it>
I am currently trying bluez AVRCP on iPod Touch (3G)
It seems, however, that it respond only at the 0x44 OpCode (PASS
THROUGH) and performs PLAY correctly.
The other codes do not give any action.
Paolo Medici wrote:
> Something like that (attached).
>
> Paolo Medici wrote:
>> Hi,
>> Are there no contraindications to complete the implementation in
>> audio/control.c of other commands (as well as VolumeUp/VolumeDown)?
>> In this case, to try to control my iPod Touch, I would like to add
>> remaining ones.
>>
>> Paolo
>> --
>> To unsubscribe from this list: send the line "unsubscribe
>> linux-bluetooth" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at http://vger.kernel.org/majordomo-info.html
>>
>
--
Paolo Medici - R&D
VisLab srl - P.I. 02516520349
Dipartimento di Ingegneria dell'Informazione
dell'Universita' di Parma - P.I. 00308780345
Via G.P.Usberti 181/A I-43100 Parma ITALY
Tel : +39 0521 90 5792
Web : http://vislab.it/medici
^ permalink raw reply
* killing stalled ACL connection
From: Pavan Savoy @ 2010-04-15 19:25 UTC (permalink / raw)
To: linux-bluetooth
I am working on a platform which has a very aggressive power management features.
So consider a situation, where an a2dp connection exists with a headset, and i pause the media over AVRCP, so my phone now goes into suspend state (shutting off UART clocks),
and when I wake-up (resume) using the AVRCP connection, via the play/pause button, I see the platform waking up and media player receiving the input, However I also see this,
hci0 ACL tx timeout.
killing stalled ACL connection.
and media is not able to play on the headset anymore.
Although the media player thinks it's being played.
Now where should I look into, as to why a perfectly nice ACL (l2cap, a2dp) connection was dropped during the suspend ?
Send free SMS to your Friends on Mobile from your Yahoo! Messenger. Download Now! http://messenger.yahoo.com/download.php
^ permalink raw reply
* [PATCH] Bluetooth: Implement Local Busy Condition handling
From: Gustavo F. Padovan @ 2010-04-16 0:11 UTC (permalink / raw)
To: linux-bluetooth; +Cc: marcel, gustavo, jprvita
In-Reply-To: <1271274112-7806-8-git-send-email-padovan@profusion.mobi>
Supports Local Busy condition handling through a waitqueue that wake ups
each 200ms and try to push the packets to the upper layer. If it can
push all the queue then it leaves the Local Busy state.
The patch modifies the behaviour of l2cap_ertm_reassembly_sdu() to
support retry of the push operation.
Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi>
Reviewed-by: João Paulo Rechi Vita <jprvita@profusion.mobi>
---
include/net/bluetooth/l2cap.h | 6 ++
net/bluetooth/l2cap.c | 185 ++++++++++++++++++++++++++++++++++++-----
2 files changed, 171 insertions(+), 20 deletions(-)
diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index 15f6e55..fd0e4e4 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -35,6 +35,7 @@
#define L2CAP_DEFAULT_MONITOR_TO 12000 /* 12 seconds */
#define L2CAP_DEFAULT_MAX_PDU_SIZE 672
#define L2CAP_DEFAULT_ACK_TO 200
+#define L2CAP_LOCAL_BUSY_TRIES 12
#define L2CAP_CONN_TIMEOUT (40000) /* 40 seconds */
#define L2CAP_INFO_TIMEOUT (4000) /* 4 seconds */
@@ -294,6 +295,7 @@ struct l2cap_conn {
#define l2cap_pi(sk) ((struct l2cap_pinfo *) sk)
#define TX_QUEUE(sk) (&l2cap_pi(sk)->tx_queue)
#define SREJ_QUEUE(sk) (&l2cap_pi(sk)->srej_queue)
+#define BUSY_QUEUE(sk) (&l2cap_pi(sk)->busy_queue)
#define SREJ_LIST(sk) (&l2cap_pi(sk)->srej_l.list)
struct srej_list {
@@ -356,6 +358,8 @@ struct l2cap_pinfo {
struct timer_list ack_timer;
struct sk_buff_head tx_queue;
struct sk_buff_head srej_queue;
+ struct sk_buff_head busy_queue;
+ struct work_struct busy_work;
struct srej_list srej_l;
struct l2cap_conn *conn;
struct sock *next_c;
@@ -383,6 +387,8 @@ struct l2cap_pinfo {
#define L2CAP_CONN_LOCAL_BUSY 0x0040
#define L2CAP_CONN_REJ_ACT 0x0080
#define L2CAP_CONN_SEND_FBIT 0x0100
+#define L2CAP_CONN_RNR_SENT 0x0200
+#define L2CAP_CONN_SAR_RETRY 0x0400
#define __mod_retrans_timer() mod_timer(&l2cap_pi(sk)->retrans_timer, \
jiffies + msecs_to_jiffies(L2CAP_DEFAULT_RETRANS_TO));
diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c
index f3a3692..0cdcd41 100644
--- a/net/bluetooth/l2cap.c
+++ b/net/bluetooth/l2cap.c
@@ -68,10 +68,14 @@ static u8 l2cap_fixed_chan[8] = { 0x02, };
static const struct proto_ops l2cap_sock_ops;
+static struct workqueue_struct *_busy_wq;
+
static struct bt_sock_list l2cap_sk_list = {
.lock = __RW_LOCK_UNLOCKED(l2cap_sk_list.lock)
};
+static void l2cap_busy_work(struct work_struct *work);
+
static void __l2cap_sock_close(struct sock *sk, int reason);
static void l2cap_sock_close(struct sock *sk);
static void l2cap_sock_kill(struct sock *sk);
@@ -386,8 +390,10 @@ static inline void l2cap_send_sframe(struct l2cap_pinfo *pi, u16 control)
static inline void l2cap_send_rr_or_rnr(struct l2cap_pinfo *pi, u16 control)
{
- if (pi->conn_state & L2CAP_CONN_LOCAL_BUSY)
+ if (pi->conn_state & L2CAP_CONN_LOCAL_BUSY) {
control |= L2CAP_SUPER_RCV_NOT_READY;
+ pi->conn_state |= L2CAP_CONN_RNR_SENT;
+ }
else
control |= L2CAP_SUPER_RCV_READY;
@@ -816,6 +822,7 @@ static void l2cap_sock_init(struct sock *sk, struct sock *parent)
pi->flush_to = L2CAP_DEFAULT_FLUSH_TO;
skb_queue_head_init(TX_QUEUE(sk));
skb_queue_head_init(SREJ_QUEUE(sk));
+ skb_queue_head_init(BUSY_QUEUE(sk));
INIT_LIST_HEAD(SREJ_LIST(sk));
}
@@ -1441,6 +1448,7 @@ static void l2cap_send_ack(struct l2cap_pinfo *pi)
if (pi->conn_state & L2CAP_CONN_LOCAL_BUSY) {
control |= L2CAP_SUPER_RCV_NOT_READY;
+ pi->conn_state |= L2CAP_CONN_RNR_SENT;
l2cap_send_sframe(pi, control);
return;
} else if (l2cap_ertm_send(sk) == 0) {
@@ -2267,6 +2275,9 @@ static inline void l2cap_ertm_init(struct sock *sk)
l2cap_ack_timeout, (unsigned long) sk);
__skb_queue_head_init(SREJ_QUEUE(sk));
+ __skb_queue_head_init(BUSY_QUEUE(sk));
+
+ INIT_WORK(&l2cap_pi(sk)->busy_work, l2cap_busy_work);
}
static int l2cap_mode_supported(__u8 mode, __u32 feat_mask)
@@ -3034,6 +3045,7 @@ static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd
if (l2cap_pi(sk)->mode == L2CAP_MODE_ERTM) {
skb_queue_purge(SREJ_QUEUE(sk));
+ skb_queue_purge(BUSY_QUEUE(sk));
del_timer(&l2cap_pi(sk)->retrans_timer);
del_timer(&l2cap_pi(sk)->monitor_timer);
del_timer(&l2cap_pi(sk)->ack_timer);
@@ -3065,6 +3077,7 @@ static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, struct l2cap_cmd
if (l2cap_pi(sk)->mode == L2CAP_MODE_ERTM) {
skb_queue_purge(SREJ_QUEUE(sk));
+ skb_queue_purge(BUSY_QUEUE(sk));
del_timer(&l2cap_pi(sk)->retrans_timer);
del_timer(&l2cap_pi(sk)->monitor_timer);
del_timer(&l2cap_pi(sk)->ack_timer);
@@ -3275,6 +3288,7 @@ static inline void l2cap_send_i_or_rr_or_rnr(struct sock *sk)
if (pi->conn_state & L2CAP_CONN_LOCAL_BUSY) {
control |= L2CAP_SUPER_RCV_NOT_READY | L2CAP_CTRL_FINAL;
l2cap_send_sframe(pi, control);
+ pi->conn_state |= L2CAP_CONN_RNR_SENT;
pi->conn_state &= ~L2CAP_CONN_SEND_FBIT;
}
@@ -3322,7 +3336,7 @@ static int l2cap_ertm_reassembly_sdu(struct sock *sk, struct sk_buff *skb, u16 c
{
struct l2cap_pinfo *pi = l2cap_pi(sk);
struct sk_buff *_skb;
- int err = 0;
+ int err;
switch (control & L2CAP_CTRL_SAR) {
case L2CAP_SDU_UNSEGMENTED:
@@ -3340,16 +3354,18 @@ static int l2cap_ertm_reassembly_sdu(struct sock *sk, struct sk_buff *skb, u16 c
goto drop;
pi->sdu_len = get_unaligned_le16(skb->data);
- skb_pull(skb, 2);
if (pi->sdu_len > pi->imtu)
goto disconnect;
pi->sdu = bt_skb_alloc(pi->sdu_len, GFP_ATOMIC);
- if (!pi->sdu) {
- err = -ENOMEM;
- break;
- }
+ if (!pi->sdu)
+ return -ENOMEM;
+
+ /* pull sdu_len bytes only after alloc, because of Local Busy
+ * condition we have to be sure that this will be executed
+ * only once, i.e., when alloc does not fail */
+ skb_pull(skb, 2);
memcpy(skb_put(pi->sdu, skb->len), skb->data, skb->len);
@@ -3379,28 +3395,40 @@ static int l2cap_ertm_reassembly_sdu(struct sock *sk, struct sk_buff *skb, u16 c
if (!pi->sdu)
goto disconnect;
- memcpy(skb_put(pi->sdu, skb->len), skb->data, skb->len);
+ if (!(pi->conn_state & L2CAP_CONN_SAR_RETRY)) {
+ memcpy(skb_put(pi->sdu, skb->len), skb->data, skb->len);
- pi->conn_state &= ~L2CAP_CONN_SAR_SDU;
- pi->partial_sdu_len += skb->len;
+ pi->partial_sdu_len += skb->len;
- if (pi->partial_sdu_len > pi->imtu)
- goto drop;
+ if (pi->partial_sdu_len > pi->imtu)
+ goto drop;
- if (pi->partial_sdu_len != pi->sdu_len)
- goto drop;
+ if (pi->partial_sdu_len != pi->sdu_len)
+ goto drop;
+ }
_skb = skb_clone(pi->sdu, GFP_ATOMIC);
+ if (!_skb) {
+ pi->conn_state |= L2CAP_CONN_SAR_RETRY;
+ return -ENOMEM;
+ }
+
err = sock_queue_rcv_skb(sk, _skb);
- if (err < 0)
+ if (err < 0) {
kfree_skb(_skb);
+ pi->conn_state |= L2CAP_CONN_SAR_RETRY;
+ return err;
+ }
+
+ pi->conn_state &= ~L2CAP_CONN_SAR_RETRY;
+ pi->conn_state &= ~L2CAP_CONN_SAR_SDU;
kfree_skb(pi->sdu);
break;
}
kfree_skb(skb);
- return err;
+ return 0;
drop:
kfree_skb(pi->sdu);
@@ -3412,6 +3440,112 @@ disconnect:
return 0;
}
+static void l2cap_busy_work(struct work_struct *work)
+{
+ DECLARE_WAITQUEUE(wait, current);
+ struct l2cap_pinfo *pi =
+ container_of(work, struct l2cap_pinfo, busy_work);
+ struct sock *sk = (struct sock *)pi;
+ int n_tries = 0, timeo = HZ/5, err;
+ struct sk_buff *skb;
+ u16 control;
+
+ lock_sock(sk);
+
+ add_wait_queue(sk->sk_sleep, &wait);
+ while ((skb = skb_peek(BUSY_QUEUE(sk)))) {
+ set_current_state(TASK_INTERRUPTIBLE);
+
+ if (n_tries++ > L2CAP_LOCAL_BUSY_TRIES) {
+ err = -EBUSY;
+ l2cap_send_disconn_req(pi->conn, sk);
+ goto done;
+ }
+
+ if (!timeo)
+ timeo = HZ/5;
+
+ if (signal_pending(current)) {
+ err = sock_intr_errno(timeo);
+ goto done;
+ }
+
+ release_sock(sk);
+ timeo = schedule_timeout(timeo);
+ lock_sock(sk);
+
+ err = sock_error(sk);
+ if (err)
+ goto done;
+
+ while((skb = skb_peek(BUSY_QUEUE(sk)))) {
+ control = bt_cb(skb)->sar << L2CAP_CTRL_SAR_SHIFT;
+ err = l2cap_ertm_reassembly_sdu(sk, skb, control);
+ if (err < 0)
+ break;
+
+ skb_dequeue(BUSY_QUEUE(sk));
+
+ pi->buffer_seq = (pi->buffer_seq + 1) % 64;
+ }
+
+ if (!skb)
+ break;
+ }
+
+ if (!(pi->conn_state & L2CAP_CONN_RNR_SENT))
+ goto done;
+
+ control = pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
+ control |= L2CAP_SUPER_RCV_READY | L2CAP_CTRL_POLL;
+ l2cap_send_sframe(pi, control);
+
+ del_timer(&pi->retrans_timer);
+ __mod_monitor_timer();
+
+ pi->conn_state &= ~L2CAP_CONN_LOCAL_BUSY;
+ pi->conn_state &= ~L2CAP_CONN_RNR_SENT;
+
+done:
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(sk->sk_sleep, &wait);
+
+ release_sock(sk);
+}
+
+static int l2cap_push_rx_skb(struct sock *sk, struct sk_buff *skb, u16 control)
+{
+ struct l2cap_pinfo *pi = l2cap_pi(sk);
+ int sctrl, err;
+
+ if (pi->conn_state & L2CAP_CONN_LOCAL_BUSY) {
+ bt_cb(skb)->sar = control >> L2CAP_CTRL_SAR_SHIFT;
+ __skb_queue_tail(BUSY_QUEUE(sk), skb);
+ return -EBUSY;
+ }
+
+ err = l2cap_ertm_reassembly_sdu(sk, skb, control);
+ if (err >= 0) {
+ pi->buffer_seq = (pi->buffer_seq + 1) % 64;
+ return err;
+ }
+
+ /* Busy Condition */
+ pi->conn_state |= L2CAP_CONN_LOCAL_BUSY;
+ bt_cb(skb)->sar = control >> L2CAP_CTRL_SAR_SHIFT;
+ __skb_queue_tail(BUSY_QUEUE(sk), skb);
+
+ sctrl = pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
+ sctrl |= L2CAP_SUPER_RCV_NOT_READY;
+ l2cap_send_sframe(pi, sctrl);
+
+ pi->conn_state |= L2CAP_CONN_RNR_SENT;
+
+ queue_work(_busy_wq, &pi->busy_work);
+
+ return err;
+}
+
static int l2cap_streaming_reassembly_sdu(struct sock *sk, struct sk_buff *skb, u16 control)
{
struct l2cap_pinfo *pi = l2cap_pi(sk);
@@ -3586,6 +3720,11 @@ static inline int l2cap_data_channel_iframe(struct sock *sk, u16 rx_control, str
if (tx_seq == pi->expected_tx_seq)
goto expected;
+ if (pi->conn_state == L2CAP_CONN_LOCAL_BUSY) {
+ kfree_skb(skb);
+ return 0;
+ }
+
/* Check for duplicated tx_seq. This actually
* subtracts 1 from expected_tx_seq */
if (tx_seq == (pi->expected_tx_seq + 63) % 64) {
@@ -3629,6 +3768,7 @@ static inline int l2cap_data_channel_iframe(struct sock *sk, u16 rx_control, str
pi->buffer_seq_srej = pi->buffer_seq;
__skb_queue_head_init(SREJ_QUEUE(sk));
+ __skb_queue_head_init(BUSY_QUEUE(sk));
l2cap_add_to_srej_queue(sk, skb, tx_seq, sar);
pi->conn_state |= L2CAP_CONN_SEND_PBIT;
@@ -3656,11 +3796,9 @@ expected:
}
}
- pi->buffer_seq = (pi->buffer_seq + 1) % 64;
-
- err = l2cap_ertm_reassembly_sdu(sk, skb, rx_control);
+ err = l2cap_push_rx_skb(sk, skb, rx_control);
if (err < 0)
- return err;
+ return 0;
__mod_ack_timer();
@@ -4355,6 +4493,10 @@ static int __init l2cap_init(void)
if (err < 0)
return err;
+ _busy_wq = create_singlethread_workqueue("l2cap");
+ if (!_busy_wq)
+ goto error;
+
err = bt_sock_register(BTPROTO_L2CAP, &l2cap_sock_family_ops);
if (err < 0) {
BT_ERR("L2CAP socket registration failed");
@@ -4389,6 +4531,9 @@ static void __exit l2cap_exit(void)
{
debugfs_remove(l2cap_debugfs);
+ flush_workqueue(_busy_wq);
+ destroy_workqueue(_busy_wq);
+
if (bt_sock_unregister(BTPROTO_L2CAP) < 0)
BT_ERR("L2CAP socket unregistration failed");
--
1.6.4.4
^ permalink raw reply related
* what is needed for SSP mode
From: Ronny Pau @ 2010-04-16 2:17 UTC (permalink / raw)
To: linux-bluetooth
Hello,
I current have a running BlueZ stack running SPP, where I am able to
pair with another device using a 4-digit passkey, establish pairing,
form a RFCOMM connection, which I am using to exchange data with my
cellphone.
Now, I would like to switch on SSP mode, where I have issued
"hciconfig hci0 sppmode 1" and verify that it is indeed on using
"hciconfig hci0 sppmode". However, if I attempt to connect with my
cellphone, I get a connection failure. Have I missed something?
Any help would be appreciated.
Thanks.
^ permalink raw reply
* Re: killing stalled ACL connection
From: Luiz Augusto von Dentz @ 2010-04-16 8:02 UTC (permalink / raw)
To: Pavan Savoy; +Cc: linux-bluetooth
In-Reply-To: <572595.91160.qm@web94916.mail.in2.yahoo.com>
Hi,
On Thu, Apr 15, 2010 at 10:25 PM, Pavan Savoy <pavan_savoy@yahoo.co.in> wrote:
> I am working on a platform which has a very aggressive power management features.
> So consider a situation, where an a2dp connection exists with a headset, and i pause the media over AVRCP, so my phone now goes into suspend state (shutting off UART clocks),
>
> and when I wake-up (resume) using the AVRCP connection, via the play/pause button, I see the platform waking up and media player receiving the input, However I also see this,
>
> hci0 ACL tx timeout.
> killing stalled ACL connection.
>
> and media is not able to play on the headset anymore.
> Although the media player thinks it's being played.
>
> Now where should I look into, as to why a perfectly nice ACL (l2cap, a2dp) connection was dropped during the suspend ?
I guess you mean the system is suspended, to be honest I thought that
would mean shutting down the bluetooth chip too which obviously will
drop all the connections, but that doesn't seems to be the case here,
does it? Anyway if you shutdown the bus which you communicate with the
chip it could eventually timeout, I guess in such situation it is
better to enter sniff mode, use some kind of bus that can
wakeup/powerup automatically if there is data to transfer or a
combination of both.
--
Luiz Augusto von Dentz
Computer Engineer
^ permalink raw reply
* Re: detecting dead link
From: Luiz Augusto von Dentz @ 2010-04-16 13:19 UTC (permalink / raw)
To: Mike Tsai; +Cc: linux-bluetooth@vger.kernel.org
In-Reply-To: <35B17FE5076C7040809188FBE7913F983A1E128B77@SC1EXMB-MBCL.global.atheros.com>
Hi,
On Thu, Apr 15, 2010 at 12:09 AM, Mike Tsai <Mike.Tsai@atheros.com> wrote:
>>>Ok, so I do miss understanding the situation. In that case, host can program link supervision timeout to a shorter time (like 3 or 4 seconds) as suggested. So the link supervision timeout shall kick in far ahead of LMP response timeout. The user will get disconnect notification sooner,
It seems that somebody already give us a favor and patented it:
http://www.freepatentsonline.com/y2009/0258596.html
That is exactly what I was looking for, depending on the link usage
(a2dp, sco) reduce the link supervision timeout to detect the link
loss faster. Well I guess the only option now is to do this
statically, which I don't think will address the problem completely
since we can only change the timeout once due to this patent.
Grrr, it is so obvious why people patent such generic usage, I really
hate software patents. Very frustrating.
--
Luiz Augusto von Dentz
Computer Engineer
^ permalink raw reply
* Re: killing stalled ACL connection
From: Pavan Savoy @ 2010-04-16 14:28 UTC (permalink / raw)
To: Luiz Augusto von Dentz; +Cc: linux-bluetooth
In-Reply-To: <p2u2d5a2c101004160102uafada73az98db61259c9e2d21@mail.gmail.com>
--- On Fri, 16/4/10, Luiz Augusto von Dentz <luiz.dentz@gmail.com> wrote:
> From: Luiz Augusto von Dentz <luiz.dentz@gmail.com>
> Subject: Re: killing stalled ACL connection
> To: "Pavan Savoy" <pavan_savoy@yahoo.co.in>
> Cc: linux-bluetooth@vger.kernel.org
> Date: Friday, 16 April, 2010, 1:32 PM
> Hi,
>
> On Thu, Apr 15, 2010 at 10:25 PM, Pavan Savoy <pavan_savoy@yahoo.co.in>
> wrote:
> > I am working on a platform which has a very aggressive
> power management features.
> > So consider a situation, where an a2dp connection
> exists with a headset, and i pause the media over AVRCP, so
> my phone now goes into suspend state (shutting off UART
> clocks),
> >
> > and when I wake-up (resume) using the AVRCP
> connection, via the play/pause button, I see the platform
> waking up and media player receiving the input, However I
> also see this,
> >
> > hci0 ACL tx timeout.
> > killing stalled ACL connection.
> >
> > and media is not able to play on the headset anymore.
> > Although the media player thinks it's being played.
> >
> > Now where should I look into, as to why a perfectly
> nice ACL (l2cap, a2dp) connection was dropped during the
> suspend ?
>
> I guess you mean the system is suspended, to be honest I
> thought that
> would mean shutting down the bluetooth chip too which
> obviously will
> drop all the connections, but that doesn't seems to be the
> case here,
> does it? Anyway if you shutdown the bus which you
> communicate with the
> chip it could eventually timeout, I guess in such situation
> it is
> better to enter sniff mode, use some kind of bus that can
> wakeup/powerup automatically if there is data to transfer
> or a
> combination of both.
UART does this kind of automatically, I mean there is no s/w calls that are made it go into suspend state. (there is a hardware module which does that - we just have to configure it)
And yes, bluetooth chip is actually alive and active after suspend/resume.
However it's only the ACL connections that are getting dropped.
Is there some sort of timeout involved ? with these ACL connections ?
because I guess even the LMP's time to leave messages would not be going to headset (if there is such a thing called TTL messages).
I need some hint as to how I can debug this ...
>
> --
> Luiz Augusto von Dentz
> Computer Engineer
>
^ permalink raw reply
* Re: killing stalled ACL connection
From: Luiz Augusto von Dentz @ 2010-04-16 15:32 UTC (permalink / raw)
To: Pavan Savoy; +Cc: linux-bluetooth
In-Reply-To: <315060.46799.qm@web94904.mail.in2.yahoo.com>
Hi,
On Fri, Apr 16, 2010 at 5:28 PM, Pavan Savoy <pavan_savoy@yahoo.co.in> wrote:
>
> --- On Fri, 16/4/10, Luiz Augusto von Dentz <luiz.dentz@gmail.com> wrote:
>
>> From: Luiz Augusto von Dentz <luiz.dentz@gmail.com>
>> Subject: Re: killing stalled ACL connection
>> To: "Pavan Savoy" <pavan_savoy@yahoo.co.in>
>> Cc: linux-bluetooth@vger.kernel.org
>> Date: Friday, 16 April, 2010, 1:32 PM
>> Hi,
>>
>> On Thu, Apr 15, 2010 at 10:25 PM, Pavan Savoy <pavan_savoy@yahoo.co.in>
>> wrote:
>> > I am working on a platform which has a very aggressive
>> power management features.
>> > So consider a situation, where an a2dp connection
>> exists with a headset, and i pause the media over AVRCP, so
>> my phone now goes into suspend state (shutting off UART
>> clocks),
>> >
>> > and when I wake-up (resume) using the AVRCP
>> connection, via the play/pause button, I see the platform
>> waking up and media player receiving the input, However I
>> also see this,
>> >
>> > hci0 ACL tx timeout.
>> > killing stalled ACL connection.
>> >
>> > and media is not able to play on the headset anymore.
>> > Although the media player thinks it's being played.
>> >
>> > Now where should I look into, as to why a perfectly
>> nice ACL (l2cap, a2dp) connection was dropped during the
>> suspend ?
>>
>> I guess you mean the system is suspended, to be honest I
>> thought that
>> would mean shutting down the bluetooth chip too which
>> obviously will
>> drop all the connections, but that doesn't seems to be the
>> case here,
>> does it? Anyway if you shutdown the bus which you
>> communicate with the
>> chip it could eventually timeout, I guess in such situation
>> it is
>> better to enter sniff mode, use some kind of bus that can
>> wakeup/powerup automatically if there is data to transfer
>> or a
>> combination of both.
>
> UART does this kind of automatically, I mean there is no s/w calls that are made it go into suspend state. (there is a hardware module which does that - we just have to configure it)
>
> And yes, bluetooth chip is actually alive and active after suspend/resume.
> However it's only the ACL connections that are getting dropped.
>
> Is there some sort of timeout involved ? with these ACL connections ?
> because I guess even the LMP's time to leave messages would not be going to headset (if there is such a thing called TTL messages).
>
> I need some hint as to how I can debug this ...
You can start here (net/bluetooth/hci_core.c:1408):
if (!test_bit(HCI_RAW, &hdev->flags)) {
/* ACL tx timeout must be longer than maximum
* link supervision timeout (40.9 seconds) */
if (!hdev->acl_cnt && time_after(jiffies, hdev->acl_last_tx + HZ * 45))
hci_acl_tx_to(hdev);
}
--
Luiz Augusto von Dentz
Computer Engineer
^ permalink raw reply
* RE: what is needed for SSP mode
From: Gunn, Brian @ 2010-04-16 17:27 UTC (permalink / raw)
To: Ronny Pau, linux-bluetooth
In-Reply-To: <p2ld6c61fb91004151917x2a93d5dfr2ef1e6c2d01819a0@mail.gmail.com>
> Now, I would like to switch on SSP mode, where I have issued
> "hciconfig hci0 sppmode 1" and verify that it is indeed on using
> "hciconfig hci0 sppmode". However, if I attempt to connect with my
> cellphone, I get a connection failure. Have I missed something?
I've tried too and have the same problem with SSP mode. I think it may work with "NoInputNoOutput" mode, but I couldn't get "DisplayYesNo" to work with a 6 digit decimal number.
(Then again, I am not using the very latest release, though I didn't see any changes to SSP lately.)
Brian
^ permalink raw reply
* Re: what is needed for SSP mode
From: Ronny Pau @ 2010-04-16 17:44 UTC (permalink / raw)
To: Gunn, Brian; +Cc: linux-bluetooth
In-Reply-To: <FE57175CCE23E5419899C1B0CFA26FAD13F022D7B5@EXMBXSD.dm.solekai.com>
>> Now, I would like to switch on SSP mode, where I have issued
>> "hciconfig hci0 sppmode 1" and verify that it is indeed on using
>> "hciconfig hci0 sppmode". However, if I attempt to connect with my
>> cellphone, I get a connection failure. Have I missed something?
>
> I've tried too and have the same problem with SSP mode. I think it may work with "NoInputNoOutput" mode, but I couldn't get "DisplayYesNo" to work with a 6 digit decimal number.
>
> (Then again, I am not using the very latest release, though I didn't see any changes to SSP lately.)
>
> Brian
>
>
I am trying to implement the Passkey Entry mode, do I need to do
something with passkey-agent? How will that impact compatibility with
2.0's 4-digit passkey?
Please help.
^ permalink raw reply
* obexd FTP server signals
From: Daniel Abraham @ 2010-04-18 16:28 UTC (permalink / raw)
To: linux-bluetooth
Hi, I have a question:
Is there any way to get more transaction-related signals from obexd,
when it's used as an FTP _server_?
As far as I can see from "obexd-api.txt" and from dbus-monitor, the
only things to catch are "session_started" and "session_removed".
But I'd like to have a level of granularity similar to the FTP client:
signals about starting/progress/canceling/completing transfers, which
specific kinds of trasfers are done (list folder, get file, put file,
etc.).
Any ideas?
Thanks
^ permalink raw reply
* Re: obexd FTP server signals
From: Vinicius Gomes @ 2010-04-18 18:27 UTC (permalink / raw)
To: Daniel Abraham; +Cc: linux-bluetooth
In-Reply-To: <x2q2c3916b71004180928s9778e8d8zdeebe9e350ae4a19@mail.gmail.com>
Hi Daniel,
On Sun, Apr 18, 2010 at 1:28 PM, Daniel Abraham
<daniel.shrugged@gmail.com> wrote:
> Hi, I have a question:
>
> Is there any way to get more transaction-related signals from obexd,
> when it's used as an FTP _server_?
>
No. At least, not yet.
> As far as I can see from "obexd-api.txt" and from dbus-monitor, the
> only things to catch are "session_started" and "session_removed".
>
> But I'd like to have a level of granularity similar to the FTP client:
> signals about starting/progress/canceling/completing transfers, which
> specific kinds of trasfers are done (list folder, get file, put file,
> etc.).
>
> Any ideas?
At first we considered some form of status reporting, but after
thinking and looking at other "file sharing" servers we noticed that
it was not really useful for the server to report that information,
for example, sshd and any ftp server, don't have any form of status
reporting.
In those cases only the client reports the status, because the client
is where the user has control. I don't think obexd is much different
from those servers.
But, do you have a concrete case for this?
>
> Thanks
> --
> To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
Cheers,
--
Vinicius
^ permalink raw reply
* Re: obexd FTP server signals
From: Daniel Abraham @ 2010-04-19 5:26 UTC (permalink / raw)
To: Vinicius Gomes; +Cc: linux-bluetooth
In-Reply-To: <l2h2a9506371004181127g305febb5leb7392a54bb5692e@mail.gmail.com>
On Sun, Apr 18, 2010 at 9:27 PM, Vinicius Gomes
<vinicius.gomes@openbossa.org> wrote:
> On Sun, Apr 18, 2010 at 1:28 PM, Daniel Abraham
> <daniel.shrugged@gmail.com> wrote:
>> But I'd like to have a level of granularity similar to the FTP client:
>> signals about starting/progress/canceling/completing transfers, which
>> specific kinds of trasfers are done (list folder, get file, put file,
>> etc.).
>
> At first we considered some form of status reporting, but after
> thinking and looking at other "file sharing" servers we noticed that
> it was not really useful for the server to report that information,
> for example, sshd and any ftp server, don't have any form of status
> reporting.
>
> In those cases only the client reports the status, because the client
> is where the user has control. I don't think obexd is much different
> from those servers.
>
> But, do you have a concrete case for this?
1. Using it as a benchmark platform
In that case, the server is the focus point for gathering data
(consistently), and the clients are just remote black boxes. If I
can't expect and respond to specific events, I'd have to write
equivalent apps for each OS, which is sometimes impossible, and then
hope that methodology & measurements are consistent.
2. Basis for server activity logging
3. Less specific, but the sky is the limit: enabling server-side
timeouts/triggers/dynamic content/etc. - based on the user actions,
flows, history...
Anyway, my personal interest is in automating, logging and timing file
transfers from/to unknown remote clients.
Thanks
^ permalink raw reply
* Re: Support for Atheros AR300x Bluetooth Chip
From: Luis R. Rodriguez @ 2010-04-19 18:11 UTC (permalink / raw)
To: Suraj Sumangala, Marcel Holtmann
Cc: Luis Rodriguez, Jothikumar Mothilal, linux-bluetooth, mcgrof
In-Reply-To: <1271673889.19858.4.camel@atheros013-desktop>
Some code comments below, Marcel if you have time please see if you have
any other feedback for their next iteration as well so that they can
incorporate on v3.
Suraj, on your v3 patch please use [PATCH v3], you can do this with
git format patch by using --subject-prefix="PATCH v3".
On Mon, Apr 19, 2010 at 03:44:49AM -0700, Suraj Sumangala wrote:
> On Mon, 2010-03-29 at 14:31 +0530, suraj wrote:
> > On Wed, 2010-03-24 at 10:57 +0530, suraj wrote:
> > > On Mon, 2010-03-15 at 10:31 +0530, suraj wrote:
> > > > This protocol implements support for power management feature provided by AR300x chip.
> > > > This lets the controller chip go to sleep mode if there is no Bluetooth activity for some time.
> > > > It then wakes up the chip in case of a Bluetooth activity.
> > > >
> > > >
> > > > Signed-off-by: Suraj <suraj@atheros.com>
Don't indent the SOB, just leave it all the way to the left.
> > > > ---
> > > > drivers/bluetooth/Kconfig | 11 ++
> > > > drivers/bluetooth/Makefile | 1 +
> > > > drivers/bluetooth/hci_ath.c | 353 +++++++++++++++++++++++++++++++++++++++++
> > > > drivers/bluetooth/hci_ldisc.c | 6 +
> > > > drivers/bluetooth/hci_uart.h | 8 +-
> > > > 5 files changed, 378 insertions(+), 1 deletions(-)
> > > > create mode 100755 drivers/bluetooth/hci_ath.c
> > > >
> > > > diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig
> > > > index 058fbcc..81abeff 100644
> > > > --- a/drivers/bluetooth/Kconfig
> > > > +++ b/drivers/bluetooth/Kconfig
> > > > @@ -58,6 +58,17 @@ config BT_HCIUART_BCSP
> > > >
> > > > Say Y here to compile support for HCI BCSP protocol.
> > > >
> > > > +config BT_HCIUART_ATH
> > > > + bool "Atheros AR300x Board support"
> > > > + depends on BT_HCIUART
> > > > + help
> > > > + HCIATH (HCI Atheros) is a serial protocol for communication
> > > > + between Bluetooth device and host with support for Atheros AR300x
> > > > + power management feature. This protocol is required for
> > > > + serial Bluetooth devices that are based on Atheros AR300x chips.
> > > > +
> > > > + Say Y here to compile support for HCIATH protocol.
> > > > +
> > > > config BT_HCIUART_LL
> > > > bool "HCILL protocol support"
> > > > depends on BT_HCIUART
> > > > diff --git a/drivers/bluetooth/Makefile b/drivers/bluetooth/Makefile
> > > > index 7e5aed5..1481faa 100644
> > > > --- a/drivers/bluetooth/Makefile
> > > > +++ b/drivers/bluetooth/Makefile
> > > > @@ -26,4 +26,5 @@ hci_uart-y := hci_ldisc.o
> > > > hci_uart-$(CONFIG_BT_HCIUART_H4) += hci_h4.o
> > > > hci_uart-$(CONFIG_BT_HCIUART_BCSP) += hci_bcsp.o
> > > > hci_uart-$(CONFIG_BT_HCIUART_LL) += hci_ll.o
> > > > +hci_uart-$(CONFIG_BT_HCIUART_ATH) += hci_ath.o
> > > > hci_uart-objs := $(hci_uart-y)
> > > > diff --git a/drivers/bluetooth/hci_ath.c b/drivers/bluetooth/hci_ath.c
> > > > new file mode 100755
> > > > index 0000000..13e4404
> > > > --- /dev/null
> > > > +++ b/drivers/bluetooth/hci_ath.c
> > > > @@ -0,0 +1,353 @@
> > > > +/*
> > > > + * Copyright (c) 2009-2010 Atheros Communications Inc.
> > > > + *
> > > > + * This program is free software; you can redistribute it and/or modify
> > > > + * it under the terms of the GNU General Public License as published by
> > > > + * the Free Software Foundation; either version 2 of the License, or
> > > > + * (at your option) any later version.
> > > > + *
> > > > + * This program is distributed in the hope that it will be useful,
> > > > + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> > > > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> > > > + * GNU General Public License for more details.
> > > > + *
> > > > + * You should have received a copy of the GNU General Public License
> > > > + * along with this program; if not, write to the Free Software
> > > > + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
> > > > + *
> > > > + */
> > > > +
> > > > +#include <linux/module.h>
> > > > +#include <linux/kernel.h>
> > > > +
> > > > +#include <linux/init.h>
> > > > +#include <linux/slab.h>
> > > > +#include <linux/tty.h>
> > > > +#include <linux/errno.h>
> > > > +#include <linux/ioctl.h>
> > > > +#include <linux/skbuff.h>
> > > > +
> > > > +#include <net/bluetooth/bluetooth.h>
> > > > +#include <net/bluetooth/hci_core.h>
> > > > +
> > > > +#include "hci_uart.h"
> > > > +
> > > > +
> > > > +/* HCIATH receiver States */
> > > > +#define HCIATH_W4_PACKET_TYPE 0
> > > > +#define HCIATH_W4_EVENT_HDR 1
> > > > +#define HCIATH_W4_ACL_HDR 2
> > > > +#define HCIATH_W4_SCO_HDR 3
> > > > +#define HCIATH_W4_DATA 4
> > > > +
> > > > +struct ath_struct {
> > > > + struct hci_uart *hu;
> > > > + unsigned int rx_state;
> > > > + unsigned int rx_count;
> > > > + unsigned int cur_sleep;
> > > > +
> > > > + spinlock_t hciath_lock;
> > > > + struct sk_buff *rx_skb;
> > > > + struct sk_buff_head txq;
> > > > + wait_queue_head_t wqevt;
> > > > + struct work_struct ctxtsw;
> > > > +};
> > > > +
> > > > +int ath_wakeup_ar3001(struct tty_struct *tty)
> > > > +{
ath_wakeup_ar3001() should be made static
> > > > + struct termios settings;
> > > > + int status = 0x00;
> > > > + mm_segment_t oldfs;
> > > > + status = tty->driver->ops->tiocmget(tty, NULL);
> > > > +
> > > > + if ((status & TIOCM_CTS))
> > > > + return status;
> > > > +
> > > > + oldfs = get_fs();
> > > > + set_fs(KERNEL_DS);
> > > > + n_tty_ioctl_helper(tty, NULL, TCGETS, (unsigned long)&settings);
> > > > +
> > > > + settings.c_cflag &= ~CRTSCTS;
> > > > + n_tty_ioctl_helper(tty, NULL, TCSETS, (unsigned long)&settings);
> > > > + set_fs(oldfs);
> > > > + status = tty->driver->ops->tiocmget(tty, NULL);
> > > > +
> > > > + /* Wake up board */
> > > > + tty->driver->ops->tiocmset(tty, NULL, 0x00, TIOCM_RTS);
> > > > + mdelay(20);
> > > > +
> > > > + status = tty->driver->ops->tiocmget(tty, NULL);
> > > > +
> > > > + tty->driver->ops->tiocmset(tty, NULL, TIOCM_RTS, 0x00);
> > > > + mdelay(20);
> > > > +
> > > > + status = tty->driver->ops->tiocmget(tty, NULL);
> > > > + oldfs = get_fs();
> > > > + set_fs(KERNEL_DS);
> > > > + n_tty_ioctl_helper(tty, NULL, TCGETS, (unsigned long)&settings);
> > > > +
> > > > + settings.c_cflag |= CRTSCTS;
> > > > + n_tty_ioctl_helper(tty, NULL, TCSETS, (unsigned long)&settings);
> > > > + set_fs(oldfs);
> > > > + return status;
> > > > +}
> > > > +
> > > > +static void ath_context_switch(struct work_struct *work)
> > > > +{
> > > > + int status;
> > > > + struct ath_struct *ath;
> > > > + struct hci_uart *hu;
> > > > + struct tty_struct *tty;
> > > > +
> > > > + ath = container_of(work, struct ath_struct, ctxtsw);
> > > > +
> > > > + hu = ath->hu;
> > > > + tty = hu->tty;
> > > > +
> > > > + /* verify and wake up controller */
> > > > + if (ath->cur_sleep) {
> > > > +
> > > > + status = ath_wakeup_ar3001(tty);
> > > > + if (!(status & TIOCM_CTS))
> > > > + return;
> > > > + }
> > > > +
> > > > + /* Ready to send Data */
> > > > + clear_bit(HCI_UART_SENDING, &hu->tx_state);
> > > > + hci_uart_tx_wakeup(hu);
> > > > +}
> > > > +
> > > > +int ath_check_sleep_cmd(struct ath_struct *ath, unsigned char *packet)
ath_check_sleep_cmd() should be made static. Also just make it return void,
you're not checking the return value. Since its so small why not just fold
the code in on ath_dequeue() ? If you're worried about the > 80 lines just
do something like:
if (skbuf != NULL)
if (packet[0] == 0x04 &&
packet[1] == 0xFC)
ath->cur_sleep = packet[3];
}
or
if (!skbuf)
return NULL;
/*
* Add some comment here explaining why you do this
* as I already forgot too.
*/
if (packet[0] == 0x04 && packet[1] == 0xFC)
ath->cur_sleep = packet[3];
return skbuf;
Please do add the comments about why this is done.
> > > > +{
> > > > + if (packet[0] == 0x04 && packet[1] == 0xFC)
> > > > + ath->cur_sleep = packet[3];
> > > > +
> > > > + return 0;
> > > > +}
> > > > +
> > > > +
> > > > +/* Initialize protocol */
> > > > +static int ath_open(struct hci_uart *hu)
> > > > +{
> > > > + struct ath_struct *ath;
> > > > + BT_DBG("hu %p", hu);
> > > > +
> > > > + ath = kzalloc(sizeof(*ath), GFP_ATOMIC);
> > > > + if (!ath)
> > > > + return -ENOMEM;
> > > > +
> > > > + skb_queue_head_init(&ath->txq);
> > > > + spin_lock_init(&ath->hciath_lock);
> > > > +
> > > > + ath->cur_sleep = 0;
> > > > + hu->priv = ath;
> > > > + ath->hu = hu;
> > > > +
> > > > + init_waitqueue_head(&ath->wqevt);
> > > > + INIT_WORK(&ath->ctxtsw, ath_context_switch);
> > > > + return 0;
> > > > +}
> > > > +
> > > > +/* Flush protocol data */
> > > > +static int ath_flush(struct hci_uart *hu)
> > > > +{
> > > > + struct ath_struct *ath = hu->priv;
> > > > + BT_DBG("hu %p", hu);
> > > > + skb_queue_purge(&ath->txq);
> > > > +
> > > > + return 0;
> > > > +}
> > > > +
> > > > +/* Close protocol */
> > > > +static int ath_close(struct hci_uart *hu)
> > > > +{
> > > > + struct ath_struct *ath = hu->priv;
> > > > + BT_DBG("hu %p", hu);
> > > > +
> > > > + skb_queue_purge(&ath->txq);
> > > > +
> > > > + if (ath->rx_skb)
> > > > + kfree_skb(ath->rx_skb);
> > > > +
> > > > + wake_up_interruptible(&ath->wqevt);
cancel_work_sync(&ath->wqevt);
would wait for it for the scheduled work to finish, how about
that instead. The wake up interruptible seems more like a hack
here, no?
> > > > + hu->priv = NULL;
> > > > + kfree(ath);
> > > > + return 0;
> > > > +}
> > > > +
> > > > +/* Enqueue frame for transmittion */
> > > > +static int ath_enqueue(struct hci_uart *hu, struct sk_buff *skb)
> > > > +{
> > > > + struct ath_struct *ath = hu->priv;
> > > > + if (bt_cb(skb)->pkt_type == HCI_SCODATA_PKT) {
> > > > +
> > > > + /* Discard SCO packet.AR3001 does not support SCO over HCI */
> > > > + BT_DBG("SCO Packet over HCI received Dropping\n");
No need for \n here
> > > > + kfree(skb);
> > > > + return 0;
> > > > + }
> > > > + BT_DBG("hu %p skb %p", hu, skb);
> > > > +
> > > > + /* Prepend skb with frame type */
> > > > + memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1);
> > > > +
> > > > + skb_queue_tail(&ath->txq, skb);
> > > > + set_bit(HCI_UART_SENDING, &hu->tx_state);
> > > > +
> > > > + schedule_work(&ath->ctxtsw);
> > > > + return 0;
> > > > +}
> > > > +
> > > > +static struct sk_buff *ath_dequeue(struct hci_uart *hu)
> > > > +{
> > > > + struct ath_struct *ath = hu->priv;
> > > > + struct sk_buff *skbuf;
> > > > +
> > > > + skbuf = skb_dequeue(&ath->txq);
> > > > + if (skbuf != NULL)
> > > > + ath_check_sleep_cmd(ath, &skbuf->data[1]);
> > > > +
> > > > + return skbuf;
> > > > +}
> > > > +
> > > > +static inline int ath_check_data_len(struct ath_struct *ath, int len)
> > > > +{
Remove the inline, and remove the return type, you never check it.
Repeat this type of review for every other routine you have. If you
are not using the return type just remove the thing. If code is
used just once then it will automatically get the inline, if its
used more than once on the same routine I am not sure if you get
your inline -- but I doubt there is a serious performance penalty
here.
> > > > + register int room = skb_tailroom(ath->rx_skb);
> > > > + BT_DBG("len %d room %d", len, room);
> > > > +
> > > > + if (len > room) {
> > > > + BT_ERR("Data length is too large");
> > > > + kfree_skb(ath->rx_skb);
> > > > + ath->rx_state = HCIATH_W4_PACKET_TYPE;
> > > > + ath->rx_skb = NULL;
> > > > + ath->rx_count = 0;
> > > > + } else {
> > > > + ath->rx_state = HCIATH_W4_DATA;
> > > > + ath->rx_count = len;
> > > > + return len;
> > > > + }
> > > > +
> > > > + return 0;
> > > > +}
> > > > +
> > > > +/* Recv data */
> > > > +static int ath_recv(struct hci_uart *hu, void *data, int count)
> > > > +{
> > > > + struct ath_struct *ath = hu->priv;
> > > > + register char *ptr;
> > > > + struct hci_event_hdr *eh;
> > > > + struct hci_acl_hdr *ah;
> > > > + struct hci_sco_hdr *sh;
> > > > + struct sk_buff *skbuf;
> > > > + register int len, type, dlen;
> > > > +
> > > > + skbuf = NULL;
> > > > + BT_DBG("hu %p count %d rx_state %d rx_count %d", hu, count,
> > > > + ath->rx_state, ath->rx_count);
> > > > + ptr = data;
> > > > + while (count) {
> > > > + if (ath->rx_count) {
> > > > +
> > > > + len = min_t(unsigned int, ath->rx_count, count);
> > > > + memcpy(skb_put(ath->rx_skb, len), ptr, len);
> > > > + ath->rx_count -= len;
> > > > + count -= len;
> > > > + ptr += len;
> > > > +
> > > > + if (ath->rx_count)
> > > > + continue;
> > > > + switch (ath->rx_state) {
> > > > + case HCIATH_W4_DATA:
> > > > + hci_recv_frame(ath->rx_skb);
> > > > + ath->rx_state = HCIATH_W4_PACKET_TYPE;
> > > > + ath->rx_skb = NULL;
> > > > + ath->rx_count = 0;
> > > > + continue;
> > > > + case HCIATH_W4_EVENT_HDR:
> > > > + eh = (struct hci_event_hdr *)ath->rx_skb->data;
> > > > + BT_DBG("Event header: evt 0x%2.2x plen %d",
> > > > + eh->evt, eh->plen);
> > > > + ath_check_data_len(ath, eh->plen);
> > > > + continue;
> > > > + case HCIATH_W4_ACL_HDR:
> > > > + ah = (struct hci_acl_hdr *)ath->rx_skb->data;
> > > > + dlen = __le16_to_cpu(ah->dlen);
> > > > + BT_DBG("ACL header: dlen %d", dlen);
> > > > + ath_check_data_len(ath, dlen);
> > > > + continue;
> > > > + case HCIATH_W4_SCO_HDR:
> > > > + sh = (struct hci_sco_hdr *)ath->rx_skb->data;
> > > > + BT_DBG("SCO header: dlen %d", sh->dlen);
> > > > + ath_check_data_len(ath, sh->dlen);
> > > > + continue;
> > > > + }
> > > > + }
> > > > +
> > > > + /* HCIATH_W4_PACKET_TYPE */
> > > > + switch (*ptr) {
> > > > + case HCI_EVENT_PKT:
> > > > + BT_DBG("Event packet");
> > > > + ath->rx_state = HCIATH_W4_EVENT_HDR;
> > > > + ath->rx_count = HCI_EVENT_HDR_SIZE;
> > > > + type = HCI_EVENT_PKT;
> > > > + break;
> > > > + case HCI_ACLDATA_PKT:
> > > > + BT_DBG("ACL packet");
> > > > + ath->rx_state = HCIATH_W4_ACL_HDR;
> > > > + ath->rx_count = HCI_ACL_HDR_SIZE;
> > > > + type = HCI_ACLDATA_PKT;
> > > > + break;
> > > > + case HCI_SCODATA_PKT:
> > > > + BT_DBG("SCO packet");
> > > > + ath->rx_state = HCIATH_W4_SCO_HDR;
> > > > + ath->rx_count = HCI_SCO_HDR_SIZE;
> > > > + type = HCI_SCODATA_PKT;
> > > > + break;
> > > > + default:
> > > > + BT_ERR("Unknown HCI packet type %2.2x", (__u8) *ptr);
> > > > + hu->hdev->stat.err_rx++;
> > > > + ptr++;
> > > > + count--;
> > > > + continue;
> > > > + };
> > > > + ptr++;
> > > > + count--;
> > > > +
> > > > + /* Allocate packet */
> > > > + ath->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC);
> > > > + if (!ath->rx_skb) {
> > > > + BT_ERR("Can't allocate mem for new packet");
> > > > + ath->rx_state = HCIATH_W4_PACKET_TYPE;
> > > > + ath->rx_count = 0;
> > > > + return -ENOMEM;
> > > > + }
> > > > + ath->rx_skb->dev = (void *)hu->hdev;
> > > > + bt_cb(ath->rx_skb)->pkt_type = type;
> > > > + } return count;
Please the return in a new line. This routien can later be cleaned up
and split into a a couple of helpers, for now its OK I guess.
> > > > +}
> > > > +
> > > > +static struct hci_uart_proto athp = {
> > > > + .id = HCI_UART_ATH,
> > > > + .open = ath_open,
> > > > + .close = ath_close,
> > > > + .recv = ath_recv,
> > > > + .enqueue = ath_enqueue,
> > > > + .dequeue = ath_dequeue,
> > > > + .flush = ath_flush,
> > > > +};
> > > > +
> > > > +int ath_init(void)
> > > > +{
> > > > + int err = hci_uart_register_proto(&athp);
> > > > + if (!err)
> > > > + BT_INFO("HCIATH protocol initialized");
> > > > +
> > > > + else
> > > > + BT_ERR("HCIATH protocol registration failed");
> > > > + return err;
> > > > +}
> > > > +
> > > > +int ath_deinit(void)
> > > > +{
> > > > + return hci_uart_unregister_proto(&athp);
> > > > +}
> > > > diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c
> > > > index 76a1abb..7dd76d1 100644
> > > > --- a/drivers/bluetooth/hci_ldisc.c
> > > > +++ b/drivers/bluetooth/hci_ldisc.c
> > > > @@ -542,6 +542,9 @@ static int __init hci_uart_init(void)
> > > > #ifdef CONFIG_BT_HCIUART_LL
> > > > ll_init();
> > > > #endif
> > > > +#ifdef CONFIG_BT_HCIUART_ATH
> > > > + ath_init();
> > > > +#endif
> > > >
> > > > return 0;
> > > > }
> > > > @@ -559,6 +562,9 @@ static void __exit hci_uart_exit(void)
> > > > #ifdef CONFIG_BT_HCIUART_LL
> > > > ll_deinit();
> > > > #endif
> > > > +#ifdef CONFIG_BT_HCIUART_ATH
> > > > + ath_deinit();
> > > > +#endif
> > > >
> > > > /* Release tty registration of line discipline */
> > > > if ((err = tty_unregister_ldisc(N_HCI)))
> > > > diff --git a/drivers/bluetooth/hci_uart.h b/drivers/bluetooth/hci_uart.h
> > > > index 50113db..385537f 100644
> > > > --- a/drivers/bluetooth/hci_uart.h
> > > > +++ b/drivers/bluetooth/hci_uart.h
> > > > @@ -33,13 +33,14 @@
> > > > #define HCIUARTGETDEVICE _IOR('U', 202, int)
> > > >
> > > > /* UART protocols */
> > > > -#define HCI_UART_MAX_PROTO 5
> > > > +#define HCI_UART_MAX_PROTO 6
> > > >
> > > > #define HCI_UART_H4 0
> > > > #define HCI_UART_BCSP 1
> > > > #define HCI_UART_3WIRE 2
> > > > #define HCI_UART_H4DS 3
> > > > #define HCI_UART_LL 4
> > > > +#define HCI_UART_ATH 5
> > > >
> > > > struct hci_uart;
> > > >
> > > > @@ -91,3 +92,8 @@ int bcsp_deinit(void);
> > > > int ll_init(void);
> > > > int ll_deinit(void);
> > > > #endif
> > > > +
> > > > +#ifdef CONFIG_BT_HCIUART_ATH
> > > > +int ath_init(void);
> > > > +int ath_deinit(void);
> > > > +#endif
> > >
> > > Hi Marcel,
> > >
> > > Can you please give your comments regarding the patch that I have sent
> > > you?
> > >
> > > Regards
> > > Suraj
> >
> > Hi marcel,
> >
> > A gentle remainder.
> >
> > Can you please update the above driver to the Linux tree? If you find
> > any issues please let me know so that I can do the needful.
> >
> > Regards
> > Suraj
>
> Hi Luis,
>
> I had sent source code to support Atheros AR300x Bluetooth Chip to
> Marcel for sending it upstream before around two month.
I don't see it being two months, I see it being one month but one month
without feedback is indeed quite a while. In my timeline I see it as:
02-22-2010 - Marcel responded to your first patch version for UART bluetooth
02-22-2010 - Suarj posted resplies to Marcel's questions
03-01-2010 - Suraj poked Marcel for feedback based on Suraj's comments
----------
03-11-2010 - Suraj posts new V2 patch but its sent busted with tabs/space mixup
03-11-2010 - Marcel asks for a resend
----------
03-14-2010 - Suaraj posts V3 patch with tabs/spaces fixed
03-23-2010 - First poke to Marcel and list
03-29-2010 - Second poke to Marcel and list
03-31-2010 - Patch for userspace hciattach.c changes posted
Please ensure to use [PATCH vX] for each X iteration so that it is clear
this is a new iteration.
> I am yet to get any response for that from his telling whether it is
> approved or rejected even after number of remainder mails.
I'd just poke again, every two days until you get a reply :)
> Can you please help me on this? I am not sure what should be my next
> step.
>
> Regards
> Suraj
Marcel, *poke* re: Atheros AR300x Bluetooth Chip
To help I've reviewed this patch and the previous comments, I've made
some of my own above. Please also install sparse and use it every time
you make changes to the kernel and sparse check the code you write.
git clone git://git.kernel.org/pub/scm/devel/sparse/chrisl/sparse.git
git checkout -b rel-042 v0.4.2
make -j
# no need to be root
make install
Then to sparse check your code do:
make C=1 M=drivers/bluetooth/
This would have caught the two static checks I noted above.
Luis
^ permalink raw reply
* Re: Patches for eL2CAP
From: Gustavo F. Padovan @ 2010-04-19 20:15 UTC (permalink / raw)
To: marcel; +Cc: linux-bluetooth, jprvita
In-Reply-To: <1270153432-6477-1-git-send-email-padovan@profusion.mobi>
Hi Marcel,
* Gustavo F. Padovan <padovan@profusion.mobi> [2010-04-01 17:23:18 -0300]:
> Hi Marcel,
>
> Here are all patches rebased against -rc3. Most of then are a resend unless
> the last five patches.
What about these patches? Merge window is coming and would be good if we
have a try on linux-next before push these patches to mainline. ;)
Please, review them.
Regards,
--
Gustavo F. Padovan
http://padovan.org
^ permalink raw reply
* RE: A strange compatible problem for eSCO audio with CSR USB Bluetooth dongle
From: Cooper Xu @ 2010-04-19 22:03 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1268707083.2700.14.camel@localhost.localdomain>
Hi,
I was written to this list one month ago about a strange compatible problem
between Bluetooth dongle of CSR chipset with HCI Rev: 0xc5c and Bluez. The
phenomena were that the eSCO connection can be made without any problem, but
I received all zero for voice data.
After some tests with several USB Dongles of CSR chipset, I found that if I
turned off eSCO, I am able to get real voice data.
The strange thing is that I used a host with Bluez and CSR dongle to test
the eSCO connection with Blackberry 8310 curve, which Blackberry has the CSR
chipset and HCI Rev: 0xc5c, the voice data worked without problem. However
if I use two hosts with CSR dongles and Bluez at the both ends, the eSCO
connection keeps receiving zero for voice data. This problem exists with all
CSR USB dongles I tried including a Bluetooth 2.1 dongle. If I turn off eSCO
mode, this problem will go away.
Does any one have clue why the eSCO connection will receive all zero if the
both side of eSCO connection are using Bluez and CSR chipset? How can eSCO
connection not compatible between USB dongles with the same CSR chipset and
firmware?
Thanks,
Cooper
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox