* [PATCHv2 04/19] Bluetooth: Lookup channel structure based on DCID
From: Mat Martineau @ 2012-10-16 23:36 UTC (permalink / raw)
To: linux-bluetooth, gustavo; +Cc: sunnyk, marcel
In-Reply-To: <1350430593-23565-1-git-send-email-mathewm@codeaurora.org>
Processing a move channel request involves getting the channel
structure using the destination channel ID. Previous code could only
look up using the source channel ID.
Signed-off-by: Mat Martineau <mathewm@codeaurora.org>
---
net/bluetooth/l2cap_core.c | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index ec2b4d9..b5b849b 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -100,6 +100,22 @@ static struct l2cap_chan *l2cap_get_chan_by_scid(struct l2cap_conn *conn,
return c;
}
+/* Find channel with given DCID.
+ * Returns locked channel. */
+static struct l2cap_chan *l2cap_get_chan_by_dcid(struct l2cap_conn *conn,
+ u16 cid)
+{
+ struct l2cap_chan *c;
+
+ mutex_lock(&conn->chan_lock);
+ c = __l2cap_get_chan_by_dcid(conn, cid);
+ if (c)
+ l2cap_chan_lock(c);
+ mutex_unlock(&conn->chan_lock);
+
+ return c;
+}
+
static struct l2cap_chan *__l2cap_get_chan_by_ident(struct l2cap_conn *conn,
u8 ident)
{
@@ -4139,6 +4155,7 @@ static inline int l2cap_move_channel_req(struct l2cap_conn *conn,
u16 cmd_len, void *data)
{
struct l2cap_move_chan_req *req = data;
+ struct l2cap_chan *chan;
u16 icid = 0;
u16 result = L2CAP_MR_NOT_ALLOWED;
--
1.7.12.3
--
Mat Martineau
Employee of Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
^ permalink raw reply related
* [PATCHv2 03/19] Bluetooth: Remove unnecessary intermediate function
From: Mat Martineau @ 2012-10-16 23:36 UTC (permalink / raw)
To: linux-bluetooth, gustavo; +Cc: sunnyk, marcel
In-Reply-To: <1350430593-23565-1-git-send-email-mathewm@codeaurora.org>
Resolves a conflict resolution issue in "Bluetooth: Fix L2CAP coding
style".
Signed-off-by: Mat Martineau <mathewm@codeaurora.org>
Acked-by: Marcel Holtmann <marcel@holtmann.org>
---
net/bluetooth/l2cap_core.c | 13 ++-----------
1 file changed, 2 insertions(+), 11 deletions(-)
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 73ce337..ec2b4d9 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -3537,7 +3537,7 @@ static int l2cap_connect_req(struct l2cap_conn *conn,
return 0;
}
-static inline int l2cap_connect_rsp(struct l2cap_conn *conn,
+static int l2cap_connect_create_rsp(struct l2cap_conn *conn,
struct l2cap_cmd_hdr *cmd, u8 *data)
{
struct l2cap_conn_rsp *rsp = (struct l2cap_conn_rsp *) data;
@@ -4091,15 +4091,6 @@ static int l2cap_create_channel_req(struct l2cap_conn *conn,
return 0;
}
-static inline int l2cap_create_channel_rsp(struct l2cap_conn *conn,
- struct l2cap_cmd_hdr *cmd,
- void *data)
-{
- BT_DBG("conn %p", conn);
-
- return l2cap_connect_rsp(conn, cmd, data);
-}
-
static void l2cap_send_move_chan_rsp(struct l2cap_conn *conn, u8 ident,
u16 icid, u16 result)
{
@@ -4306,7 +4297,7 @@ static inline int l2cap_bredr_sig_cmd(struct l2cap_conn *conn,
case L2CAP_CONN_RSP:
case L2CAP_CREATE_CHAN_RSP:
- err = l2cap_connect_rsp(conn, cmd, data);
+ err = l2cap_connect_create_rsp(conn, cmd, data);
break;
case L2CAP_CONF_REQ:
--
1.7.12.3
--
Mat Martineau
Employee of Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
^ permalink raw reply related
* [PATCHv2 02/19] Bluetooth: Add L2CAP create channel request handling
From: Mat Martineau @ 2012-10-16 23:36 UTC (permalink / raw)
To: linux-bluetooth, gustavo; +Cc: sunnyk, marcel, Andrei Emeltchenko
In-Reply-To: <1350430593-23565-1-git-send-email-mathewm@codeaurora.org>
The L2CAP create channel request is very similar to an L2CAP connect
request, but it has an additional parameter for the controller ID. If
the controller id is 0, the channel is set up on the BR/EDR controller
(just like a connect request). Using a valid high speed controller ID
will cause the channel to be initially created on that high speed
controller. While the L2CAP data will be initially routed over the
AMP controller, the L2CAP fixed signaling channel only uses BR/EDR.
When a create channel request is received for a high speed controller,
a pending response is always sent first. After the high speed
physical and logical links are complete a success response will be
sent.
Signed-off-by: Mat Martineau <mathewm@codeaurora.org>
Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
Acked-by: Marcel Holtmann <marcel@holtmann.org>
---
net/bluetooth/l2cap_core.c | 62 +++++++++++++++++++++++++++++++++++-----------
1 file changed, 47 insertions(+), 15 deletions(-)
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index f8d78f5..73ce337 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -3400,8 +3400,9 @@ static inline int l2cap_command_rej(struct l2cap_conn *conn,
return 0;
}
-static void l2cap_connect(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd,
- u8 *data, u8 rsp_code, u8 amp_id)
+static struct l2cap_chan *l2cap_connect(struct l2cap_conn *conn,
+ struct l2cap_cmd_hdr *cmd,
+ u8 *data, u8 rsp_code, u8 amp_id)
{
struct l2cap_conn_req *req = (struct l2cap_conn_req *) data;
struct l2cap_conn_rsp rsp;
@@ -3452,6 +3453,7 @@ static void l2cap_connect(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd,
bacpy(&bt_sk(sk)->dst, conn->dst);
chan->psm = psm;
chan->dcid = scid;
+ chan->local_amp_id = amp_id;
__l2cap_chan_add(conn, chan);
@@ -3469,8 +3471,16 @@ static void l2cap_connect(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd,
status = L2CAP_CS_AUTHOR_PEND;
chan->ops->defer(chan);
} else {
- __l2cap_state_change(chan, BT_CONFIG);
- result = L2CAP_CR_SUCCESS;
+ /* Force pending result for AMP controllers.
+ * The connection will succeed after the
+ * physical link is up. */
+ if (amp_id) {
+ __l2cap_state_change(chan, BT_CONNECT2);
+ result = L2CAP_CR_PEND;
+ } else {
+ __l2cap_state_change(chan, BT_CONFIG);
+ result = L2CAP_CR_SUCCESS;
+ }
status = L2CAP_CS_NO_INFO;
}
} else {
@@ -3516,6 +3526,8 @@ sendresp:
l2cap_build_conf_req(chan, buf), buf);
chan->num_conf_req++;
}
+
+ return chan;
}
static int l2cap_connect_req(struct l2cap_conn *conn,
@@ -4028,12 +4040,12 @@ static inline int l2cap_information_rsp(struct l2cap_conn *conn,
return 0;
}
-static inline int l2cap_create_channel_req(struct l2cap_conn *conn,
- struct l2cap_cmd_hdr *cmd,
- u16 cmd_len, void *data)
+static int l2cap_create_channel_req(struct l2cap_conn *conn,
+ struct l2cap_cmd_hdr *cmd,
+ u16 cmd_len, void *data)
{
struct l2cap_create_chan_req *req = data;
- struct l2cap_create_chan_rsp rsp;
+ struct l2cap_chan *chan;
u16 psm, scid;
if (cmd_len != sizeof(*req))
@@ -4047,14 +4059,34 @@ static inline int l2cap_create_channel_req(struct l2cap_conn *conn,
BT_DBG("psm 0x%2.2x, scid 0x%4.4x, amp_id %d", psm, scid, req->amp_id);
- /* Placeholder: Always reject */
- rsp.dcid = 0;
- rsp.scid = cpu_to_le16(scid);
- rsp.result = __constant_cpu_to_le16(L2CAP_CR_NO_MEM);
- rsp.status = __constant_cpu_to_le16(L2CAP_CS_NO_INFO);
+ if (req->amp_id) {
+ struct hci_dev *hdev;
- l2cap_send_cmd(conn, cmd->ident, L2CAP_CREATE_CHAN_RSP,
- sizeof(rsp), &rsp);
+ /* Validate AMP controller id */
+ hdev = hci_dev_get(req->amp_id);
+ if (!hdev || hdev->dev_type != HCI_AMP ||
+ !test_bit(HCI_UP, &hdev->flags)) {
+ struct l2cap_create_chan_rsp rsp;
+
+ rsp.dcid = 0;
+ rsp.scid = cpu_to_le16(scid);
+ rsp.result = __constant_cpu_to_le16(L2CAP_CR_BAD_AMP);
+ rsp.status = __constant_cpu_to_le16(L2CAP_CS_NO_INFO);
+
+ l2cap_send_cmd(conn, cmd->ident, L2CAP_CREATE_CHAN_RSP,
+ sizeof(rsp), &rsp);
+
+ if (hdev)
+ hci_dev_put(hdev);
+
+ return 0;
+ }
+
+ hci_dev_put(hdev);
+ }
+
+ chan = l2cap_connect(conn, cmd, data, L2CAP_CREATE_CHAN_RSP,
+ req->amp_id);
return 0;
}
--
1.7.12.3
--
Mat Martineau
Employee of Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
^ permalink raw reply related
* [PATCHv2 01/19] Bluetooth: Add new l2cap_chan struct members for high speed channels
From: Mat Martineau @ 2012-10-16 23:36 UTC (permalink / raw)
To: linux-bluetooth, gustavo; +Cc: sunnyk, marcel, Andrei Emeltchenko
In-Reply-To: <1350430593-23565-1-git-send-email-mathewm@codeaurora.org>
An L2CAP channel using high speed continues to be associated with a
BR/EDR l2cap_conn, while also tracking an additional hci_conn
(representing a physical link on a high speed controller) and hci_chan
(representing a logical link). There may only be one physical link
between two high speed controllers. Each physical link may contain
several logical links, with each logical link representing a channel
with specific quality of service.
During a channel move, the destination channel id, current move state,
and role (initiator vs. responder) are tracked and used by the channel
move state machine. The ident value associated with a move request
must also be stored in order to use it in later move responses.
The active channel is stored in local_amp_id.
Signed-off-by: Mat Martineau <mathewm@codeaurora.org>
Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
Acked-by: Marcel Holtmann <marcel@holtmann.org>
---
include/net/bluetooth/l2cap.h | 29 +++++++++++++++++++++++++++++
net/bluetooth/l2cap_core.c | 5 +++++
2 files changed, 34 insertions(+)
diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index 6e23afd..6d3615e 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -434,6 +434,8 @@ struct l2cap_chan {
struct sock *sk;
struct l2cap_conn *conn;
+ struct hci_conn *hs_hcon;
+ struct hci_chan *hs_hchan;
struct kref kref;
__u8 state;
@@ -477,6 +479,11 @@ struct l2cap_chan {
unsigned long conn_state;
unsigned long flags;
+ __u8 local_amp_id;
+ __u8 move_id;
+ __u8 move_state;
+ __u8 move_role;
+
__u16 next_tx_seq;
__u16 expected_ack_seq;
__u16 expected_tx_seq;
@@ -644,6 +651,9 @@ enum {
enum {
L2CAP_RX_STATE_RECV,
L2CAP_RX_STATE_SREJ_SENT,
+ L2CAP_RX_STATE_MOVE,
+ L2CAP_RX_STATE_WAIT_P,
+ L2CAP_RX_STATE_WAIT_F,
};
enum {
@@ -674,6 +684,25 @@ enum {
L2CAP_EV_RECV_FRAME,
};
+enum {
+ L2CAP_MOVE_ROLE_NONE,
+ L2CAP_MOVE_ROLE_INITIATOR,
+ L2CAP_MOVE_ROLE_RESPONDER,
+};
+
+enum {
+ L2CAP_MOVE_STABLE,
+ L2CAP_MOVE_WAIT_REQ,
+ L2CAP_MOVE_WAIT_RSP,
+ L2CAP_MOVE_WAIT_RSP_SUCCESS,
+ L2CAP_MOVE_WAIT_CONFIRM,
+ L2CAP_MOVE_WAIT_CONFIRM_RSP,
+ L2CAP_MOVE_WAIT_LOGICAL_COMP,
+ L2CAP_MOVE_WAIT_LOGICAL_CFM,
+ L2CAP_MOVE_WAIT_LOCAL_BUSY,
+ L2CAP_MOVE_WAIT_PREPARE,
+};
+
void l2cap_chan_hold(struct l2cap_chan *c);
void l2cap_chan_put(struct l2cap_chan *c);
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index f873619..f8d78f5 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -2788,6 +2788,11 @@ int l2cap_ertm_init(struct l2cap_chan *chan)
skb_queue_head_init(&chan->tx_q);
+ chan->local_amp_id = 0;
+ chan->move_id = 0;
+ chan->move_state = L2CAP_MOVE_STABLE;
+ chan->move_role = L2CAP_MOVE_ROLE_NONE;
+
if (chan->mode != L2CAP_MODE_ERTM)
return 0;
--
1.7.12.3
--
Mat Martineau
Employee of Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
^ permalink raw reply related
* [PATCHv2 00/19] L2CAP signaling for AMP channel create/move
From: Mat Martineau @ 2012-10-16 23:36 UTC (permalink / raw)
To: linux-bluetooth, gustavo; +Cc: sunnyk, marcel
Here are the changes that process commands on the L2CAP signaling
channel for setting up AMP channels. There's still a lot of
integration to do as other AMP functionality is implemented. I've
marked places that require this integration with "Placeholder"
comments (look for that string).
Changes:
* PATCHv2 - Fixed formatting and style issues, added acks
* PATCHv1 - Rebased after AMP physical link patch set, incorporated
mailing list feedback.
* RFCv1 - Finished commit messages, fixed formatting/style issues
* RFCv0 - Initial post
Mat Martineau (19):
Bluetooth: Add new l2cap_chan struct members for high speed channels
Bluetooth: Add L2CAP create channel request handling
Bluetooth: Remove unnecessary intermediate function
Bluetooth: Lookup channel structure based on DCID
Bluetooth: Channel move request handling
Bluetooth: Add new ERTM receive states for channel move
Bluetooth: Add move channel confirm handling
Bluetooth: Add state to hci_chan
Bluetooth: Move channel response
Bluetooth: Add logical link confirm
Bluetooth: Add move confirm response handling
Bluetooth: Handle physical link completion
Bluetooth: Flag ACL frames as complete for AMP controllers
Bluetooth: Do not send data during channel move
Bluetooth: Configure appropriate timeouts for AMP controllers
Bluetooth: Ignore BR/EDR packet size constraints when fragmenting for
AMP
Bluetooth: Send create channel request instead of connect for AMP
Bluetooth: Do not retransmit data during a channel move
Bluetooth: Start channel move when socket option is changed
include/net/bluetooth/hci_core.h | 1 +
include/net/bluetooth/l2cap.h | 32 ++
net/bluetooth/hci_conn.c | 1 +
net/bluetooth/l2cap_core.c | 973 +++++++++++++++++++++++++++++++++++++--
net/bluetooth/l2cap_sock.c | 5 +
5 files changed, 972 insertions(+), 40 deletions(-)
--
1.7.12.3
--
Mat Martineau
Employee of Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
^ permalink raw reply
* Re: [PATCH 07/19] Bluetooth: Add move channel confirm handling
From: Mat Martineau @ 2012-10-16 23:00 UTC (permalink / raw)
To: Andrei Emeltchenko; +Cc: linux-bluetooth, gustavo, sunnyk, marcel
In-Reply-To: <20121016102726.GG14036@aemeltch-MOBL1>
On Tue, 16 Oct 2012, Andrei Emeltchenko wrote:
> Hi Mat,
>
> On Mon, Oct 15, 2012 at 08:33:56AM -0700, Mat Martineau wrote:
>> After sending a move channel response, a move responder waits for a
>> move channel confirm command. If the received command has a
>> "confirmed" result the move is proceeding, and "unconfirmed" means the
>> move has failed and the channel will not change controllers.
>>
>> Signed-off-by: Mat Martineau <mathewm@codeaurora.org>
>> ---
>> net/bluetooth/l2cap_core.c | 70 ++++++++++++++++++++++++++++++++++++++++++++--
>> 1 file changed, 67 insertions(+), 3 deletions(-)
>>
>> diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
>> index aab7f79..ef744a9 100644
>> --- a/net/bluetooth/l2cap_core.c
>> +++ b/net/bluetooth/l2cap_core.c
>> @@ -1030,6 +1030,42 @@ static void l2cap_move_setup(struct l2cap_chan *chan)
>> set_bit(CONN_REMOTE_BUSY, &chan->conn_state);
>> }
>>
>> +static void l2cap_move_success(struct l2cap_chan *chan)
>> +{
>> + BT_DBG("chan %p", chan);
>> +
>> + if (chan->mode != L2CAP_MODE_ERTM)
>> + return;
>> +
>> + switch (chan->move_role) {
>> + case L2CAP_MOVE_ROLE_INITIATOR:
>> + l2cap_tx(chan, NULL, NULL, L2CAP_EV_EXPLICIT_POLL);
>> + chan->rx_state = L2CAP_RX_STATE_WAIT_F;
>> + break;
>> + case L2CAP_MOVE_ROLE_RESPONDER:
>> + chan->rx_state = L2CAP_RX_STATE_WAIT_P;
>> + break;
>> + }
>> +}
>> +
>> +static void l2cap_move_revert(struct l2cap_chan *chan)
>> +{
>> + BT_DBG("chan %p", chan);
>> +
>> + if (chan->mode != L2CAP_MODE_ERTM)
>> + return;
>
> Not sure that all those function need to check for ERTM. Can it be done
> before calling them (for example in l2cap_move_channel_confirm)?
I prefer to leave the checks where they are for ERTM. Either
streaming mode or ERTM channels may be moved, and these functions need
to do something different for ERTM and streaming mode. These are not
redundant mode checks.
Regards,
--
Mat Martineau
Employee of Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
^ permalink raw reply
* Re: [PATCH 10/19] Bluetooth: Add logical link confirm
From: Mat Martineau @ 2012-10-16 22:25 UTC (permalink / raw)
To: Andrei Emeltchenko; +Cc: linux-bluetooth, gustavo, sunnyk, marcel
In-Reply-To: <20121016103855.GH14036@aemeltch-MOBL1>
Hi Andrei -
On Tue, 16 Oct 2012, Andrei Emeltchenko wrote:
> Hi Mat,
>
> On Mon, Oct 15, 2012 at 08:33:59AM -0700, Mat Martineau wrote:
>> The logical link confirm callback is executed when the AMP controller
>> completes its logical link setup. During a channel move, a newly
>> formed logical link allows a move responder to send a move channel
>> response. A move initiator will send a move channel confirm. A
>> failed logical link will end the channel move and send an appropriate
>> response or confirm command indicating a failure.
>>
>> If the channel is being created on an AMP controller, L2CAP
>> configuration is started after the logical link is set up.
>>
>> Signed-off-by: Mat Martineau <mathewm@codeaurora.org>
>> ---
>> net/bluetooth/l2cap_core.c | 117 ++++++++++++++++++++++++++++++++++++++++++++-
>> 1 file changed, 115 insertions(+), 2 deletions(-)
>>
>> diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
>> index c687cc1..7e31e98 100644
>> --- a/net/bluetooth/l2cap_core.c
>> +++ b/net/bluetooth/l2cap_core.c
>> @@ -3779,6 +3779,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn,
>> goto unlock;
>> }
>>
>> + chan->ident = cmd->ident;
>> l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP, len, rsp);
>> chan->num_conf_rsp++;
>>
>> @@ -4221,11 +4222,123 @@ static void l2cap_send_move_chan_cfm_rsp(struct l2cap_conn *conn, u8 ident,
>> l2cap_send_cmd(conn, ident, L2CAP_MOVE_CHAN_CFM_RSP, sizeof(rsp), &rsp);
>> }
>>
>> +/* Call with chan locked */
>> static void l2cap_logical_cfm(struct l2cap_chan *chan, struct hci_chan *hchan,
>> u8 status)
>> {
>> - /* Placeholder */
>> - return;
>> + BT_DBG("chan %p, hchan %p, status %d", chan, hchan, status);
>> +
>> + if (chan->state != BT_CONNECTED && !chan->local_amp_id)
>> + return;
>> +
>> + if (!status && chan->state != BT_CONNECTED) {
>> + struct l2cap_conf_rsp rsp;
>> + u8 code;
>> +
>> + /* Create channel complete */
>> + chan->hs_hcon = hchan->conn;
>> + chan->hs_hcon->l2cap_data = chan->conn;
>> +
>> + code = l2cap_build_conf_rsp(chan, &rsp,
>> + L2CAP_CONF_SUCCESS, 0);
>> + l2cap_send_cmd(chan->conn, chan->ident, L2CAP_CONF_RSP, code,
>> + &rsp);
>> + set_bit(CONF_OUTPUT_DONE, &chan->conf_state);
>> +
>> + if (test_bit(CONF_INPUT_DONE, &chan->conf_state)) {
>> + int err = 0;
>> +
>> + set_default_fcs(chan);
>> +
>> + if (chan->mode == L2CAP_MODE_ERTM ||
>> + chan->mode == L2CAP_MODE_STREAMING)
>
> Shall we check for this? Can we have here basic mode?
It would make sense to enforce this earlier in the configuration
process for AMP channels.
--
Mat Martineau
Employee of Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
^ permalink raw reply
* Re: [PATCH 09/19] Bluetooth: Move channel response
From: Mat Martineau @ 2012-10-16 17:56 UTC (permalink / raw)
To: Marcel Holtmann; +Cc: linux-bluetooth, gustavo, sunnyk
In-Reply-To: <1350325792.26318.13.camel@aeonflux>
Hi Marcel -
On Mon, 15 Oct 2012, Marcel Holtmann wrote:
> Hi Mat,
>
>> The move response command includes a result code indicationg
>> "pending", "success", or "failure" status. A pending result is
>> received when the remote address is still setting up a physical link,
>> and will be followed by success or failure. On success, logical link
>> setup will proceed. On failure, the move is stopped. The receiver of
>> a move channel response must always follow up by sending a move
>> channel confirm command.
>>
>> Signed-off-by: Mat Martineau <mathewm@codeaurora.org>
>> ---
>> include/net/bluetooth/l2cap.h | 2 +
>> net/bluetooth/l2cap_core.c | 137 +++++++++++++++++++++++++++++++++++++++++-
>> 2 files changed, 137 insertions(+), 2 deletions(-)
>>
>> diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
>> index 6d3615e..b4c3c65 100644
>> --- a/include/net/bluetooth/l2cap.h
>> +++ b/include/net/bluetooth/l2cap.h
>> @@ -52,6 +52,8 @@
>> #define L2CAP_ENC_TIMEOUT msecs_to_jiffies(5000)
>> #define L2CAP_CONN_TIMEOUT msecs_to_jiffies(40000)
>> #define L2CAP_INFO_TIMEOUT msecs_to_jiffies(4000)
>> +#define L2CAP_MOVE_TIMEOUT msecs_to_jiffies(4000)
>> +#define L2CAP_MOVE_ERTX_TIMEOUT msecs_to_jiffies(60000)
>>
>> #define L2CAP_A2MP_DEFAULT_MTU 670
>>
>> diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
>> index ef744a9..c687cc1 100644
>> --- a/net/bluetooth/l2cap_core.c
>> +++ b/net/bluetooth/l2cap_core.c
>> @@ -4221,6 +4221,13 @@ static void l2cap_send_move_chan_cfm_rsp(struct l2cap_conn *conn, u8 ident,
>> l2cap_send_cmd(conn, ident, L2CAP_MOVE_CHAN_CFM_RSP, sizeof(rsp), &rsp);
>> }
>>
>> +static void l2cap_logical_cfm(struct l2cap_chan *chan, struct hci_chan *hchan,
>> + u8 status)
>> +{
>> + /* Placeholder */
>> + return;
>> +}
>> +
>> static inline int l2cap_move_channel_req(struct l2cap_conn *conn,
>> struct l2cap_cmd_hdr *cmd,
>> u16 cmd_len, void *data)
>> @@ -4317,6 +4324,7 @@ static inline int l2cap_move_channel_rsp(struct l2cap_conn *conn,
>> u16 cmd_len, void *data)
>> {
>> struct l2cap_move_chan_rsp *rsp = data;
>> + struct l2cap_chan *chan = NULL;
>
> do we need the = NULL assignment here?
>
>> u16 icid, result;
>>
>> if (cmd_len != sizeof(*rsp))
>> @@ -4327,8 +4335,133 @@ static inline int l2cap_move_channel_rsp(struct l2cap_conn *conn,
>>
>> BT_DBG("icid 0x%4.4x, result 0x%4.4x", icid, result);
>>
>> - /* Placeholder: Always unconfirmed */
>> - l2cap_send_move_chan_cfm(conn, NULL, icid, L2CAP_MC_UNCONFIRMED);
>> + switch (result) {
>> + case L2CAP_MR_SUCCESS:
>> + case L2CAP_MR_PEND:
>> + chan = l2cap_get_chan_by_scid(conn, icid);
>> + if (!chan) {
>> + l2cap_send_move_chan_cfm(conn, NULL, icid,
>> + L2CAP_MC_UNCONFIRMED);
>> + break;
>> + }
>> +
>> + __clear_chan_timer(chan);
>> + if (result == L2CAP_MR_PEND)
>> + __set_chan_timer(chan, L2CAP_MOVE_ERTX_TIMEOUT);
>> +
>> + if (chan->move_state == L2CAP_MOVE_WAIT_LOGICAL_COMP) {
>> + /* Move confirm will be sent when logical link
>> + * is complete.
>> + */
>> + chan->move_state = L2CAP_MOVE_WAIT_LOGICAL_CFM;
>> + } else if (chan->move_state == L2CAP_MOVE_WAIT_RSP_SUCCESS) {
>> + if (result == L2CAP_MR_PEND) {
>> + break;
>> + } else if (test_bit(CONN_LOCAL_BUSY,
>> + &chan->conn_state)) {
>> + chan->move_state = L2CAP_MOVE_WAIT_LOCAL_BUSY;
>> + } else {
>> + /* Logical link is up or moving to BR/EDR,
>> + * proceed with move */
>> + chan->move_state = L2CAP_MOVE_WAIT_CONFIRM_RSP;
>> + l2cap_send_move_chan_cfm(conn, chan, chan->scid,
>> + L2CAP_MC_CONFIRMED);
>> + __set_chan_timer(chan, L2CAP_MOVE_TIMEOUT);
>> + }
>> + } else if (chan->move_state == L2CAP_MOVE_WAIT_RSP) {
>> + struct hci_chan *hchan = NULL;
>> + /* Moving to AMP */
>> + if (result == L2CAP_MR_SUCCESS) {
>> + /* Remote is ready, send confirm immediately
>> + * after logical link is ready
>> + */
>> + chan->move_state = L2CAP_MOVE_WAIT_LOGICAL_CFM;
>> + } else {
>> + /* Both logical link and move success
>> + * are required to confirm
>> + */
>> + chan->move_state = L2CAP_MOVE_WAIT_LOGICAL_COMP;
>> + }
>> +
>> + /* Placeholder - get hci_chan for logical link */
>> + if (!hchan) {
>> + /* Logical link not available */
>> + l2cap_send_move_chan_cfm(conn, chan, chan->scid,
>> + L2CAP_MC_UNCONFIRMED);
>> + break;
>> + }
>> +
>> + /* If the logical link is not yet connected, do not
>> + * send confirmation.
>> + */
>> + if (hchan->state != BT_CONNECTED)
>> + break;
>> +
>> + /* Logical link is already ready to go */
>> +
>> + chan->hs_hcon = hchan->conn;
>> + chan->hs_hcon->l2cap_data = chan->conn;
>> +
>> + if (result == L2CAP_MR_SUCCESS) {
>> + /* Can confirm now */
>> + l2cap_send_move_chan_cfm(conn, chan, chan->scid,
>> + L2CAP_MC_CONFIRMED);
>> + } else {
>> + /* Now only need move success
>> + * to confirm
>> + */
>> + chan->move_state = L2CAP_MOVE_WAIT_RSP_SUCCESS;
>> + }
>> +
>> + l2cap_logical_cfm(chan, hchan, L2CAP_MR_SUCCESS);
>> + } else {
>> + /* Any other amp move state means the move failed. */
>> + chan->move_id = chan->local_amp_id;
>> + chan->move_state = L2CAP_MOVE_STABLE;
>> + l2cap_move_revert(chan);
>> + chan->move_role = L2CAP_MOVE_ROLE_NONE;
>> + l2cap_send_move_chan_cfm(conn, chan, chan->scid,
>> + L2CAP_MC_UNCONFIRMED);
>> + __set_chan_timer(chan, L2CAP_MOVE_TIMEOUT);
>> + }
>> + break;
>> + default:
>> + /* Failed (including collision case) */
>> + mutex_lock(&conn->chan_lock);
>> + chan = __l2cap_get_chan_by_ident(conn, cmd->ident);
>> + if (chan)
>> + l2cap_chan_lock(chan);
>> + mutex_unlock(&conn->chan_lock);
>
> Don't we have a function for this?
>
It was unused, so I submitted a patch to remove it earlier this year.
:)
I'll add it back in.
>> +
>> + if (!chan) {
>> + /* Could not locate channel, icid is best guess */
>> + l2cap_send_move_chan_cfm(conn, NULL, icid,
>> + L2CAP_MC_UNCONFIRMED);
>> + break;
>> + }
>> +
>> + __clear_chan_timer(chan);
>> +
>> + if (chan->move_role == L2CAP_MOVE_ROLE_INITIATOR) {
>> + if (result == L2CAP_MR_COLLISION) {
>> + chan->move_role = L2CAP_MOVE_ROLE_RESPONDER;
>> + } else {
>> + /* Cleanup - cancel move */
>> + chan->move_id = chan->local_amp_id;
>> + chan->move_state = L2CAP_MOVE_STABLE;
>> + l2cap_move_revert(chan);
>> + chan->move_role = L2CAP_MOVE_ROLE_NONE;
>> + }
>> + }
>> +
>> + l2cap_send_move_chan_cfm(conn, chan, chan->scid,
>> + L2CAP_MC_UNCONFIRMED);
>> + __set_chan_timer(chan, L2CAP_MOVE_TIMEOUT);
>> + break;
>> + }
>> +
>> + if (chan)
>> + l2cap_chan_unlock(chan);
>
> I rather prefer that we unlock in the case statements. And not a global
> one. And we might have to split out the case statements into separate
> functions for readability.
Ok, I'll make separate functions.
--
Mat Martineau
Employee of Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
^ permalink raw reply
* Re: [PATCH] avdtp: Fix crash on connection lost
From: Luiz Augusto von Dentz @ 2012-10-16 17:43 UTC (permalink / raw)
To: Szymon Janc; +Cc: linux-bluetooth
In-Reply-To: <CABBYNZLbX__mxzwvZMOd3noCeoJTRrXshFTEovM9Tco4bziLRg@mail.gmail.com>
Hi again,
On Tue, Oct 16, 2012 at 7:34 PM, Luiz Augusto von Dentz
<luiz.dentz@gmail.com> wrote:
> Hi Szymon,
>
> On Tue, Oct 16, 2012 at 2:37 PM, Szymon Janc <szymon.janc@tieto.com> wrote:
>> This fix avdtp session reference counting. avdtp_unref has a special
>> case when ref==1 and due to nested calls session could be free in
>> consecutive call resulting in accesing already freed memory.
>>
>> Instead of having extra free lock keep extra local reference. This also
>> make avdtp_unref easier to undertand as there is no double ref
>> decrement inside one unref call.
>>
>> avdtp_unref will set session state to disconnected when reference count
>> drops to 1 so there is no need to explicite set it in connection_lost.
>>
>> bluetoothd[29474]: audio/avdtp.c:avdtp_ref() 0x555555856aa0: ref=2
>> bluetoothd[29474]: audio/source.c:source_connect() stream creation in progress
>> bluetoothd[29474]: src/mgmt.c:mgmt_event() cond 1
>> bluetoothd[29474]: src/mgmt.c:mgmt_event() Received 31 bytes from management socket
>> bluetoothd[29474]: src/mgmt.c:mgmt_device_connected() hci0 device 84:00:D2:DB:F7:8C connected eir_len 12
>> bluetoothd[29474]: src/adapter.c:adapter_get_device() 84:00:D2:DB:F7:8C
>> bluetoothd[29474]: src/mgmt.c:mgmt_event() cond 1
>> bluetoothd[29474]: src/mgmt.c:mgmt_event() Received 14 bytes from management socket
>> bluetoothd[29474]: src/mgmt.c:mgmt_auth_failed() hci0 auth failed status 6
>> bluetoothd[29474]: src/device.c:device_bonding_complete() bonding (nil) status 0x06
>> bluetoothd[29474]: connect error: Invalid exchange (52)
>> bluetoothd[29474]: audio/avdtp.c:connection_lost() Disconnected from 84:00:D2:DB:F7:8C
>> bluetoothd[29474]: audio/avdtp.c:avdtp_unref() 0x555555856aa0: ref=1
>> bluetoothd[29474]: audio/avdtp.c:avdtp_unref() 0x555555856aa0: ref=0
>> bluetoothd[29474]: audio/avdtp.c:avdtp_unref() 0x555555856aa0: freeing session and removing from list
>> bluetoothd[29474]: audio/avdtp.c:avdtp_unref() 0x555555856aa0: freeing session and removing from list
>>
>> Program received signal SIGSEGV, Segmentation fault.
>> avdtp_unref (session=0x555555856aa0) at audio/avdtp.c:1239
>> 1239 server->sessions = g_slist_remove(server->sessions, session);
>>
>> ---
>> audio/avdtp.c | 10 ++--------
>> 1 file changed, 2 insertions(+), 8 deletions(-)
>>
>> diff --git a/audio/avdtp.c b/audio/avdtp.c
>> index bd91cb6..4109be9 100644
>> --- a/audio/avdtp.c
>> +++ b/audio/avdtp.c
>> @@ -388,7 +388,6 @@ struct avdtp_stream {
>>
>> struct avdtp {
>> int ref;
>> - int free_lock;
>>
>> uint16_t version;
>>
>> @@ -1158,14 +1157,14 @@ static void connection_lost(struct avdtp *session, int err)
>> if (err != EACCES)
>> avdtp_cancel_authorization(session);
>>
>> - session->free_lock = 1;
>> + avdtp_ref(session);
>>
>> finalize_discovery(session, err);
>>
>> g_slist_foreach(session->streams, (GFunc) release_stream, session);
>> session->streams = NULL;
>>
>> - session->free_lock = 0;
>> + avdtp_unref(session);
>>
>> if (session->io) {
>> g_io_channel_shutdown(session->io, FALSE, NULL);
>> @@ -1173,8 +1172,6 @@ static void connection_lost(struct avdtp *session, int err)
>> session->io = NULL;
>> }
>>
>> - avdtp_set_state(session, AVDTP_SESSION_STATE_DISCONNECTED);
>
> This is actually the one that we need in case we got disconnect by
> remote after discovery completes. avctp.c has a similar structure to
> handler such states, but without the refcounting all is much simpler.
>
>> if (session->io_id) {
>> g_source_remove(session->io_id);
>> session->io_id = 0;
>> @@ -1221,9 +1218,6 @@ void avdtp_unref(struct avdtp *session)
>>
>> if (session->io)
>> set_disconnect_timer(session);
>> - else if (!session->free_lock) /* Drop the local ref if we
>> - aren't connected */
>> - session->ref--;
>> }
>>
>> if (session->ref > 0)
>> --
>> 1.7.9.5
>
> We should probably get rid of the free_lock as well.
I just remembered the reason we have this strange refcount 1, it was
to keep the session up while the unix client/alsa client reconnects. I
think we can drop this altogether now that we don't support such bogus
clients, this also means dropping dc_timer and which should fix the
refcount for good.
--
Luiz Augusto von Dentz
^ permalink raw reply
* Re: [PATCH] avdtp: Fix crash on connection lost
From: Luiz Augusto von Dentz @ 2012-10-16 17:34 UTC (permalink / raw)
To: Szymon Janc; +Cc: linux-bluetooth
In-Reply-To: <1350391036-29997-1-git-send-email-szymon.janc@tieto.com>
Hi Szymon,
On Tue, Oct 16, 2012 at 2:37 PM, Szymon Janc <szymon.janc@tieto.com> wrote:
> This fix avdtp session reference counting. avdtp_unref has a special
> case when ref==1 and due to nested calls session could be free in
> consecutive call resulting in accesing already freed memory.
>
> Instead of having extra free lock keep extra local reference. This also
> make avdtp_unref easier to undertand as there is no double ref
> decrement inside one unref call.
>
> avdtp_unref will set session state to disconnected when reference count
> drops to 1 so there is no need to explicite set it in connection_lost.
>
> bluetoothd[29474]: audio/avdtp.c:avdtp_ref() 0x555555856aa0: ref=2
> bluetoothd[29474]: audio/source.c:source_connect() stream creation in progress
> bluetoothd[29474]: src/mgmt.c:mgmt_event() cond 1
> bluetoothd[29474]: src/mgmt.c:mgmt_event() Received 31 bytes from management socket
> bluetoothd[29474]: src/mgmt.c:mgmt_device_connected() hci0 device 84:00:D2:DB:F7:8C connected eir_len 12
> bluetoothd[29474]: src/adapter.c:adapter_get_device() 84:00:D2:DB:F7:8C
> bluetoothd[29474]: src/mgmt.c:mgmt_event() cond 1
> bluetoothd[29474]: src/mgmt.c:mgmt_event() Received 14 bytes from management socket
> bluetoothd[29474]: src/mgmt.c:mgmt_auth_failed() hci0 auth failed status 6
> bluetoothd[29474]: src/device.c:device_bonding_complete() bonding (nil) status 0x06
> bluetoothd[29474]: connect error: Invalid exchange (52)
> bluetoothd[29474]: audio/avdtp.c:connection_lost() Disconnected from 84:00:D2:DB:F7:8C
> bluetoothd[29474]: audio/avdtp.c:avdtp_unref() 0x555555856aa0: ref=1
> bluetoothd[29474]: audio/avdtp.c:avdtp_unref() 0x555555856aa0: ref=0
> bluetoothd[29474]: audio/avdtp.c:avdtp_unref() 0x555555856aa0: freeing session and removing from list
> bluetoothd[29474]: audio/avdtp.c:avdtp_unref() 0x555555856aa0: freeing session and removing from list
>
> Program received signal SIGSEGV, Segmentation fault.
> avdtp_unref (session=0x555555856aa0) at audio/avdtp.c:1239
> 1239 server->sessions = g_slist_remove(server->sessions, session);
>
> ---
> audio/avdtp.c | 10 ++--------
> 1 file changed, 2 insertions(+), 8 deletions(-)
>
> diff --git a/audio/avdtp.c b/audio/avdtp.c
> index bd91cb6..4109be9 100644
> --- a/audio/avdtp.c
> +++ b/audio/avdtp.c
> @@ -388,7 +388,6 @@ struct avdtp_stream {
>
> struct avdtp {
> int ref;
> - int free_lock;
>
> uint16_t version;
>
> @@ -1158,14 +1157,14 @@ static void connection_lost(struct avdtp *session, int err)
> if (err != EACCES)
> avdtp_cancel_authorization(session);
>
> - session->free_lock = 1;
> + avdtp_ref(session);
>
> finalize_discovery(session, err);
>
> g_slist_foreach(session->streams, (GFunc) release_stream, session);
> session->streams = NULL;
>
> - session->free_lock = 0;
> + avdtp_unref(session);
>
> if (session->io) {
> g_io_channel_shutdown(session->io, FALSE, NULL);
> @@ -1173,8 +1172,6 @@ static void connection_lost(struct avdtp *session, int err)
> session->io = NULL;
> }
>
> - avdtp_set_state(session, AVDTP_SESSION_STATE_DISCONNECTED);
This is actually the one that we need in case we got disconnect by
remote after discovery completes. avctp.c has a similar structure to
handler such states, but without the refcounting all is much simpler.
> if (session->io_id) {
> g_source_remove(session->io_id);
> session->io_id = 0;
> @@ -1221,9 +1218,6 @@ void avdtp_unref(struct avdtp *session)
>
> if (session->io)
> set_disconnect_timer(session);
> - else if (!session->free_lock) /* Drop the local ref if we
> - aren't connected */
> - session->ref--;
> }
>
> if (session->ref > 0)
> --
> 1.7.9.5
We should probably get rid of the free_lock as well.
--
Luiz Augusto von Dentz
^ permalink raw reply
* Re: [PATCH 07/19] Bluetooth: Add move channel confirm handling
From: Mat Martineau @ 2012-10-16 17:30 UTC (permalink / raw)
To: Marcel Holtmann; +Cc: linux-bluetooth, gustavo, sunnyk
In-Reply-To: <1350325523.26318.10.camel@aeonflux>
Hi Marcel -
On Mon, 15 Oct 2012, Marcel Holtmann wrote:
> Hi Mat,
>
>> After sending a move channel response, a move responder waits for a
>> move channel confirm command. If the received command has a
>> "confirmed" result the move is proceeding, and "unconfirmed" means the
>> move has failed and the channel will not change controllers.
>>
>> Signed-off-by: Mat Martineau <mathewm@codeaurora.org>
>> ---
>> net/bluetooth/l2cap_core.c | 70 ++++++++++++++++++++++++++++++++++++++++++++--
>> 1 file changed, 67 insertions(+), 3 deletions(-)
>>
>> diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
>> index aab7f79..ef744a9 100644
>> --- a/net/bluetooth/l2cap_core.c
>> +++ b/net/bluetooth/l2cap_core.c
>> @@ -1030,6 +1030,42 @@ static void l2cap_move_setup(struct l2cap_chan *chan)
>> set_bit(CONN_REMOTE_BUSY, &chan->conn_state);
>> }
>>
>> +static void l2cap_move_success(struct l2cap_chan *chan)
>> +{
>> + BT_DBG("chan %p", chan);
>> +
>> + if (chan->mode != L2CAP_MODE_ERTM)
>> + return;
>> +
>> + switch (chan->move_role) {
>> + case L2CAP_MOVE_ROLE_INITIATOR:
>> + l2cap_tx(chan, NULL, NULL, L2CAP_EV_EXPLICIT_POLL);
>> + chan->rx_state = L2CAP_RX_STATE_WAIT_F;
>> + break;
>> + case L2CAP_MOVE_ROLE_RESPONDER:
>> + chan->rx_state = L2CAP_RX_STATE_WAIT_P;
>> + break;
>> + }
>> +}
>> +
>> +static void l2cap_move_revert(struct l2cap_chan *chan)
>> +{
>> + BT_DBG("chan %p", chan);
>> +
>> + if (chan->mode != L2CAP_MODE_ERTM)
>> + return;
>> +
>> + switch (chan->move_role) {
>> + case L2CAP_MOVE_ROLE_INITIATOR:
>> + l2cap_tx(chan, NULL, NULL, L2CAP_EV_EXPLICIT_POLL);
>> + chan->rx_state = L2CAP_RX_STATE_WAIT_F;
>> + break;
>> + case L2CAP_MOVE_ROLE_RESPONDER:
>> + chan->rx_state = L2CAP_RX_STATE_WAIT_P;
>> + break;
>> + }
>> +}
>> +
>> static void l2cap_chan_ready(struct l2cap_chan *chan)
>> {
>> /* This clears all conf flags, including CONF_NOT_COMPLETE */
>> @@ -4297,11 +4333,12 @@ static inline int l2cap_move_channel_rsp(struct l2cap_conn *conn,
>> return 0;
>> }
>>
>> -static inline int l2cap_move_channel_confirm(struct l2cap_conn *conn,
>> - struct l2cap_cmd_hdr *cmd,
>> - u16 cmd_len, void *data)
>> +static int l2cap_move_channel_confirm(struct l2cap_conn *conn,
>> + struct l2cap_cmd_hdr *cmd,
>> + u16 cmd_len, void *data)
>> {
>> struct l2cap_move_chan_cfm *cfm = data;
>> + struct l2cap_chan *chan;
>> u16 icid, result;
>>
>> if (cmd_len != sizeof(*cfm))
>> @@ -4312,8 +4349,35 @@ static inline int l2cap_move_channel_confirm(struct l2cap_conn *conn,
>>
>> BT_DBG("icid 0x%4.4x, result 0x%4.4x", icid, result);
>>
>> + chan = l2cap_get_chan_by_dcid(conn, icid);
>> + if (!chan)
>> + goto send_move_confirm_response;
>> +
>> + if (chan->move_state == L2CAP_MOVE_WAIT_CONFIRM) {
>> + chan->move_state = L2CAP_MOVE_STABLE;
>> + if (result == L2CAP_MC_CONFIRMED) {
>> + chan->local_amp_id = chan->move_id;
>> + if (!chan->local_amp_id) {
>> + /* Have moved off of AMP, free the channel */
>> + chan->hs_hchan = NULL;
>> + chan->hs_hcon = NULL;
>> +
>> + /* Placeholder - free the logical link */
>> + }
>> + l2cap_move_success(chan);
>> + } else {
>> + chan->move_id = chan->local_amp_id;
>> + l2cap_move_revert(chan);
>> + }
>> + chan->move_role = L2CAP_MOVE_ROLE_NONE;
>> + }
>> +
>> +send_move_confirm_response:
>> l2cap_send_move_chan_cfm_rsp(conn, cmd->ident, icid);
>>
>> + if (chan)
>> + l2cap_chan_unlock(chan);
>> +
>> return 0;
>> }
>>
>
> the more I read into this one, can we not have a clean exit when (!chan)
> for this one. Or am I missing something.
Are you thinking this should send a COMMAND_REJ if it can't find the
matching channel?
I think sending the confirm response is the appropriate thing to do.
The spec says "When a device receives a Move Channel Confirmation
packet it shall send a Move Channel Confirmation response packet".
Sending this response doesn't indicate that the move was successful.
--
Mat Martineau
Employee of Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
^ permalink raw reply
* [RFCv0 8/8] Bluetooth: Add put(hcon) when deleting hchan
From: Andrei Emeltchenko @ 2012-10-16 15:01 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1350399670-12418-1-git-send-email-Andrei.Emeltchenko.news@gmail.com>
From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
When refcnt reaches zero disconnect timeout will run and hci_conn
will be disconnected.
Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
net/bluetooth/hci_conn.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index fe64621..6f9c2b3 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -976,6 +976,8 @@ void hci_chan_del(struct hci_chan *chan)
synchronize_rcu();
+ hci_conn_put(conn);
+
skb_queue_purge(&chan->data_q);
kfree(chan);
}
--
1.7.9.5
^ permalink raw reply related
* [RFCv0 7/8] Bluetooth: Disconnect logical link when deleteing chan
From: Andrei Emeltchenko @ 2012-10-16 15:01 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1350399670-12418-1-git-send-email-Andrei.Emeltchenko.news@gmail.com>
From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
Disconnect logical link for high speed channel hs_hchan
associated with L2CAP channel chan.
Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
include/net/bluetooth/amp.h | 1 +
net/bluetooth/amp.c | 14 ++++++++++++++
net/bluetooth/l2cap_core.c | 7 +++++++
3 files changed, 22 insertions(+)
diff --git a/include/net/bluetooth/amp.h b/include/net/bluetooth/amp.h
index 405fb9c..f1c0017 100644
--- a/include/net/bluetooth/amp.h
+++ b/include/net/bluetooth/amp.h
@@ -47,6 +47,7 @@ void amp_accept_phylink(struct hci_dev *hdev, struct amp_mgr *mgr,
void amp_write_remote_assoc(struct hci_dev *hdev, u8 handle);
void amp_write_rem_assoc_continue(struct hci_dev *hdev, u8 handle);
void amp_create_logical_link(struct l2cap_chan *chan);
+void amp_disconnect_logical_link(struct hci_chan *hchan);
void amp_destroy_logical_link(struct hci_chan *hchan, u8 reason);
#endif /* __AMP_H */
diff --git a/net/bluetooth/amp.c b/net/bluetooth/amp.c
index 40c5d95..0cbc325 100644
--- a/net/bluetooth/amp.c
+++ b/net/bluetooth/amp.c
@@ -421,6 +421,20 @@ done:
hci_dev_put(hdev);
}
+void amp_disconnect_logical_link(struct hci_chan *hchan)
+{
+ struct hci_conn *hcon = hchan->conn;
+ struct hci_cp_disconn_logical_link cp;
+
+ if (hcon->state != BT_CONNECTED) {
+ BT_DBG("hchan %p not connected", hchan);
+ return;
+ }
+
+ cp.log_handle = cpu_to_le16(hchan->handle);
+ hci_send_cmd(hcon->hdev, HCI_OP_DISCONN_LOGICAL_LINK, sizeof(cp), &cp);
+}
+
void amp_destroy_logical_link(struct hci_chan *hchan, u8 reason)
{
BT_DBG("hchan %p", hchan);
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 382d92a..748f022 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -547,6 +547,13 @@ void l2cap_chan_del(struct l2cap_chan *chan, int err)
mgr->bredr_chan = NULL;
}
+ if (chan->hs_hchan) {
+ struct hci_chan *hs_hchan = chan->hs_hchan;
+
+ BT_DBG("chan %p disconnect hs_hchan %p", chan, hs_hchan);
+ amp_disconnect_logical_link(hs_hchan);
+ }
+
chan->ops->teardown(chan, err);
if (test_bit(CONF_NOT_COMPLETE, &chan->conf_state))
--
1.7.9.5
^ permalink raw reply related
* [RFCv0 6/8] Bluetooth: AMP: Remove hci_conn receiving error command status
From: Andrei Emeltchenko @ 2012-10-16 15:01 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1350399670-12418-1-git-send-email-Andrei.Emeltchenko.news@gmail.com>
From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
When receiving HCI Event: Command Status for Create Physical Link
with Error code remove AMP hcon.
Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
net/bluetooth/hci_event.c | 17 +++++++++++++----
1 file changed, 13 insertions(+), 4 deletions(-)
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 3440e52..e534209 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -1718,14 +1718,23 @@ static void hci_cs_create_phylink(struct hci_dev *hdev, u8 status)
BT_DBG("%s status 0x%2.2x", hdev->name, status);
- if (status)
- return;
-
cp = hci_sent_cmd_data(hdev, HCI_OP_CREATE_PHY_LINK);
if (!cp)
return;
- amp_write_remote_assoc(hdev, cp->phy_handle);
+ hci_dev_lock(hdev);
+
+ if (status) {
+ struct hci_conn *hcon;
+
+ hcon = hci_conn_hash_lookup_handle(hdev, cp->phy_handle);
+ if (hcon)
+ hci_conn_del(hcon);
+ } else {
+ amp_write_remote_assoc(hdev, cp->phy_handle);
+ }
+
+ hci_dev_unlock(hdev);
}
static void hci_cs_accept_phylink(struct hci_dev *hdev, u8 status)
--
1.7.9.5
^ permalink raw reply related
* [RFCv0 5/8] Bluetooth: AMP: Process Disc Physical Link complete evt
From: Andrei Emeltchenko @ 2012-10-16 15:01 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1350399670-12418-1-git-send-email-Andrei.Emeltchenko.news@gmail.com>
From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
Add processing for HCI Disconnection Physical Link Complete Event.
Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
net/bluetooth/hci_event.c | 26 ++++++++++++++++++++++++++
1 file changed, 26 insertions(+)
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index dc24489..3440e52 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -3663,6 +3663,28 @@ unlock:
hci_dev_unlock(hdev);
}
+static void hci_disconn_phylink_complete_evt(struct hci_dev *hdev,
+ struct sk_buff *skb)
+{
+ struct hci_ev_disconn_phy_link_complete *ev = (void *) skb->data;
+ struct hci_conn *hcon;
+
+ BT_DBG("%s status %d", hdev->name, ev->status);
+
+ if (ev->status)
+ return;
+
+ hci_dev_lock(hdev);
+
+ hcon = hci_conn_hash_lookup_handle(hdev, ev->phy_handle);
+ if (hcon) {
+ hcon->state = BT_CLOSED;
+ hci_conn_del(hcon);
+ }
+
+ hci_dev_unlock(hdev);
+}
+
static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
struct hci_ev_le_conn_complete *ev = (void *) skb->data;
@@ -4002,6 +4024,10 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
hci_disconn_loglink_complete_evt(hdev, skb);
break;
+ case HCI_EV_DISCONN_PHY_LINK_COMPLETE:
+ hci_disconn_phylink_complete_evt(hdev, skb);
+ break;
+
case HCI_EV_NUM_COMP_BLOCKS:
hci_num_comp_blocks_evt(hdev, skb);
break;
--
1.7.9.5
^ permalink raw reply related
* [RFCv0 4/8] Bluetooth: AMP: Process Disc Logical Link
From: Andrei Emeltchenko @ 2012-10-16 15:01 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1350399670-12418-1-git-send-email-Andrei.Emeltchenko.news@gmail.com>
From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
Add processing for HCI Disconnection Logical Link Complete
Event.
Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
include/net/bluetooth/amp.h | 1 +
net/bluetooth/amp.c | 7 +++++++
net/bluetooth/hci_event.c | 28 ++++++++++++++++++++++++++++
3 files changed, 36 insertions(+)
diff --git a/include/net/bluetooth/amp.h b/include/net/bluetooth/amp.h
index 70d5c15..405fb9c 100644
--- a/include/net/bluetooth/amp.h
+++ b/include/net/bluetooth/amp.h
@@ -47,5 +47,6 @@ void amp_accept_phylink(struct hci_dev *hdev, struct amp_mgr *mgr,
void amp_write_remote_assoc(struct hci_dev *hdev, u8 handle);
void amp_write_rem_assoc_continue(struct hci_dev *hdev, u8 handle);
void amp_create_logical_link(struct l2cap_chan *chan);
+void amp_destroy_logical_link(struct hci_chan *hchan, u8 reason);
#endif /* __AMP_H */
diff --git a/net/bluetooth/amp.c b/net/bluetooth/amp.c
index 6f10e8b..40c5d95 100644
--- a/net/bluetooth/amp.c
+++ b/net/bluetooth/amp.c
@@ -420,3 +420,10 @@ void amp_create_logical_link(struct l2cap_chan *chan)
done:
hci_dev_put(hdev);
}
+
+void amp_destroy_logical_link(struct hci_chan *hchan, u8 reason)
+{
+ BT_DBG("hchan %p", hchan);
+
+ hci_chan_del(hchan);
+}
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 3f99214..dc24489 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -3639,6 +3639,30 @@ static void hci_loglink_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
}
}
+static void hci_disconn_loglink_complete_evt(struct hci_dev *hdev,
+ struct sk_buff *skb)
+{
+ struct hci_ev_disconn_logical_link_complete *ev = (void *) skb->data;
+ struct hci_chan *hchan;
+
+ BT_DBG("%s log handle 0x%4.4x status 0x%2.2x", hdev->name,
+ le16_to_cpu(ev->handle), ev->status);
+
+ if (ev->status)
+ return;
+
+ hci_dev_lock(hdev);
+
+ hchan = hci_chan_lookup_handle(hdev, le16_to_cpu(ev->handle));
+ if (!hchan)
+ goto unlock;
+
+ amp_destroy_logical_link(hchan, ev->reason);
+
+unlock:
+ hci_dev_unlock(hdev);
+}
+
static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
struct hci_ev_le_conn_complete *ev = (void *) skb->data;
@@ -3974,6 +3998,10 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
hci_loglink_complete_evt(hdev, skb);
break;
+ case HCI_EV_DISCONN_LOGICAL_LINK_COMPLETE:
+ hci_disconn_loglink_complete_evt(hdev, skb);
+ break;
+
case HCI_EV_NUM_COMP_BLOCKS:
hci_num_comp_blocks_evt(hdev, skb);
break;
--
1.7.9.5
^ permalink raw reply related
* [RFCv0 3/8] Bluetooth: Add logical link create function
From: Andrei Emeltchenko @ 2012-10-16 15:01 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1350399670-12418-1-git-send-email-Andrei.Emeltchenko.news@gmail.com>
From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
After physical link is created logical link needs to be created
above physical link.
Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
include/net/bluetooth/amp.h | 1 +
net/bluetooth/amp.c | 46 +++++++++++++++++++++++++++++++++++++++++++
net/bluetooth/hci_event.c | 9 +++++++++
net/bluetooth/l2cap_core.c | 9 +++++++++
4 files changed, 65 insertions(+)
diff --git a/include/net/bluetooth/amp.h b/include/net/bluetooth/amp.h
index 2e7c79e..70d5c15 100644
--- a/include/net/bluetooth/amp.h
+++ b/include/net/bluetooth/amp.h
@@ -46,5 +46,6 @@ void amp_accept_phylink(struct hci_dev *hdev, struct amp_mgr *mgr,
struct hci_conn *hcon);
void amp_write_remote_assoc(struct hci_dev *hdev, u8 handle);
void amp_write_rem_assoc_continue(struct hci_dev *hdev, u8 handle);
+void amp_create_logical_link(struct l2cap_chan *chan);
#endif /* __AMP_H */
diff --git a/net/bluetooth/amp.c b/net/bluetooth/amp.c
index e525e23..6f10e8b 100644
--- a/net/bluetooth/amp.c
+++ b/net/bluetooth/amp.c
@@ -374,3 +374,49 @@ void amp_accept_phylink(struct hci_dev *hdev, struct amp_mgr *mgr,
hci_send_cmd(hdev, HCI_OP_ACCEPT_PHY_LINK, sizeof(cp), &cp);
}
+
+void amp_create_logical_link(struct l2cap_chan *chan)
+{
+ struct hci_cp_create_accept_logical_link cp;
+ struct hci_conn *hcon;
+ struct hci_dev *hdev;
+
+ BT_DBG("chan %p", chan);
+
+ hdev = hci_dev_get(chan->ctrl_id);
+ if (!hdev)
+ return;
+
+ BT_DBG("chan %p ctrl_id %d dst %pMR", chan, chan->ctrl_id,
+ chan->conn->dst);
+
+ hcon = hci_conn_hash_lookup_ba(hdev, AMP_LINK, chan->conn->dst);
+ if (!hcon)
+ goto done;
+
+ cp.phy_handle = hcon->handle;
+
+ cp.tx_flow_spec.id = chan->local_id;
+ cp.tx_flow_spec.stype = chan->local_stype;
+ cp.tx_flow_spec.msdu = cpu_to_le16(chan->local_msdu);
+ cp.tx_flow_spec.sdu_itime = cpu_to_le32(chan->local_sdu_itime);
+ cp.tx_flow_spec.acc_lat = cpu_to_le32(chan->local_acc_lat);
+ cp.tx_flow_spec.flush_to = cpu_to_le32(chan->local_flush_to);
+
+ cp.rx_flow_spec.id = chan->remote_id;
+ cp.rx_flow_spec.stype = chan->remote_stype;
+ cp.rx_flow_spec.msdu = cpu_to_le16(chan->remote_msdu);
+ cp.rx_flow_spec.sdu_itime = cpu_to_le32(chan->remote_sdu_itime);
+ cp.rx_flow_spec.acc_lat = cpu_to_le32(chan->remote_acc_lat);
+ cp.rx_flow_spec.flush_to = cpu_to_le32(chan->remote_flush_to);
+
+ if (hcon->out)
+ hci_send_cmd(hdev, HCI_OP_CREATE_LOGICAL_LINK, sizeof(cp),
+ &cp);
+ else
+ hci_send_cmd(hdev, HCI_OP_ACCEPT_LOGICAL_LINK, sizeof(cp),
+ &cp);
+
+done:
+ hci_dev_put(hdev);
+}
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 2c37896..3f99214 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -1744,6 +1744,11 @@ static void hci_cs_accept_phylink(struct hci_dev *hdev, u8 status)
amp_write_remote_assoc(hdev, cp->phy_handle);
}
+static void hci_cs_create_logical_link(struct hci_dev *hdev, u8 status)
+{
+ BT_DBG("%s status 0x%2.2x", hdev->name, status);
+}
+
static void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
__u8 status = *((__u8 *) skb->data);
@@ -2570,6 +2575,10 @@ static void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb)
hci_cs_accept_phylink(hdev, ev->status);
break;
+ case HCI_OP_CREATE_LOGICAL_LINK:
+ hci_cs_create_logical_link(hdev, ev->status);
+ break;
+
default:
BT_DBG("%s opcode 0x%4.4x", hdev->name, opcode);
break;
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index f3cfe89..382d92a 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -38,6 +38,7 @@
#include <net/bluetooth/l2cap.h>
#include <net/bluetooth/smp.h>
#include <net/bluetooth/a2mp.h>
+#include <net/bluetooth/amp.h>
bool disable_ertm;
@@ -964,6 +965,12 @@ static bool __amp_capable(struct l2cap_chan *chan)
return false;
}
+static bool l2cap_check_efs(struct l2cap_chan *chan)
+{
+ /* Check EFS parameters */
+ return true;
+}
+
void l2cap_send_conn_req(struct l2cap_chan *chan)
{
struct l2cap_conn *conn = chan->conn;
@@ -3801,6 +3808,8 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn,
}
/* check compatibility */
+ if (l2cap_check_efs(chan))
+ amp_create_logical_link(chan);
if (!chan->ctrl_id)
l2cap_send_efs_conf_rsp(chan, buf, cmd->ident,
--
1.7.9.5
^ permalink raw reply related
* [RFCv0 2/8] Bluetooth: AMP: Process Logical Link complete evt
From: Andrei Emeltchenko @ 2012-10-16 15:01 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1350399670-12418-1-git-send-email-Andrei.Emeltchenko.news@gmail.com>
From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
After receiving HCI Logical Link Complete event finish EFS
configuration by sending L2CAP Conf Response with success code.
Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
include/net/bluetooth/l2cap.h | 1 +
net/bluetooth/hci_event.c | 42 +++++++++++++++++++++++++++++++++++++++++
net/bluetooth/l2cap_core.c | 17 +++++++++++++++++
3 files changed, 60 insertions(+)
diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index 6d3615e..150199e 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -807,5 +807,6 @@ void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan);
void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan);
void l2cap_chan_del(struct l2cap_chan *chan, int err);
void l2cap_send_conn_req(struct l2cap_chan *chan);
+void l2cap_finish_efs_config(struct l2cap_chan *chan);
#endif /* __L2CAP_H */
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index a1ce09f..2c37896 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -3592,6 +3592,44 @@ static void hci_phy_link_complete_evt(struct hci_dev *hdev,
}
}
+static void hci_loglink_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
+{
+ struct hci_ev_logical_link_complete *ev = (void *) skb->data;
+ struct hci_conn *hcon;
+ struct hci_chan *hchan;
+ struct amp_mgr *mgr;
+
+ BT_DBG("%s log_handle 0x%4.4x phy_handle 0x%2.2x status 0x%2.2x",
+ hdev->name, le16_to_cpu(ev->handle), ev->phy_handle,
+ ev->status);
+
+ hcon = hci_conn_hash_lookup_handle(hdev, ev->phy_handle);
+ if (!hcon)
+ return;
+
+ /* Create AMP hchan */
+ hchan = hci_chan_create(hcon);
+ if (!hchan)
+ return;
+
+ hchan->handle = le16_to_cpu(ev->handle);
+
+ BT_DBG("hcon %p mgr %p hchan %p", hcon, hcon->amp_mgr, hchan);
+
+ mgr = hcon->amp_mgr;
+ if (mgr && mgr->bredr_chan) {
+ struct l2cap_chan *bredr_chan = mgr->bredr_chan;
+
+ bredr_chan->hs_hcon = hcon;
+ bredr_chan->hs_hchan = hchan;
+ hcon->l2cap_data = bredr_chan->conn;
+
+ l2cap_finish_efs_config(bredr_chan);
+ hci_conn_hold(hcon);
+ bredr_chan->conn->mtu = hdev->block_mtu;
+ }
+}
+
static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
struct hci_ev_le_conn_complete *ev = (void *) skb->data;
@@ -3923,6 +3961,10 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
hci_phy_link_complete_evt(hdev, skb);
break;
+ case HCI_EV_LOGICAL_LINK_COMPLETE:
+ hci_loglink_complete_evt(hdev, skb);
+ break;
+
case HCI_EV_NUM_COMP_BLOCKS:
hci_num_comp_blocks_evt(hdev, skb);
break;
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 4035fce..f3cfe89 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -3635,6 +3635,23 @@ static void l2cap_send_efs_conf_rsp(struct l2cap_chan *chan, void *data,
L2CAP_CONF_SUCCESS, flags), data);
}
+void l2cap_finish_efs_config(struct l2cap_chan *chan)
+{
+ char buf[64];
+
+ BT_DBG("chan %p", chan);
+
+ /* Init also BR/EDR chan */
+ l2cap_ertm_init(chan);
+
+ l2cap_send_efs_conf_rsp(chan, buf, chan->ident, 0);
+
+ if (test_bit(CONF_INPUT_DONE, &chan->conf_state)) {
+ set_default_fcs(chan);
+ l2cap_chan_ready(chan);
+ }
+}
+
static inline int l2cap_config_req(struct l2cap_conn *conn,
struct l2cap_cmd_hdr *cmd, u16 cmd_len,
u8 *data)
--
1.7.9.5
^ permalink raw reply related
* [RFCv0 1/8] Bluetooth: AMP: Process Physical Link Complete evt
From: Andrei Emeltchenko @ 2012-10-16 15:01 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1350399670-12418-1-git-send-email-Andrei.Emeltchenko.news@gmail.com>
From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
Add processing for HCI Physical Link Complete event. Upon
successful status received start L2CAP create channel process.
Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
net/bluetooth/hci_event.c | 52 +++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 52 insertions(+)
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 0383635..a1ce09f 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -3544,6 +3544,54 @@ unlock:
hci_dev_unlock(hdev);
}
+static void hci_phy_link_complete_evt(struct hci_dev *hdev,
+ struct sk_buff *skb)
+{
+ struct hci_ev_phy_link_complete *ev = (void *) skb->data;
+ struct hci_conn *hcon, *bredr_hcon;
+
+ BT_DBG("%s handle 0x%2.2x status 0x%2.2x", hdev->name, ev->phy_handle,
+ ev->status);
+
+ hci_dev_lock(hdev);
+
+ hcon = hci_conn_hash_lookup_handle(hdev, ev->phy_handle);
+ if (!hcon) {
+ hci_dev_unlock(hdev);
+ return;
+ }
+
+ if (ev->status) {
+ hci_conn_del(hcon);
+ hci_dev_unlock(hdev);
+ return;
+ }
+
+ bredr_hcon = hcon->amp_mgr->l2cap_conn->hcon;
+
+ hcon->state = BT_CONNECTED;
+ bacpy(&hcon->dst, &bredr_hcon->dst);
+
+ hci_conn_hold(hcon);
+ hcon->disc_timeout = HCI_DISCONN_TIMEOUT;
+ hci_conn_put(hcon);
+
+ hci_conn_hold_device(hcon);
+ hci_conn_add_sysfs(hcon);
+
+ hci_dev_unlock(hdev);
+
+ if (hcon->out) {
+ struct hci_dev *bredr_hdev = bredr_hcon->hdev;
+
+ hci_dev_hold(bredr_hdev);
+ /* Placeholder - create chan req
+ l2cap_chan_create_cfm(bredr_hcon, hcon->remote_id);
+ */
+ hci_dev_put(bredr_hdev);
+ }
+}
+
static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
struct hci_ev_le_conn_complete *ev = (void *) skb->data;
@@ -3871,6 +3919,10 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
hci_remote_oob_data_request_evt(hdev, skb);
break;
+ case HCI_EV_PHY_LINK_COMPLETE:
+ hci_phy_link_complete_evt(hdev, skb);
+ break;
+
case HCI_EV_NUM_COMP_BLOCKS:
hci_num_comp_blocks_evt(hdev, skb);
break;
--
1.7.9.5
^ permalink raw reply related
* [RFCv0 0/8] Handling physical and logical link
From: Andrei Emeltchenko @ 2012-10-16 15:01 UTC (permalink / raw)
To: linux-bluetooth
From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
Set of patches adding handling for physical and logical link
complete events.
Andrei Emeltchenko (8):
Bluetooth: AMP: Process Physical Link Complete evt
Bluetooth: AMP: Process Logical Link complete evt
Bluetooth: Add logical link create function
Bluetooth: AMP: Process Disc Logical Link
Bluetooth: AMP: Process Disc Physical Link complete evt
Bluetooth: AMP: Remove hci_conn receiving error command status
Bluetooth: Disconnect logical link when deleteing chan
Bluetooth: Add put(hcon) when deleting hchan
include/net/bluetooth/amp.h | 3 +
include/net/bluetooth/l2cap.h | 1 +
net/bluetooth/amp.c | 67 ++++++++++++++++
net/bluetooth/hci_conn.c | 2 +
net/bluetooth/hci_event.c | 174 ++++++++++++++++++++++++++++++++++++++++-
net/bluetooth/l2cap_core.c | 33 ++++++++
6 files changed, 276 insertions(+), 4 deletions(-)
--
1.7.9.5
^ permalink raw reply
* Re: gatttool and multiple devices connected
From: Kim Schulz @ 2012-10-16 14:51 UTC (permalink / raw)
To: Anderson Lizardo; +Cc: linux-bluetooth
In-Reply-To: <CAJdJm_NZwNbLwAHNj7JVPVKK2eBe90AeqPRFfqD0Rqr9=bWpNg@mail.gmail.com>
On 10/16/2012 04:45 PM, Anderson Lizardo wrote:
> Which kernel version are you running? Older kernels had a LE
> connection routing issue which I believe was fixed long ago. And what
> do you mean with not being able to get services? which error did you
> get? Do you have hcidump logs from these sessions? Regards,
The Bluez code is one taken from git a few days ago. I don't recall
which kernel version (will have to check at the office tomorrow) but it
is one of the latest that we compiled for this test.
We do have some logs of the session and I will be looking at those more
thoroughly tomorrow.
kim
^ permalink raw reply
* Re: [PATCH BlueZ 2/2] AVRCP: Don't respond with errors when no player is registered
From: Luiz Augusto von Dentz @ 2012-10-16 14:47 UTC (permalink / raw)
To: Lucas De Marchi; +Cc: linux-bluetooth
In-Reply-To: <CAMOw1v5mMvJqp7=fazgxSVL+95Fjmka1HLaT50WSO90jU3HigQ@mail.gmail.com>
Hi Lucas,
On Tue, Oct 16, 2012 at 3:58 PM, Lucas De Marchi
<lucas.demarchi@profusion.mobi> wrote:
> On Tue, Oct 16, 2012 at 8:58 AM, Luiz Augusto von Dentz
> <luiz.dentz@gmail.com> wrote:
>> From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
>>
>> Some devices w.g. Sony MW600 will stop using certain commands if an
>> error happen, so the code now just fake a player and once a real
>> player is registered it takes place of the fake one.
>> ---
>> audio/avrcp.c | 91 ++++++++++++++++++++++++++++++++++++++++++++++++-----------
>> 1 file changed, 74 insertions(+), 17 deletions(-)
>>
>> diff --git a/audio/avrcp.c b/audio/avrcp.c
>> index 5a18cb4..cd57358 100644
>> --- a/audio/avrcp.c
>> +++ b/audio/avrcp.c
>> @@ -493,6 +493,28 @@ void avrcp_player_event(struct avrcp_player *player, uint8_t id, void *data)
>> return;
>> }
>>
>> +static const char *player_get_string(struct avrcp_player *player, uint32_t attr)
>> +{
>
> Instead of adding these wrapper functions, did you consider having a
> default_avrcp_player with all hooks set and player pointing to it if
> there's no player registered?
It is probably more code, besides I would not like to mix const
pointers with dynamic allocated ones.
--
Luiz Augusto von Dentz
^ permalink raw reply
* Re: gatttool and multiple devices connected
From: Anderson Lizardo @ 2012-10-16 14:45 UTC (permalink / raw)
To: Kim Schulz; +Cc: linux-bluetooth
In-Reply-To: <507D6F26.8040306@schulz.dk>
Hi Kim,
On Tue, Oct 16, 2012 at 11:28 AM, Kim Schulz <kim@schulz.dk> wrote:
> Hi guys,
> I was just testing the LE functionality a bit and decided to connect to two
> different LE devices at the same time using gatttool in interactive mode
> (two different terminals). Connection to the two devices went well, but when
> I tried to get primary services on the devices it was only possible to do so
> on one of the devices.
> Connecting to them one by one showed that it was actually possible to get
> the primary service listing of both devices - just not when both are
> connected at the same time.
> I guess this is a bug somewhere in the primary-service lookup code but have
> yet to look more into the details of this.
>
> Just thought that you might wanted to know about this.
Which kernel version are you running? Older kernels had a LE
connection routing issue which I believe was fixed long ago.
And what do you mean with not being able to get services? which error
did you get?
Do you have hcidump logs from these sessions?
Regards,
--
Anderson Lizardo
Instituto Nokia de Tecnologia - INdT
Manaus - Brazil
^ permalink raw reply
* Re: [PATCH BlueZ 1/2] AVRCP: Fix using void * for metadata values
From: Luiz Augusto von Dentz @ 2012-10-16 14:28 UTC (permalink / raw)
To: Lucas De Marchi; +Cc: linux-bluetooth
In-Reply-To: <CAMOw1v5VCTnzJyD2LLFO-oS=ZVf=Kv1AdGr8q_Xj10KQaBuqOw@mail.gmail.com>
Hi Lucas,
On Tue, Oct 16, 2012 at 3:56 PM, Lucas De Marchi
<lucas.demarchi@profusion.mobi> wrote:
> Hi Luiz
>
> On Tue, Oct 16, 2012 at 8:58 AM, Luiz Augusto von Dentz
> <luiz.dentz@gmail.com> wrote:
>> From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
>>
>> This replaces get_metadata callback with get_string and get_uint32
>> which uses proper types as return.
>> ---
>
> I fail to see what this commit is fixing. It seems more like
> refactoring void* to explicit types.
>
>
>> audio/avrcp.c | 32 ++++++++++++++++++--------------
>> audio/avrcp.h | 3 ++-
>> audio/media.c | 31 ++++++++++++++++++++++++-------
>> 3 files changed, 44 insertions(+), 22 deletions(-)
>>
>> diff --git a/audio/avrcp.c b/audio/avrcp.c
>> index 2f5df21..5a18cb4 100644
>> --- a/audio/avrcp.c
>> +++ b/audio/avrcp.c
>> @@ -501,23 +501,29 @@ static uint16_t player_write_media_attribute(struct avrcp_player *player,
>> uint16_t len;
>> uint16_t attr_len;
>> char valstr[20];
>> - void *value;
>> + const char *value = NULL;
>> + uint32_t num;
>>
>> DBG("%u", id);
>>
>> - value = player->cb->get_metadata(id, player->user_data);
>> - if (value == NULL) {
>> - *offset = 0;
>> - return 0;
>> - }
>> -
>> switch (id) {
>> case AVRCP_MEDIA_ATTRIBUTE_TRACK:
>> case AVRCP_MEDIA_ATTRIBUTE_N_TRACKS:
>> case AVRCP_MEDIA_ATTRIBUTE_DURATION:
>> - snprintf(valstr, 20, "%u", GPOINTER_TO_UINT(value));
>> + num = player->cb->get_uint32(id, player->user_data);
>> + if (num == 0)
>> + break;
>> +
>> + snprintf(valstr, 20, "%u", num);
>
> The downside here is that we loose the ability to differentiate
> attribute not present from the value 0. 0 doesn't make sense for
> duration, but is a valid value for the other 2.
Which ones? You mean track and track number, I guess we can skip those
if they are 0.
--
Luiz Augusto von Dentz
^ permalink raw reply
* gatttool and multiple devices connected
From: Kim Schulz @ 2012-10-16 14:28 UTC (permalink / raw)
To: linux-bluetooth
Hi guys,
I was just testing the LE functionality a bit and decided to connect to
two different LE devices at the same time using gatttool in interactive
mode (two different terminals). Connection to the two devices went well,
but when I tried to get primary services on the devices it was only
possible to do so on one of the devices.
Connecting to them one by one showed that it was actually possible to
get the primary service listing of both devices - just not when both are
connected at the same time.
I guess this is a bug somewhere in the primary-service lookup code but
have yet to look more into the details of this.
Just thought that you might wanted to know about this.
cheers
Kim
^ 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