aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/net/bluetooth/l2cap.h2
-rw-r--r--net/bluetooth/l2cap_core.c183
2 files changed, 170 insertions, 15 deletions
diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index 6d3615eed97c..b4c3c65c1f58 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -52,6 +52,8 @@
52#define L2CAP_ENC_TIMEOUT msecs_to_jiffies(5000) 52#define L2CAP_ENC_TIMEOUT msecs_to_jiffies(5000)
53#define L2CAP_CONN_TIMEOUT msecs_to_jiffies(40000) 53#define L2CAP_CONN_TIMEOUT msecs_to_jiffies(40000)
54#define L2CAP_INFO_TIMEOUT msecs_to_jiffies(4000) 54#define L2CAP_INFO_TIMEOUT msecs_to_jiffies(4000)
55#define L2CAP_MOVE_TIMEOUT msecs_to_jiffies(4000)
56#define L2CAP_MOVE_ERTX_TIMEOUT msecs_to_jiffies(60000)
55 57
56#define L2CAP_A2MP_DEFAULT_MTU 670 58#define L2CAP_A2MP_DEFAULT_MTU 670
57 59
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}