Bluetooth: RFCOMM: Handle signalling connection request
Handles the SABM request to dlci 0 and sends UA response which makes session state as CONNECTED. Session mtu is set as min of l2cap tx and rx mtu since in rfcomm mtu is symmetric (unlike L2CAP). This means that mtu of all the dlcs should be less than or equal to its session mtu so that each rfcomm frame can be contained in single l2cap pdu. > ACL Data RX: Handle 256 flags 0x02 dlen 8 [hci0] 210.078442 Channel: 64 len 4 [PSM 3 mode 0] {chan 0} RFCOMM: Set Async Balance Mode (SABM) (0x2f) Address: 0x03 cr 1 dlci 0x00 Control: 0x3f poll/final 1 Length: 0 FCS: 0x1c < ACL Data TX: Handle 256 flags 0x00 dlen 8 [hci0] 210.080586 Channel: 64 len 4 [PSM 3 mode 0] {chan 0} RFCOMM: Unnumbered Ack (UA) (0x63) Address: 0x03 cr 1 dlci 0x00 Control: 0x73 poll/final 1 Length: 0 FCS: 0xd7 This also inntroduces table and functions to calculate and check FCS. These are taken from GSM 07.10 TS 101 369 V6.5.0 Change-Id: Ief5822b7f9350f50e700ff4f460c818a5a1068b7 Signed-off-by: Jaganath Kanakkassery <jaganathx.kanakkassery@intel.com>
This commit is contained in:
parent
a816142687
commit
7eec8a4442
2 changed files with 176 additions and 2 deletions
|
@ -62,6 +62,77 @@ static NET_BUF_POOL(rfcomm_session_pool, CONFIG_BLUETOOTH_MAX_CONN,
|
|||
|
||||
static struct bt_rfcomm_session bt_rfcomm_pool[CONFIG_BLUETOOTH_MAX_CONN];
|
||||
|
||||
/* reversed, 8-bit, poly=0x07 */
|
||||
static const uint8_t rfcomm_crc_table[256] = {
|
||||
0x00, 0x91, 0xe3, 0x72, 0x07, 0x96, 0xe4, 0x75,
|
||||
0x0e, 0x9f, 0xed, 0x7c, 0x09, 0x98, 0xea, 0x7b,
|
||||
0x1c, 0x8d, 0xff, 0x6e, 0x1b, 0x8a, 0xf8, 0x69,
|
||||
0x12, 0x83, 0xf1, 0x60, 0x15, 0x84, 0xf6, 0x67,
|
||||
|
||||
0x38, 0xa9, 0xdb, 0x4a, 0x3f, 0xae, 0xdc, 0x4d,
|
||||
0x36, 0xa7, 0xd5, 0x44, 0x31, 0xa0, 0xd2, 0x43,
|
||||
0x24, 0xb5, 0xc7, 0x56, 0x23, 0xb2, 0xc0, 0x51,
|
||||
0x2a, 0xbb, 0xc9, 0x58, 0x2d, 0xbc, 0xce, 0x5f,
|
||||
|
||||
0x70, 0xe1, 0x93, 0x02, 0x77, 0xe6, 0x94, 0x05,
|
||||
0x7e, 0xef, 0x9d, 0x0c, 0x79, 0xe8, 0x9a, 0x0b,
|
||||
0x6c, 0xfd, 0x8f, 0x1e, 0x6b, 0xfa, 0x88, 0x19,
|
||||
0x62, 0xf3, 0x81, 0x10, 0x65, 0xf4, 0x86, 0x17,
|
||||
|
||||
0x48, 0xd9, 0xab, 0x3a, 0x4f, 0xde, 0xac, 0x3d,
|
||||
0x46, 0xd7, 0xa5, 0x34, 0x41, 0xd0, 0xa2, 0x33,
|
||||
0x54, 0xc5, 0xb7, 0x26, 0x53, 0xc2, 0xb0, 0x21,
|
||||
0x5a, 0xcb, 0xb9, 0x28, 0x5d, 0xcc, 0xbe, 0x2f,
|
||||
|
||||
0xe0, 0x71, 0x03, 0x92, 0xe7, 0x76, 0x04, 0x95,
|
||||
0xee, 0x7f, 0x0d, 0x9c, 0xe9, 0x78, 0x0a, 0x9b,
|
||||
0xfc, 0x6d, 0x1f, 0x8e, 0xfb, 0x6a, 0x18, 0x89,
|
||||
0xf2, 0x63, 0x11, 0x80, 0xf5, 0x64, 0x16, 0x87,
|
||||
|
||||
0xd8, 0x49, 0x3b, 0xaa, 0xdf, 0x4e, 0x3c, 0xad,
|
||||
0xd6, 0x47, 0x35, 0xa4, 0xd1, 0x40, 0x32, 0xa3,
|
||||
0xc4, 0x55, 0x27, 0xb6, 0xc3, 0x52, 0x20, 0xb1,
|
||||
0xca, 0x5b, 0x29, 0xb8, 0xcd, 0x5c, 0x2e, 0xbf,
|
||||
|
||||
0x90, 0x01, 0x73, 0xe2, 0x97, 0x06, 0x74, 0xe5,
|
||||
0x9e, 0x0f, 0x7d, 0xec, 0x99, 0x08, 0x7a, 0xeb,
|
||||
0x8c, 0x1d, 0x6f, 0xfe, 0x8b, 0x1a, 0x68, 0xf9,
|
||||
0x82, 0x13, 0x61, 0xf0, 0x85, 0x14, 0x66, 0xf7,
|
||||
|
||||
0xa8, 0x39, 0x4b, 0xda, 0xaf, 0x3e, 0x4c, 0xdd,
|
||||
0xa6, 0x37, 0x45, 0xd4, 0xa1, 0x30, 0x42, 0xd3,
|
||||
0xb4, 0x25, 0x57, 0xc6, 0xb3, 0x22, 0x50, 0xc1,
|
||||
0xba, 0x2b, 0x59, 0xc8, 0xbd, 0x2c, 0x5e, 0xcf
|
||||
};
|
||||
|
||||
static uint8_t rfcomm_calc_fcs(uint16_t len, const uint8_t *data)
|
||||
{
|
||||
uint8_t fcs = 0xff;
|
||||
|
||||
while (len--) {
|
||||
fcs = rfcomm_crc_table[fcs ^ *data++];
|
||||
}
|
||||
|
||||
/* Ones compliment */
|
||||
return (0xff - fcs);
|
||||
}
|
||||
|
||||
static bool rfcomm_check_fcs(uint16_t len, const uint8_t *data,
|
||||
uint8_t recvd_fcs)
|
||||
{
|
||||
uint8_t fcs = 0xff;
|
||||
|
||||
while (len--) {
|
||||
fcs = rfcomm_crc_table[fcs ^ *data++];
|
||||
}
|
||||
|
||||
/* Ones compliment */
|
||||
fcs = rfcomm_crc_table[fcs ^ recvd_fcs];
|
||||
|
||||
/*0xCF is the reversed order of 11110011.*/
|
||||
return (fcs == 0xcf);
|
||||
}
|
||||
|
||||
static struct bt_rfcomm_server *rfcomm_server_lookup_channel(uint8_t channel)
|
||||
{
|
||||
struct bt_rfcomm_server *server;
|
||||
|
@ -98,7 +169,14 @@ int bt_rfcomm_server_register(struct bt_rfcomm_server *server)
|
|||
|
||||
static void rfcomm_connected(struct bt_l2cap_chan *chan)
|
||||
{
|
||||
BT_DBG("Session %p", RFCOMM_SESSION(chan));
|
||||
struct bt_rfcomm_session *session = RFCOMM_SESSION(chan);
|
||||
|
||||
BT_DBG("Session %p", session);
|
||||
|
||||
/* Need to include UIH header and FCS*/
|
||||
session->mtu = min(session->br_chan.rx.mtu,
|
||||
session->br_chan.tx.mtu) -
|
||||
BT_RFCOMM_HDR_SIZE + BT_RFCOMM_FCS_SIZE;
|
||||
}
|
||||
|
||||
static void rfcomm_disconnected(struct bt_l2cap_chan *chan)
|
||||
|
@ -106,8 +184,77 @@ static void rfcomm_disconnected(struct bt_l2cap_chan *chan)
|
|||
BT_DBG("Session %p", RFCOMM_SESSION(chan));
|
||||
}
|
||||
|
||||
static int rfcomm_send_ua(struct bt_rfcomm_session *session, uint8_t dlci)
|
||||
{
|
||||
struct bt_rfcomm_hdr *hdr;
|
||||
struct net_buf *buf;
|
||||
uint8_t cr, fcs;
|
||||
|
||||
buf = bt_l2cap_create_pdu(&rfcomm_session);
|
||||
if (!buf) {
|
||||
BT_ERR("No buffers");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
hdr = net_buf_add(buf, sizeof(*hdr));
|
||||
cr = session->initiator ? 0 : 1;
|
||||
hdr->address = BT_RFCOMM_SET_ADDR(dlci, cr);
|
||||
hdr->control = BT_RFCOMM_SET_CTRL(BT_RFCOMM_UA, 1);
|
||||
hdr->length = BT_RFCOMM_SET_LEN_8(0);
|
||||
|
||||
fcs = rfcomm_calc_fcs(BT_RFCOMM_FCS_LEN_NON_UIH, buf->data);
|
||||
net_buf_add_u8(buf, fcs);
|
||||
|
||||
return bt_l2cap_chan_send(&session->br_chan.chan, buf);
|
||||
}
|
||||
|
||||
static void rfcomm_handle_sabm(struct bt_rfcomm_session *session, uint8_t dlci)
|
||||
{
|
||||
if (!dlci) {
|
||||
session->initiator = false;
|
||||
|
||||
if (rfcomm_send_ua(session, dlci) < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
session->state = BT_RFCOMM_STATE_CONNECTED;
|
||||
}
|
||||
}
|
||||
|
||||
static void rfcomm_recv(struct bt_l2cap_chan *chan, struct net_buf *buf)
|
||||
{
|
||||
struct bt_rfcomm_session *session = RFCOMM_SESSION(chan);
|
||||
struct bt_rfcomm_hdr *hdr = (void *)buf->data;
|
||||
uint8_t dlci, frame_type, fcs, fcs_len;
|
||||
|
||||
/* Need to consider FCS also*/
|
||||
if (buf->len < (sizeof(*hdr) + 1)) {
|
||||
BT_ERR("Too small RFCOMM Frame");
|
||||
return;
|
||||
}
|
||||
|
||||
dlci = BT_RFCOMM_GET_DLCI(hdr->address);
|
||||
frame_type = BT_RFCOMM_GET_FRAME_TYPE(hdr->control);
|
||||
|
||||
BT_DBG("session %p dlci %x type %x", session, dlci, frame_type);
|
||||
|
||||
fcs_len = (frame_type == BT_RFCOMM_UIH) ? BT_RFCOMM_FCS_LEN_UIH :
|
||||
BT_RFCOMM_FCS_LEN_NON_UIH;
|
||||
fcs = *(net_buf_tail(buf) - 1);
|
||||
if (!rfcomm_check_fcs(fcs_len, buf->data, fcs)) {
|
||||
BT_ERR("FCS check failed");
|
||||
return;
|
||||
}
|
||||
|
||||
switch (frame_type) {
|
||||
case BT_RFCOMM_SABM:
|
||||
rfcomm_handle_sabm(session, dlci);
|
||||
break;
|
||||
default:
|
||||
BT_WARN("Unknown/Unsupported RFCOMM Frame type 0x%02x",
|
||||
frame_type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int rfcomm_accept(struct bt_conn *conn, struct bt_l2cap_chan **chan)
|
||||
|
|
|
@ -25,12 +25,15 @@ struct bt_rfcomm_session {
|
|||
/* L2CAP channel this context is associated with */
|
||||
struct bt_l2cap_br_chan br_chan;
|
||||
struct bt_rfcomm_dlc *dlcs;
|
||||
uint16_t mtu;
|
||||
uint8_t state;
|
||||
bool initiator;
|
||||
};
|
||||
|
||||
enum {
|
||||
BT_RFCOMM_STATE_IDLE,
|
||||
BT_RFCOMM_STATE_INIT,
|
||||
BT_RFCOMM_STATE_CONNECTED,
|
||||
};
|
||||
|
||||
struct bt_rfcomm_hdr {
|
||||
|
@ -39,7 +42,16 @@ struct bt_rfcomm_hdr {
|
|||
uint8_t length;
|
||||
} __packed;
|
||||
|
||||
#define BT_RFCOMM_SIG_MIN_MTU 23
|
||||
#define BT_RFCOMM_SABM 0x2f
|
||||
#define BT_RFCOMM_UA 0x63
|
||||
#define BT_RFCOMM_UIH 0xef
|
||||
|
||||
struct bt_rfcomm_msg_hdr {
|
||||
uint8_t type;
|
||||
uint8_t len;
|
||||
} __packed;
|
||||
|
||||
#define BT_RFCOMM_SIG_MIN_MTU 23
|
||||
|
||||
/* Helper to calculate needed outgoing buffer size */
|
||||
#define BT_RFCOMM_BUF_SIZE(mtu) (CONFIG_BLUETOOTH_HCI_SEND_RESERVE + \
|
||||
|
@ -47,5 +59,20 @@ struct bt_rfcomm_hdr {
|
|||
sizeof(struct bt_l2cap_hdr) + \
|
||||
sizeof(struct bt_rfcomm_hdr) + (mtu))
|
||||
|
||||
#define BT_RFCOMM_GET_DLCI(addr) (((addr) & 0xfc) >> 2)
|
||||
#define BT_RFCOMM_GET_FRAME_TYPE(ctrl) ((ctrl) & 0xef)
|
||||
|
||||
#define BT_RFCOMM_SET_ADDR(dlci, cr) ((((dlci) & 0x3f) << 2) | \
|
||||
((cr) << 1) | 0x01)
|
||||
#define BT_RFCOMM_SET_CTRL(type, pf) (((type) & 0xef) | ((pf) << 4))
|
||||
#define BT_RFCOMM_SET_LEN_8(len) (((len) << 1) | 1)
|
||||
|
||||
/* Length can be 2 bytes depending on data size */
|
||||
#define BT_RFCOMM_HDR_SIZE (sizeof(struct bt_rfcomm_hdr) + 1)
|
||||
#define BT_RFCOMM_FCS_SIZE 1
|
||||
|
||||
#define BT_RFCOMM_FCS_LEN_UIH 2
|
||||
#define BT_RFCOMM_FCS_LEN_NON_UIH 3
|
||||
|
||||
/* Initialize RFCOMM signal layer */
|
||||
void bt_rfcomm_init(void);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue