aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMat Martineau <mathewm@codeaurora.org>2012-10-23 18:24:15 -0400
committerGustavo Padovan <gustavo.padovan@collabora.co.uk>2012-10-23 22:21:41 -0400
commit1500109bbc6cc42ec6c8445f1cf04d25fa54a57b (patch)
treeb9cc56660249c438ed56e3b284642bc230f72ff4
parent5b155ef960202b20a5cae43b9e675f4326e2375c (diff)
Bluetooth: Add logical link confirm
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 completed after the logical link is set up. 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>
-rw-r--r--net/bluetooth/l2cap_core.c134
1 files changed, 123 insertions, 11 deletions
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 2277ed504283..4d240c23e9dc 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -3787,6 +3787,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn,
3787 goto unlock; 3787 goto unlock;
3788 } 3788 }
3789 3789
3790 chan->ident = cmd->ident;
3790 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP, len, rsp); 3791 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP, len, rsp);
3791 chan->num_conf_rsp++; 3792 chan->num_conf_rsp++;
3792 3793
@@ -4186,17 +4187,17 @@ static int l2cap_create_channel_req(struct l2cap_conn *conn,
4186 return 0; 4187 return 0;
4187} 4188}
4188 4189
4189static void l2cap_send_move_chan_rsp(struct l2cap_conn *conn, u8 ident, 4190static void l2cap_send_move_chan_rsp(struct l2cap_chan *chan, u16 result)
4190 u16 icid, u16 result)
4191{ 4191{
4192 struct l2cap_move_chan_rsp rsp; 4192 struct l2cap_move_chan_rsp rsp;
4193 4193
4194 BT_DBG("icid 0x%4.4x, result 0x%4.4x", icid, result); 4194 BT_DBG("chan %p, result 0x%4.4x", chan, result);
4195 4195
4196 rsp.icid = cpu_to_le16(icid); 4196 rsp.icid = cpu_to_le16(chan->dcid);
4197 rsp.result = cpu_to_le16(result); 4197 rsp.result = cpu_to_le16(result);
4198 4198
4199 l2cap_send_cmd(conn, ident, L2CAP_MOVE_CHAN_RSP, sizeof(rsp), &rsp); 4199 l2cap_send_cmd(chan->conn, chan->ident, L2CAP_MOVE_CHAN_RSP,
4200 sizeof(rsp), &rsp);
4200} 4201}
4201 4202
4202static void l2cap_send_move_chan_cfm(struct l2cap_chan *chan, u16 result) 4203static void l2cap_send_move_chan_cfm(struct l2cap_chan *chan, u16 result)
@@ -4248,11 +4249,118 @@ static void __release_logical_link(struct l2cap_chan *chan)
4248 /* Placeholder - release the logical link */ 4249 /* Placeholder - release the logical link */
4249} 4250}
4250 4251
4252static void l2cap_logical_fail(struct l2cap_chan *chan)
4253{
4254 /* Logical link setup failed */
4255 if (chan->state != BT_CONNECTED) {
4256 /* Create channel failure, disconnect */
4257 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
4258 return;
4259 }
4260
4261 switch (chan->move_role) {
4262 case L2CAP_MOVE_ROLE_RESPONDER:
4263 l2cap_move_done(chan);
4264 l2cap_send_move_chan_rsp(chan, L2CAP_MR_NOT_SUPP);
4265 break;
4266 case L2CAP_MOVE_ROLE_INITIATOR:
4267 if (chan->move_state == L2CAP_MOVE_WAIT_LOGICAL_COMP ||
4268 chan->move_state == L2CAP_MOVE_WAIT_LOGICAL_CFM) {
4269 /* Remote has only sent pending or
4270 * success responses, clean up
4271 */
4272 l2cap_move_done(chan);
4273 }
4274
4275 /* Other amp move states imply that the move
4276 * has already aborted
4277 */
4278 l2cap_send_move_chan_cfm(chan, L2CAP_MC_UNCONFIRMED);
4279 break;
4280 }
4281}
4282
4283static void l2cap_logical_finish_create(struct l2cap_chan *chan,
4284 struct hci_chan *hchan)
4285{
4286 struct l2cap_conf_rsp rsp;
4287 u8 code;
4288
4289 chan->hs_hcon = hchan->conn;
4290 chan->hs_hcon->l2cap_data = chan->conn;
4291
4292 code = l2cap_build_conf_rsp(chan, &rsp,
4293 L2CAP_CONF_SUCCESS, 0);
4294 l2cap_send_cmd(chan->conn, chan->ident, L2CAP_CONF_RSP, code,
4295 &rsp);
4296 set_bit(CONF_OUTPUT_DONE, &chan->conf_state);
4297
4298 if (test_bit(CONF_INPUT_DONE, &chan->conf_state)) {
4299 int err = 0;
4300
4301 set_default_fcs(chan);
4302
4303 err = l2cap_ertm_init(chan);
4304 if (err < 0)
4305 l2cap_send_disconn_req(chan->conn, chan, -err);
4306 else
4307 l2cap_chan_ready(chan);
4308 }
4309}
4310
4311static void l2cap_logical_finish_move(struct l2cap_chan *chan,
4312 struct hci_chan *hchan)
4313{
4314 chan->hs_hcon = hchan->conn;
4315 chan->hs_hcon->l2cap_data = chan->conn;
4316
4317 BT_DBG("move_state %d", chan->move_state);
4318
4319 switch (chan->move_state) {
4320 case L2CAP_MOVE_WAIT_LOGICAL_COMP:
4321 /* Move confirm will be sent after a success
4322 * response is received
4323 */
4324 chan->move_state = L2CAP_MOVE_WAIT_RSP_SUCCESS;
4325 break;
4326 case L2CAP_MOVE_WAIT_LOGICAL_CFM:
4327 if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
4328 chan->move_state = L2CAP_MOVE_WAIT_LOCAL_BUSY;
4329 } else if (chan->move_role == L2CAP_MOVE_ROLE_INITIATOR) {
4330 chan->move_state = L2CAP_MOVE_WAIT_CONFIRM_RSP;
4331 l2cap_send_move_chan_cfm(chan, L2CAP_MC_CONFIRMED);
4332 } else if (chan->move_role == L2CAP_MOVE_ROLE_RESPONDER) {
4333 chan->move_state = L2CAP_MOVE_WAIT_CONFIRM;
4334 l2cap_send_move_chan_rsp(chan, L2CAP_MR_SUCCESS);
4335 }
4336 break;
4337 default:
4338 /* Move was not in expected state, free the channel */
4339 __release_logical_link(chan);
4340
4341 chan->move_state = L2CAP_MOVE_STABLE;
4342 }
4343}
4344
4345/* Call with chan locked */
4251static void l2cap_logical_cfm(struct l2cap_chan *chan, struct hci_chan *hchan, 4346static void l2cap_logical_cfm(struct l2cap_chan *chan, struct hci_chan *hchan,
4252 u8 status) 4347 u8 status)
4253{ 4348{
4254 /* Placeholder */ 4349 BT_DBG("chan %p, hchan %p, status %d", chan, hchan, status);
4255 return; 4350
4351 if (status) {
4352 l2cap_logical_fail(chan);
4353 __release_logical_link(chan);
4354 return;
4355 }
4356
4357 if (chan->state != BT_CONNECTED) {
4358 /* Ignore logical link if channel is on BR/EDR */
4359 if (chan->local_amp_id)
4360 l2cap_logical_finish_create(chan, hchan);
4361 } else {
4362 l2cap_logical_finish_move(chan, hchan);
4363 }
4256} 4364}
4257 4365
4258static inline int l2cap_move_channel_req(struct l2cap_conn *conn, 4366static inline int l2cap_move_channel_req(struct l2cap_conn *conn,
@@ -4260,6 +4368,7 @@ static inline int l2cap_move_channel_req(struct l2cap_conn *conn,
4260 u16 cmd_len, void *data) 4368 u16 cmd_len, void *data)
4261{ 4369{
4262 struct l2cap_move_chan_req *req = data; 4370 struct l2cap_move_chan_req *req = data;
4371 struct l2cap_move_chan_rsp rsp;
4263 struct l2cap_chan *chan; 4372 struct l2cap_chan *chan;
4264 u16 icid = 0; 4373 u16 icid = 0;
4265 u16 result = L2CAP_MR_NOT_ALLOWED; 4374 u16 result = L2CAP_MR_NOT_ALLOWED;
@@ -4276,11 +4385,15 @@ static inline int l2cap_move_channel_req(struct l2cap_conn *conn,
4276 4385
4277 chan = l2cap_get_chan_by_dcid(conn, icid); 4386 chan = l2cap_get_chan_by_dcid(conn, icid);
4278 if (!chan) { 4387 if (!chan) {
4279 l2cap_send_move_chan_rsp(conn, cmd->ident, icid, 4388 rsp.icid = cpu_to_le16(icid);
4280 L2CAP_MR_NOT_ALLOWED); 4389 rsp.result = __constant_cpu_to_le16(L2CAP_MR_NOT_ALLOWED);
4390 l2cap_send_cmd(conn, cmd->ident, L2CAP_MOVE_CHAN_RSP,
4391 sizeof(rsp), &rsp);
4281 return 0; 4392 return 0;
4282 } 4393 }
4283 4394
4395 chan->ident = cmd->ident;
4396
4284 if (chan->scid < L2CAP_CID_DYN_START || 4397 if (chan->scid < L2CAP_CID_DYN_START ||
4285 chan->chan_policy == BT_CHANNEL_POLICY_BREDR_ONLY || 4398 chan->chan_policy == BT_CHANNEL_POLICY_BREDR_ONLY ||
4286 (chan->mode != L2CAP_MODE_ERTM && 4399 (chan->mode != L2CAP_MODE_ERTM &&
@@ -4319,7 +4432,6 @@ static inline int l2cap_move_channel_req(struct l2cap_conn *conn,
4319 goto send_move_response; 4432 goto send_move_response;
4320 } 4433 }
4321 4434
4322 chan->ident = cmd->ident;
4323 chan->move_role = L2CAP_MOVE_ROLE_RESPONDER; 4435 chan->move_role = L2CAP_MOVE_ROLE_RESPONDER;
4324 l2cap_move_setup(chan); 4436 l2cap_move_setup(chan);
4325 chan->move_id = req->dest_amp_id; 4437 chan->move_id = req->dest_amp_id;
@@ -4342,7 +4454,7 @@ static inline int l2cap_move_channel_req(struct l2cap_conn *conn,
4342 } 4454 }
4343 4455
4344send_move_response: 4456send_move_response:
4345 l2cap_send_move_chan_rsp(conn, cmd->ident, icid, result); 4457 l2cap_send_move_chan_rsp(chan, result);
4346 4458
4347 l2cap_chan_unlock(chan); 4459 l2cap_chan_unlock(chan);
4348 4460