aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorMat Martineau <mathewm@codeaurora.org>2012-10-23 18:24:14 -0400
committerGustavo Padovan <gustavo.padovan@collabora.co.uk>2012-10-23 22:20:54 -0400
commit5b155ef960202b20a5cae43b9e675f4326e2375c (patch)
tree57100cad151ef8e532a11d8b684ded0efc3f8cbf /net
parent168df8e57e7c1afce3f86a86ae106f82ff7c18d8 (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.c183
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
132static 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
132static struct l2cap_chan *__l2cap_global_chan_by_addr(__le16 psm, bdaddr_t *src) 146static 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
4188static void l2cap_send_move_chan_cfm(struct l2cap_conn *conn, 4202static 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
4219static 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
4207static void l2cap_send_move_chan_cfm_rsp(struct l2cap_conn *conn, u8 ident, 4232static 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
4251static void l2cap_logical_cfm(struct l2cap_chan *chan, struct hci_chan *hchan,
4252 u8 status)
4253{
4254 /* Placeholder */
4255 return;
4256}
4257
4226static inline int l2cap_move_channel_req(struct l2cap_conn *conn, 4258static 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
4320static inline int l2cap_move_channel_rsp(struct l2cap_conn *conn, 4352static 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
4442static 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
4471static 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}