From 8166de77db000186dce85509d7c22d8230d9da1c Mon Sep 17 00:00:00 2001 From: Jaganath Kanakkassery Date: Mon, 24 Oct 2016 22:09:27 +0530 Subject: [PATCH] Bluetooth: RFCOMM: Initiate DLC This patch initiate a DLC when user calls connect. It first does Parameter negotiation and then establish connection to the dlci derived from channel given by user. < ACL Data TX: Handle 256 flags 0x00 dlen 18 Channel: 64 len 14 [PSM 3 mode 0] {chan 0} RFCOMM: Unnumbered Info with Header Check (UIH) (0xef) Address: 0x03 cr 1 dlci 0x00 Control: 0xef poll/final 0 Length: 10 FCS: 0x70 MCC Message type: DLC Parameter Negotiation CMD (0x20) Length: 8 dlci 3 frame_type 0 credit_flow 15 pri 0 ack_timer 0 frame_size 30 max_retrans 0 credits 4 > ACL Data RX: Handle 256 flags 0x02 dlen 18 Channel: 64 len 14 [PSM 3 mode 0] {chan 0} RFCOMM: Unnumbered Info with Header Check (UIH) (0xef) Address: 0x01 cr 0 dlci 0x00 Control: 0xef poll/final 0 Length: 10 FCS: 0xaa MCC Message type: DLC Parameter Negotiation RSP (0x20) Length: 8 dlci 3 frame_type 0 credit_flow 14 pri 0 ack_timer 0 frame_size 30 max_retrans 0 credits 7 < ACL Data TX: Handle 256 flags 0x00 dlen 8 Channel: 64 len 4 [PSM 3 mode 0] {chan 0} RFCOMM: Set Async Balance Mode (SABM) (0x2f) Address: 0x0b cr 1 dlci 0x02 Control: 0x3f poll/final 1 Length: 0 FCS: 0x59 > ACL Data RX: Handle 256 flags 0x02 dlen 8 Channel: 64 len 4 [PSM 3 mode 0] {chan 0} RFCOMM: Unnumbered Ack (UA) (0x63) Address: 0x0b cr 1 dlci 0x02 Control: 0x73 poll/final 1 Length: 0 FCS: 0x92 Change-Id: I62a19f624fc4bb89eb9a109a5352fa763c1241d2 Signed-off-by: Jaganath Kanakkassery --- subsys/bluetooth/host/rfcomm.c | 59 +++++++++++++++++++++++-- subsys/bluetooth/host/rfcomm_internal.h | 3 ++ 2 files changed, 58 insertions(+), 4 deletions(-) diff --git a/subsys/bluetooth/host/rfcomm.c b/subsys/bluetooth/host/rfcomm.c index 05e77635aff..6577b92960b 100644 --- a/subsys/bluetooth/host/rfcomm.c +++ b/subsys/bluetooth/host/rfcomm.c @@ -718,14 +718,36 @@ static int rfcomm_send_credit(struct bt_rfcomm_dlc *dlc, uint8_t credits) return bt_l2cap_chan_send(&dlc->session->br_chan.chan, buf); } +static void rfcomm_dlc_start(struct bt_rfcomm_dlc *dlc) +{ + BT_DBG("dlc %p", dlc); + + /* TODO: Need to check Security */ + dlc->mtu = min(dlc->mtu, dlc->session->mtu); + dlc->state = BT_RFCOMM_STATE_CONFIG; + rfcomm_send_pn(dlc, BT_RFCOMM_MSG_CMD_CR); +} + static void rfcomm_handle_ua(struct bt_rfcomm_session *session, uint8_t dlci) { + struct bt_rfcomm_dlc *dlc; + if (!dlci) { if (session->state != BT_RFCOMM_STATE_CONNECTING) { return; } session->state = BT_RFCOMM_STATE_CONNECTED; - /* TODO: STart dlc */ + for (dlc = session->dlcs; dlc; dlc = dlc->_next) { + if (dlc->role == BT_RFCOMM_ROLE_INITIATOR && + dlc->state == BT_RFCOMM_STATE_INIT) { + rfcomm_dlc_start(dlc); + } + } + } else { + dlc = rfcomm_dlcs_lookup_dlci(session->dlcs, dlci); + if (dlc && dlc->state == BT_RFCOMM_STATE_CONNECTING) { + rfcomm_dlc_connected(dlc); + } } } @@ -789,6 +811,15 @@ static void rfcomm_handle_pn(struct bt_rfcomm_session *session, } dlc->mtu = min(dlc->mtu, sys_le16_to_cpu(pn->mtu)); rfcomm_send_pn(dlc, BT_RFCOMM_MSG_RESP_CR); + } else { + if (dlc->state != BT_RFCOMM_STATE_CONFIG) { + return; + } + + dlc->mtu = min(dlc->mtu, sys_le16_to_cpu(pn->mtu)); + rfcomm_dlc_tx_give_credits(dlc, pn->credits); + dlc->state = BT_RFCOMM_STATE_CONNECTING; + rfcomm_send_sabm(session, dlc->dlci); } } } @@ -1066,6 +1097,7 @@ int bt_rfcomm_dlc_connect(struct bt_conn *conn, struct bt_rfcomm_dlc *dlc, { struct bt_rfcomm_session *session; struct bt_l2cap_chan *chan; + uint8_t dlci; int ret; BT_DBG("conn %p dlc %p channel %d", conn, dlc, channel); @@ -1082,6 +1114,10 @@ int bt_rfcomm_dlc_connect(struct bt_conn *conn, struct bt_rfcomm_dlc *dlc, return -EINVAL; } + if (!BT_RFCOMM_CHECK_MTU(dlc->mtu)) { + return -EINVAL; + } + session = rfcomm_sessions_lookup_bt_conn(conn); if (!session) { session = rfcomm_session_new(BT_RFCOMM_ROLE_INITIATOR); @@ -1090,6 +1126,14 @@ int bt_rfcomm_dlc_connect(struct bt_conn *conn, struct bt_rfcomm_dlc *dlc, } } + dlci = BT_RFCOMM_DLCI(session->role, channel); + + if (rfcomm_dlcs_lookup_dlci(session->dlcs, dlci)) { + return -EBUSY; + } + + rfcomm_dlc_init(dlc, session, dlci, BT_RFCOMM_ROLE_INITIATOR); + switch (session->state) { case BT_RFCOMM_STATE_INIT: if (session->role == BT_RFCOMM_ROLE_ACCEPTOR) { @@ -1100,21 +1144,28 @@ int bt_rfcomm_dlc_connect(struct bt_conn *conn, struct bt_rfcomm_dlc *dlc, ret = bt_l2cap_chan_connect(conn, chan, BT_L2CAP_PSM_RFCOMM); if (ret < 0) { session->state = BT_RFCOMM_STATE_IDLE; - return ret; + goto fail; } session->state = BT_RFCOMM_STATE_CONNECTING; break; case BT_RFCOMM_STATE_CONNECTING: break; case BT_RFCOMM_STATE_CONNECTED: - /* TODO: Start dlc */ + rfcomm_dlc_start(dlc); break; default: BT_ERR("Invalid session state %d", session->state); - return -EINVAL; + ret = -EINVAL; + goto fail; } return 0; + +fail: + rfcomm_dlcs_remove_dlci(session->dlcs, dlc->dlci); + dlc->state = BT_RFCOMM_STATE_IDLE; + dlc->session = NULL; + return ret; } static int rfcomm_accept(struct bt_conn *conn, struct bt_l2cap_chan **chan) diff --git a/subsys/bluetooth/host/rfcomm_internal.h b/subsys/bluetooth/host/rfcomm_internal.h index ac358416697..2543d6e66b7 100644 --- a/subsys/bluetooth/host/rfcomm_internal.h +++ b/subsys/bluetooth/host/rfcomm_internal.h @@ -135,6 +135,9 @@ struct bt_rfcomm_msc { #define BT_RFCOMM_MSG_CMD_CR 1 #define BT_RFCOMM_MSG_RESP_CR 0 +#define BT_RFCOMM_DLCI(role, channel) ((((channel) & 0x1f) << 1) | \ + ((role) == BT_RFCOMM_ROLE_ACCEPTOR)) + /* Excluding ext bit */ #define BT_RFCOMM_MAX_LEN_8 127