* Re: [PATCH 12/19] Bluetooth: Handle physical link completion
From: Marcel Holtmann @ 2012-10-15 18:40 UTC (permalink / raw)
To: Mat Martineau; +Cc: linux-bluetooth, gustavo, sunnyk
In-Reply-To: <1350315248-7690-13-git-send-email-mathewm@codeaurora.org>
Hi Mat,
> Several different actions may be taken when an AMP physical link
> becomes available. A channel being created on an AMP controller must
> continue the connection process. A channel being moved needs to
> either send a move request or a move response. A failed physical link
> will revert to using a BR/EDR controller if possible.
>
> Signed-off-by: Mat Martineau <mathewm@codeaurora.org>
> ---
> net/bluetooth/l2cap_core.c | 166 +++++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 166 insertions(+)
Acked-by: Marcel Holtmann <marcel@holtmann.org>
Regards
Marcel
^ permalink raw reply
* Re: [PATCH 11/19] Bluetooth: Add move confirm response handling
From: Marcel Holtmann @ 2012-10-15 18:38 UTC (permalink / raw)
To: Mat Martineau; +Cc: linux-bluetooth, gustavo, sunnyk
In-Reply-To: <1350315248-7690-12-git-send-email-mathewm@codeaurora.org>
Hi Mat,
> The move confirm response concludes the channel move command sequence.
> Receipt of this command indicates that data may begin to flow again.
>
> Signed-off-by: Mat Martineau <mathewm@codeaurora.org>
> ---
> net/bluetooth/l2cap_core.c | 26 ++++++++++++++++++++++++++
> 1 file changed, 26 insertions(+)
>
> diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
> index 7e31e98..ac9d34a 100644
> --- a/net/bluetooth/l2cap_core.c
> +++ b/net/bluetooth/l2cap_core.c
> @@ -4632,6 +4632,7 @@ static inline int l2cap_move_channel_confirm_rsp(struct l2cap_conn *conn,
> u16 cmd_len, void *data)
> {
> struct l2cap_move_chan_cfm_rsp *rsp = data;
> + struct l2cap_chan *chan;
> u16 icid;
>
> if (cmd_len != sizeof(*rsp))
> @@ -4641,6 +4642,31 @@ static inline int l2cap_move_channel_confirm_rsp(struct l2cap_conn *conn,
>
> BT_DBG("icid 0x%4.4x", icid);
>
> + chan = l2cap_get_chan_by_scid(conn, icid);
> + if (!chan)
> + return 0;
> +
> + __clear_chan_timer(chan);
> +
> + if (chan->move_state == L2CAP_MOVE_WAIT_CONFIRM_RSP) {
> + chan->move_state = L2CAP_MOVE_STABLE;
> + chan->local_amp_id = chan->move_id;
> +
> + if (!chan->local_amp_id && chan->hs_hchan) {
> + /* 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);
> +
> + chan->move_role = L2CAP_MOVE_ROLE_NONE;
> + }
> +
> + l2cap_chan_unlock(chan);
> +
> return 0;
> }
>
this is how it looks fine to me. We should be doing it this style
everywhere.
Acked-by: Marcel Holtmann <marcel@holtmann.org>
Regards
Marcel
^ permalink raw reply
* Re: [PATCH 10/19] Bluetooth: Add logical link confirm
From: Marcel Holtmann @ 2012-10-15 18:37 UTC (permalink / raw)
To: Mat Martineau; +Cc: linux-bluetooth, gustavo, sunnyk
In-Reply-To: <1350315248-7690-11-git-send-email-mathewm@codeaurora.org>
Hi Mat,
> 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) {
checking chan->state twice here is a bit ugly.
> + 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)
> + err = l2cap_ertm_init(chan);
> +
> + if (err < 0)
> + l2cap_send_disconn_req(chan->conn, chan, -err);
> + else
> + l2cap_chan_ready(chan);
> + }
> + } else if (chan && !status) {
If chan is really NULL, then this would have crashed already ;)
> + /* Channel move */
> + chan->hs_hcon = hchan->conn;
> + chan->hs_hcon->l2cap_data = chan->conn;
> +
> + BT_DBG("move_state %d", chan->move_state);
> +
> + if (chan->state != BT_CONNECTED)
> + return;
And again checking chan->state ???
> +
> + switch (chan->move_state) {
> + case L2CAP_MOVE_WAIT_LOGICAL_COMP:
> + /* Move confirm will be sent after a success
> + * response is received
> + */
> + chan->move_state = L2CAP_MOVE_WAIT_RSP_SUCCESS;
> + break;
> + case L2CAP_MOVE_WAIT_LOGICAL_CFM:
> + if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
> + chan->move_state = L2CAP_MOVE_WAIT_LOCAL_BUSY;
> + } else if (chan->move_role ==
> + L2CAP_MOVE_ROLE_INITIATOR) {
> + chan->move_state = L2CAP_MOVE_WAIT_CONFIRM_RSP;
> + l2cap_send_move_chan_cfm(chan->conn, chan,
> + chan->scid,
> + L2CAP_MR_SUCCESS);
> + __set_chan_timer(chan, L2CAP_MOVE_TIMEOUT);
> + } else if (chan->move_role ==
> + L2CAP_MOVE_ROLE_RESPONDER) {
> + chan->move_state = L2CAP_MOVE_WAIT_CONFIRM;
> + l2cap_send_move_chan_rsp(chan->conn,
> + chan->ident,
> + chan->dcid,
> + L2CAP_MR_SUCCESS);
> + }
> + break;
> + default:
> + /* Move was not in expected state, free the channel */
> + chan->hs_hchan = NULL;
> + chan->hs_hcon = NULL;
> +
> + /* Placeholder - free the logical link */
> +
> + chan->move_state = L2CAP_MOVE_STABLE;
> + }
> + } else {
> + /* Logical link setup failed. */
> +
> + if (chan->state != BT_CONNECTED)
And again ???
> + l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
> + else if (chan->move_role == L2CAP_MOVE_ROLE_RESPONDER) {
> + l2cap_move_revert(chan);
> + chan->move_role = L2CAP_MOVE_ROLE_NONE;
> + chan->move_state = L2CAP_MOVE_STABLE;
> + l2cap_send_move_chan_rsp(chan->conn, chan->ident,
> + chan->dcid, L2CAP_MR_NOT_SUPP);
> + } else if (chan->move_role == L2CAP_MOVE_ROLE_INITIATOR) {
> + if (chan->move_state == L2CAP_MOVE_WAIT_LOGICAL_COMP ||
> + chan->move_state == L2CAP_MOVE_WAIT_LOGICAL_CFM) {
> + /* Remote has only sent pending or
> + * success responses, clean up
> + */
> + l2cap_move_revert(chan);
> + chan->move_role = L2CAP_MOVE_ROLE_NONE;
> + chan->move_state = L2CAP_MOVE_STABLE;
> + }
> +
> + /* Other amp move states imply that the move
> + * has already aborted
> + */
> + l2cap_send_move_chan_cfm(chan->conn, chan, chan->scid,
> + L2CAP_MC_UNCONFIRMED);
> + __set_chan_timer(chan, L2CAP_MOVE_TIMEOUT);
> + }
> +
> + chan->hs_hchan = NULL;
> + chan->hs_hcon = NULL;
> +
> + /* Placeholder - free logical link */
> + }
> }
>
> static inline int l2cap_move_channel_req(struct l2cap_conn *conn,
Regards
Marcel
^ permalink raw reply
* Re: [PATCH 09/19] Bluetooth: Move channel response
From: Marcel Holtmann @ 2012-10-15 18:29 UTC (permalink / raw)
To: Mat Martineau; +Cc: linux-bluetooth, gustavo, sunnyk
In-Reply-To: <1350315248-7690-10-git-send-email-mathewm@codeaurora.org>
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?
> +
> + 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.
Regards
Marcel
^ permalink raw reply
* Re: [PATCH 08/19] Bluetooth: Add state to hci_chan
From: Marcel Holtmann @ 2012-10-15 18:26 UTC (permalink / raw)
To: Mat Martineau; +Cc: linux-bluetooth, gustavo, sunnyk
In-Reply-To: <1350315248-7690-9-git-send-email-mathewm@codeaurora.org>
Hi Mat,
> On an AMP controller, hci_chan maps to a logical link. When a channel
> is being moved, the logical link may or may not be connected already.
> The hci_chan->state is used to determine the existance of a useable
> logical link so the link can be either used or requested.
>
> Signed-off-by: Mat Martineau <mathewm@codeaurora.org>
> ---
> include/net/bluetooth/hci_core.h | 1 +
> net/bluetooth/hci_conn.c | 1 +
> 2 files changed, 2 insertions(+)
Acked-by: Marcel Holtmann <marcel@holtmann.org>
Regards
Marcel
^ permalink raw reply
* Re: [PATCH 07/19] Bluetooth: Add move channel confirm handling
From: Marcel Holtmann @ 2012-10-15 18:25 UTC (permalink / raw)
To: Mat Martineau; +Cc: linux-bluetooth, gustavo, sunnyk
In-Reply-To: <1350315248-7690-8-git-send-email-mathewm@codeaurora.org>
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.
Regards
Marcel
^ permalink raw reply
* Re: [PATCH 06/19] Bluetooth: Add new ERTM receive states for channel move
From: Marcel Holtmann @ 2012-10-15 18:23 UTC (permalink / raw)
To: Mat Martineau; +Cc: linux-bluetooth, gustavo, sunnyk
In-Reply-To: <1350315248-7690-7-git-send-email-mathewm@codeaurora.org>
Hi Mat,
> Two new states are required to implement channel moves with the ERTM
> receive state machine.
>
> The "WAIT_P" state is used by a move responder to wait for a "poll"
> flag after a move is completed (success or failure). "WAIT_F" is
> similarly used by a move initiator to wait for a "final" flag when the
> move is completing. In either state, the reqseq value in the
> poll/final frame tells the state machine exactly which frame should be
> expected next.
>
> Signed-off-by: Mat Martineau <mathewm@codeaurora.org>
> ---
> net/bluetooth/l2cap_core.c | 106 +++++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 106 insertions(+)
>
> diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
> index 649c06b..aab7f79 100644
> --- a/net/bluetooth/l2cap_core.c
> +++ b/net/bluetooth/l2cap_core.c
> @@ -5207,6 +5207,106 @@ static int l2cap_rx_state_srej_sent(struct l2cap_chan *chan,
> return err;
> }
>
> +static int l2cap_finish_move(struct l2cap_chan *chan)
> +{
> + int err = 0;
> +
> + BT_DBG("chan %p", chan);
> +
> + chan->move_role = L2CAP_MOVE_ROLE_NONE;
> + chan->rx_state = L2CAP_RX_STATE_RECV;
> +
> + if (chan->hs_hcon)
> + chan->conn->mtu = chan->hs_hcon->hdev->acl_mtu;
> + else
> + chan->conn->mtu = chan->conn->hcon->hdev->acl_mtu;
> +
> + /* Placeholder - resegment based on new conn->mtu */
> + /*err = l2cap_resegment(chan);*/
> +
> + return err;
if you are not planning to add more here, then please
return l2cap_resegment(chan);
> +}
> +
> +static int l2cap_rx_state_wait_p(struct l2cap_chan *chan,
> + struct l2cap_ctrl *control,
> + struct sk_buff *skb, u8 event)
> +{
> + int err = -EPROTO;
int err;
> +
> + BT_DBG("chan %p, control %p, skb %p, event %d", chan, control, skb,
> + event);
> +
> + if (!control->poll)
> + return err;
No way. Please do return -EPROTO; here.
> +
> + l2cap_process_reqseq(chan, control->reqseq);
> +
> + if (!skb_queue_empty(&chan->tx_q))
> + chan->tx_send_head = skb_peek(&chan->tx_q);
> + else
> + chan->tx_send_head = NULL;
> +
> + /* Rewind next_tx_seq to the point expected
> + * by the receiver.
> + */
> + chan->next_tx_seq = control->reqseq;
> + chan->unacked_frames = 0;
> +
> + err = l2cap_finish_move(chan);
> +
No empty line here.
> + if (err)
> + return err;
> +
> + set_bit(CONN_SEND_FBIT, &chan->conn_state);
> + l2cap_send_i_or_rr_or_rnr(chan);
> +
> + if (event == L2CAP_EV_RECV_IFRAME)
> + err = -EPROTO;
> + else
> + err = l2cap_rx_state_recv(chan, control, NULL, event);
if (event == L2CAP_EV_RECV_IFRAME)
return -EPROTO;
return l2cap_rx_state...(...);
> +
> + return err;
> +}
Unless you know that other things happen, but then please let us now.
> +
> +static int l2cap_rx_state_wait_f(struct l2cap_chan *chan,
> + struct l2cap_ctrl *control,
> + struct sk_buff *skb, u8 event)
> +{
> + int err = -EPROTO;
> +
> + if (control->final) {
> + clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
> + chan->move_role = L2CAP_MOVE_ROLE_NONE;
> +
> + chan->rx_state = L2CAP_RX_STATE_RECV;
> + l2cap_process_reqseq(chan, control->reqseq);
> +
> + if (!skb_queue_empty(&chan->tx_q))
> + chan->tx_send_head = skb_peek(&chan->tx_q);
> + else
> + chan->tx_send_head = NULL;
> +
> + /* Rewind next_tx_seq to the point expected
> + * by the receiver.
> + */
> + chan->next_tx_seq = control->reqseq;
> + chan->unacked_frames = 0;
> +
> + if (chan->hs_hcon)
> + chan->conn->mtu = chan->hs_hcon->hdev->acl_mtu;
> + else
> + chan->conn->mtu = chan->conn->hcon->hdev->acl_mtu;
> +
> + /* Placeholder - resegment based on new conn->mtu */
> + /*err = l2cap_resegment(chan);*/
> +
> + if (!err)
> + err = l2cap_rx_state_recv(chan, control, skb, event);
> + }
Is more coming or can an if (!control) return -EPROTO be used as well.
> +
> + return err;
> +}
> +
> static bool __valid_reqseq(struct l2cap_chan *chan, u16 reqseq)
> {
> /* Make sure reqseq is for a packet that has been sent but not acked */
> @@ -5233,6 +5333,12 @@ static int l2cap_rx(struct l2cap_chan *chan, struct l2cap_ctrl *control,
> err = l2cap_rx_state_srej_sent(chan, control, skb,
> event);
> break;
> + case L2CAP_RX_STATE_WAIT_P:
> + err = l2cap_rx_state_wait_p(chan, control, skb, event);
> + break;
> + case L2CAP_RX_STATE_WAIT_F:
> + err = l2cap_rx_state_wait_f(chan, control, skb, event);
> + break;
> default:
> /* shut it down */
> break;
Besides these minor ones it looks fine to me.
Regards
Marcel
^ permalink raw reply
* Re: [PATCH 05/19] Bluetooth: Channel move request handling
From: Marcel Holtmann @ 2012-10-15 18:17 UTC (permalink / raw)
To: Mat Martineau; +Cc: linux-bluetooth, gustavo, sunnyk
In-Reply-To: <1350315248-7690-6-git-send-email-mathewm@codeaurora.org>
Hi Mat,
> On receipt of a channel move request, the request must be validated
> based on the L2CAP mode, connection state, and controller
> capabilities. ERTM channels must have their state machines cleared
> and transmission paused while the channel move takes place.
>
> If the channel is being moved to an AMP controller then
> an AMP physical link must be prepared. Moving the channel back to
> BR/EDR proceeds immediately.
>
> Signed-off-by: Mat Martineau <mathewm@codeaurora.org>
> ---
> net/bluetooth/l2cap_core.c | 98 +++++++++++++++++++++++++++++++++++++++++++++-
> 1 file changed, 97 insertions(+), 1 deletion(-)
>
> diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
> index a55644f..649c06b 100644
> --- a/net/bluetooth/l2cap_core.c
> +++ b/net/bluetooth/l2cap_core.c
> @@ -995,6 +995,41 @@ void l2cap_send_conn_req(struct l2cap_chan *chan)
> l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_REQ, sizeof(req), &req);
> }
>
> +static void l2cap_move_setup(struct l2cap_chan *chan)
> +{
> + struct sk_buff *skb;
> +
> + BT_DBG("chan %p", chan);
> +
> + if (chan->mode != L2CAP_MODE_ERTM)
> + return;
> +
> + __clear_retrans_timer(chan);
> + __clear_monitor_timer(chan);
> + __clear_ack_timer(chan);
> +
> + chan->retry_count = 0;
> + skb_queue_walk(&chan->tx_q, skb) {
> + if (bt_cb(skb)->control.retries)
> + bt_cb(skb)->control.retries = 1;
> + else
> + break;
> + }
> +
> + chan->expected_tx_seq = chan->buffer_seq;
> +
> + clear_bit(CONN_REJ_ACT, &chan->conn_state);
> + clear_bit(CONN_SREJ_ACT, &chan->conn_state);
> + l2cap_seq_list_clear(&chan->retrans_list);
> + l2cap_seq_list_clear(&chan->srej_list);
> + skb_queue_purge(&chan->srej_q);
> +
> + chan->tx_state = L2CAP_TX_STATE_XMIT;
> + chan->rx_state = L2CAP_RX_STATE_MOVE;
> +
> + set_bit(CONN_REMOTE_BUSY, &chan->conn_state);
> +}
> +
> static void l2cap_chan_ready(struct l2cap_chan *chan)
> {
> /* This clears all conf flags, including CONF_NOT_COMPLETE */
> @@ -4171,7 +4206,68 @@ static inline int l2cap_move_channel_req(struct l2cap_conn *conn,
>
> chan = l2cap_get_chan_by_dcid(conn, icid);
>
> - /* Placeholder: Always refuse */
> + if (!chan || chan->scid < L2CAP_CID_DYN_START ||
> + (chan->mode != L2CAP_MODE_ERTM &&
> + chan->mode != L2CAP_MODE_STREAMING)) {
> + result = L2CAP_MR_NOT_ALLOWED;
> + goto send_move_response;
> + }
> +
> + if (chan->local_amp_id == req->dest_amp_id) {
> + result = L2CAP_MR_SAME_ID;
> + goto send_move_response;
> + }
> +
> + if (req->dest_amp_id) {
> + struct hci_dev *hdev;
> + hdev = hci_dev_get(req->dest_amp_id);
> + if (!hdev || hdev->dev_type != HCI_AMP ||
> + !test_bit(HCI_UP, &hdev->flags)) {
> + if (hdev)
> + hci_dev_put(hdev);
> +
> + result = L2CAP_MR_BAD_ID;
> + goto send_move_response;
> + }
> + hci_dev_put(hdev);
> + }
> +
> + if (((chan->move_state != L2CAP_MOVE_STABLE &&
> + chan->move_state != L2CAP_MOVE_WAIT_PREPARE) ||
> + chan->move_role != L2CAP_MOVE_ROLE_NONE) &&
> + bacmp(conn->src, conn->dst) > 0) {
This one needs a comment on top of it.
> + result = L2CAP_MR_COLLISION;
> + goto send_move_response;
> + }
> +
> + if (chan->chan_policy == BT_CHANNEL_POLICY_BREDR_ONLY) {
> + result = L2CAP_MR_NOT_ALLOWED;
> + goto send_move_response;
> + }
> +
> + chan->ident = cmd->ident;
> + chan->move_role = L2CAP_MOVE_ROLE_RESPONDER;
> + l2cap_move_setup(chan);
> + chan->move_id = req->dest_amp_id;
> + icid = chan->dcid;
> +
> + if (req->dest_amp_id == 0) {
> + /* Moving to BR/EDR */
> + if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
> + chan->move_state = L2CAP_MOVE_WAIT_LOCAL_BUSY;
> + result = L2CAP_MR_PEND;
> + } else {
> + chan->move_state = L2CAP_MOVE_WAIT_CONFIRM;
> + result = L2CAP_MR_SUCCESS;
> + }
> + } else {
> + chan->move_state = L2CAP_MOVE_WAIT_PREPARE;
> + /* Placeholder - uncomment when amp functions are available */
> + /*amp_accept_physical(chan, req->dest_amp_id);*/
> + result = L2CAP_MR_PEND;
> + }
> +
> +send_move_response:
> l2cap_send_move_chan_rsp(conn, cmd->ident, icid, result);
>
> if (chan)
Otherwise this looks fine to me.
Acked-by: Marcel Holtmann <marcel@holtmann.org>
I do realize my question from before, but I think it is still valid. If
we don't have (!chan), we can just refuse. Make the initial if statement
a bit simpler and split this down for people to follow. Anyway, the
general way is fine. It is just sugar to make this read easier.
Regards
Marcel
^ permalink raw reply
* Re: [PATCH 1/4] Bluetooth: Fix L2CAP PSM bind issue
From: Syam Sidhardhan @ 2012-10-15 18:16 UTC (permalink / raw)
To: Luiz Augusto von Dentz, Marcel Holtmann; +Cc: linux-bluetooth
In-Reply-To: <CABBYNZ+rGP0cirHDexU49+SJnSn2hRd+GVH0sVOFU53DfNnq0g@mail.gmail.com>
Hi Marcel, Luiz,
----- Original Message -----
From: "Luiz Augusto von Dentz" <luiz.dentz@gmail.com>
To: "Marcel Holtmann" <marcel@holtmann.org>
Cc: "Syam Sidhardhan" <s.syam@samsung.com>;
<linux-bluetooth@vger.kernel.org>
Sent: Thursday, October 11, 2012 7:59 PM
Subject: Re: [PATCH 1/4] Bluetooth: Fix L2CAP PSM bind issue
> Hi Marcel,
>
> On Thu, Oct 11, 2012 at 3:56 PM, Marcel Holtmann <marcel@holtmann.org>
> wrote:
>> Hi Syam,
>>
>>> >> Problem: If we bind a particular PSM with source address as
>>> >> BDADDR_ANY,
>>> >> then we are able to bind the same PSM with adapter address(or any
>>> >> other
>>> >> address), which is incorrect.
>>> >
>>> > why is this incorrect? Explain that to me.
>>> >
>>>
>>> Here there is a correction required in the commit message.
>>>
>>> As per my understanding the a particular PSM can be binded only once
>>> for a single adapter address. Kindly correct me if I'm wrong here.
>>
>> a PSM can be bound once per adapter address. And of course once per
>> BDADDR_ANY.
>>
>> So you can bind PSM 23 to BDADDR_ANY and 11:22:33:44:55:66. An incoming
>> connection to 11:22:33:44:55:66 will arrive to that specific socket, but
>> an incoming to all others will be handled by the BDADDR_ANY.
>>
>> The BDADDR_ANY is special. Consider it a wildcard bound with lower
>> priority. If overwritten with a specific address bound, that will be
>> considered first of course.
>>
>> If we are not doing it that way, than that is a bug.
>>
>> Outgoing connections should behave the same btw. If a specific address
>> is bound, than that will be used. If not available, then you can not
>> connect. If BDADDR_ANY is used, then the next available adapter will be
>> used.
>
> The real problem is by giving psm 0 the kernel should return the first
> available psm in the non-reserved space, but since we reuse the same
> code to do the matching it end up given both obexd and hdp the same
> psm, IMO in this case we should consider using Syam code and not
> __l2cap_global_chan_by_addr as the userspace is probably asking for a
> psm not in use which should exclude those in use by BDADDR_ANY.
>
It seems there is a bug.
I tried to listen first using BDADDR_ANY and then again listen
using the adapter address for a particular PSM. If I try to connect
on that particular PSM from the remote device, then the incoming
connection follows the order of the listen rather than the priority.
Ex:
1) Listen
-sh-4.1# /opt/l2test -d -P 11
l2test[3450]: Waiting for connection on psm 11 ...
2) Listen
-sh-4.1# /opt/l2test -w -P 11 -i hci0
l2test[3451]: Waiting for connection on psm 11 ...
If we try to connect from the remote device, then the connection goes to
First listen
-sh-4.1# /opt/l2test -n -P 11 00:02:4B:28:2C:48
Similarly if we swap the order of the listen 1 & 2, then connection goes to
hci0 one.
The following diff resolves the issue for me. I'm not sure its correct or
not.
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 33b5d34..12f9b52 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -1499,7 +1499,7 @@ static struct l2cap_chan *l2cap_global_chan_by_psm(int
state, __le16 psm,
src_any = !bacmp(&bt_sk(sk)->src, BDADDR_ANY);
dst_any = !bacmp(&bt_sk(sk)->dst, BDADDR_ANY);
if ((src_match && dst_any) || (src_any && dst_match)
||
- (src_any && dst_any))
+ (!c1 && src_any && dst_any))
c1 = c;
}
}
Regards,
Syam
^ permalink raw reply related
* Re: [PATCH 04/19] Bluetooth: Lookup channel structure based on DCID
From: Marcel Holtmann @ 2012-10-15 18:13 UTC (permalink / raw)
To: Mat Martineau; +Cc: linux-bluetooth, gustavo, sunnyk
In-Reply-To: <1350315248-7690-5-git-send-email-mathewm@codeaurora.org>
Hi Mat,
> 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 | 22 ++++++++++++++++++++++
> 1 file changed, 22 insertions(+)
>
> diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
> index ec2b4d9..a55644f 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;
>
> @@ -4152,9 +4169,14 @@ static inline int l2cap_move_channel_req(struct l2cap_conn *conn,
> if (!enable_hs)
> return -EINVAL;
>
> + chan = l2cap_get_chan_by_dcid(conn, icid);
> +
if (!chan)
goto refuse;
/* Placeholder ... */
refuse:
> /* Placeholder: Always refuse */
> l2cap_send_move_chan_rsp(conn, cmd->ident, icid, result);
>
l2cap_chan_unlock(chan);
> return 0;
> }
>
You might have some intention here that I do not see yet, but I think
this is a bit too complicated.
Regards
Marcel
^ permalink raw reply
* Re: [PATCH 03/19] Bluetooth: Remove unnecessary intermediate function
From: Marcel Holtmann @ 2012-10-15 18:10 UTC (permalink / raw)
To: Mat Martineau; +Cc: linux-bluetooth, gustavo, sunnyk
In-Reply-To: <1350315248-7690-4-git-send-email-mathewm@codeaurora.org>
Hi Mat,
> Resolves a conflict resolution issue in "Bluetooth: Fix L2CAP coding
> style".
>
> Signed-off-by: Mat Martineau <mathewm@codeaurora.org>
> ---
> net/bluetooth/l2cap_core.c | 13 ++-----------
> 1 file changed, 2 insertions(+), 11 deletions(-)
Acked-by: Marcel Holtmann <marcel@holtmann.org>
Regards
Marcel
^ permalink raw reply
* Re: Is it incorrect in checking of "NO_RESET" bit in hci_core.c:hci_dev_do_close()?
From: Anderson Lizardo @ 2012-10-15 18:09 UTC (permalink / raw)
To: Marcel Holtmann; +Cc: chen kris, linux-bluetooth
In-Reply-To: <1350324127.26318.0.camel@aeonflux>
Hi,
On Mon, Oct 15, 2012 at 3:02 PM, Marcel Holtmann <marcel@holtmann.org> wrote:
> Hi Chen,
>
>> static int hci_dev_do_close(struct hci_dev *hdev)
>> {
>> ...
>>
>> /* Reset device */
>> skb_queue_purge(&hdev->cmd_q);
>> atomic_set(&hdev->cmd_cnt, 1);
>> if (!test_bit(HCI_RAW, &hdev->flags) &&
>> test_bit(HCI_QUIRK_NO_RESET, &hdev->quirks)) {
>> set_bit(HCI_INIT, &hdev->flags);
>> __hci_request(hdev, hci_reset_req, 0,
>> msecs_to_jiffies(250));
>> clear_bit(HCI_INIT, &hdev->flags);
>> }
>> ...
>> }
>>
>> I guess the condition should be as following:
>>
>> if (!test_bit(HCI_RAW, &hdev->flags) &&
>> *! *test_bit(HCI_QUIRK_NO_RESET, &hdev->quirks))
>>
>> it means the code should sent HCI_RESET, only if both of the following
>> conditions are met:
>> 1. HCI_RAW is NOT set;
>> 2. HCI_QUIRK_NO_RESET is *NOT* set.
>
> the name is confusing, when closing the device and NO_RESET is set, then
> it needs to send the HCI Reset.
I was almost sure this flag has been renamed to something like
"HCI_QUIRK_RESET_ON_CLOSE" on recent kernels?
Regards,
--
Anderson Lizardo
Instituto Nokia de Tecnologia - INdT
Manaus - Brazil
^ permalink raw reply
* Re: Is it incorrect in checking of "NO_RESET" bit in hci_core.c:hci_dev_do_close()?
From: Marcel Holtmann @ 2012-10-15 18:02 UTC (permalink / raw)
To: chen kris; +Cc: linux-bluetooth
In-Reply-To: <CACKG3X=Jky7m=gU7b=rPYOO1ZqQR_79fgoL-EQCYgog6wNZsLQ@mail.gmail.com>
Hi Chen,
> static int hci_dev_do_close(struct hci_dev *hdev)
> {
> ...
>
> /* Reset device */
> skb_queue_purge(&hdev->cmd_q);
> atomic_set(&hdev->cmd_cnt, 1);
> if (!test_bit(HCI_RAW, &hdev->flags) &&
> test_bit(HCI_QUIRK_NO_RESET, &hdev->quirks)) {
> set_bit(HCI_INIT, &hdev->flags);
> __hci_request(hdev, hci_reset_req, 0,
> msecs_to_jiffies(250));
> clear_bit(HCI_INIT, &hdev->flags);
> }
> ...
> }
>
> I guess the condition should be as following:
>
> if (!test_bit(HCI_RAW, &hdev->flags) &&
> *! *test_bit(HCI_QUIRK_NO_RESET, &hdev->quirks))
>
> it means the code should sent HCI_RESET, only if both of the following
> conditions are met:
> 1. HCI_RAW is NOT set;
> 2. HCI_QUIRK_NO_RESET is *NOT* set.
the name is confusing, when closing the device and NO_RESET is set, then
it needs to send the HCI Reset.
Regards
Marcel
^ permalink raw reply
* Re: [RFC obexd 02/11] build: Add --enable-fuse for gobexfuse
From: Michał Poczwardowski @ 2012-10-15 15:37 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Luiz Augusto von Dentz
In-Reply-To: <CABBYNZLYHpWzEOKfv8wKE4s1Yzsd8cZCv38na707yf5XmktXGg@mail.gmail.com>
I will change that :)
On 15 October 2012 16:43, Luiz Augusto von Dentz <luiz.dentz@gmail.com> wrote:
> Hi Michal,
>
> On Tue, Oct 9, 2012 at 8:34 PM, Marcel Holtmann <marcel@holtmann.org> wrote:
>> Hi Michal,
>>
>>> Makefile.am | 9 +++++++++
>>> configure.ac | 15 +++++++++++++++
>>> 2 files changed, 24 insertions(+), 0 deletions(-)
>>>
>>> diff --git a/Makefile.am b/Makefile.am
>>> index 724dd5d..95b99a6 100644
>>> --- a/Makefile.am
>>> +++ b/Makefile.am
>>> @@ -132,6 +132,15 @@ client_obex_client_SOURCES = $(gdbus_sources) $(gobex_sources) \
>>> client_obex_client_LDADD = @GLIB_LIBS@ @DBUS_LIBS@ @BLUEZ_LIBS@
>>> endif
>>>
>>> +if FUSE
>>> +bin_PROGRAMS = fuse/gobexfuse
>>
>> I rather call this obexfuse or similar. I don't want to have any "g"
>> prefixes in the future anymore.
>
> Are you looking into this? I will probably need more time to look in
> detail what you have done, but at least the binary name should be
> changed as Marcel suggested.
>
> --
> Luiz Augusto von Dentz
> --
> 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
^ permalink raw reply
* [PATCH 19/19] Bluetooth: Start channel move when socket option is changed
From: Mat Martineau @ 2012-10-15 15:34 UTC (permalink / raw)
To: linux-bluetooth, gustavo; +Cc: sunnyk, marcel
In-Reply-To: <1350315248-7690-1-git-send-email-mathewm@codeaurora.org>
Channel moves are triggered by changes to the BT_CHANNEL_POLICY
sockopt when an ERTM or streaming-mode channel is connected.
Moves are only started if enable_hs is true.
Signed-off-by: Mat Martineau <mathewm@codeaurora.org>
---
include/net/bluetooth/l2cap.h | 1 +
net/bluetooth/l2cap_core.c | 20 ++++++++++++++++++++
net/bluetooth/l2cap_sock.c | 5 +++++
3 files changed, 26 insertions(+)
diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index b4c3c65..49783e9 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -809,5 +809,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_move_start(struct l2cap_chan *chan);
#endif /* __L2CAP_H */
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index d7819c1..c23cfd8 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -4467,6 +4467,26 @@ static void l2cap_logical_cfm(struct l2cap_chan *chan, struct hci_chan *hchan,
}
}
+void l2cap_move_start(struct l2cap_chan *chan)
+{
+ BT_DBG("chan %p", chan);
+
+ if (chan->local_amp_id == 0) {
+ if (chan->chan_policy != BT_CHANNEL_POLICY_AMP_PREFERRED)
+ return;
+ chan->move_role = L2CAP_MOVE_ROLE_INITIATOR;
+ chan->move_state = L2CAP_MOVE_WAIT_PREPARE;
+ /* Placeholder - start physical link setup */
+ } else {
+ chan->move_role = L2CAP_MOVE_ROLE_INITIATOR;
+ chan->move_state = L2CAP_MOVE_WAIT_RSP_SUCCESS;
+ chan->move_id = 0;
+ l2cap_move_start(chan);
+ l2cap_send_move_chan_req(chan, 0);
+ __set_chan_timer(chan, L2CAP_MOVE_TIMEOUT);
+ }
+}
+
static void l2cap_do_create(struct l2cap_chan *chan, int result,
u8 local_amp_id, u8 remote_amp_id)
{
diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c
index 5fae2bd..7cb4d73 100644
--- a/net/bluetooth/l2cap_sock.c
+++ b/net/bluetooth/l2cap_sock.c
@@ -735,6 +735,11 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname,
}
chan->chan_policy = (u8) opt;
+
+ if (sk->sk_state == BT_CONNECTED &&
+ chan->move_role == L2CAP_MOVE_ROLE_NONE)
+ l2cap_move_start(chan);
+
break;
default:
--
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
* [PATCH 18/19] Bluetooth: Do not retransmit data during a channel move
From: Mat Martineau @ 2012-10-15 15:34 UTC (permalink / raw)
To: linux-bluetooth, gustavo; +Cc: sunnyk, marcel
In-Reply-To: <1350315248-7690-1-git-send-email-mathewm@codeaurora.org>
Do not retransmit previously-sent data when a "receiver ready" s-frame
with the "final" flag is received during a move.
The ERTM state machines will resynchronize at the end of a channel
move, and the state machine needs to avoid state changes during a
move.
Signed-off-by: Mat Martineau <mathewm@codeaurora.org>
---
net/bluetooth/l2cap_core.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 57b1b02..d7819c1 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -5615,8 +5615,9 @@ static int l2cap_rx_state_recv(struct l2cap_chan *chan,
if (control->final) {
clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
- if (!test_and_clear_bit(CONN_REJ_ACT,
- &chan->conn_state)) {
+ if (!test_and_clear_bit(CONN_REJ_ACT, &chan->conn_state)
+ && (chan->move_state == L2CAP_MOVE_STABLE ||
+ chan->move_state == L2CAP_MOVE_WAIT_PREPARE)) {
control->final = 0;
l2cap_retransmit_all(chan, control);
}
--
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
* [PATCH 17/19] Bluetooth: Send create channel request instead of connect for AMP
From: Mat Martineau @ 2012-10-15 15:34 UTC (permalink / raw)
To: linux-bluetooth, gustavo; +Cc: sunnyk, marcel
In-Reply-To: <1350315248-7690-1-git-send-email-mathewm@codeaurora.org>
When the channel policy is set to prefer AMP, then an L2CAP channel is
set up using the "create channel" command rather than the "connect"
command. A physical link is also set up before sending "create
channel".
Behavior is unchanged if enable_hs is false.
Signed-off-by: Mat Martineau <mathewm@codeaurora.org>
---
net/bluetooth/l2cap_core.c | 42 ++++++++++++++++++++++++++++++++++++++++++
1 file changed, 42 insertions(+)
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 3b142a0..57b1b02 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -58,6 +58,9 @@ static void l2cap_send_disconn_req(struct l2cap_conn *conn,
static void l2cap_tx(struct l2cap_chan *chan, struct l2cap_ctrl *control,
struct sk_buff_head *skbs, u8 event);
+static void l2cap_logical_cfm(struct l2cap_chan *chan, struct hci_chan *hchan,
+ u8 status);
+
/* ---- L2CAP channels ---- */
static struct l2cap_chan *__l2cap_get_chan_by_dcid(struct l2cap_conn *conn,
@@ -562,6 +565,13 @@ void l2cap_chan_del(struct l2cap_chan *chan, int err)
mgr->bredr_chan = NULL;
}
+ if (chan->hs_hchan) {
+ chan->hs_hchan = NULL;
+ chan->hs_hcon = NULL;
+
+ /* Placeholder - free logical link */
+ }
+
chan->ops->teardown(chan, err);
if (test_bit(CONF_NOT_COMPLETE, &chan->conf_state))
@@ -1108,6 +1118,7 @@ static void l2cap_start_connection(struct l2cap_chan *chan)
{
if (__amp_capable(chan)) {
BT_DBG("chan %p AMP capable: discover AMPs", chan);
+ set_bit(CONF_CONNECT_PEND, &chan->conf_state);
a2mp_discover_amp(chan);
} else {
l2cap_send_conn_req(chan);
@@ -1253,6 +1264,16 @@ static void l2cap_conn_start(struct l2cap_conn *conn)
rsp.status = __constant_cpu_to_le16(L2CAP_CS_AUTHEN_PEND);
}
+ if (rsp.result == __constant_cpu_to_le16(L2CAP_CR_SUCCESS) &&
+ chan->local_amp_id) {
+ /* Placeholder - uncomment when amp functions
+ * are available
+ amp_accept_physical(chan, chan->local_amp_id);
+ */
+ l2cap_chan_unlock(chan);
+ continue;
+ }
+
l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP,
sizeof(rsp), &rsp);
@@ -3344,6 +3365,18 @@ done:
rfc.mode = chan->mode;
}
+ if (test_bit(CONF_LOC_CONF_PEND, &chan->conf_state) &&
+ chan->local_amp_id) {
+ struct hci_chan *hchan = NULL;
+
+ /* Placeholder - get hci_chan for logical link */
+
+ if (hchan && hchan->state == BT_CONNECTED) {
+ l2cap_logical_cfm(chan, hchan,
+ L2CAP_MR_SUCCESS);
+ }
+ }
+
if (result == L2CAP_CONF_SUCCESS)
set_bit(CONF_OUTPUT_DONE, &chan->conf_state);
}
@@ -6354,6 +6387,15 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
stat = L2CAP_CS_AUTHOR_PEND;
chan->ops->defer(chan);
} else {
+ if (chan->local_amp_id) {
+ /* Placeholder - accept physical
+ * link
+ amp_accept_physical(chan,
+ chan->local_amp_id);
+ */
+ continue;
+ }
+
__l2cap_state_change(chan, BT_CONFIG);
res = L2CAP_CR_SUCCESS;
stat = L2CAP_CS_NO_INFO;
--
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
* [PATCH 16/19] Bluetooth: Ignore BR/EDR packet size constraints when fragmenting for AMP
From: Mat Martineau @ 2012-10-15 15:34 UTC (permalink / raw)
To: linux-bluetooth, gustavo; +Cc: sunnyk, marcel, Andrei Emeltchenko
In-Reply-To: <1350315248-7690-1-git-send-email-mathewm@codeaurora.org>
When operating over BR/EDR, ERTM accounts for the maximum over-the-air
packet size when setting the PDU size. AMP controllers do not use the
same over-the-air packets, so the PDU size should only be based on the
HCI MTU of the AMP controller.
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 | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index dbcd1e3..3b142a0 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -2270,7 +2270,9 @@ static int l2cap_segment_sdu(struct l2cap_chan *chan,
/* PDU size is derived from the HCI MTU */
pdu_len = chan->conn->mtu;
- pdu_len = min_t(size_t, pdu_len, L2CAP_BREDR_MAX_PAYLOAD);
+ /* Constrain PDU size for BR/EDR connections */
+ if (!chan->hs_hcon)
+ pdu_len = min_t(size_t, pdu_len, L2CAP_BREDR_MAX_PAYLOAD);
/* Adjust for largest possible L2CAP overhead. */
if (chan->fcs)
--
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
* [PATCH 15/19] Bluetooth: Configure appropriate timeouts for AMP controllers
From: Mat Martineau @ 2012-10-15 15:34 UTC (permalink / raw)
To: linux-bluetooth, gustavo; +Cc: sunnyk, marcel
In-Reply-To: <1350315248-7690-1-git-send-email-mathewm@codeaurora.org>
The L2CAP spec recommends specific retransmit and monitor timeouts for
ERTM channels that are on AMP controllers. These timeouts are
calculated from the AMP controller's best effort flush timeout.
BR/EDR controllers use the default retransmit and monitor timeouts.
Signed-off-by: Mat Martineau <mathewm@codeaurora.org>
---
net/bluetooth/l2cap_core.c | 47 ++++++++++++++++++++++++++++++++++++++++------
1 file changed, 41 insertions(+), 6 deletions(-)
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index cf1dc4e..dbcd1e3 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -2965,6 +2965,44 @@ static inline bool __l2cap_efs_supported(struct l2cap_chan *chan)
return enable_hs && chan->conn->feat_mask & L2CAP_FEAT_EXT_FLOW;
}
+static void __l2cap_set_ertm_timeouts(struct l2cap_chan *chan,
+ struct l2cap_conf_rfc *rfc)
+{
+ if (chan->local_amp_id && chan->hs_hcon) {
+ u64 ertm_to = chan->hs_hcon->hdev->amp_be_flush_to;
+
+ /* Class 1 devices have must have ERTM timeouts
+ * exceeding the Link Supervision Timeout. The
+ * default Link Supervision Timeout for AMP
+ * controllers is 10 seconds.
+ *
+ * Class 1 devices use 0xffffffff for their
+ * best-effort flush timeout, so the clamping logic
+ * will result in a timeout that meets the above
+ * requirement. ERTM timeouts are 16-bit values, so
+ * the maximum timeout is 65.535 seconds.
+ */
+
+ /* Convert timeout to milliseconds and round */
+ ertm_to = div_u64(ertm_to + 999, 1000);
+
+ /* This is the recommended formula for class 2 devices
+ * that start ERTM timers when packets are sent to the
+ * controller.
+ */
+ ertm_to = 3 * ertm_to + 500;
+
+ if (ertm_to > 0xffff)
+ ertm_to = 0xffff;
+
+ rfc->retrans_timeout = cpu_to_le16((u16) ertm_to);
+ rfc->monitor_timeout = rfc->retrans_timeout;
+ } else {
+ rfc->retrans_timeout = __constant_cpu_to_le16(L2CAP_DEFAULT_RETRANS_TO);
+ rfc->monitor_timeout = __constant_cpu_to_le16(L2CAP_DEFAULT_MONITOR_TO);
+ }
+}
+
static inline void l2cap_txwin_setup(struct l2cap_chan *chan)
{
if (chan->tx_win > L2CAP_DEFAULT_TX_WINDOW &&
@@ -3031,8 +3069,8 @@ done:
case L2CAP_MODE_ERTM:
rfc.mode = L2CAP_MODE_ERTM;
rfc.max_transmit = chan->max_tx;
- rfc.retrans_timeout = 0;
- rfc.monitor_timeout = 0;
+
+ __l2cap_set_ertm_timeouts(chan, &rfc);
size = min_t(u16, L2CAP_DEFAULT_MAX_PDU_SIZE, chan->conn->mtu -
L2CAP_EXT_HDR_SIZE - L2CAP_SDULEN_SIZE -
@@ -3260,10 +3298,7 @@ done:
rfc.max_pdu_size = cpu_to_le16(size);
chan->remote_mps = size;
- rfc.retrans_timeout =
- __constant_cpu_to_le16(L2CAP_DEFAULT_RETRANS_TO);
- rfc.monitor_timeout =
- __constant_cpu_to_le16(L2CAP_DEFAULT_MONITOR_TO);
+ __l2cap_set_ertm_timeouts(chan, &rfc);
set_bit(CONF_MODE_DONE, &chan->conf_state);
--
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
* [PATCH 14/19] Bluetooth: Do not send data during channel move
From: Mat Martineau @ 2012-10-15 15:34 UTC (permalink / raw)
To: linux-bluetooth, gustavo; +Cc: sunnyk, marcel
In-Reply-To: <1350315248-7690-1-git-send-email-mathewm@codeaurora.org>
Outgoing ERTM data is queued during a channel move. The ERTM state
machine is partially reset at the start of a move, and must be
resynchronized with the remote state machine at the end of the move.
Data is not sent so that there are no state transitions between the
partial reset and the resync.
Streaming mode frames are dropped during a move.
Signed-off-by: Mat Martineau <mathewm@codeaurora.org>
---
net/bluetooth/l2cap_core.c | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index d7b1bf3..cf1dc4e 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -927,6 +927,10 @@ static void l2cap_send_sframe(struct l2cap_chan *chan,
if (!control->sframe)
return;
+ if (chan->move_state != L2CAP_MOVE_STABLE &&
+ chan->move_state != L2CAP_MOVE_WAIT_PREPARE)
+ return;
+
if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state) &&
!control->poll)
control->final = 1;
@@ -1805,6 +1809,10 @@ static void l2cap_streaming_send(struct l2cap_chan *chan,
BT_DBG("chan %p, skbs %p", chan, skbs);
+ if (chan->move_state != L2CAP_MOVE_STABLE &&
+ chan->move_state != L2CAP_MOVE_WAIT_PREPARE)
+ return;
+
skb_queue_splice_tail_init(skbs, &chan->tx_q);
while (!skb_queue_empty(&chan->tx_q)) {
@@ -1847,6 +1855,10 @@ static int l2cap_ertm_send(struct l2cap_chan *chan)
if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state))
return 0;
+ if (chan->move_state != L2CAP_MOVE_STABLE &&
+ chan->move_state != L2CAP_MOVE_WAIT_PREPARE)
+ return 0;
+
while (chan->tx_send_head &&
chan->unacked_frames < chan->remote_tx_win &&
chan->tx_state == L2CAP_TX_STATE_XMIT) {
@@ -1912,6 +1924,10 @@ static void l2cap_ertm_resend(struct l2cap_chan *chan)
if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state))
return;
+ if (chan->move_state != L2CAP_MOVE_STABLE &&
+ chan->move_state != L2CAP_MOVE_WAIT_PREPARE)
+ return;
+
while (chan->retrans_list.head != L2CAP_SEQ_LIST_CLEAR) {
seq = l2cap_seq_list_pop(&chan->retrans_list);
--
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
* [PATCH 13/19] Bluetooth: Flag ACL frames as complete for AMP controllers
From: Mat Martineau @ 2012-10-15 15:34 UTC (permalink / raw)
To: linux-bluetooth, gustavo; +Cc: sunnyk, marcel
In-Reply-To: <1350315248-7690-1-git-send-email-mathewm@codeaurora.org>
AMP controllers expect to transmit only "complete" ACL frames. These
frames have both the "start" and "cont" bits set. AMP does not allow
fragmented ACLs.
Signed-off-by: Mat Martineau <mathewm@codeaurora.org>
---
net/bluetooth/l2cap_core.c | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 592699f..d7b1bf3 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -742,6 +742,16 @@ static void l2cap_do_send(struct l2cap_chan *chan, struct sk_buff *skb)
BT_DBG("chan %p, skb %p len %d priority %u", chan, skb, skb->len,
skb->priority);
+ if (chan->hs_hcon && (chan->move_state == L2CAP_MOVE_STABLE ||
+ chan->move_state == L2CAP_MOVE_WAIT_PREPARE)) {
+ if (chan->hs_hchan)
+ hci_send_acl(chan->hs_hchan, skb, ACL_COMPLETE);
+ else
+ kfree_skb(skb);
+
+ return;
+ }
+
if (!test_bit(FLAG_FLUSHABLE, &chan->flags) &&
lmp_no_flush_capable(hcon->hdev))
flags = ACL_START_NO_FLUSH;
--
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
* [PATCH 12/19] Bluetooth: Handle physical link completion
From: Mat Martineau @ 2012-10-15 15:34 UTC (permalink / raw)
To: linux-bluetooth, gustavo; +Cc: sunnyk, marcel
In-Reply-To: <1350315248-7690-1-git-send-email-mathewm@codeaurora.org>
Several different actions may be taken when an AMP physical link
becomes available. A channel being created on an AMP controller must
continue the connection process. A channel being moved needs to
either send a move request or a move response. A failed physical link
will revert to using a BR/EDR controller if possible.
Signed-off-by: Mat Martineau <mathewm@codeaurora.org>
---
net/bluetooth/l2cap_core.c | 166 +++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 166 insertions(+)
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index ac9d34a..592699f 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -995,6 +995,19 @@ void l2cap_send_conn_req(struct l2cap_chan *chan)
l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_REQ, sizeof(req), &req);
}
+static void l2cap_send_create_chan_req(struct l2cap_chan *chan, u8 amp_id)
+{
+ struct l2cap_create_chan_req req;
+ req.scid = cpu_to_le16(chan->scid);
+ req.psm = chan->psm;
+ req.amp_id = amp_id;
+
+ chan->ident = l2cap_get_ident(chan->conn);
+
+ l2cap_send_cmd(chan->conn, chan->ident, L2CAP_CREATE_CHAN_REQ,
+ sizeof(req), &req);
+}
+
static void l2cap_move_setup(struct l2cap_chan *chan)
{
struct sk_buff *skb;
@@ -4179,6 +4192,23 @@ static int l2cap_create_channel_req(struct l2cap_conn *conn,
return 0;
}
+static void l2cap_send_move_chan_req(struct l2cap_chan *chan, u8 dest_amp_id)
+{
+ struct l2cap_move_chan_req req;
+ u8 ident;
+
+ BT_DBG("chan %p, dest_amp_id %d", chan, dest_amp_id);
+
+ ident = l2cap_get_ident(chan->conn);
+ chan->ident = ident;
+
+ req.icid = cpu_to_le16(chan->scid);
+ req.dest_amp_id = dest_amp_id;
+
+ l2cap_send_cmd(chan->conn, ident, L2CAP_MOVE_CHAN_REQ, sizeof(req),
+ &req);
+}
+
static void l2cap_send_move_chan_rsp(struct l2cap_conn *conn, u8 ident,
u16 icid, u16 result)
{
@@ -4341,6 +4371,142 @@ static void l2cap_logical_cfm(struct l2cap_chan *chan, struct hci_chan *hchan,
}
}
+static void l2cap_do_create(struct l2cap_chan *chan, int result,
+ u8 local_amp_id, u8 remote_amp_id)
+{
+ if (!test_bit(CONF_CONNECT_PEND, &chan->conf_state)) {
+ struct l2cap_conn_rsp rsp;
+ char buf[128];
+ rsp.scid = cpu_to_le16(chan->dcid);
+ rsp.dcid = cpu_to_le16(chan->scid);
+
+ /* Incoming channel on AMP */
+ if (result == L2CAP_CR_SUCCESS) {
+ /* Send successful response */
+ rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS);
+ rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
+ } else {
+ /* Send negative response */
+ rsp.result = cpu_to_le16(L2CAP_CR_NO_MEM);
+ rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
+ }
+
+ l2cap_send_cmd(chan->conn, chan->ident, L2CAP_CREATE_CHAN_RSP,
+ sizeof(rsp), &rsp);
+
+ if (result == L2CAP_CR_SUCCESS) {
+ __l2cap_state_change(chan, BT_CONFIG);
+ set_bit(CONF_REQ_SENT, &chan->conf_state);
+ l2cap_send_cmd(chan->conn, l2cap_get_ident(chan->conn),
+ L2CAP_CONF_REQ,
+ l2cap_build_conf_req(chan, buf), buf);
+ chan->num_conf_req++;
+ }
+ } else {
+ /* Outgoing channel on AMP */
+ if (result == L2CAP_CR_SUCCESS) {
+ chan->local_amp_id = local_amp_id;
+ l2cap_send_create_chan_req(chan, remote_amp_id);
+ } else {
+ /* Revert to BR/EDR connect */
+ l2cap_send_conn_req(chan);
+ }
+ }
+}
+
+static void l2cap_do_move_initiate(struct l2cap_chan *chan, u8 local_amp_id,
+ u8 remote_amp_id)
+{
+ l2cap_move_setup(chan);
+ chan->move_id = local_amp_id;
+ chan->move_state = L2CAP_MOVE_WAIT_RSP;
+
+ l2cap_send_move_chan_req(chan, remote_amp_id);
+ __set_chan_timer(chan, L2CAP_MOVE_TIMEOUT);
+}
+
+static void l2cap_do_move_respond(struct l2cap_chan *chan, int result)
+{
+ struct hci_chan *hchan = NULL;
+
+ /* Placeholder - get hci_chan for logical link */
+
+ if (hchan) {
+ if (hchan->state == BT_CONNECTED) {
+ /* Logical link is ready to go */
+ chan->hs_hcon = hchan->conn;
+ chan->hs_hcon->l2cap_data = chan->conn;
+ chan->move_state = L2CAP_MOVE_WAIT_CONFIRM;
+ l2cap_send_move_chan_rsp(chan->conn, chan->ident,
+ chan->dcid, L2CAP_MR_SUCCESS);
+
+ l2cap_logical_cfm(chan, hchan, L2CAP_MR_SUCCESS);
+ } else {
+ /* Wait for logical link to be ready */
+ chan->move_state = L2CAP_MOVE_WAIT_LOGICAL_CFM;
+ }
+ } else {
+ /* Logical link not available */
+ l2cap_send_move_chan_rsp(chan->conn, chan->ident, chan->dcid,
+ L2CAP_MR_NOT_ALLOWED);
+ }
+}
+
+static void l2cap_do_move_cancel(struct l2cap_chan *chan, int result)
+{
+ if (chan->move_role == L2CAP_MOVE_ROLE_RESPONDER) {
+ u8 rsp_result;
+ if (result == -EINVAL)
+ rsp_result = L2CAP_MR_BAD_ID;
+ else
+ rsp_result = L2CAP_MR_NOT_ALLOWED;
+
+ l2cap_send_move_chan_rsp(chan->conn, chan->ident, chan->dcid,
+ rsp_result);
+ }
+
+ chan->move_role = L2CAP_MOVE_ROLE_NONE;
+ chan->move_state = L2CAP_MOVE_STABLE;
+
+ /* Restart data transmission */
+ l2cap_ertm_send(chan);
+}
+
+void l2cap_physical_cfm(struct l2cap_chan *chan, int result, u8 local_amp_id,
+ u8 remote_amp_id)
+{
+ BT_DBG("chan %p, result %d, local_amp_id %d, remote_amp_id %d",
+ chan, result, local_amp_id, remote_amp_id);
+
+ l2cap_chan_lock(chan);
+
+ if (chan->state == BT_DISCONN || chan->state == BT_CLOSED) {
+ l2cap_chan_unlock(chan);
+ return;
+ }
+
+ if (chan->state != BT_CONNECTED) {
+ l2cap_do_create(chan, result, local_amp_id, remote_amp_id);
+ } else if (result != L2CAP_MR_SUCCESS) {
+ l2cap_do_move_cancel(chan, result);
+ } else {
+ switch (chan->move_role) {
+ case L2CAP_MOVE_ROLE_INITIATOR:
+ l2cap_do_move_initiate(chan, local_amp_id,
+ remote_amp_id);
+ break;
+ case L2CAP_MOVE_ROLE_RESPONDER:
+ l2cap_do_move_respond(chan, result);
+ break;
+ default:
+ l2cap_do_move_cancel(chan, result);
+ break;
+ }
+ }
+
+ l2cap_chan_unlock(chan);
+}
+
static inline int l2cap_move_channel_req(struct l2cap_conn *conn,
struct l2cap_cmd_hdr *cmd,
u16 cmd_len, void *data)
--
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
* [PATCH 11/19] Bluetooth: Add move confirm response handling
From: Mat Martineau @ 2012-10-15 15:34 UTC (permalink / raw)
To: linux-bluetooth, gustavo; +Cc: sunnyk, marcel
In-Reply-To: <1350315248-7690-1-git-send-email-mathewm@codeaurora.org>
The move confirm response concludes the channel move command sequence.
Receipt of this command indicates that data may begin to flow again.
Signed-off-by: Mat Martineau <mathewm@codeaurora.org>
---
net/bluetooth/l2cap_core.c | 26 ++++++++++++++++++++++++++
1 file changed, 26 insertions(+)
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 7e31e98..ac9d34a 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -4632,6 +4632,7 @@ static inline int l2cap_move_channel_confirm_rsp(struct l2cap_conn *conn,
u16 cmd_len, void *data)
{
struct l2cap_move_chan_cfm_rsp *rsp = data;
+ struct l2cap_chan *chan;
u16 icid;
if (cmd_len != sizeof(*rsp))
@@ -4641,6 +4642,31 @@ static inline int l2cap_move_channel_confirm_rsp(struct l2cap_conn *conn,
BT_DBG("icid 0x%4.4x", icid);
+ chan = l2cap_get_chan_by_scid(conn, icid);
+ if (!chan)
+ return 0;
+
+ __clear_chan_timer(chan);
+
+ if (chan->move_state == L2CAP_MOVE_WAIT_CONFIRM_RSP) {
+ chan->move_state = L2CAP_MOVE_STABLE;
+ chan->local_amp_id = chan->move_id;
+
+ if (!chan->local_amp_id && chan->hs_hchan) {
+ /* 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);
+
+ chan->move_role = L2CAP_MOVE_ROLE_NONE;
+ }
+
+ l2cap_chan_unlock(chan);
+
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
* [PATCH 10/19] Bluetooth: Add logical link confirm
From: Mat Martineau @ 2012-10-15 15:33 UTC (permalink / raw)
To: linux-bluetooth, gustavo; +Cc: sunnyk, marcel
In-Reply-To: <1350315248-7690-1-git-send-email-mathewm@codeaurora.org>
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)
+ err = l2cap_ertm_init(chan);
+
+ if (err < 0)
+ l2cap_send_disconn_req(chan->conn, chan, -err);
+ else
+ l2cap_chan_ready(chan);
+ }
+ } else if (chan && !status) {
+ /* Channel move */
+ chan->hs_hcon = hchan->conn;
+ chan->hs_hcon->l2cap_data = chan->conn;
+
+ BT_DBG("move_state %d", chan->move_state);
+
+ if (chan->state != BT_CONNECTED)
+ return;
+
+ switch (chan->move_state) {
+ case L2CAP_MOVE_WAIT_LOGICAL_COMP:
+ /* Move confirm will be sent after a success
+ * response is received
+ */
+ chan->move_state = L2CAP_MOVE_WAIT_RSP_SUCCESS;
+ break;
+ case L2CAP_MOVE_WAIT_LOGICAL_CFM:
+ if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
+ chan->move_state = L2CAP_MOVE_WAIT_LOCAL_BUSY;
+ } else if (chan->move_role ==
+ L2CAP_MOVE_ROLE_INITIATOR) {
+ chan->move_state = L2CAP_MOVE_WAIT_CONFIRM_RSP;
+ l2cap_send_move_chan_cfm(chan->conn, chan,
+ chan->scid,
+ L2CAP_MR_SUCCESS);
+ __set_chan_timer(chan, L2CAP_MOVE_TIMEOUT);
+ } else if (chan->move_role ==
+ L2CAP_MOVE_ROLE_RESPONDER) {
+ chan->move_state = L2CAP_MOVE_WAIT_CONFIRM;
+ l2cap_send_move_chan_rsp(chan->conn,
+ chan->ident,
+ chan->dcid,
+ L2CAP_MR_SUCCESS);
+ }
+ break;
+ default:
+ /* Move was not in expected state, free the channel */
+ chan->hs_hchan = NULL;
+ chan->hs_hcon = NULL;
+
+ /* Placeholder - free the logical link */
+
+ chan->move_state = L2CAP_MOVE_STABLE;
+ }
+ } else {
+ /* Logical link setup failed. */
+
+ if (chan->state != BT_CONNECTED)
+ l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
+ else if (chan->move_role == L2CAP_MOVE_ROLE_RESPONDER) {
+ l2cap_move_revert(chan);
+ chan->move_role = L2CAP_MOVE_ROLE_NONE;
+ chan->move_state = L2CAP_MOVE_STABLE;
+ l2cap_send_move_chan_rsp(chan->conn, chan->ident,
+ chan->dcid, L2CAP_MR_NOT_SUPP);
+ } else if (chan->move_role == L2CAP_MOVE_ROLE_INITIATOR) {
+ if (chan->move_state == L2CAP_MOVE_WAIT_LOGICAL_COMP ||
+ chan->move_state == L2CAP_MOVE_WAIT_LOGICAL_CFM) {
+ /* Remote has only sent pending or
+ * success responses, clean up
+ */
+ l2cap_move_revert(chan);
+ chan->move_role = L2CAP_MOVE_ROLE_NONE;
+ chan->move_state = L2CAP_MOVE_STABLE;
+ }
+
+ /* Other amp move states imply that the move
+ * has already aborted
+ */
+ l2cap_send_move_chan_cfm(chan->conn, chan, chan->scid,
+ L2CAP_MC_UNCONFIRMED);
+ __set_chan_timer(chan, L2CAP_MOVE_TIMEOUT);
+ }
+
+ chan->hs_hchan = NULL;
+ chan->hs_hcon = NULL;
+
+ /* Placeholder - free logical link */
+ }
}
static inline int l2cap_move_channel_req(struct l2cap_conn *conn,
--
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
* [PATCH 09/19] Bluetooth: Move channel response
From: Mat Martineau @ 2012-10-15 15:33 UTC (permalink / raw)
To: linux-bluetooth, gustavo; +Cc: sunnyk, marcel
In-Reply-To: <1350315248-7690-1-git-send-email-mathewm@codeaurora.org>
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;
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);
+
+ 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);
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
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