| /* |
| * Copyright (c) 2017 Nordic Semiconductor ASA |
| * Copyright (c) 2015 Intel Corporation |
| * |
| * SPDX-License-Identifier: Apache-2.0 |
| */ |
| |
| #include <zephyr/bluetooth/buf.h> |
| #include <zephyr/bluetooth/l2cap.h> |
| |
| #include "hci_core.h" |
| #include "conn_internal.h" |
| #include "iso_internal.h" |
| |
| #define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_DEBUG_HCI_CORE) |
| #define LOG_MODULE_NAME bt_buf |
| #include "common/log.h" |
| |
| #if defined(CONFIG_BT_CONN) |
| #if defined(CONFIG_BT_ISO) |
| #define MAX_EVENT_COUNT CONFIG_BT_MAX_CONN + CONFIG_BT_ISO_MAX_CHAN |
| #else |
| #define MAX_EVENT_COUNT CONFIG_BT_MAX_CONN |
| #endif /* CONFIG_BT_ISO */ |
| #elif defined(CONFIG_BT_ISO) |
| #define MAX_EVENT_COUNT CONFIG_BT_ISO_MAX_CHAN |
| #endif /* CONFIG_BT_CONN */ |
| |
| #if defined(CONFIG_BT_CONN) || defined(CONFIG_BT_ISO) |
| #define NUM_COMLETE_EVENT_SIZE BT_BUF_EVT_SIZE( \ |
| sizeof(struct bt_hci_cp_host_num_completed_packets) + \ |
| MAX_EVENT_COUNT * sizeof(struct bt_hci_handle_count)) |
| /* Dedicated pool for HCI_Number_of_Completed_Packets. This event is always |
| * consumed synchronously by bt_recv_prio() so a single buffer is enough. |
| * Having a dedicated pool for it ensures that exhaustion of the RX pool |
| * cannot block the delivery of this priority event. |
| */ |
| NET_BUF_POOL_FIXED_DEFINE(num_complete_pool, 1, NUM_COMLETE_EVENT_SIZE, 8, NULL); |
| #endif /* CONFIG_BT_CONN || CONFIG_BT_ISO */ |
| |
| NET_BUF_POOL_FIXED_DEFINE(discardable_pool, CONFIG_BT_BUF_EVT_DISCARDABLE_COUNT, |
| BT_BUF_EVT_SIZE(CONFIG_BT_BUF_EVT_DISCARDABLE_SIZE), 8, |
| NULL); |
| |
| #if defined(CONFIG_BT_HCI_ACL_FLOW_CONTROL) |
| NET_BUF_POOL_DEFINE(acl_in_pool, CONFIG_BT_BUF_ACL_RX_COUNT, |
| BT_BUF_ACL_SIZE(CONFIG_BT_BUF_ACL_RX_SIZE), |
| sizeof(struct acl_data), bt_hci_host_num_completed_packets); |
| |
| NET_BUF_POOL_FIXED_DEFINE(evt_pool, CONFIG_BT_BUF_EVT_RX_COUNT, |
| BT_BUF_EVT_RX_SIZE, 8, |
| NULL); |
| #else |
| NET_BUF_POOL_FIXED_DEFINE(hci_rx_pool, BT_BUF_RX_COUNT, |
| BT_BUF_RX_SIZE, 8, |
| NULL); |
| #endif /* CONFIG_BT_HCI_ACL_FLOW_CONTROL */ |
| |
| struct net_buf *bt_buf_get_rx(enum bt_buf_type type, k_timeout_t timeout) |
| { |
| struct net_buf *buf; |
| |
| __ASSERT(type == BT_BUF_EVT || type == BT_BUF_ACL_IN || |
| type == BT_BUF_ISO_IN, "Invalid buffer type requested"); |
| |
| if ((IS_ENABLED(CONFIG_BT_ISO_UNICAST) || |
| IS_ENABLED(CONFIG_BT_ISO_SYNC_RECEIVER)) && |
| type == BT_BUF_ISO_IN) { |
| return bt_iso_get_rx(timeout); |
| } |
| |
| #if defined(CONFIG_BT_HCI_ACL_FLOW_CONTROL) |
| if (type == BT_BUF_EVT) { |
| buf = net_buf_alloc(&evt_pool, timeout); |
| } else { |
| buf = net_buf_alloc(&acl_in_pool, timeout); |
| } |
| #else |
| buf = net_buf_alloc(&hci_rx_pool, timeout); |
| #endif |
| |
| if (buf) { |
| net_buf_reserve(buf, BT_BUF_RESERVE); |
| bt_buf_set_type(buf, type); |
| } |
| |
| return buf; |
| } |
| |
| struct net_buf *bt_buf_get_cmd_complete(k_timeout_t timeout) |
| { |
| struct net_buf *buf; |
| |
| if (bt_dev.sent_cmd) { |
| buf = net_buf_ref(bt_dev.sent_cmd); |
| |
| bt_buf_set_type(buf, BT_BUF_EVT); |
| buf->len = 0U; |
| net_buf_reserve(buf, BT_BUF_RESERVE); |
| |
| return buf; |
| } |
| |
| return bt_buf_get_rx(BT_BUF_EVT, timeout); |
| } |
| |
| struct net_buf *bt_buf_get_evt(uint8_t evt, bool discardable, |
| k_timeout_t timeout) |
| { |
| switch (evt) { |
| #if defined(CONFIG_BT_CONN) || defined(CONFIG_BT_ISO) |
| case BT_HCI_EVT_NUM_COMPLETED_PACKETS: |
| { |
| struct net_buf *buf; |
| |
| buf = net_buf_alloc(&num_complete_pool, timeout); |
| if (buf) { |
| net_buf_reserve(buf, BT_BUF_RESERVE); |
| bt_buf_set_type(buf, BT_BUF_EVT); |
| } |
| |
| return buf; |
| } |
| #endif /* CONFIG_BT_CONN || CONFIG_BT_ISO */ |
| case BT_HCI_EVT_CMD_COMPLETE: |
| case BT_HCI_EVT_CMD_STATUS: |
| return bt_buf_get_cmd_complete(timeout); |
| default: |
| if (discardable) { |
| struct net_buf *buf; |
| |
| buf = net_buf_alloc(&discardable_pool, timeout); |
| if (buf) { |
| net_buf_reserve(buf, BT_BUF_RESERVE); |
| bt_buf_set_type(buf, BT_BUF_EVT); |
| } |
| |
| return buf; |
| } |
| |
| return bt_buf_get_rx(BT_BUF_EVT, timeout); |
| } |
| } |
| |
| #ifdef ZTEST_UNITTEST |
| #if defined(CONFIG_BT_HCI_ACL_FLOW_CONTROL) |
| struct net_buf_pool *bt_buf_get_evt_pool(void) |
| { |
| return &evt_pool; |
| } |
| |
| struct net_buf_pool *bt_buf_get_acl_in_pool(void) |
| { |
| return &acl_in_pool; |
| } |
| #else |
| struct net_buf_pool *bt_buf_get_hci_rx_pool(void) |
| { |
| return &hci_rx_pool; |
| } |
| #endif /* CONFIG_BT_HCI_ACL_FLOW_CONTROL */ |
| |
| #if defined(CONFIG_BT_BUF_EVT_DISCARDABLE_COUNT) |
| struct net_buf_pool *bt_buf_get_discardable_pool(void) |
| { |
| return &discardable_pool; |
| } |
| #endif /* CONFIG_BT_BUF_EVT_DISCARDABLE_COUNT */ |
| |
| #if defined(CONFIG_BT_CONN) || defined(CONFIG_BT_ISO) |
| struct net_buf_pool *bt_buf_get_num_complete_pool(void) |
| { |
| return &num_complete_pool; |
| } |
| #endif /* CONFIG_BT_CONN || CONFIG_BT_ISO */ |
| #endif /* ZTEST_UNITTEST */ |