aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorJohan Hedberg <johan.hedberg@intel.com>2013-05-14 06:27:21 -0400
committerMarcel Holtmann <marcel@holtmann.org>2013-12-05 10:05:33 -0500
commit27e2d4c8d28be1d1b4ecfbffab572d7dbd35254d (patch)
tree08d2b9dd538a3c410cfb2e6648048ae54766a7bc /net
parent791d60f71a8d743df17a5029bb080a24afc4fff6 (diff)
Bluetooth: Add basic LE L2CAP connect request receiving support
This patch adds the necessary boiler plate code to handle receiving L2CAP connect requests over LE and respond to them with a proper connect response. Signed-off-by: Johan Hedberg <johan.hedberg@intel.com> Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
Diffstat (limited to 'net')
-rw-r--r--net/bluetooth/l2cap_core.c152
1 files changed, 152 insertions, 0 deletions
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 5f9287fd86df..d6f518d7e61b 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -617,6 +617,29 @@ void l2cap_chan_del(struct l2cap_chan *chan, int err)
617 return; 617 return;
618} 618}
619 619
620static void l2cap_chan_le_connect_reject(struct l2cap_chan *chan)
621{
622 struct l2cap_conn *conn = chan->conn;
623 struct l2cap_le_conn_rsp rsp;
624 u16 result;
625
626 if (test_bit(FLAG_DEFER_SETUP, &chan->flags))
627 result = L2CAP_CR_AUTHORIZATION;
628 else
629 result = L2CAP_CR_BAD_PSM;
630
631 l2cap_state_change(chan, BT_DISCONN);
632
633 rsp.dcid = cpu_to_le16(chan->scid);
634 rsp.mtu = cpu_to_le16(chan->imtu);
635 rsp.mps = __constant_cpu_to_le16(L2CAP_LE_DEFAULT_MPS);
636 rsp.credits = __constant_cpu_to_le16(L2CAP_LE_MAX_CREDITS);
637 rsp.result = cpu_to_le16(result);
638
639 l2cap_send_cmd(conn, chan->ident, L2CAP_LE_CONN_RSP, sizeof(rsp),
640 &rsp);
641}
642
620static void l2cap_chan_connect_reject(struct l2cap_chan *chan) 643static void l2cap_chan_connect_reject(struct l2cap_chan *chan)
621{ 644{
622 struct l2cap_conn *conn = chan->conn; 645 struct l2cap_conn *conn = chan->conn;
@@ -663,6 +686,8 @@ void l2cap_chan_close(struct l2cap_chan *chan, int reason)
663 if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED) { 686 if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED) {
664 if (conn->hcon->type == ACL_LINK) 687 if (conn->hcon->type == ACL_LINK)
665 l2cap_chan_connect_reject(chan); 688 l2cap_chan_connect_reject(chan);
689 else if (conn->hcon->type == LE_LINK)
690 l2cap_chan_le_connect_reject(chan);
666 } 691 }
667 692
668 l2cap_chan_del(chan, reason); 693 l2cap_chan_del(chan, reason);
@@ -3641,6 +3666,23 @@ static int l2cap_build_conf_rsp(struct l2cap_chan *chan, void *data,
3641 return ptr - data; 3666 return ptr - data;
3642} 3667}
3643 3668
3669void __l2cap_le_connect_rsp_defer(struct l2cap_chan *chan)
3670{
3671 struct l2cap_le_conn_rsp rsp;
3672 struct l2cap_conn *conn = chan->conn;
3673
3674 BT_DBG("chan %p", chan);
3675
3676 rsp.dcid = cpu_to_le16(chan->scid);
3677 rsp.mtu = cpu_to_le16(chan->imtu);
3678 rsp.mps = __constant_cpu_to_le16(L2CAP_LE_DEFAULT_MPS);
3679 rsp.credits = __constant_cpu_to_le16(L2CAP_LE_MAX_CREDITS);
3680 rsp.result = __constant_cpu_to_le16(L2CAP_CR_SUCCESS);
3681
3682 l2cap_send_cmd(conn, chan->ident, L2CAP_LE_CONN_RSP, sizeof(rsp),
3683 &rsp);
3684}
3685
3644void __l2cap_connect_rsp_defer(struct l2cap_chan *chan) 3686void __l2cap_connect_rsp_defer(struct l2cap_chan *chan)
3645{ 3687{
3646 struct l2cap_conn_rsp rsp; 3688 struct l2cap_conn_rsp rsp;
@@ -5382,6 +5424,113 @@ static inline int l2cap_bredr_sig_cmd(struct l2cap_conn *conn,
5382 return err; 5424 return err;
5383} 5425}
5384 5426
5427static int l2cap_le_connect_req(struct l2cap_conn *conn,
5428 struct l2cap_cmd_hdr *cmd, u16 cmd_len,
5429 u8 *data)
5430{
5431 struct l2cap_le_conn_req *req = (struct l2cap_le_conn_req *) data;
5432 struct l2cap_le_conn_rsp rsp;
5433 struct l2cap_chan *chan, *pchan;
5434 u16 dcid, scid, mtu, mps;
5435 __le16 psm;
5436 u8 result;
5437
5438 if (cmd_len != sizeof(*req))
5439 return -EPROTO;
5440
5441 scid = __le16_to_cpu(req->scid);
5442 mtu = __le16_to_cpu(req->mtu);
5443 mps = __le16_to_cpu(req->mps);
5444 psm = req->psm;
5445 dcid = 0;
5446
5447 if (mtu < 23 || mps < 23)
5448 return -EPROTO;
5449
5450 BT_DBG("psm 0x%2.2x scid 0x%4.4x mtu %u mps %u", __le16_to_cpu(psm),
5451 scid, mtu, mps);
5452
5453 /* Check if we have socket listening on psm */
5454 pchan = l2cap_global_chan_by_psm(BT_LISTEN, psm, &conn->hcon->src,
5455 &conn->hcon->dst, LE_LINK);
5456 if (!pchan) {
5457 result = L2CAP_CR_BAD_PSM;
5458 chan = NULL;
5459 goto response;
5460 }
5461
5462 mutex_lock(&conn->chan_lock);
5463 l2cap_chan_lock(pchan);
5464
5465 if (!smp_sufficient_security(conn->hcon, pchan->sec_level)) {
5466 result = L2CAP_CR_AUTHENTICATION;
5467 chan = NULL;
5468 goto response_unlock;
5469 }
5470
5471 /* Check if we already have channel with that dcid */
5472 if (__l2cap_get_chan_by_dcid(conn, scid)) {
5473 result = L2CAP_CR_NO_MEM;
5474 chan = NULL;
5475 goto response_unlock;
5476 }
5477
5478 chan = pchan->ops->new_connection(pchan);
5479 if (!chan) {
5480 result = L2CAP_CR_NO_MEM;
5481 goto response_unlock;
5482 }
5483
5484 bacpy(&chan->src, &conn->hcon->src);
5485 bacpy(&chan->dst, &conn->hcon->dst);
5486 chan->src_type = bdaddr_type(conn->hcon, conn->hcon->src_type);
5487 chan->dst_type = bdaddr_type(conn->hcon, conn->hcon->dst_type);
5488 chan->psm = psm;
5489 chan->dcid = scid;
5490 chan->omtu = mtu;
5491 chan->remote_mps = mps;
5492
5493 __l2cap_chan_add(conn, chan);
5494 dcid = chan->scid;
5495
5496 __set_chan_timer(chan, chan->ops->get_sndtimeo(chan));
5497
5498 chan->ident = cmd->ident;
5499
5500 if (test_bit(FLAG_DEFER_SETUP, &chan->flags)) {
5501 l2cap_state_change(chan, BT_CONNECT2);
5502 result = L2CAP_CR_PEND;
5503 chan->ops->defer(chan);
5504 } else {
5505 l2cap_chan_ready(chan);
5506 result = L2CAP_CR_SUCCESS;
5507 }
5508
5509response_unlock:
5510 l2cap_chan_unlock(pchan);
5511 mutex_unlock(&conn->chan_lock);
5512
5513 if (result == L2CAP_CR_PEND)
5514 return 0;
5515
5516response:
5517 if (chan) {
5518 rsp.mtu = cpu_to_le16(chan->imtu);
5519 rsp.mps = __constant_cpu_to_le16(L2CAP_LE_DEFAULT_MPS);
5520 } else {
5521 rsp.mtu = 0;
5522 rsp.mps = 0;
5523 }
5524
5525 rsp.dcid = cpu_to_le16(dcid);
5526 rsp.credits = __constant_cpu_to_le16(L2CAP_LE_MAX_CREDITS);
5527 rsp.result = cpu_to_le16(result);
5528
5529 l2cap_send_cmd(conn, cmd->ident, L2CAP_LE_CONN_RSP, sizeof(rsp), &rsp);
5530
5531 return 0;
5532}
5533
5385static inline int l2cap_le_sig_cmd(struct l2cap_conn *conn, 5534static inline int l2cap_le_sig_cmd(struct l2cap_conn *conn,
5386 struct l2cap_cmd_hdr *cmd, u16 cmd_len, 5535 struct l2cap_cmd_hdr *cmd, u16 cmd_len,
5387 u8 *data) 5536 u8 *data)
@@ -5400,6 +5549,9 @@ static inline int l2cap_le_sig_cmd(struct l2cap_conn *conn,
5400 l2cap_le_connect_rsp(conn, cmd, cmd_len, data); 5549 l2cap_le_connect_rsp(conn, cmd, cmd_len, data);
5401 return 0; 5550 return 0;
5402 5551
5552 case L2CAP_LE_CONN_REQ:
5553 return l2cap_le_connect_req(conn, cmd, cmd_len, data);
5554
5403 default: 5555 default:
5404 BT_ERR("Unknown LE signaling command 0x%2.2x", cmd->code); 5556 BT_ERR("Unknown LE signaling command 0x%2.2x", cmd->code);
5405 return -EINVAL; 5557 return -EINVAL;