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 <jaganathx.kanakkassery@intel.com>
This commit is contained in:
Jaganath Kanakkassery 2016-10-24 22:09:27 +05:30
commit 8166de77db
2 changed files with 58 additions and 4 deletions

View file

@ -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)

View file

@ -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