diff options
author | Mat Martineau <mathewm@codeaurora.org> | 2012-10-23 18:24:12 -0400 |
---|---|---|
committer | Gustavo Padovan <gustavo.padovan@collabora.co.uk> | 2012-10-23 22:15:03 -0400 |
commit | 5f3847a4788e7205a6ad2ac363f968c9618074f1 (patch) | |
tree | d8cc36ebccf19691c10311f0661fe59fcedbea47 | |
parent | 32b32735ca1439e2ead658dd63234c0c380af8ac (diff) |
Bluetooth: Add move channel confirm handling
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>
Acked-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
Acked-by: Marcel Holtmann <marcel@holtmann.org>
Signed-off-by: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
-rw-r--r-- | net/bluetooth/l2cap_core.c | 58 |
1 files changed, 55 insertions, 3 deletions
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index b9a91bf3d95e..fef0394add18 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c | |||
@@ -1037,6 +1037,28 @@ static void l2cap_move_setup(struct l2cap_chan *chan) | |||
1037 | set_bit(CONN_REMOTE_BUSY, &chan->conn_state); | 1037 | set_bit(CONN_REMOTE_BUSY, &chan->conn_state); |
1038 | } | 1038 | } |
1039 | 1039 | ||
1040 | static void l2cap_move_done(struct l2cap_chan *chan) | ||
1041 | { | ||
1042 | u8 move_role = chan->move_role; | ||
1043 | BT_DBG("chan %p", chan); | ||
1044 | |||
1045 | chan->move_state = L2CAP_MOVE_STABLE; | ||
1046 | chan->move_role = L2CAP_MOVE_ROLE_NONE; | ||
1047 | |||
1048 | if (chan->mode != L2CAP_MODE_ERTM) | ||
1049 | return; | ||
1050 | |||
1051 | switch (move_role) { | ||
1052 | case L2CAP_MOVE_ROLE_INITIATOR: | ||
1053 | l2cap_tx(chan, NULL, NULL, L2CAP_EV_EXPLICIT_POLL); | ||
1054 | chan->rx_state = L2CAP_RX_STATE_WAIT_F; | ||
1055 | break; | ||
1056 | case L2CAP_MOVE_ROLE_RESPONDER: | ||
1057 | chan->rx_state = L2CAP_RX_STATE_WAIT_P; | ||
1058 | break; | ||
1059 | } | ||
1060 | } | ||
1061 | |||
1040 | static void l2cap_chan_ready(struct l2cap_chan *chan) | 1062 | static void l2cap_chan_ready(struct l2cap_chan *chan) |
1041 | { | 1063 | { |
1042 | /* This clears all conf flags, including CONF_NOT_COMPLETE */ | 1064 | /* This clears all conf flags, including CONF_NOT_COMPLETE */ |
@@ -4193,6 +4215,14 @@ static void l2cap_send_move_chan_cfm_rsp(struct l2cap_conn *conn, u8 ident, | |||
4193 | l2cap_send_cmd(conn, ident, L2CAP_MOVE_CHAN_CFM_RSP, sizeof(rsp), &rsp); | 4215 | l2cap_send_cmd(conn, ident, L2CAP_MOVE_CHAN_CFM_RSP, sizeof(rsp), &rsp); |
4194 | } | 4216 | } |
4195 | 4217 | ||
4218 | static void __release_logical_link(struct l2cap_chan *chan) | ||
4219 | { | ||
4220 | chan->hs_hchan = NULL; | ||
4221 | chan->hs_hcon = NULL; | ||
4222 | |||
4223 | /* Placeholder - release the logical link */ | ||
4224 | } | ||
4225 | |||
4196 | static inline int l2cap_move_channel_req(struct l2cap_conn *conn, | 4226 | static inline int l2cap_move_channel_req(struct l2cap_conn *conn, |
4197 | struct l2cap_cmd_hdr *cmd, | 4227 | struct l2cap_cmd_hdr *cmd, |
4198 | u16 cmd_len, void *data) | 4228 | u16 cmd_len, void *data) |
@@ -4308,11 +4338,12 @@ static inline int l2cap_move_channel_rsp(struct l2cap_conn *conn, | |||
4308 | return 0; | 4338 | return 0; |
4309 | } | 4339 | } |
4310 | 4340 | ||
4311 | static inline int l2cap_move_channel_confirm(struct l2cap_conn *conn, | 4341 | static int l2cap_move_channel_confirm(struct l2cap_conn *conn, |
4312 | struct l2cap_cmd_hdr *cmd, | 4342 | struct l2cap_cmd_hdr *cmd, |
4313 | u16 cmd_len, void *data) | 4343 | u16 cmd_len, void *data) |
4314 | { | 4344 | { |
4315 | struct l2cap_move_chan_cfm *cfm = data; | 4345 | struct l2cap_move_chan_cfm *cfm = data; |
4346 | struct l2cap_chan *chan; | ||
4316 | u16 icid, result; | 4347 | u16 icid, result; |
4317 | 4348 | ||
4318 | if (cmd_len != sizeof(*cfm)) | 4349 | if (cmd_len != sizeof(*cfm)) |
@@ -4323,8 +4354,29 @@ static inline int l2cap_move_channel_confirm(struct l2cap_conn *conn, | |||
4323 | 4354 | ||
4324 | BT_DBG("icid 0x%4.4x, result 0x%4.4x", icid, result); | 4355 | BT_DBG("icid 0x%4.4x, result 0x%4.4x", icid, result); |
4325 | 4356 | ||
4357 | chan = l2cap_get_chan_by_dcid(conn, icid); | ||
4358 | if (!chan) { | ||
4359 | /* Spec requires a response even if the icid was not found */ | ||
4360 | l2cap_send_move_chan_cfm_rsp(conn, cmd->ident, icid); | ||
4361 | return 0; | ||
4362 | } | ||
4363 | |||
4364 | if (chan->move_state == L2CAP_MOVE_WAIT_CONFIRM) { | ||
4365 | if (result == L2CAP_MC_CONFIRMED) { | ||
4366 | chan->local_amp_id = chan->move_id; | ||
4367 | if (!chan->local_amp_id) | ||
4368 | __release_logical_link(chan); | ||
4369 | } else { | ||
4370 | chan->move_id = chan->local_amp_id; | ||
4371 | } | ||
4372 | |||
4373 | l2cap_move_done(chan); | ||
4374 | } | ||
4375 | |||
4326 | l2cap_send_move_chan_cfm_rsp(conn, cmd->ident, icid); | 4376 | l2cap_send_move_chan_cfm_rsp(conn, cmd->ident, icid); |
4327 | 4377 | ||
4378 | l2cap_chan_unlock(chan); | ||
4379 | |||
4328 | return 0; | 4380 | return 0; |
4329 | } | 4381 | } |
4330 | 4382 | ||