Skip to content

Commit d111394

Browse files
VudentzAnas Nashif
authored andcommitted
Bluetooth: L2CAP: Move functions in preparation for queuing
This moves necessary functions that will be needed for queuing packets while waiting for more credits. Jira: ZEP-1776 Change-Id: I030c696d432ec5be1b8e6b649e953da145929777 Signed-off-by: Luiz Augusto von Dentz <[email protected]>
1 parent cc39120 commit d111394

File tree

1 file changed

+128
-125
lines changed

1 file changed

+128
-125
lines changed

subsys/bluetooth/host/l2cap.c

Lines changed: 128 additions & 125 deletions
Original file line numberDiff line numberDiff line change
@@ -998,6 +998,134 @@ static void le_disconn_rsp(struct bt_l2cap *l2cap, uint8_t ident,
998998
bt_l2cap_chan_del(&chan->chan);
999999
}
10001000

1001+
static struct net_buf *l2cap_chan_create_seg(struct bt_l2cap_le_chan *ch,
1002+
struct net_buf *buf,
1003+
size_t sdu_hdr_len)
1004+
{
1005+
struct net_buf *seg;
1006+
uint16_t headroom;
1007+
uint16_t len;
1008+
1009+
/* Segment if data (+ data headroom) is bigger than MPS */
1010+
if (buf->len + sdu_hdr_len > ch->tx.mps) {
1011+
goto segment;
1012+
}
1013+
1014+
/* Segment if there is no space in the user_data */
1015+
if (buf->pool->user_data_size < BT_BUF_USER_DATA_MIN) {
1016+
BT_WARN("Too small buffer user_data_size %u",
1017+
buf->pool->user_data_size);
1018+
goto segment;
1019+
}
1020+
1021+
headroom = sizeof(struct bt_hci_acl_hdr) +
1022+
sizeof(struct bt_l2cap_hdr) + sdu_hdr_len;
1023+
1024+
/* Check if original buffer has enough headroom and don't have any
1025+
* fragments.
1026+
*/
1027+
if (net_buf_headroom(buf) >= headroom && !buf->frags) {
1028+
if (sdu_hdr_len) {
1029+
/* Push SDU length if set */
1030+
net_buf_push_le16(buf, net_buf_frags_len(buf));
1031+
}
1032+
return net_buf_ref(buf);
1033+
}
1034+
1035+
segment:
1036+
seg = bt_l2cap_create_pdu(&le_data_pool, 0);
1037+
1038+
if (sdu_hdr_len) {
1039+
net_buf_add_le16(seg, net_buf_frags_len(buf));
1040+
}
1041+
1042+
/* Don't send more that TX MPS including SDU length */
1043+
len = min(net_buf_tailroom(seg), ch->tx.mps - sdu_hdr_len);
1044+
/* Limit if original buffer is smaller than the segment */
1045+
len = min(buf->len, len);
1046+
net_buf_add_mem(seg, buf->data, len);
1047+
net_buf_pull(buf, len);
1048+
1049+
BT_DBG("ch %p seg %p len %u", ch, seg, seg->len);
1050+
1051+
return seg;
1052+
}
1053+
1054+
static int l2cap_chan_le_send(struct bt_l2cap_le_chan *ch, struct net_buf *buf,
1055+
uint16_t sdu_hdr_len)
1056+
{
1057+
int len;
1058+
1059+
/* Wait for credits */
1060+
if (k_sem_take(&ch->tx.credits, K_NO_WAIT)) {
1061+
BT_DBG("No credits to transmit packet");
1062+
return -EAGAIN;
1063+
}
1064+
1065+
buf = l2cap_chan_create_seg(ch, buf, sdu_hdr_len);
1066+
if (!buf) {
1067+
return -ENOMEM;
1068+
}
1069+
1070+
/* Channel may have been disconnected while waiting for credits */
1071+
if (!ch->chan.conn) {
1072+
net_buf_unref(buf);
1073+
return -ECONNRESET;
1074+
}
1075+
1076+
BT_DBG("ch %p cid 0x%04x len %u credits %u", ch, ch->tx.cid,
1077+
buf->len, k_sem_count_get(&ch->tx.credits));
1078+
1079+
len = buf->len;
1080+
1081+
bt_l2cap_send(ch->chan.conn, ch->tx.cid, buf);
1082+
1083+
return len;
1084+
}
1085+
1086+
static int l2cap_chan_le_send_sdu(struct bt_l2cap_le_chan *ch,
1087+
struct net_buf *buf)
1088+
{
1089+
int ret, sent, total_len;
1090+
struct net_buf *frag;
1091+
1092+
total_len = net_buf_frags_len(buf);
1093+
1094+
if (total_len > ch->tx.mtu) {
1095+
return -EMSGSIZE;
1096+
}
1097+
1098+
frag = buf;
1099+
if (!frag->len && frag->frags) {
1100+
frag = frag->frags;
1101+
}
1102+
1103+
/* Add SDU length for the first segment */
1104+
ret = l2cap_chan_le_send(ch, frag, BT_L2CAP_SDU_HDR_LEN);
1105+
if (ret < 0) {
1106+
return ret;
1107+
}
1108+
1109+
/* Send remaining segments */
1110+
for (sent = ret; sent < total_len; sent += ret) {
1111+
/* Proceed to next fragment */
1112+
if (!frag->len) {
1113+
frag = net_buf_frag_del(buf, frag);
1114+
}
1115+
1116+
ret = l2cap_chan_le_send(ch, frag, 0);
1117+
if (ret < 0) {
1118+
return ret;
1119+
}
1120+
}
1121+
1122+
BT_DBG("ch %p cid 0x%04x sent %u", ch, ch->tx.cid, sent);
1123+
1124+
net_buf_unref(buf);
1125+
1126+
return ret;
1127+
}
1128+
10011129
static void le_credits(struct bt_l2cap *l2cap, uint8_t ident,
10021130
struct net_buf *buf)
10031131
{
@@ -1499,131 +1627,6 @@ int bt_l2cap_chan_disconnect(struct bt_l2cap_chan *chan)
14991627
return 0;
15001628
}
15011629

1502-
static struct net_buf *l2cap_chan_create_seg(struct bt_l2cap_le_chan *ch,
1503-
struct net_buf *buf,
1504-
size_t sdu_hdr_len)
1505-
{
1506-
struct net_buf *seg;
1507-
uint16_t headroom;
1508-
uint16_t len;
1509-
1510-
/* Segment if data (+ data headroom) is bigger than MPS */
1511-
if (buf->len + sdu_hdr_len > ch->tx.mps) {
1512-
goto segment;
1513-
}
1514-
1515-
/* Segment if there is no space in the user_data */
1516-
if (buf->pool->user_data_size < BT_BUF_USER_DATA_MIN) {
1517-
BT_WARN("Too small buffer user_data_size %u",
1518-
buf->pool->user_data_size);
1519-
goto segment;
1520-
}
1521-
1522-
headroom = sizeof(struct bt_hci_acl_hdr) +
1523-
sizeof(struct bt_l2cap_hdr) + sdu_hdr_len;
1524-
1525-
/* Check if original buffer has enough headroom and don't have any
1526-
* fragments.
1527-
*/
1528-
if (net_buf_headroom(buf) >= headroom && !buf->frags) {
1529-
if (sdu_hdr_len) {
1530-
/* Push SDU length if set */
1531-
net_buf_push_le16(buf, net_buf_frags_len(buf));
1532-
}
1533-
return net_buf_ref(buf);
1534-
}
1535-
1536-
segment:
1537-
seg = bt_l2cap_create_pdu(&le_data_pool, 0);
1538-
1539-
if (sdu_hdr_len) {
1540-
net_buf_add_le16(seg, net_buf_frags_len(buf));
1541-
}
1542-
1543-
/* Don't send more that TX MPS including SDU length */
1544-
len = min(net_buf_tailroom(seg), ch->tx.mps - sdu_hdr_len);
1545-
/* Limit if original buffer is smaller than the segment */
1546-
len = min(buf->len, len);
1547-
net_buf_add_mem(seg, buf->data, len);
1548-
net_buf_pull(buf, len);
1549-
1550-
BT_DBG("ch %p seg %p len %u", ch, seg, seg->len);
1551-
1552-
return seg;
1553-
}
1554-
1555-
static int l2cap_chan_le_send(struct bt_l2cap_le_chan *ch, struct net_buf *buf,
1556-
uint16_t sdu_hdr_len)
1557-
{
1558-
int len;
1559-
1560-
/* Wait for credits */
1561-
k_sem_take(&ch->tx.credits, K_FOREVER);
1562-
1563-
buf = l2cap_chan_create_seg(ch, buf, sdu_hdr_len);
1564-
if (!buf) {
1565-
return -ENOMEM;
1566-
}
1567-
1568-
/* Channel may have been disconnected while waiting for credits */
1569-
if (!ch->chan.conn) {
1570-
net_buf_unref(buf);
1571-
return -ECONNRESET;
1572-
}
1573-
1574-
BT_DBG("ch %p cid 0x%04x len %u credits %u", ch, ch->tx.cid,
1575-
buf->len, k_sem_count_get(&ch->tx.credits));
1576-
1577-
len = buf->len;
1578-
1579-
bt_l2cap_send(ch->chan.conn, ch->tx.cid, buf);
1580-
1581-
return len;
1582-
}
1583-
1584-
static int l2cap_chan_le_send_sdu(struct bt_l2cap_le_chan *ch,
1585-
struct net_buf *buf)
1586-
{
1587-
int ret, sent, total_len;
1588-
struct net_buf *frag;
1589-
1590-
total_len = net_buf_frags_len(buf);
1591-
1592-
if (total_len > ch->tx.mtu) {
1593-
return -EMSGSIZE;
1594-
}
1595-
1596-
frag = buf;
1597-
if (!frag->len && frag->frags) {
1598-
frag = frag->frags;
1599-
}
1600-
1601-
/* Add SDU length for the first segment */
1602-
ret = l2cap_chan_le_send(ch, frag, BT_L2CAP_SDU_HDR_LEN);
1603-
if (ret < 0) {
1604-
return ret;
1605-
}
1606-
1607-
/* Send remaining segments */
1608-
for (sent = ret; sent < total_len; sent += ret) {
1609-
/* Proceed to next fragment */
1610-
if (!frag->len) {
1611-
frag = net_buf_frag_del(buf, frag);
1612-
}
1613-
1614-
ret = l2cap_chan_le_send(ch, frag, 0);
1615-
if (ret < 0) {
1616-
return ret;
1617-
}
1618-
}
1619-
1620-
BT_DBG("ch %p cid 0x%04x sent %u", ch, ch->tx.cid, sent);
1621-
1622-
net_buf_unref(buf);
1623-
1624-
return sent;
1625-
}
1626-
16271630
int bt_l2cap_chan_send(struct bt_l2cap_chan *chan, struct net_buf *buf)
16281631
{
16291632
int err;

0 commit comments

Comments
 (0)