diff options
author | Mat Martineau <mathewm@codeaurora.org> | 2012-10-23 18:24:14 -0400 |
---|---|---|
committer | Gustavo Padovan <gustavo.padovan@collabora.co.uk> | 2012-10-23 22:20:54 -0400 |
commit | 5b155ef960202b20a5cae43b9e675f4326e2375c (patch) | |
tree | 57100cad151ef8e532a11d8b684ded0efc3f8cbf /net | |
parent | 168df8e57e7c1afce3f86a86ae106f82ff7c18d8 (diff) |
Bluetooth: Move channel response
The move response command includes a result code indicating
"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>
Acked-by: Marcel Holtmann <marcel@holtmann.org>
Signed-off-by: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
Diffstat (limited to 'net')
-rw-r--r-- | net/bluetooth/l2cap_core.c | 183 |
1 files changed, 168 insertions, 15 deletions
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index fef0394add18..2277ed504283 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c | |||
@@ -129,6 +129,20 @@ static struct l2cap_chan *__l2cap_get_chan_by_ident(struct l2cap_conn *conn, | |||
129 | return NULL; | 129 | return NULL; |
130 | } | 130 | } |
131 | 131 | ||
132 | static struct l2cap_chan *l2cap_get_chan_by_ident(struct l2cap_conn *conn, | ||
133 | u8 ident) | ||
134 | { | ||
135 | struct l2cap_chan *c; | ||
136 | |||
137 | mutex_lock(&conn->chan_lock); | ||
138 | c = __l2cap_get_chan_by_ident(conn, ident); | ||
139 | if (c) | ||
140 | l2cap_chan_lock(c); | ||
141 | mutex_unlock(&conn->chan_lock); | ||
142 | |||
143 | return c; | ||
144 | } | ||
145 | |||
132 | static struct l2cap_chan *__l2cap_global_chan_by_addr(__le16 psm, bdaddr_t *src) | 146 | static struct l2cap_chan *__l2cap_global_chan_by_addr(__le16 psm, bdaddr_t *src) |
133 | { | 147 | { |
134 | struct l2cap_chan *c; | 148 | struct l2cap_chan *c; |
@@ -4185,23 +4199,34 @@ static void l2cap_send_move_chan_rsp(struct l2cap_conn *conn, u8 ident, | |||
4185 | l2cap_send_cmd(conn, ident, L2CAP_MOVE_CHAN_RSP, sizeof(rsp), &rsp); | 4199 | l2cap_send_cmd(conn, ident, L2CAP_MOVE_CHAN_RSP, sizeof(rsp), &rsp); |
4186 | } | 4200 | } |
4187 | 4201 | ||
4188 | static void l2cap_send_move_chan_cfm(struct l2cap_conn *conn, | 4202 | static void l2cap_send_move_chan_cfm(struct l2cap_chan *chan, u16 result) |
4189 | struct l2cap_chan *chan, | ||
4190 | u16 icid, u16 result) | ||
4191 | { | 4203 | { |
4192 | struct l2cap_move_chan_cfm cfm; | 4204 | struct l2cap_move_chan_cfm cfm; |
4193 | u8 ident; | ||
4194 | 4205 | ||
4195 | BT_DBG("icid 0x%4.4x, result 0x%4.4x", icid, result); | 4206 | BT_DBG("chan %p, result 0x%4.4x", chan, result); |
4196 | 4207 | ||
4197 | ident = l2cap_get_ident(conn); | 4208 | chan->ident = l2cap_get_ident(chan->conn); |
4198 | if (chan) | ||
4199 | chan->ident = ident; | ||
4200 | 4209 | ||
4201 | cfm.icid = cpu_to_le16(icid); | 4210 | cfm.icid = cpu_to_le16(chan->scid); |
4202 | cfm.result = cpu_to_le16(result); | 4211 | cfm.result = cpu_to_le16(result); |
4203 | 4212 | ||
4204 | l2cap_send_cmd(conn, ident, L2CAP_MOVE_CHAN_CFM, sizeof(cfm), &cfm); | 4213 | l2cap_send_cmd(chan->conn, chan->ident, L2CAP_MOVE_CHAN_CFM, |
4214 | sizeof(cfm), &cfm); | ||
4215 | |||
4216 | __set_chan_timer(chan, L2CAP_MOVE_TIMEOUT); | ||
4217 | } | ||
4218 | |||
4219 | static void l2cap_send_move_chan_cfm_icid(struct l2cap_conn *conn, u16 icid) | ||
4220 | { | ||
4221 | struct l2cap_move_chan_cfm cfm; | ||
4222 | |||
4223 | BT_DBG("conn %p, icid 0x%4.4x", conn, icid); | ||
4224 | |||
4225 | cfm.icid = cpu_to_le16(icid); | ||
4226 | cfm.result = __constant_cpu_to_le16(L2CAP_MC_UNCONFIRMED); | ||
4227 | |||
4228 | l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_MOVE_CHAN_CFM, | ||
4229 | sizeof(cfm), &cfm); | ||
4205 | } | 4230 | } |
4206 | 4231 | ||
4207 | static void l2cap_send_move_chan_cfm_rsp(struct l2cap_conn *conn, u8 ident, | 4232 | static void l2cap_send_move_chan_cfm_rsp(struct l2cap_conn *conn, u8 ident, |
@@ -4223,6 +4248,13 @@ static void __release_logical_link(struct l2cap_chan *chan) | |||
4223 | /* Placeholder - release the logical link */ | 4248 | /* Placeholder - release the logical link */ |
4224 | } | 4249 | } |
4225 | 4250 | ||
4251 | static void l2cap_logical_cfm(struct l2cap_chan *chan, struct hci_chan *hchan, | ||
4252 | u8 status) | ||
4253 | { | ||
4254 | /* Placeholder */ | ||
4255 | return; | ||
4256 | } | ||
4257 | |||
4226 | static inline int l2cap_move_channel_req(struct l2cap_conn *conn, | 4258 | static inline int l2cap_move_channel_req(struct l2cap_conn *conn, |
4227 | struct l2cap_cmd_hdr *cmd, | 4259 | struct l2cap_cmd_hdr *cmd, |
4228 | u16 cmd_len, void *data) | 4260 | u16 cmd_len, void *data) |
@@ -4317,9 +4349,128 @@ send_move_response: | |||
4317 | return 0; | 4349 | return 0; |
4318 | } | 4350 | } |
4319 | 4351 | ||
4320 | static inline int l2cap_move_channel_rsp(struct l2cap_conn *conn, | 4352 | static void l2cap_move_continue(struct l2cap_conn *conn, u16 icid, u16 result) |
4321 | struct l2cap_cmd_hdr *cmd, | 4353 | { |
4322 | u16 cmd_len, void *data) | 4354 | struct l2cap_chan *chan; |
4355 | struct hci_chan *hchan = NULL; | ||
4356 | |||
4357 | chan = l2cap_get_chan_by_scid(conn, icid); | ||
4358 | if (!chan) { | ||
4359 | l2cap_send_move_chan_cfm_icid(conn, icid); | ||
4360 | return; | ||
4361 | } | ||
4362 | |||
4363 | __clear_chan_timer(chan); | ||
4364 | if (result == L2CAP_MR_PEND) | ||
4365 | __set_chan_timer(chan, L2CAP_MOVE_ERTX_TIMEOUT); | ||
4366 | |||
4367 | switch (chan->move_state) { | ||
4368 | case L2CAP_MOVE_WAIT_LOGICAL_COMP: | ||
4369 | /* Move confirm will be sent when logical link | ||
4370 | * is complete. | ||
4371 | */ | ||
4372 | chan->move_state = L2CAP_MOVE_WAIT_LOGICAL_CFM; | ||
4373 | break; | ||
4374 | case L2CAP_MOVE_WAIT_RSP_SUCCESS: | ||
4375 | if (result == L2CAP_MR_PEND) { | ||
4376 | break; | ||
4377 | } else if (test_bit(CONN_LOCAL_BUSY, | ||
4378 | &chan->conn_state)) { | ||
4379 | chan->move_state = L2CAP_MOVE_WAIT_LOCAL_BUSY; | ||
4380 | } else { | ||
4381 | /* Logical link is up or moving to BR/EDR, | ||
4382 | * proceed with move | ||
4383 | */ | ||
4384 | chan->move_state = L2CAP_MOVE_WAIT_CONFIRM_RSP; | ||
4385 | l2cap_send_move_chan_cfm(chan, L2CAP_MC_CONFIRMED); | ||
4386 | } | ||
4387 | break; | ||
4388 | case L2CAP_MOVE_WAIT_RSP: | ||
4389 | /* Moving to AMP */ | ||
4390 | if (result == L2CAP_MR_SUCCESS) { | ||
4391 | /* Remote is ready, send confirm immediately | ||
4392 | * after logical link is ready | ||
4393 | */ | ||
4394 | chan->move_state = L2CAP_MOVE_WAIT_LOGICAL_CFM; | ||
4395 | } else { | ||
4396 | /* Both logical link and move success | ||
4397 | * are required to confirm | ||
4398 | */ | ||
4399 | chan->move_state = L2CAP_MOVE_WAIT_LOGICAL_COMP; | ||
4400 | } | ||
4401 | |||
4402 | /* Placeholder - get hci_chan for logical link */ | ||
4403 | if (!hchan) { | ||
4404 | /* Logical link not available */ | ||
4405 | l2cap_send_move_chan_cfm(chan, L2CAP_MC_UNCONFIRMED); | ||
4406 | break; | ||
4407 | } | ||
4408 | |||
4409 | /* If the logical link is not yet connected, do not | ||
4410 | * send confirmation. | ||
4411 | */ | ||
4412 | if (hchan->state != BT_CONNECTED) | ||
4413 | break; | ||
4414 | |||
4415 | /* Logical link is already ready to go */ | ||
4416 | |||
4417 | chan->hs_hcon = hchan->conn; | ||
4418 | chan->hs_hcon->l2cap_data = chan->conn; | ||
4419 | |||
4420 | if (result == L2CAP_MR_SUCCESS) { | ||
4421 | /* Can confirm now */ | ||
4422 | l2cap_send_move_chan_cfm(chan, L2CAP_MC_CONFIRMED); | ||
4423 | } else { | ||
4424 | /* Now only need move success | ||
4425 | * to confirm | ||
4426 | */ | ||
4427 | chan->move_state = L2CAP_MOVE_WAIT_RSP_SUCCESS; | ||
4428 | } | ||
4429 | |||
4430 | l2cap_logical_cfm(chan, hchan, L2CAP_MR_SUCCESS); | ||
4431 | break; | ||
4432 | default: | ||
4433 | /* Any other amp move state means the move failed. */ | ||
4434 | chan->move_id = chan->local_amp_id; | ||
4435 | l2cap_move_done(chan); | ||
4436 | l2cap_send_move_chan_cfm(chan, L2CAP_MC_UNCONFIRMED); | ||
4437 | } | ||
4438 | |||
4439 | l2cap_chan_unlock(chan); | ||
4440 | } | ||
4441 | |||
4442 | static void l2cap_move_fail(struct l2cap_conn *conn, u8 ident, u16 icid, | ||
4443 | u16 result) | ||
4444 | { | ||
4445 | struct l2cap_chan *chan; | ||
4446 | |||
4447 | chan = l2cap_get_chan_by_ident(conn, ident); | ||
4448 | if (!chan) { | ||
4449 | /* Could not locate channel, icid is best guess */ | ||
4450 | l2cap_send_move_chan_cfm_icid(conn, icid); | ||
4451 | return; | ||
4452 | } | ||
4453 | |||
4454 | __clear_chan_timer(chan); | ||
4455 | |||
4456 | if (chan->move_role == L2CAP_MOVE_ROLE_INITIATOR) { | ||
4457 | if (result == L2CAP_MR_COLLISION) { | ||
4458 | chan->move_role = L2CAP_MOVE_ROLE_RESPONDER; | ||
4459 | } else { | ||
4460 | /* Cleanup - cancel move */ | ||
4461 | chan->move_id = chan->local_amp_id; | ||
4462 | l2cap_move_done(chan); | ||
4463 | } | ||
4464 | } | ||
4465 | |||
4466 | l2cap_send_move_chan_cfm(chan, L2CAP_MC_UNCONFIRMED); | ||
4467 | |||
4468 | l2cap_chan_unlock(chan); | ||
4469 | } | ||
4470 | |||
4471 | static int l2cap_move_channel_rsp(struct l2cap_conn *conn, | ||
4472 | struct l2cap_cmd_hdr *cmd, | ||
4473 | u16 cmd_len, void *data) | ||
4323 | { | 4474 | { |
4324 | struct l2cap_move_chan_rsp *rsp = data; | 4475 | struct l2cap_move_chan_rsp *rsp = data; |
4325 | u16 icid, result; | 4476 | u16 icid, result; |
@@ -4332,8 +4483,10 @@ static inline int l2cap_move_channel_rsp(struct l2cap_conn *conn, | |||
4332 | 4483 | ||
4333 | BT_DBG("icid 0x%4.4x, result 0x%4.4x", icid, result); | 4484 | BT_DBG("icid 0x%4.4x, result 0x%4.4x", icid, result); |
4334 | 4485 | ||
4335 | /* Placeholder: Always unconfirmed */ | 4486 | if (result == L2CAP_MR_SUCCESS || result == L2CAP_MR_PEND) |
4336 | l2cap_send_move_chan_cfm(conn, NULL, icid, L2CAP_MC_UNCONFIRMED); | 4487 | l2cap_move_continue(conn, icid, result); |
4488 | else | ||
4489 | l2cap_move_fail(conn, cmd->ident, icid, result); | ||
4337 | 4490 | ||
4338 | return 0; | 4491 | return 0; |
4339 | } | 4492 | } |