Skip to content

Commit b7ab7c9

Browse files
lylezhu2012nashif
authored andcommitted
Bluetooth: L2CAP_BR: Process all defined OPTs
Currently, Only configuration opt MTU is handled. For opt `Flush timeout`, `QOS`, `Retransmission and Flow Control`, and `FCS`, response wilt result `BT_L2CAP_CONF_UNACCEPT`. For opt `extended flow specification` and `extended windows size`, response wilt result `BT_L2CAP_CONF_REJECT`. Signed-off-by: Lyle Zhu <lyle.zhu@nxp.com>
1 parent c564804 commit b7ab7c9

File tree

2 files changed

+201
-12
lines changed

2 files changed

+201
-12
lines changed

subsys/bluetooth/host/classic/l2cap_br.c

Lines changed: 153 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1211,19 +1211,22 @@ static uint16_t l2cap_br_conf_opt_mtu(struct bt_l2cap_chan *chan,
12111211
struct net_buf *buf, size_t len)
12121212
{
12131213
uint16_t mtu, result = BT_L2CAP_CONF_SUCCESS;
1214+
struct bt_l2cap_conf_opt_mtu *opt_mtu;
12141215

12151216
/* Core 4.2 [Vol 3, Part A, 5.1] MTU payload length */
1216-
if (len != 2) {
1217+
if (len != sizeof(*opt_mtu)) {
12171218
LOG_ERR("tx MTU length %zu invalid", len);
12181219
result = BT_L2CAP_CONF_REJECT;
12191220
goto done;
12201221
}
12211222

1222-
/* pulling MTU value moves buf data to next option item */
1223-
mtu = net_buf_pull_le16(buf);
1223+
opt_mtu = (struct bt_l2cap_conf_opt_mtu *)buf->data;
1224+
1225+
mtu = sys_le16_to_cpu(opt_mtu->mtu);
12241226
if (mtu < L2CAP_BR_MIN_MTU) {
12251227
result = BT_L2CAP_CONF_UNACCEPT;
12261228
BR_CHAN(chan)->tx.mtu = L2CAP_BR_MIN_MTU;
1229+
opt_mtu->mtu = sys_cpu_to_le16(L2CAP_BR_MIN_MTU);
12271230
LOG_DBG("tx MTU %u invalid", mtu);
12281231
goto done;
12291232
}
@@ -1234,6 +1237,116 @@ static uint16_t l2cap_br_conf_opt_mtu(struct bt_l2cap_chan *chan,
12341237
return result;
12351238
}
12361239

1240+
static uint16_t l2cap_br_conf_opt_flush_timeout(struct bt_l2cap_chan *chan,
1241+
struct net_buf *buf, size_t len)
1242+
{
1243+
uint16_t result = BT_L2CAP_CONF_SUCCESS;
1244+
struct bt_l2cap_conf_opt_flush_timeout *opt_to;
1245+
1246+
if (len != sizeof(*opt_to)) {
1247+
LOG_ERR("qos frame length %zu invalid", len);
1248+
result = BT_L2CAP_CONF_REJECT;
1249+
goto done;
1250+
}
1251+
1252+
opt_to = (struct bt_l2cap_conf_opt_flush_timeout *)buf->data;
1253+
1254+
LOG_DBG("Flush timeout %u", opt_to->timeout);
1255+
1256+
opt_to->timeout = sys_cpu_to_le16(0xFFFF);
1257+
result = BT_L2CAP_CONF_UNACCEPT;
1258+
done:
1259+
return result;
1260+
}
1261+
1262+
static uint16_t l2cap_br_conf_opt_qos(struct bt_l2cap_chan *chan,
1263+
struct net_buf *buf, size_t len)
1264+
{
1265+
uint16_t result = BT_L2CAP_CONF_SUCCESS;
1266+
struct bt_l2cap_conf_opt_qos *opt_qos;
1267+
1268+
if (len != sizeof(*opt_qos)) {
1269+
LOG_ERR("qos frame length %zu invalid", len);
1270+
result = BT_L2CAP_CONF_REJECT;
1271+
goto done;
1272+
}
1273+
1274+
opt_qos = (struct bt_l2cap_conf_opt_qos *)buf->data;
1275+
1276+
LOG_DBG("QOS Type %u", opt_qos->service_type);
1277+
1278+
if (opt_qos->service_type == BT_L2CAP_QOS_TYPE_GUARANTEED) {
1279+
/* Set to default value */
1280+
result = BT_L2CAP_CONF_UNACCEPT;
1281+
opt_qos->flags = 0x00;
1282+
/* do not care */
1283+
opt_qos->token_rate = sys_cpu_to_le32(0x00000000);
1284+
/* no token bucket is needed */
1285+
opt_qos->token_bucket_size = sys_cpu_to_le32(0x00000000);
1286+
/* do not care */
1287+
opt_qos->peak_bandwidth = sys_cpu_to_le32(0x00000000);
1288+
/* do not care */
1289+
opt_qos->latency = sys_cpu_to_le32(0xFFFFFFFF);
1290+
/* do not care */
1291+
opt_qos->delay_variation = sys_cpu_to_le32(0xFFFFFFFF);
1292+
}
1293+
1294+
done:
1295+
return result;
1296+
}
1297+
1298+
static uint16_t l2cap_br_conf_opt_ret_fc(struct bt_l2cap_chan *chan,
1299+
struct net_buf *buf, size_t len)
1300+
{
1301+
uint16_t result = BT_L2CAP_CONF_SUCCESS;
1302+
struct bt_l2cap_conf_opt_ret_fc *opt_ret_fc;
1303+
1304+
if (len != sizeof(*opt_ret_fc)) {
1305+
LOG_ERR("ret_fc frame length %zu invalid", len);
1306+
result = BT_L2CAP_CONF_REJECT;
1307+
goto done;
1308+
}
1309+
1310+
opt_ret_fc = (struct bt_l2cap_conf_opt_ret_fc *)buf->data;
1311+
1312+
LOG_DBG("ret_fc mode %u", opt_ret_fc->mode);
1313+
1314+
if (opt_ret_fc->mode != BT_L2CAP_RET_FC_MODE_BASIC) {
1315+
/* Set to default value */
1316+
result = BT_L2CAP_CONF_UNACCEPT;
1317+
opt_ret_fc->mode = BT_L2CAP_RET_FC_MODE_BASIC;
1318+
}
1319+
1320+
done:
1321+
return result;
1322+
}
1323+
1324+
static uint16_t l2cap_br_conf_opt_fcs(struct bt_l2cap_chan *chan,
1325+
struct net_buf *buf, size_t len)
1326+
{
1327+
uint16_t result = BT_L2CAP_CONF_SUCCESS;
1328+
struct bt_l2cap_conf_opt_fcs *opt_fcs;
1329+
1330+
if (len != sizeof(*opt_fcs)) {
1331+
LOG_ERR("fcs frame length %zu invalid", len);
1332+
result = BT_L2CAP_CONF_REJECT;
1333+
goto done;
1334+
}
1335+
1336+
opt_fcs = (struct bt_l2cap_conf_opt_fcs *)buf->data;
1337+
1338+
LOG_DBG("FCS type %u", opt_fcs->type);
1339+
1340+
if (opt_fcs->type != BT_L2CAP_FCS_TYPE_NO) {
1341+
/* Set to default value */
1342+
result = BT_L2CAP_CONF_UNACCEPT;
1343+
opt_fcs->type = BT_L2CAP_FCS_TYPE_NO;
1344+
}
1345+
1346+
done:
1347+
return result;
1348+
}
1349+
12371350
static void l2cap_br_conf_req(struct bt_l2cap_br *l2cap, uint8_t ident,
12381351
uint16_t len, struct net_buf *buf)
12391352
{
@@ -1260,9 +1373,10 @@ static void l2cap_br_conf_req(struct bt_l2cap_br *l2cap, uint8_t ident,
12601373
chan = bt_l2cap_br_lookup_rx_cid(conn, dcid);
12611374
if (!chan) {
12621375
LOG_ERR("rx channel mismatch!");
1263-
struct bt_l2cap_cmd_reject_cid_data data = {.scid = req->dcid,
1264-
.dcid = 0,
1265-
};
1376+
struct bt_l2cap_cmd_reject_cid_data data = {
1377+
.scid = req->dcid,
1378+
.dcid = 0,
1379+
};
12661380

12671381
l2cap_br_send_reject(conn, ident, BT_L2CAP_REJ_INVALID_CID,
12681382
&data, sizeof(data));
@@ -1298,17 +1412,46 @@ static void l2cap_br_conf_req(struct bt_l2cap_br *l2cap, uint8_t ident,
12981412
* way out here.
12991413
*/
13001414
goto send_rsp;
1415+
case BT_L2CAP_CONF_OPT_FLUSH_TIMEOUT:
1416+
result = l2cap_br_conf_opt_flush_timeout(chan, buf, opt->len);
1417+
if (result != BT_L2CAP_CONF_SUCCESS) {
1418+
goto send_rsp;
1419+
}
1420+
break;
1421+
case BT_L2CAP_CONF_OPT_QOS:
1422+
result = l2cap_br_conf_opt_qos(chan, buf, opt->len);
1423+
if (result != BT_L2CAP_CONF_SUCCESS) {
1424+
goto send_rsp;
1425+
}
1426+
break;
1427+
case BT_L2CAP_CONF_OPT_RET_FC:
1428+
result = l2cap_br_conf_opt_ret_fc(chan, buf, opt->len);
1429+
if (result != BT_L2CAP_CONF_SUCCESS) {
1430+
goto send_rsp;
1431+
}
1432+
break;
1433+
case BT_L2CAP_CONF_OPT_FCS:
1434+
result = l2cap_br_conf_opt_fcs(chan, buf, opt->len);
1435+
if (result != BT_L2CAP_CONF_SUCCESS) {
1436+
goto send_rsp;
1437+
}
1438+
break;
1439+
case BT_L2CAP_CONF_OPT_EXT_FLOW_SPEC:
1440+
__fallthrough;
1441+
case BT_L2CAP_CONF_OPT_EXT_WIN_SIZE:
1442+
result = BT_L2CAP_CONF_REJECT;
1443+
goto send_rsp;
13011444
default:
13021445
if (!hint) {
13031446
LOG_DBG("option %u not handled", opt->type);
13041447
result = BT_L2CAP_CONF_UNKNOWN_OPT;
13051448
goto send_rsp;
13061449
}
1307-
1308-
/* Update buffer to point at next option */
1309-
net_buf_pull(buf, opt->len);
13101450
break;
13111451
}
1452+
1453+
/* Update buffer to point at next option */
1454+
net_buf_pull(buf, opt->len);
13121455
}
13131456

13141457
send_rsp:
@@ -1328,9 +1471,7 @@ static void l2cap_br_conf_req(struct bt_l2cap_br *l2cap, uint8_t ident,
13281471
* the options chain need to be modified and taken into account when
13291472
* sending back to peer.
13301473
*/
1331-
if (result == BT_L2CAP_CONF_UNACCEPT) {
1332-
l2cap_br_conf_add_mtu(buf, BR_CHAN(chan)->tx.mtu);
1333-
} else if (result == BT_L2CAP_CONF_UNKNOWN_OPT) {
1474+
if ((result == BT_L2CAP_CONF_UNKNOWN_OPT) || (result == BT_L2CAP_CONF_UNACCEPT)) {
13341475
if (opt) {
13351476
l2cap_br_conf_add_opt(buf, opt);
13361477
}

subsys/bluetooth/host/classic/l2cap_br_internal.h

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,13 @@ struct bt_l2cap_conf_rsp {
9393

9494
/* Option type used by MTU config request data */
9595
#define BT_L2CAP_CONF_OPT_MTU 0x01
96+
#define BT_L2CAP_CONF_OPT_FLUSH_TIMEOUT 0x02
97+
#define BT_L2CAP_CONF_OPT_QOS 0x03
98+
#define BT_L2CAP_CONF_OPT_RET_FC 0x04
99+
#define BT_L2CAP_CONF_OPT_FCS 0x05
100+
#define BT_L2CAP_CONF_OPT_EXT_FLOW_SPEC 0x06
101+
#define BT_L2CAP_CONF_OPT_EXT_WIN_SIZE 0x07
102+
96103
/* Options bits selecting most significant bit (hint) in type field */
97104
#define BT_L2CAP_CONF_HINT 0x80
98105
#define BT_L2CAP_CONF_MASK 0x7f
@@ -103,6 +110,47 @@ struct bt_l2cap_conf_opt {
103110
uint8_t data[0];
104111
} __packed;
105112

113+
struct bt_l2cap_conf_opt_mtu {
114+
uint16_t mtu;
115+
} __packed;
116+
117+
struct bt_l2cap_conf_opt_flush_timeout {
118+
uint16_t timeout;
119+
} __packed;
120+
121+
#define BT_L2CAP_QOS_TYPE_NO_TRAFFIC 0x00
122+
#define BT_L2CAP_QOS_TYPE_BEST_EFFORT 0x01
123+
#define BT_L2CAP_QOS_TYPE_GUARANTEED 0x02
124+
struct bt_l2cap_conf_opt_qos {
125+
uint8_t flags;
126+
uint8_t service_type;
127+
uint32_t token_rate;
128+
uint32_t token_bucket_size;
129+
uint32_t peak_bandwidth;
130+
uint32_t latency;
131+
uint32_t delay_variation;
132+
} __packed;
133+
134+
#define BT_L2CAP_RET_FC_MODE_BASIC 0x00
135+
#define BT_L2CAP_RET_FC_MODE_RET 0x01
136+
#define BT_L2CAP_RET_FC_MODE_FC 0x02
137+
#define BT_L2CAP_RET_FC_MODE_ENH_RET 0x03
138+
#define BT_L2CAP_RET_FC_MODE_STREAM 0x04
139+
struct bt_l2cap_conf_opt_ret_fc {
140+
uint8_t mode;
141+
uint8_t tx_windows_size;
142+
uint8_t max_transmit;
143+
uint16_t retransmission_timeout;
144+
uint16_t monitor_timeout;
145+
uint16_t mps;
146+
} __packed;
147+
148+
#define BT_L2CAP_FCS_TYPE_NO 0x00
149+
#define BT_L2CAP_FCS_TYPE_16BIT 0x01
150+
struct bt_l2cap_conf_opt_fcs {
151+
uint8_t type;
152+
} __packed;
153+
106154
#define BT_L2CAP_DISCONN_REQ 0x06
107155
struct bt_l2cap_disconn_req {
108156
uint16_t dcid;

0 commit comments

Comments
 (0)