Revert "Bluetooth: HCI: Remove HCI_AMP support"

This reverts commit 5af2e235b0 which is
commit 84a4bb6548 upstream.

It breaks the Android kernel abi and can be brought back in the future
in an abi-safe way if it is really needed.

Bug: 161946584
Change-Id: I46c1b881dedde98ee4820e04781cb399e3b5fc3d
Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
This commit is contained in:
Greg Kroah-Hartman 2024-06-14 09:02:41 +00:00
parent cfa231a1fa
commit 4091ea13a1
20 changed files with 663 additions and 50 deletions

View File

@ -121,6 +121,13 @@ int btmrvl_process_event(struct btmrvl_private *priv, struct sk_buff *skb)
((event->data[2] == MODULE_BROUGHT_UP) ||
(event->data[2] == MODULE_ALREADY_UP)) ?
"Bring-up succeed" : "Bring-up failed");
if (event->length > 3 && event->data[3])
priv->btmrvl_dev.dev_type = HCI_AMP;
else
priv->btmrvl_dev.dev_type = HCI_PRIMARY;
BT_DBG("dev_type: %d", priv->btmrvl_dev.dev_type);
} else if (priv->btmrvl_dev.sendcmdflag &&
event->data[1] == MODULE_SHUTDOWN_REQ) {
BT_DBG("EVENT:%s", (event->data[2]) ?
@ -679,6 +686,8 @@ int btmrvl_register_hdev(struct btmrvl_private *priv)
hdev->wakeup = btmrvl_wakeup;
SET_HCIDEV_DEV(hdev, &card->func->dev);
hdev->dev_type = priv->btmrvl_dev.dev_type;
ret = hci_register_dev(hdev);
if (ret < 0) {
BT_ERR("Can not register HCI device");

View File

@ -134,6 +134,7 @@ static int rsi_hci_attach(void *priv, struct rsi_proto_ops *ops)
hdev->bus = HCI_USB;
hci_set_drvdata(hdev, h_adapter);
hdev->dev_type = HCI_PRIMARY;
hdev->open = rsi_hci_open;
hdev->close = rsi_hci_close;
hdev->flush = rsi_hci_flush;

View File

@ -32,6 +32,9 @@ static const struct sdio_device_id btsdio_table[] = {
/* Generic Bluetooth Type-B SDIO device */
{ SDIO_DEVICE_CLASS(SDIO_CLASS_BT_B) },
/* Generic Bluetooth AMP controller */
{ SDIO_DEVICE_CLASS(SDIO_CLASS_BT_AMP) },
{ } /* Terminating entry */
};
@ -316,6 +319,11 @@ static int btsdio_probe(struct sdio_func *func,
hdev->bus = HCI_SDIO;
hci_set_drvdata(hdev, data);
if (id->class == SDIO_CLASS_BT_AMP)
hdev->dev_type = HCI_AMP;
else
hdev->dev_type = HCI_PRIMARY;
data->hdev = hdev;
SET_HCIDEV_DEV(hdev, &func->dev);

View File

@ -4308,6 +4308,11 @@ static int btusb_probe(struct usb_interface *intf,
hdev->bus = HCI_USB;
hci_set_drvdata(hdev, data);
if (id->driver_info & BTUSB_AMP)
hdev->dev_type = HCI_AMP;
else
hdev->dev_type = HCI_PRIMARY;
data->hdev = hdev;
SET_HCIDEV_DEV(hdev, &intf->dev);

View File

@ -2361,6 +2361,7 @@ static int bcm4377_probe(struct pci_dev *pdev, const struct pci_device_id *id)
bcm4377->hdev = hdev;
hdev->bus = HCI_PCI;
hdev->dev_type = HCI_PRIMARY;
hdev->open = bcm4377_hci_open;
hdev->close = bcm4377_hci_close;
hdev->send = bcm4377_hci_send_frame;

View File

@ -667,6 +667,11 @@ static int hci_uart_register_dev(struct hci_uart *hu)
if (!test_bit(HCI_UART_RESET_ON_INIT, &hu->hdev_flags))
set_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks);
if (test_bit(HCI_UART_CREATE_AMP, &hu->hdev_flags))
hdev->dev_type = HCI_AMP;
else
hdev->dev_type = HCI_PRIMARY;
/* Only call open() for the protocol after hdev is fully initialized as
* open() (or a timer/workqueue it starts) may attempt to reference it.
*/
@ -717,6 +722,7 @@ static int hci_uart_set_flags(struct hci_uart *hu, unsigned long flags)
{
unsigned long valid_flags = BIT(HCI_UART_RAW_DEVICE) |
BIT(HCI_UART_RESET_ON_INIT) |
BIT(HCI_UART_CREATE_AMP) |
BIT(HCI_UART_INIT_PENDING) |
BIT(HCI_UART_EXT_CONFIG) |
BIT(HCI_UART_VND_DETECT);

View File

@ -366,6 +366,11 @@ int hci_uart_register_device_priv(struct hci_uart *hu,
if (test_bit(HCI_UART_EXT_CONFIG, &hu->hdev_flags))
set_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks);
if (test_bit(HCI_UART_CREATE_AMP, &hu->hdev_flags))
hdev->dev_type = HCI_AMP;
else
hdev->dev_type = HCI_PRIMARY;
if (test_bit(HCI_UART_INIT_PENDING, &hu->hdev_flags))
return 0;

View File

@ -37,6 +37,7 @@
#define HCI_UART_RAW_DEVICE 0
#define HCI_UART_RESET_ON_INIT 1
#define HCI_UART_CREATE_AMP 2
#define HCI_UART_INIT_PENDING 3
#define HCI_UART_EXT_CONFIG 4
#define HCI_UART_VND_DETECT 5

View File

@ -384,10 +384,17 @@ static int __vhci_create_device(struct vhci_data *data, __u8 opcode)
{
struct hci_dev *hdev;
struct sk_buff *skb;
__u8 dev_type;
if (data->hdev)
return -EBADFD;
/* bits 0-1 are dev_type (Primary or AMP) */
dev_type = opcode & 0x03;
if (dev_type != HCI_PRIMARY && dev_type != HCI_AMP)
return -EINVAL;
/* bits 2-5 are reserved (must be zero) */
if (opcode & 0x3c)
return -EINVAL;
@ -405,6 +412,7 @@ static int __vhci_create_device(struct vhci_data *data, __u8 opcode)
data->hdev = hdev;
hdev->bus = HCI_VIRTUAL;
hdev->dev_type = dev_type;
hci_set_drvdata(hdev, data);
hdev->open = vhci_open_dev;
@ -626,7 +634,7 @@ static void vhci_open_timeout(struct work_struct *work)
struct vhci_data *data = container_of(work, struct vhci_data,
open_timeout.work);
vhci_create_device(data, 0x00);
vhci_create_device(data, amp ? HCI_AMP : HCI_PRIMARY);
}
static int vhci_open(struct inode *inode, struct file *file)

View File

@ -274,6 +274,7 @@ static int virtbt_probe(struct virtio_device *vdev)
switch (type) {
case VIRTIO_BT_CONFIG_TYPE_PRIMARY:
case VIRTIO_BT_CONFIG_TYPE_AMP:
break;
default:
return -EINVAL;
@ -302,6 +303,7 @@ static int virtbt_probe(struct virtio_device *vdev)
vbt->hdev = hdev;
hdev->bus = HCI_VIRTIO;
hdev->dev_type = type;
hci_set_drvdata(hdev, vbt);
hdev->open = virtbt_open;

View File

@ -33,6 +33,9 @@
#define HCI_MAX_FRAME_SIZE (HCI_MAX_ACL_SIZE + 4)
#define HCI_LINK_KEY_SIZE 16
#define HCI_AMP_LINK_KEY_SIZE (2 * HCI_LINK_KEY_SIZE)
#define HCI_MAX_AMP_ASSOC_SIZE 672
#define HCI_MAX_CPB_DATA_SIZE 252
@ -68,6 +71,26 @@
#define HCI_SMD 9
#define HCI_VIRTIO 10
/* HCI controller types */
#define HCI_PRIMARY 0x00
#define HCI_AMP 0x01
/* First BR/EDR Controller shall have ID = 0 */
#define AMP_ID_BREDR 0x00
/* AMP controller types */
#define AMP_TYPE_BREDR 0x00
#define AMP_TYPE_80211 0x01
/* AMP controller status */
#define AMP_STATUS_POWERED_DOWN 0x00
#define AMP_STATUS_BLUETOOTH_ONLY 0x01
#define AMP_STATUS_NO_CAPACITY 0x02
#define AMP_STATUS_LOW_CAPACITY 0x03
#define AMP_STATUS_MEDIUM_CAPACITY 0x04
#define AMP_STATUS_HIGH_CAPACITY 0x05
#define AMP_STATUS_FULL_CAPACITY 0x06
/* HCI device quirks */
enum {
/* When this quirk is set, the HCI Reset command is send when
@ -503,6 +526,7 @@ enum {
#define ESCO_LINK 0x02
/* Low Energy links do not have defined link type. Use invented one */
#define LE_LINK 0x80
#define AMP_LINK 0x81
#define ISO_LINK 0x82
#define INVALID_LINK 0xff
@ -916,6 +940,56 @@ struct hci_cp_io_capability_neg_reply {
__u8 reason;
} __packed;
#define HCI_OP_CREATE_PHY_LINK 0x0435
struct hci_cp_create_phy_link {
__u8 phy_handle;
__u8 key_len;
__u8 key_type;
__u8 key[HCI_AMP_LINK_KEY_SIZE];
} __packed;
#define HCI_OP_ACCEPT_PHY_LINK 0x0436
struct hci_cp_accept_phy_link {
__u8 phy_handle;
__u8 key_len;
__u8 key_type;
__u8 key[HCI_AMP_LINK_KEY_SIZE];
} __packed;
#define HCI_OP_DISCONN_PHY_LINK 0x0437
struct hci_cp_disconn_phy_link {
__u8 phy_handle;
__u8 reason;
} __packed;
struct ext_flow_spec {
__u8 id;
__u8 stype;
__le16 msdu;
__le32 sdu_itime;
__le32 acc_lat;
__le32 flush_to;
} __packed;
#define HCI_OP_CREATE_LOGICAL_LINK 0x0438
#define HCI_OP_ACCEPT_LOGICAL_LINK 0x0439
struct hci_cp_create_accept_logical_link {
__u8 phy_handle;
struct ext_flow_spec tx_flow_spec;
struct ext_flow_spec rx_flow_spec;
} __packed;
#define HCI_OP_DISCONN_LOGICAL_LINK 0x043a
struct hci_cp_disconn_logical_link {
__le16 log_handle;
} __packed;
#define HCI_OP_LOGICAL_LINK_CANCEL 0x043b
struct hci_cp_logical_link_cancel {
__u8 phy_handle;
__u8 flow_spec_id;
} __packed;
#define HCI_OP_ENHANCED_SETUP_SYNC_CONN 0x043d
struct hci_coding_format {
__u8 id;
@ -1537,6 +1611,46 @@ struct hci_rp_read_enc_key_size {
__u8 key_size;
} __packed;
#define HCI_OP_READ_LOCAL_AMP_INFO 0x1409
struct hci_rp_read_local_amp_info {
__u8 status;
__u8 amp_status;
__le32 total_bw;
__le32 max_bw;
__le32 min_latency;
__le32 max_pdu;
__u8 amp_type;
__le16 pal_cap;
__le16 max_assoc_size;
__le32 max_flush_to;
__le32 be_flush_to;
} __packed;
#define HCI_OP_READ_LOCAL_AMP_ASSOC 0x140a
struct hci_cp_read_local_amp_assoc {
__u8 phy_handle;
__le16 len_so_far;
__le16 max_len;
} __packed;
struct hci_rp_read_local_amp_assoc {
__u8 status;
__u8 phy_handle;
__le16 rem_len;
__u8 frag[];
} __packed;
#define HCI_OP_WRITE_REMOTE_AMP_ASSOC 0x140b
struct hci_cp_write_remote_amp_assoc {
__u8 phy_handle;
__le16 len_so_far;
__le16 rem_len;
__u8 frag[];
} __packed;
struct hci_rp_write_remote_amp_assoc {
__u8 status;
__u8 phy_handle;
} __packed;
#define HCI_OP_GET_MWS_TRANSPORT_CONFIG 0x140c
#define HCI_OP_ENABLE_DUT_MODE 0x1803

View File

@ -127,6 +127,7 @@ enum suspended_state {
struct hci_conn_hash {
struct list_head list;
unsigned int acl_num;
unsigned int amp_num;
unsigned int sco_num;
unsigned int iso_num;
unsigned int le_num;
@ -341,6 +342,14 @@ struct adv_monitor {
/* Default authenticated payload timeout 30s */
#define DEFAULT_AUTH_PAYLOAD_TIMEOUT 0x0bb8
struct amp_assoc {
__u16 len;
__u16 offset;
__u16 rem_len;
__u16 len_so_far;
__u8 data[HCI_MAX_AMP_ASSOC_SIZE];
};
#define HCI_MAX_PAGES 3
struct hci_dev {
@ -353,6 +362,7 @@ struct hci_dev {
unsigned long flags;
__u16 id;
__u8 bus;
__u8 dev_type;
bdaddr_t bdaddr;
bdaddr_t setup_addr;
bdaddr_t public_addr;
@ -458,6 +468,21 @@ struct hci_dev {
__u16 sniff_min_interval;
__u16 sniff_max_interval;
__u8 amp_status;
__u32 amp_total_bw;
__u32 amp_max_bw;
__u32 amp_min_latency;
__u32 amp_max_pdu;
__u8 amp_type;
__u16 amp_pal_cap;
__u16 amp_assoc_size;
__u32 amp_max_flush_to;
__u32 amp_be_flush_to;
struct amp_assoc loc_assoc;
__u8 flow_ctl_mode;
unsigned int auto_accept_delay;
unsigned long quirks;
@ -477,6 +502,11 @@ struct hci_dev {
unsigned int le_pkts;
unsigned int iso_pkts;
__u16 block_len;
__u16 block_mtu;
__u16 num_blocks;
__u16 block_cnt;
unsigned long acl_last_tx;
unsigned long sco_last_tx;
unsigned long le_last_tx;
@ -752,6 +782,7 @@ struct hci_conn {
void *l2cap_data;
void *sco_data;
void *iso_data;
struct amp_mgr *amp_mgr;
struct list_head link_list;
struct hci_conn *parent;
@ -783,7 +814,6 @@ struct hci_chan {
struct sk_buff_head data_q;
unsigned int sent;
__u8 state;
bool amp;
ANDROID_KABI_RESERVE(1);
};
@ -996,6 +1026,9 @@ static inline void hci_conn_hash_add(struct hci_dev *hdev, struct hci_conn *c)
case ACL_LINK:
h->acl_num++;
break;
case AMP_LINK:
h->amp_num++;
break;
case LE_LINK:
h->le_num++;
if (c->role == HCI_ROLE_SLAVE)
@ -1022,6 +1055,9 @@ static inline void hci_conn_hash_del(struct hci_dev *hdev, struct hci_conn *c)
case ACL_LINK:
h->acl_num--;
break;
case AMP_LINK:
h->amp_num--;
break;
case LE_LINK:
h->le_num--;
if (c->role == HCI_ROLE_SLAVE)
@ -1043,6 +1079,8 @@ static inline unsigned int hci_conn_num(struct hci_dev *hdev, __u8 type)
switch (type) {
case ACL_LINK:
return h->acl_num;
case AMP_LINK:
return h->amp_num;
case LE_LINK:
return h->le_num;
case SCO_LINK:
@ -1059,7 +1097,7 @@ static inline unsigned int hci_conn_count(struct hci_dev *hdev)
{
struct hci_conn_hash *c = &hdev->conn_hash;
return c->acl_num + c->sco_num + c->le_num + c->iso_num;
return c->acl_num + c->amp_num + c->sco_num + c->le_num + c->iso_num;
}
static inline __u8 hci_conn_lookup_type(struct hci_dev *hdev, __u16 handle)
@ -1545,6 +1583,10 @@ static inline void hci_conn_drop(struct hci_conn *conn)
}
break;
case AMP_LINK:
timeo = conn->disc_timeout;
break;
default:
timeo = 0;
break;

View File

@ -13,6 +13,7 @@
enum virtio_bt_config_type {
VIRTIO_BT_CONFIG_TYPE_PRIMARY = 0,
VIRTIO_BT_CONFIG_TYPE_AMP = 1,
};
enum virtio_bt_config_vendor {

View File

@ -1200,7 +1200,8 @@ struct hci_dev *hci_get_route(bdaddr_t *dst, bdaddr_t *src, uint8_t src_type)
list_for_each_entry(d, &hci_dev_list, list) {
if (!test_bit(HCI_UP, &d->flags) ||
hci_dev_test_flag(d, HCI_USER_CHANNEL))
hci_dev_test_flag(d, HCI_USER_CHANNEL) ||
d->dev_type != HCI_PRIMARY)
continue;
/* Simple routing:

View File

@ -395,6 +395,11 @@ int hci_inquiry(void __user *arg)
goto done;
}
if (hdev->dev_type != HCI_PRIMARY) {
err = -EOPNOTSUPP;
goto done;
}
if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
err = -EOPNOTSUPP;
goto done;
@ -747,6 +752,11 @@ int hci_dev_cmd(unsigned int cmd, void __user *arg)
goto done;
}
if (hdev->dev_type != HCI_PRIMARY) {
err = -EOPNOTSUPP;
goto done;
}
if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
err = -EOPNOTSUPP;
goto done;
@ -900,7 +910,7 @@ int hci_get_dev_info(void __user *arg)
strscpy(di.name, hdev->name, sizeof(di.name));
di.bdaddr = hdev->bdaddr;
di.type = (hdev->bus & 0x0f);
di.type = (hdev->bus & 0x0f) | ((hdev->dev_type & 0x03) << 4);
di.flags = flags;
di.pkt_type = hdev->pkt_type;
if (lmp_bredr_capable(hdev)) {
@ -985,7 +995,8 @@ static void hci_power_on(struct work_struct *work)
*/
if (hci_dev_test_flag(hdev, HCI_RFKILLED) ||
hci_dev_test_flag(hdev, HCI_UNCONFIGURED) ||
(!bacmp(&hdev->bdaddr, BDADDR_ANY) &&
(hdev->dev_type == HCI_PRIMARY &&
!bacmp(&hdev->bdaddr, BDADDR_ANY) &&
!bacmp(&hdev->static_addr, BDADDR_ANY))) {
hci_dev_clear_flag(hdev, HCI_AUTO_OFF);
hci_dev_do_close(hdev);
@ -2593,7 +2604,21 @@ int hci_register_dev(struct hci_dev *hdev)
if (!hdev->open || !hdev->close || !hdev->send)
return -EINVAL;
id = ida_alloc_max(&hci_index_ida, HCI_MAX_ID - 1, GFP_KERNEL);
/* Do not allow HCI_AMP devices to register at index 0,
* so the index can be used as the AMP controller ID.
*/
switch (hdev->dev_type) {
case HCI_PRIMARY:
id = ida_alloc_max(&hci_index_ida, HCI_MAX_ID - 1, GFP_KERNEL);
break;
case HCI_AMP:
id = ida_alloc_range(&hci_index_ida, 1, HCI_MAX_ID - 1,
GFP_KERNEL);
break;
default:
return -EINVAL;
}
if (id < 0)
return id;
@ -2645,10 +2670,12 @@ int hci_register_dev(struct hci_dev *hdev)
hci_dev_set_flag(hdev, HCI_SETUP);
hci_dev_set_flag(hdev, HCI_AUTO_OFF);
/* Assume BR/EDR support until proven otherwise (such as
* through reading supported features during init.
*/
hci_dev_set_flag(hdev, HCI_BREDR_ENABLED);
if (hdev->dev_type == HCI_PRIMARY) {
/* Assume BR/EDR support until proven otherwise (such as
* through reading supported features during init.
*/
hci_dev_set_flag(hdev, HCI_BREDR_ENABLED);
}
write_lock(&hci_dev_list_lock);
list_add(&hdev->list, &hci_dev_list);
@ -3184,7 +3211,17 @@ static void hci_queue_acl(struct hci_chan *chan, struct sk_buff_head *queue,
hci_skb_pkt_type(skb) = HCI_ACLDATA_PKT;
hci_add_acl_hdr(skb, conn->handle, flags);
switch (hdev->dev_type) {
case HCI_PRIMARY:
hci_add_acl_hdr(skb, conn->handle, flags);
break;
case HCI_AMP:
hci_add_acl_hdr(skb, chan->handle, flags);
break;
default:
bt_dev_err(hdev, "unknown dev_type %d", hdev->dev_type);
return;
}
list = skb_shinfo(skb)->frag_list;
if (!list) {
@ -3344,6 +3381,9 @@ static inline void hci_quote_sent(struct hci_conn *conn, int num, int *quote)
case ACL_LINK:
cnt = hdev->acl_cnt;
break;
case AMP_LINK:
cnt = hdev->block_cnt;
break;
case SCO_LINK:
case ESCO_LINK:
cnt = hdev->sco_cnt;
@ -3541,6 +3581,12 @@ static void hci_prio_recalculate(struct hci_dev *hdev, __u8 type)
}
static inline int __get_blocks(struct hci_dev *hdev, struct sk_buff *skb)
{
/* Calculate count of blocks used by this packet */
return DIV_ROUND_UP(skb->len - HCI_ACL_HDR_SIZE, hdev->block_len);
}
static void __check_timeout(struct hci_dev *hdev, unsigned int cnt, u8 type)
{
unsigned long last_tx;
@ -3654,15 +3700,81 @@ static void hci_sched_acl_pkt(struct hci_dev *hdev)
hci_prio_recalculate(hdev, ACL_LINK);
}
static void hci_sched_acl_blk(struct hci_dev *hdev)
{
unsigned int cnt = hdev->block_cnt;
struct hci_chan *chan;
struct sk_buff *skb;
int quote;
u8 type;
BT_DBG("%s", hdev->name);
if (hdev->dev_type == HCI_AMP)
type = AMP_LINK;
else
type = ACL_LINK;
__check_timeout(hdev, cnt, type);
while (hdev->block_cnt > 0 &&
(chan = hci_chan_sent(hdev, type, &quote))) {
u32 priority = (skb_peek(&chan->data_q))->priority;
while (quote > 0 && (skb = skb_peek(&chan->data_q))) {
int blocks;
BT_DBG("chan %p skb %p len %d priority %u", chan, skb,
skb->len, skb->priority);
/* Stop if priority has changed */
if (skb->priority < priority)
break;
skb = skb_dequeue(&chan->data_q);
blocks = __get_blocks(hdev, skb);
if (blocks > hdev->block_cnt)
return;
hci_conn_enter_active_mode(chan->conn,
bt_cb(skb)->force_active);
hci_send_frame(hdev, skb);
hdev->acl_last_tx = jiffies;
hdev->block_cnt -= blocks;
quote -= blocks;
chan->sent += blocks;
chan->conn->sent += blocks;
}
}
if (cnt != hdev->block_cnt)
hci_prio_recalculate(hdev, type);
}
static void hci_sched_acl(struct hci_dev *hdev)
{
BT_DBG("%s", hdev->name);
/* No ACL link over BR/EDR controller */
if (!hci_conn_num(hdev, ACL_LINK))
if (!hci_conn_num(hdev, ACL_LINK) && hdev->dev_type == HCI_PRIMARY)
return;
hci_sched_acl_pkt(hdev);
/* No AMP link over AMP controller */
if (!hci_conn_num(hdev, AMP_LINK) && hdev->dev_type == HCI_AMP)
return;
switch (hdev->flow_ctl_mode) {
case HCI_FLOW_CTL_MODE_PACKET_BASED:
hci_sched_acl_pkt(hdev);
break;
case HCI_FLOW_CTL_MODE_BLOCK_BASED:
hci_sched_acl_blk(hdev);
break;
}
}
static void hci_sched_le(struct hci_dev *hdev)

View File

@ -917,6 +917,21 @@ static u8 hci_cc_read_local_ext_features(struct hci_dev *hdev, void *data,
return rp->status;
}
static u8 hci_cc_read_flow_control_mode(struct hci_dev *hdev, void *data,
struct sk_buff *skb)
{
struct hci_rp_read_flow_control_mode *rp = data;
bt_dev_dbg(hdev, "status 0x%2.2x", rp->status);
if (rp->status)
return rp->status;
hdev->flow_ctl_mode = rp->mode;
return rp->status;
}
static u8 hci_cc_read_buffer_size(struct hci_dev *hdev, void *data,
struct sk_buff *skb)
{
@ -1060,6 +1075,28 @@ static u8 hci_cc_write_page_scan_type(struct hci_dev *hdev, void *data,
return rp->status;
}
static u8 hci_cc_read_data_block_size(struct hci_dev *hdev, void *data,
struct sk_buff *skb)
{
struct hci_rp_read_data_block_size *rp = data;
bt_dev_dbg(hdev, "status 0x%2.2x", rp->status);
if (rp->status)
return rp->status;
hdev->block_mtu = __le16_to_cpu(rp->max_acl_len);
hdev->block_len = __le16_to_cpu(rp->block_len);
hdev->num_blocks = __le16_to_cpu(rp->num_blocks);
hdev->block_cnt = hdev->num_blocks;
BT_DBG("%s blk mtu %d cnt %d len %d", hdev->name, hdev->block_mtu,
hdev->block_cnt, hdev->block_len);
return rp->status;
}
static u8 hci_cc_read_clock(struct hci_dev *hdev, void *data,
struct sk_buff *skb)
{
@ -1094,6 +1131,30 @@ unlock:
return rp->status;
}
static u8 hci_cc_read_local_amp_info(struct hci_dev *hdev, void *data,
struct sk_buff *skb)
{
struct hci_rp_read_local_amp_info *rp = data;
bt_dev_dbg(hdev, "status 0x%2.2x", rp->status);
if (rp->status)
return rp->status;
hdev->amp_status = rp->amp_status;
hdev->amp_total_bw = __le32_to_cpu(rp->total_bw);
hdev->amp_max_bw = __le32_to_cpu(rp->max_bw);
hdev->amp_min_latency = __le32_to_cpu(rp->min_latency);
hdev->amp_max_pdu = __le32_to_cpu(rp->max_pdu);
hdev->amp_type = rp->amp_type;
hdev->amp_pal_cap = __le16_to_cpu(rp->pal_cap);
hdev->amp_assoc_size = __le16_to_cpu(rp->max_assoc_size);
hdev->amp_be_flush_to = __le32_to_cpu(rp->be_flush_to);
hdev->amp_max_flush_to = __le32_to_cpu(rp->max_flush_to);
return rp->status;
}
static u8 hci_cc_read_inq_rsp_tx_power(struct hci_dev *hdev, void *data,
struct sk_buff *skb)
{
@ -4073,6 +4134,12 @@ static const struct hci_cc {
HCI_CC(HCI_OP_READ_PAGE_SCAN_TYPE, hci_cc_read_page_scan_type,
sizeof(struct hci_rp_read_page_scan_type)),
HCI_CC_STATUS(HCI_OP_WRITE_PAGE_SCAN_TYPE, hci_cc_write_page_scan_type),
HCI_CC(HCI_OP_READ_DATA_BLOCK_SIZE, hci_cc_read_data_block_size,
sizeof(struct hci_rp_read_data_block_size)),
HCI_CC(HCI_OP_READ_FLOW_CONTROL_MODE, hci_cc_read_flow_control_mode,
sizeof(struct hci_rp_read_flow_control_mode)),
HCI_CC(HCI_OP_READ_LOCAL_AMP_INFO, hci_cc_read_local_amp_info,
sizeof(struct hci_rp_read_local_amp_info)),
HCI_CC(HCI_OP_READ_CLOCK, hci_cc_read_clock,
sizeof(struct hci_rp_read_clock)),
HCI_CC(HCI_OP_READ_ENC_KEY_SIZE, hci_cc_read_enc_key_size,
@ -4407,6 +4474,11 @@ static void hci_num_comp_pkts_evt(struct hci_dev *hdev, void *data,
flex_array_size(ev, handles, ev->num)))
return;
if (hdev->flow_ctl_mode != HCI_FLOW_CTL_MODE_PACKET_BASED) {
bt_dev_err(hdev, "wrong event for mode %d", hdev->flow_ctl_mode);
return;
}
bt_dev_dbg(hdev, "num %d", ev->num);
for (i = 0; i < ev->num; i++) {
@ -4474,6 +4546,78 @@ static void hci_num_comp_pkts_evt(struct hci_dev *hdev, void *data,
queue_work(hdev->workqueue, &hdev->tx_work);
}
static struct hci_conn *__hci_conn_lookup_handle(struct hci_dev *hdev,
__u16 handle)
{
struct hci_chan *chan;
switch (hdev->dev_type) {
case HCI_PRIMARY:
return hci_conn_hash_lookup_handle(hdev, handle);
case HCI_AMP:
chan = hci_chan_lookup_handle(hdev, handle);
if (chan)
return chan->conn;
break;
default:
bt_dev_err(hdev, "unknown dev_type %d", hdev->dev_type);
break;
}
return NULL;
}
static void hci_num_comp_blocks_evt(struct hci_dev *hdev, void *data,
struct sk_buff *skb)
{
struct hci_ev_num_comp_blocks *ev = data;
int i;
if (!hci_ev_skb_pull(hdev, skb, HCI_EV_NUM_COMP_BLOCKS,
flex_array_size(ev, handles, ev->num_hndl)))
return;
if (hdev->flow_ctl_mode != HCI_FLOW_CTL_MODE_BLOCK_BASED) {
bt_dev_err(hdev, "wrong event for mode %d",
hdev->flow_ctl_mode);
return;
}
bt_dev_dbg(hdev, "num_blocks %d num_hndl %d", ev->num_blocks,
ev->num_hndl);
for (i = 0; i < ev->num_hndl; i++) {
struct hci_comp_blocks_info *info = &ev->handles[i];
struct hci_conn *conn = NULL;
__u16 handle, block_count;
handle = __le16_to_cpu(info->handle);
block_count = __le16_to_cpu(info->blocks);
conn = __hci_conn_lookup_handle(hdev, handle);
if (!conn)
continue;
conn->sent -= block_count;
switch (conn->type) {
case ACL_LINK:
case AMP_LINK:
hdev->block_cnt += block_count;
if (hdev->block_cnt > hdev->num_blocks)
hdev->block_cnt = hdev->num_blocks;
break;
default:
bt_dev_err(hdev, "unknown type %d conn %p",
conn->type, conn);
break;
}
}
queue_work(hdev->workqueue, &hdev->tx_work);
}
static void hci_mode_change_evt(struct hci_dev *hdev, void *data,
struct sk_buff *skb)
{
@ -7387,6 +7531,9 @@ static const struct hci_ev {
/* [0x3e = HCI_EV_LE_META] */
HCI_EV_REQ_VL(HCI_EV_LE_META, hci_le_meta_evt,
sizeof(struct hci_ev_le_meta), HCI_MAX_EVENT_SIZE),
/* [0x48 = HCI_EV_NUM_COMP_BLOCKS] */
HCI_EV(HCI_EV_NUM_COMP_BLOCKS, hci_num_comp_blocks_evt,
sizeof(struct hci_ev_num_comp_blocks)),
/* [0xff = HCI_EV_VENDOR] */
HCI_EV_VL(HCI_EV_VENDOR, msft_vendor_evt, 0, HCI_MAX_EVENT_SIZE),
};

View File

@ -485,7 +485,7 @@ static struct sk_buff *create_monitor_event(struct hci_dev *hdev, int event)
return NULL;
ni = skb_put(skb, HCI_MON_NEW_INDEX_SIZE);
ni->type = 0x00; /* Old hdev->dev_type */
ni->type = hdev->dev_type;
ni->bus = hdev->bus;
bacpy(&ni->bdaddr, &hdev->bdaddr);
memcpy_and_pad(ni->name, sizeof(ni->name), hdev->name,
@ -1007,6 +1007,9 @@ static int hci_sock_bound_ioctl(struct sock *sk, unsigned int cmd,
if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED))
return -EOPNOTSUPP;
if (hdev->dev_type != HCI_PRIMARY)
return -EOPNOTSUPP;
switch (cmd) {
case HCISETRAW:
if (!capable(CAP_NET_ADMIN))

View File

@ -3440,6 +3440,10 @@ static int hci_unconf_init_sync(struct hci_dev *hdev)
/* Read Local Supported Features. */
static int hci_read_local_features_sync(struct hci_dev *hdev)
{
/* Not all AMP controllers support this command */
if (hdev->dev_type == HCI_AMP && !(hdev->commands[14] & 0x20))
return 0;
return __hci_cmd_sync_status(hdev, HCI_OP_READ_LOCAL_FEATURES,
0, NULL, HCI_CMD_TIMEOUT);
}
@ -3474,6 +3478,51 @@ static int hci_read_local_cmds_sync(struct hci_dev *hdev)
return 0;
}
/* Read Local AMP Info */
static int hci_read_local_amp_info_sync(struct hci_dev *hdev)
{
return __hci_cmd_sync_status(hdev, HCI_OP_READ_LOCAL_AMP_INFO,
0, NULL, HCI_CMD_TIMEOUT);
}
/* Read Data Blk size */
static int hci_read_data_block_size_sync(struct hci_dev *hdev)
{
return __hci_cmd_sync_status(hdev, HCI_OP_READ_DATA_BLOCK_SIZE,
0, NULL, HCI_CMD_TIMEOUT);
}
/* Read Flow Control Mode */
static int hci_read_flow_control_mode_sync(struct hci_dev *hdev)
{
return __hci_cmd_sync_status(hdev, HCI_OP_READ_FLOW_CONTROL_MODE,
0, NULL, HCI_CMD_TIMEOUT);
}
/* Read Location Data */
static int hci_read_location_data_sync(struct hci_dev *hdev)
{
return __hci_cmd_sync_status(hdev, HCI_OP_READ_LOCATION_DATA,
0, NULL, HCI_CMD_TIMEOUT);
}
/* AMP Controller init stage 1 command sequence */
static const struct hci_init_stage amp_init1[] = {
/* HCI_OP_READ_LOCAL_VERSION */
HCI_INIT(hci_read_local_version_sync),
/* HCI_OP_READ_LOCAL_COMMANDS */
HCI_INIT(hci_read_local_cmds_sync),
/* HCI_OP_READ_LOCAL_AMP_INFO */
HCI_INIT(hci_read_local_amp_info_sync),
/* HCI_OP_READ_DATA_BLOCK_SIZE */
HCI_INIT(hci_read_data_block_size_sync),
/* HCI_OP_READ_FLOW_CONTROL_MODE */
HCI_INIT(hci_read_flow_control_mode_sync),
/* HCI_OP_READ_LOCATION_DATA */
HCI_INIT(hci_read_location_data_sync),
{}
};
static int hci_init1_sync(struct hci_dev *hdev)
{
int err;
@ -3487,9 +3536,28 @@ static int hci_init1_sync(struct hci_dev *hdev)
return err;
}
return hci_init_stage_sync(hdev, br_init1);
switch (hdev->dev_type) {
case HCI_PRIMARY:
hdev->flow_ctl_mode = HCI_FLOW_CTL_MODE_PACKET_BASED;
return hci_init_stage_sync(hdev, br_init1);
case HCI_AMP:
hdev->flow_ctl_mode = HCI_FLOW_CTL_MODE_BLOCK_BASED;
return hci_init_stage_sync(hdev, amp_init1);
default:
bt_dev_err(hdev, "Unknown device type %d", hdev->dev_type);
break;
}
return 0;
}
/* AMP Controller init stage 2 command sequence */
static const struct hci_init_stage amp_init2[] = {
/* HCI_OP_READ_LOCAL_FEATURES */
HCI_INIT(hci_read_local_features_sync),
{}
};
/* Read Buffer Size (ACL mtu, max pkt, etc.) */
static int hci_read_buffer_size_sync(struct hci_dev *hdev)
{
@ -3747,6 +3815,9 @@ static int hci_init2_sync(struct hci_dev *hdev)
bt_dev_dbg(hdev, "");
if (hdev->dev_type == HCI_AMP)
return hci_init_stage_sync(hdev, amp_init2);
err = hci_init_stage_sync(hdev, hci_init2);
if (err)
return err;
@ -4584,6 +4655,13 @@ static int hci_init_sync(struct hci_dev *hdev)
if (err < 0)
return err;
/* HCI_PRIMARY covers both single-mode LE, BR/EDR and dual-mode
* BR/EDR/LE type controllers. AMP controllers only need the
* first two stages of init.
*/
if (hdev->dev_type != HCI_PRIMARY)
return 0;
err = hci_init3_sync(hdev);
if (err < 0)
return err;
@ -4812,8 +4890,12 @@ int hci_dev_open_sync(struct hci_dev *hdev)
* In case of user channel usage, it is not important
* if a public address or static random address is
* available.
*
* This check is only valid for BR/EDR controllers
* since AMP controllers do not have an address.
*/
if (!hci_dev_test_flag(hdev, HCI_USER_CHANNEL) &&
hdev->dev_type == HCI_PRIMARY &&
!bacmp(&hdev->bdaddr, BDADDR_ANY) &&
!bacmp(&hdev->static_addr, BDADDR_ANY)) {
ret = -EADDRNOTAVAIL;
@ -4848,7 +4930,8 @@ int hci_dev_open_sync(struct hci_dev *hdev)
!hci_dev_test_flag(hdev, HCI_CONFIG) &&
!hci_dev_test_flag(hdev, HCI_UNCONFIGURED) &&
!hci_dev_test_flag(hdev, HCI_USER_CHANNEL) &&
hci_dev_test_flag(hdev, HCI_MGMT)) {
hci_dev_test_flag(hdev, HCI_MGMT) &&
hdev->dev_type == HCI_PRIMARY) {
ret = hci_powered_update_sync(hdev);
mgmt_power_on(hdev, ret);
}
@ -4994,7 +5077,8 @@ int hci_dev_close_sync(struct hci_dev *hdev)
auto_off = hci_dev_test_and_clear_flag(hdev, HCI_AUTO_OFF);
if (!auto_off && !hci_dev_test_flag(hdev, HCI_USER_CHANNEL) &&
if (!auto_off && hdev->dev_type == HCI_PRIMARY &&
!hci_dev_test_flag(hdev, HCI_USER_CHANNEL) &&
hci_dev_test_flag(hdev, HCI_MGMT))
__mgmt_power_off(hdev);
@ -5056,6 +5140,9 @@ int hci_dev_close_sync(struct hci_dev *hdev)
hdev->flags &= BIT(HCI_RAW);
hci_dev_clear_volatile_flags(hdev);
/* Controller radio is available but is currently powered down */
hdev->amp_status = AMP_STATUS_POWERED_DOWN;
memset(hdev->eir, 0, sizeof(hdev->eir));
memset(hdev->dev_class, 0, sizeof(hdev->dev_class));
bacpy(&hdev->random_addr, BDADDR_ANY);
@ -5092,7 +5179,8 @@ static int hci_power_on_sync(struct hci_dev *hdev)
*/
if (hci_dev_test_flag(hdev, HCI_RFKILLED) ||
hci_dev_test_flag(hdev, HCI_UNCONFIGURED) ||
(!bacmp(&hdev->bdaddr, BDADDR_ANY) &&
(hdev->dev_type == HCI_PRIMARY &&
!bacmp(&hdev->bdaddr, BDADDR_ANY) &&
!bacmp(&hdev->static_addr, BDADDR_ANY))) {
hci_dev_clear_flag(hdev, HCI_AUTO_OFF);
hci_dev_close_sync(hdev);
@ -5195,11 +5283,27 @@ int hci_stop_discovery_sync(struct hci_dev *hdev)
return 0;
}
static int hci_disconnect_phy_link_sync(struct hci_dev *hdev, u16 handle,
u8 reason)
{
struct hci_cp_disconn_phy_link cp;
memset(&cp, 0, sizeof(cp));
cp.phy_handle = HCI_PHY_HANDLE(handle);
cp.reason = reason;
return __hci_cmd_sync_status(hdev, HCI_OP_DISCONN_PHY_LINK,
sizeof(cp), &cp, HCI_CMD_TIMEOUT);
}
static int hci_disconnect_sync(struct hci_dev *hdev, struct hci_conn *conn,
u8 reason)
{
struct hci_cp_disconnect cp;
if (conn->type == AMP_LINK)
return hci_disconnect_phy_link_sync(hdev, conn->handle, reason);
if (test_bit(HCI_CONN_BIG_CREATED, &conn->flags)) {
/* This is a BIS connection, hci_conn_del will
* do the necessary cleanup.

View File

@ -3930,7 +3930,7 @@ static inline int l2cap_command_rej(struct l2cap_conn *conn,
}
static void l2cap_connect(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd,
u8 *data, u8 rsp_code)
u8 *data, u8 rsp_code, u8 amp_id)
{
struct l2cap_conn_req *req = (struct l2cap_conn_req *) data;
struct l2cap_conn_rsp rsp;
@ -4009,8 +4009,17 @@ static void l2cap_connect(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd,
status = L2CAP_CS_AUTHOR_PEND;
chan->ops->defer(chan);
} else {
l2cap_state_change(chan, BT_CONNECT2);
result = L2CAP_CR_PEND;
/* Force pending result for AMP controllers.
* The connection will succeed after the
* physical link is up.
*/
if (amp_id == AMP_ID_BREDR) {
l2cap_state_change(chan, BT_CONFIG);
result = L2CAP_CR_SUCCESS;
} else {
l2cap_state_change(chan, BT_CONNECT2);
result = L2CAP_CR_PEND;
}
status = L2CAP_CS_NO_INFO;
}
} else {
@ -4075,7 +4084,7 @@ static int l2cap_connect_req(struct l2cap_conn *conn,
mgmt_device_connected(hdev, hcon, NULL, 0);
hci_dev_unlock(hdev);
l2cap_connect(conn, cmd, data, L2CAP_CONN_RSP);
l2cap_connect(conn, cmd, data, L2CAP_CONN_RSP, 0);
return 0;
}
@ -7488,6 +7497,10 @@ void l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 flags)
struct l2cap_conn *conn = hcon->l2cap_data;
int len;
/* For AMP controller do not create l2cap conn */
if (!conn && hcon->hdev->dev_type != HCI_PRIMARY)
goto drop;
if (!conn)
conn = l2cap_conn_add(hcon);

View File

@ -443,7 +443,8 @@ static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data,
count = 0;
list_for_each_entry(d, &hci_dev_list, list) {
if (!hci_dev_test_flag(d, HCI_UNCONFIGURED))
if (d->dev_type == HCI_PRIMARY &&
!hci_dev_test_flag(d, HCI_UNCONFIGURED))
count++;
}
@ -467,7 +468,8 @@ static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data,
if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks))
continue;
if (!hci_dev_test_flag(d, HCI_UNCONFIGURED)) {
if (d->dev_type == HCI_PRIMARY &&
!hci_dev_test_flag(d, HCI_UNCONFIGURED)) {
rp->index[count++] = cpu_to_le16(d->id);
bt_dev_dbg(hdev, "Added hci%u", d->id);
}
@ -501,7 +503,8 @@ static int read_unconf_index_list(struct sock *sk, struct hci_dev *hdev,
count = 0;
list_for_each_entry(d, &hci_dev_list, list) {
if (hci_dev_test_flag(d, HCI_UNCONFIGURED))
if (d->dev_type == HCI_PRIMARY &&
hci_dev_test_flag(d, HCI_UNCONFIGURED))
count++;
}
@ -525,7 +528,8 @@ static int read_unconf_index_list(struct sock *sk, struct hci_dev *hdev,
if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks))
continue;
if (hci_dev_test_flag(d, HCI_UNCONFIGURED)) {
if (d->dev_type == HCI_PRIMARY &&
hci_dev_test_flag(d, HCI_UNCONFIGURED)) {
rp->index[count++] = cpu_to_le16(d->id);
bt_dev_dbg(hdev, "Added hci%u", d->id);
}
@ -557,8 +561,10 @@ static int read_ext_index_list(struct sock *sk, struct hci_dev *hdev,
read_lock(&hci_dev_list_lock);
count = 0;
list_for_each_entry(d, &hci_dev_list, list)
count++;
list_for_each_entry(d, &hci_dev_list, list) {
if (d->dev_type == HCI_PRIMARY || d->dev_type == HCI_AMP)
count++;
}
rp = kmalloc(struct_size(rp, entry, count), GFP_ATOMIC);
if (!rp) {
@ -579,10 +585,16 @@ static int read_ext_index_list(struct sock *sk, struct hci_dev *hdev,
if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks))
continue;
if (hci_dev_test_flag(d, HCI_UNCONFIGURED))
rp->entry[count].type = 0x01;
else
rp->entry[count].type = 0x00;
if (d->dev_type == HCI_PRIMARY) {
if (hci_dev_test_flag(d, HCI_UNCONFIGURED))
rp->entry[count].type = 0x01;
else
rp->entry[count].type = 0x00;
} else if (d->dev_type == HCI_AMP) {
rp->entry[count].type = 0x02;
} else {
continue;
}
rp->entry[count].bus = d->bus;
rp->entry[count++].index = cpu_to_le16(d->id);
@ -9312,14 +9324,23 @@ void mgmt_index_added(struct hci_dev *hdev)
if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
return;
if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) {
mgmt_index_event(MGMT_EV_UNCONF_INDEX_ADDED, hdev, NULL, 0,
HCI_MGMT_UNCONF_INDEX_EVENTS);
ev.type = 0x01;
} else {
mgmt_index_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0,
HCI_MGMT_INDEX_EVENTS);
ev.type = 0x00;
switch (hdev->dev_type) {
case HCI_PRIMARY:
if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) {
mgmt_index_event(MGMT_EV_UNCONF_INDEX_ADDED, hdev,
NULL, 0, HCI_MGMT_UNCONF_INDEX_EVENTS);
ev.type = 0x01;
} else {
mgmt_index_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0,
HCI_MGMT_INDEX_EVENTS);
ev.type = 0x00;
}
break;
case HCI_AMP:
ev.type = 0x02;
break;
default:
return;
}
ev.bus = hdev->bus;
@ -9336,16 +9357,25 @@ void mgmt_index_removed(struct hci_dev *hdev)
if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
return;
mgmt_pending_foreach(0, hdev, cmd_complete_rsp, &status);
switch (hdev->dev_type) {
case HCI_PRIMARY:
mgmt_pending_foreach(0, hdev, cmd_complete_rsp, &status);
if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) {
mgmt_index_event(MGMT_EV_UNCONF_INDEX_REMOVED, hdev, NULL, 0,
HCI_MGMT_UNCONF_INDEX_EVENTS);
ev.type = 0x01;
} else {
mgmt_index_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0,
HCI_MGMT_INDEX_EVENTS);
ev.type = 0x00;
if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) {
mgmt_index_event(MGMT_EV_UNCONF_INDEX_REMOVED, hdev,
NULL, 0, HCI_MGMT_UNCONF_INDEX_EVENTS);
ev.type = 0x01;
} else {
mgmt_index_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0,
HCI_MGMT_INDEX_EVENTS);
ev.type = 0x00;
}
break;
case HCI_AMP:
ev.type = 0x02;
break;
default:
return;
}
ev.bus = hdev->bus;