Bluetooth: RFCOMM: Handle data and credit from peer

Data is transferred in UIH frame to a valid dlci. In this case the
meaning of PF bit is different, if PF bit is 1 then credit is there
in the frame otherwise no credit (only user data). So basically UIH
frame to a valid dlci can be "Only data, Only credit, both credit and
data"

Only credit
> ACL Data RX: Handle 256 flags 0x02 dlen 9
      Channel: 64 len 5 [PSM 3 mode 0] {chan 0}
      RFCOMM: Unnumbered Info with Header Check (UIH) (0xef)
         Address: 0x0b cr 1 dlci 0x02
         Control: 0xff poll/final 1
         Length: 0
         FCS: 0x86
         Credits: 33
        86

Only data
> ACL Data RX: Handle 256 flags 0x02 dlen 9
      Channel: 64 len 5 [PSM 3 mode 0] {chan 0}
      RFCOMM: Unnumbered Info with Header Check (UIH) (0xef)
         Address: 0x0b cr 1 dlci 0x02
         Control: 0xef poll/final 0
         Length: 1
         FCS: 0x9a
        ff 9a

Change-Id: Iaa48f9aa022f33e1a1217f19dc59ce761cfeac74
Signed-off-by: Jaganath Kanakkassery <jaganathx.kanakkassery@intel.com>
This commit is contained in:
Jaganath Kanakkassery 2016-08-22 20:52:06 +05:30 committed by Johan Hedberg
commit 407013f3c7
2 changed files with 49 additions and 0 deletions

View file

@ -460,6 +460,48 @@ static void rfcomm_handle_msg(struct bt_rfcomm_session *session,
}
}
static void rfcomm_handle_data(struct bt_rfcomm_session *session,
struct net_buf *buf, uint8_t dlci, uint8_t pf)
{
struct bt_rfcomm_dlc *dlc;
BT_DBG("dlci %d, pf %d", dlci, pf);
dlc = rfcomm_dlcs_lookup_dlci(session->dlcs, dlci);
if (!dlc) {
BT_ERR("Data recvd in non existing DLC");
return;
}
BT_DBG("dlc %p rx credit %d", dlc, dlc->rx_credit);
if (dlc->state != BT_RFCOMM_STATE_CONNECTED) {
return;
}
if (!dlc->rx_credit) {
BT_ERR("Data recvd when rx credit is 0");
/* Disconnect */
return;
}
if (pf == BT_RFCOMM_PF_CREDIT) {
/* TODO: Modify it to semaphore */
dlc->tx_credit += net_buf_pull_u8(buf);
BT_DBG("updated tx credit %d", dlc->tx_credit);
}
if (buf->len > BT_RFCOMM_FCS_SIZE) {
/* Remove FCS */
buf->len -= BT_RFCOMM_FCS_SIZE;
if (dlc->ops && dlc->ops->recv) {
dlc->ops->recv(dlc, buf);
}
dlc->rx_credit--;
}
}
static void rfcomm_recv(struct bt_l2cap_chan *chan, struct net_buf *buf)
{
struct bt_rfcomm_session *session = RFCOMM_SESSION(chan);
@ -498,6 +540,9 @@ static void rfcomm_recv(struct bt_l2cap_chan *chan, struct net_buf *buf)
case BT_RFCOMM_UIH:
if (!dlci) {
rfcomm_handle_msg(session, buf);
} else {
rfcomm_handle_data(session, buf, dlci,
BT_RFCOMM_GET_PF(hdr->control));
}
break;
default:

View file

@ -90,6 +90,7 @@ struct bt_rfcomm_msc {
#define BT_RFCOMM_GET_MSG_CR(type) (((type) & 0x02) >> 1)
#define BT_RFCOMM_GET_LEN(len) (((len) & 0xfe) >> 1)
#define BT_RFCOMM_GET_CHANNEL(dlci) ((dlci) >> 1)
#define BT_RFCOMM_GET_PF(ctrl) (((ctrl) & 0x10) >> 4)
#define BT_RFCOMM_SET_ADDR(dlci, cr) ((((dlci) & 0x3f) << 2) | \
((cr) << 1) | 0x01)
@ -109,5 +110,8 @@ struct bt_rfcomm_msc {
#define BT_RFCOMM_FCS_LEN_UIH 2
#define BT_RFCOMM_FCS_LEN_NON_UIH 3
#define BT_RFCOMM_PF_CREDIT 1
#define BT_RFCOMM_PF_NO_CREDIT 0
/* Initialize RFCOMM signal layer */
void bt_rfcomm_init(void);