static void le_conn_rsp(struct bt_l2cap *l2cap, uint8_t ident, struct net_buf *buf) { struct bt_conn *conn = l2cap->chan.chan.conn; struct bt_l2cap_le_chan *chan; struct bt_l2cap_le_conn_rsp *rsp = (void *)buf->data; uint16_t dcid, mtu, mps, credits, result; if (buf->len < sizeof(*rsp)) { BT_ERR("Too small LE conn rsp packet size"); return; } dcid = sys_le16_to_cpu(rsp->dcid); mtu = sys_le16_to_cpu(rsp->mtu); mps = sys_le16_to_cpu(rsp->mps); credits = sys_le16_to_cpu(rsp->credits); result = sys_le16_to_cpu(rsp->result); BT_DBG("dcid 0x%04x mtu %u mps %u credits %u result 0x%04x", dcid, mtu, mps, credits, result); if (result == BT_L2CAP_SUCCESS) { chan = l2cap_lookup_ident(conn, ident); } else { chan = l2cap_remove_ident(conn, ident); } if (!chan) { BT_ERR("Cannot find channel for ident %u", ident); return; } switch (result) { case BT_L2CAP_SUCCESS: /* Reset ident since it is no longer pending */ chan->ident = 0; chan->tx.cid = dcid; chan->tx.mtu = mtu; chan->tx.mps = mps; if (chan->chan.ops && chan->chan.ops->connected) { chan->chan.ops->connected(&chan->chan); } /* Give credits */ l2cap_chan_tx_give_credits(chan, credits); l2cap_chan_rx_give_credits(chan, L2CAP_LE_MAX_CREDITS); break; /* TODO: Retry on Authentication and Encryption errors */ default: l2cap_chan_del(&chan->chan); } }
static void le_conn_rsp(struct bt_l2cap *l2cap, uint8_t ident, struct net_buf *buf) { struct bt_conn *conn = l2cap->chan.chan.conn; struct bt_l2cap_le_chan *chan; struct bt_l2cap_le_conn_rsp *rsp = (void *)buf->data; uint16_t dcid, mtu, mps, credits, result; if (buf->len < sizeof(*rsp)) { BT_ERR("Too small LE conn rsp packet size"); return; } dcid = sys_le16_to_cpu(rsp->dcid); mtu = sys_le16_to_cpu(rsp->mtu); mps = sys_le16_to_cpu(rsp->mps); credits = sys_le16_to_cpu(rsp->credits); result = sys_le16_to_cpu(rsp->result); BT_DBG("dcid 0x%04x mtu %u mps %u credits %u result 0x%04x", dcid, mtu, mps, credits, result); /* Keep the channel in case of security errors */ if (result == BT_L2CAP_SUCCESS || result == BT_L2CAP_ERR_AUTHENTICATION || result == BT_L2CAP_ERR_ENCRYPTION) { chan = l2cap_lookup_ident(conn, ident); } else { chan = l2cap_remove_ident(conn, ident); } if (!chan) { BT_ERR("Cannot find channel for ident %u", ident); return; } /* Cancel RTX work */ k_delayed_work_cancel(&chan->chan.rtx_work); /* Reset ident since it got a response */ chan->chan.ident = 0; switch (result) { case BT_L2CAP_SUCCESS: chan->tx.cid = dcid; chan->tx.mtu = mtu; chan->tx.mps = mps; /* Update state */ bt_l2cap_chan_set_state(&chan->chan, BT_L2CAP_CONNECTED); if (chan->chan.ops && chan->chan.ops->connected) { chan->chan.ops->connected(&chan->chan); } /* Give credits */ l2cap_chan_tx_give_credits(chan, credits); l2cap_chan_rx_give_credits(chan, chan->rx.init_credits); break; case BT_L2CAP_ERR_AUTHENTICATION: case BT_L2CAP_ERR_ENCRYPTION: /* If security needs changing wait it to be completed */ if (l2cap_change_security(chan, result) == 0) { return; } l2cap_detach_chan(conn, &chan->chan); default: bt_l2cap_chan_del(&chan->chan); } }