Bluetooth: RFCOMM: Disconnect session after last dlc disconnection

As per the spec the station which disconnects last dlc should initiate
session disconnection and then l2cap disconnection.

< ACL Data TX: Handle 256 flags 0x00 dlen 8
      Channel: 64 len 4 [PSM 3 mode 0] {chan 0}
      RFCOMM: Disconnect (DISC) (0x43)
         Address: 0x03 cr 1 dlci 0x00
         Control: 0x53 poll/final 1
         Length: 0
         FCS: 0xfd

> 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: 0x01 cr 0 dlci 0x00
         Control: 0x73 poll/final 1
         Length: 0
         FCS: 0xb6

Change-Id: I2d1d7d284995529d5d1522e0ca6082097db19bc2
Signed-off-by: Jaganath Kanakkassery <jaganathx.kanakkassery@intel.com>
This commit is contained in:
Jaganath Kanakkassery 2016-11-25 18:07:46 +05:30 committed by Johan Hedberg
commit a95de4360c

View file

@ -804,23 +804,46 @@ static int rfcomm_dlc_start(struct bt_rfcomm_dlc *dlc)
return 0;
}
static void rfcomm_session_disconnect(struct bt_rfcomm_session *session)
{
if (session->dlcs) {
return;
}
session->state = BT_RFCOMM_STATE_DISCONNECTING;
rfcomm_send_disc(session, 0);
}
static void rfcomm_handle_ua(struct bt_rfcomm_session *session, uint8_t dlci)
{
struct bt_rfcomm_dlc *dlc, *tmp;
int err;
if (!dlci) {
if (session->state != BT_RFCOMM_STATE_CONNECTING) {
return;
}
session->state = BT_RFCOMM_STATE_CONNECTED;
for (dlc = session->dlcs; dlc; dlc = tmp) {
tmp = dlc->_next;
if (dlc->role == BT_RFCOMM_ROLE_INITIATOR &&
dlc->state == BT_RFCOMM_STATE_INIT) {
if (rfcomm_dlc_start(dlc) < 0) {
rfcomm_dlc_drop(dlc);
switch (session->state) {
case BT_RFCOMM_STATE_CONNECTING:
session->state = BT_RFCOMM_STATE_CONNECTED;
for (dlc = session->dlcs; dlc; dlc = tmp) {
tmp = dlc->_next;
if (dlc->role == BT_RFCOMM_ROLE_INITIATOR &&
dlc->state == BT_RFCOMM_STATE_INIT) {
if (rfcomm_dlc_start(dlc) < 0) {
rfcomm_dlc_drop(dlc);
}
}
}
/* Disconnect session if there is no dlcs left */
rfcomm_session_disconnect(session);
break;
case BT_RFCOMM_STATE_DISCONNECTING:
session->state = BT_RFCOMM_STATE_DISCONNECTED;
err = bt_l2cap_chan_disconnect(&session->br_chan.chan);
if (err < 0) {
session->state = BT_RFCOMM_STATE_IDLE;
}
break;
default:
break;
}
} else {
dlc = rfcomm_dlcs_lookup_dlci(session->dlcs, dlci);
@ -834,6 +857,7 @@ static void rfcomm_handle_ua(struct bt_rfcomm_session *session, uint8_t dlci)
break;
case BT_RFCOMM_STATE_DISCONNECTING:
rfcomm_dlc_drop(dlc);
rfcomm_session_disconnect(session);
break;
default:
break;