mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-12 05:48:40 +00:00
Merge branch 'for-upstream' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next
This commit is contained in:
commit
0006433a5b
13 changed files with 407 additions and 138 deletions
|
@ -59,6 +59,8 @@ struct btmrvl_device {
|
|||
};
|
||||
|
||||
struct btmrvl_adapter {
|
||||
void *hw_regs_buf;
|
||||
u8 *hw_regs;
|
||||
u32 int_count;
|
||||
struct sk_buff_head tx_queue;
|
||||
u8 psmode;
|
||||
|
@ -140,7 +142,7 @@ void btmrvl_interrupt(struct btmrvl_private *priv);
|
|||
bool btmrvl_check_evtpkt(struct btmrvl_private *priv, struct sk_buff *skb);
|
||||
int btmrvl_process_event(struct btmrvl_private *priv, struct sk_buff *skb);
|
||||
|
||||
int btmrvl_send_module_cfg_cmd(struct btmrvl_private *priv, int subcmd);
|
||||
int btmrvl_send_module_cfg_cmd(struct btmrvl_private *priv, u8 subcmd);
|
||||
int btmrvl_send_hscfg_cmd(struct btmrvl_private *priv);
|
||||
int btmrvl_enable_ps(struct btmrvl_private *priv);
|
||||
int btmrvl_prepare_command(struct btmrvl_private *priv);
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include <net/bluetooth/hci_core.h>
|
||||
|
||||
#include "btmrvl_drv.h"
|
||||
#include "btmrvl_sdio.h"
|
||||
|
||||
#define VERSION "1.0"
|
||||
|
||||
|
@ -201,7 +202,7 @@ static int btmrvl_send_sync_cmd(struct btmrvl_private *priv, u16 opcode,
|
|||
return 0;
|
||||
}
|
||||
|
||||
int btmrvl_send_module_cfg_cmd(struct btmrvl_private *priv, int subcmd)
|
||||
int btmrvl_send_module_cfg_cmd(struct btmrvl_private *priv, u8 subcmd)
|
||||
{
|
||||
int ret;
|
||||
|
||||
|
@ -337,10 +338,25 @@ static int btmrvl_tx_pkt(struct btmrvl_private *priv, struct sk_buff *skb)
|
|||
|
||||
static void btmrvl_init_adapter(struct btmrvl_private *priv)
|
||||
{
|
||||
int buf_size;
|
||||
|
||||
skb_queue_head_init(&priv->adapter->tx_queue);
|
||||
|
||||
priv->adapter->ps_state = PS_AWAKE;
|
||||
|
||||
buf_size = ALIGN_SZ(SDIO_BLOCK_SIZE, BTSDIO_DMA_ALIGN);
|
||||
priv->adapter->hw_regs_buf = kzalloc(buf_size, GFP_KERNEL);
|
||||
if (!priv->adapter->hw_regs_buf) {
|
||||
priv->adapter->hw_regs = NULL;
|
||||
BT_ERR("Unable to allocate buffer for hw_regs.");
|
||||
} else {
|
||||
priv->adapter->hw_regs =
|
||||
(u8 *)ALIGN_ADDR(priv->adapter->hw_regs_buf,
|
||||
BTSDIO_DMA_ALIGN);
|
||||
BT_DBG("hw_regs_buf=%p hw_regs=%p",
|
||||
priv->adapter->hw_regs_buf, priv->adapter->hw_regs);
|
||||
}
|
||||
|
||||
init_waitqueue_head(&priv->adapter->cmd_wait_q);
|
||||
}
|
||||
|
||||
|
@ -348,6 +364,7 @@ static void btmrvl_free_adapter(struct btmrvl_private *priv)
|
|||
{
|
||||
skb_queue_purge(&priv->adapter->tx_queue);
|
||||
|
||||
kfree(priv->adapter->hw_regs_buf);
|
||||
kfree(priv->adapter);
|
||||
|
||||
priv->adapter = NULL;
|
||||
|
|
|
@ -64,6 +64,7 @@ static const struct btmrvl_sdio_card_reg btmrvl_reg_8688 = {
|
|||
.io_port_0 = 0x00,
|
||||
.io_port_1 = 0x01,
|
||||
.io_port_2 = 0x02,
|
||||
.int_read_to_clear = false,
|
||||
};
|
||||
static const struct btmrvl_sdio_card_reg btmrvl_reg_87xx = {
|
||||
.cfg = 0x00,
|
||||
|
@ -80,6 +81,7 @@ static const struct btmrvl_sdio_card_reg btmrvl_reg_87xx = {
|
|||
.io_port_0 = 0x78,
|
||||
.io_port_1 = 0x79,
|
||||
.io_port_2 = 0x7a,
|
||||
.int_read_to_clear = false,
|
||||
};
|
||||
|
||||
static const struct btmrvl_sdio_card_reg btmrvl_reg_88xx = {
|
||||
|
@ -97,6 +99,9 @@ static const struct btmrvl_sdio_card_reg btmrvl_reg_88xx = {
|
|||
.io_port_0 = 0xd8,
|
||||
.io_port_1 = 0xd9,
|
||||
.io_port_2 = 0xda,
|
||||
.int_read_to_clear = true,
|
||||
.host_int_rsr = 0x01,
|
||||
.card_misc_cfg = 0xcc,
|
||||
};
|
||||
|
||||
static const struct btmrvl_sdio_device btmrvl_sdio_sd8688 = {
|
||||
|
@ -667,6 +672,53 @@ static int btmrvl_sdio_process_int_status(struct btmrvl_private *priv)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int btmrvl_sdio_read_to_clear(struct btmrvl_sdio_card *card, u8 *ireg)
|
||||
{
|
||||
struct btmrvl_adapter *adapter = card->priv->adapter;
|
||||
int ret;
|
||||
|
||||
ret = sdio_readsb(card->func, adapter->hw_regs, 0, SDIO_BLOCK_SIZE);
|
||||
if (ret) {
|
||||
BT_ERR("sdio_readsb: read int hw_regs failed: %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
*ireg = adapter->hw_regs[card->reg->host_intstatus];
|
||||
BT_DBG("hw_regs[%#x]=%#x", card->reg->host_intstatus, *ireg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int btmrvl_sdio_write_to_clear(struct btmrvl_sdio_card *card, u8 *ireg)
|
||||
{
|
||||
int ret;
|
||||
|
||||
*ireg = sdio_readb(card->func, card->reg->host_intstatus, &ret);
|
||||
if (ret) {
|
||||
BT_ERR("sdio_readb: read int status failed: %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (*ireg) {
|
||||
/*
|
||||
* DN_LD_HOST_INT_STATUS and/or UP_LD_HOST_INT_STATUS
|
||||
* Clear the interrupt status register and re-enable the
|
||||
* interrupt.
|
||||
*/
|
||||
BT_DBG("int_status = 0x%x", *ireg);
|
||||
|
||||
sdio_writeb(card->func, ~(*ireg) & (DN_LD_HOST_INT_STATUS |
|
||||
UP_LD_HOST_INT_STATUS),
|
||||
card->reg->host_intstatus, &ret);
|
||||
if (ret) {
|
||||
BT_ERR("sdio_writeb: clear int status failed: %d", ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void btmrvl_sdio_interrupt(struct sdio_func *func)
|
||||
{
|
||||
struct btmrvl_private *priv;
|
||||
|
@ -684,28 +736,13 @@ static void btmrvl_sdio_interrupt(struct sdio_func *func)
|
|||
|
||||
priv = card->priv;
|
||||
|
||||
ireg = sdio_readb(card->func, card->reg->host_intstatus, &ret);
|
||||
if (ret) {
|
||||
BT_ERR("sdio_readb: read int status register failed");
|
||||
if (card->reg->int_read_to_clear)
|
||||
ret = btmrvl_sdio_read_to_clear(card, &ireg);
|
||||
else
|
||||
ret = btmrvl_sdio_write_to_clear(card, &ireg);
|
||||
|
||||
if (ret)
|
||||
return;
|
||||
}
|
||||
|
||||
if (ireg != 0) {
|
||||
/*
|
||||
* DN_LD_HOST_INT_STATUS and/or UP_LD_HOST_INT_STATUS
|
||||
* Clear the interrupt status register and re-enable the
|
||||
* interrupt.
|
||||
*/
|
||||
BT_DBG("ireg = 0x%x", ireg);
|
||||
|
||||
sdio_writeb(card->func, ~(ireg) & (DN_LD_HOST_INT_STATUS |
|
||||
UP_LD_HOST_INT_STATUS),
|
||||
card->reg->host_intstatus, &ret);
|
||||
if (ret) {
|
||||
BT_ERR("sdio_writeb: clear int status register failed");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&priv->driver_lock, flags);
|
||||
sdio_ireg |= ireg;
|
||||
|
@ -777,6 +814,30 @@ static int btmrvl_sdio_register_dev(struct btmrvl_sdio_card *card)
|
|||
|
||||
BT_DBG("SDIO FUNC%d IO port: 0x%x", func->num, card->ioport);
|
||||
|
||||
if (card->reg->int_read_to_clear) {
|
||||
reg = sdio_readb(func, card->reg->host_int_rsr, &ret);
|
||||
if (ret < 0) {
|
||||
ret = -EIO;
|
||||
goto release_irq;
|
||||
}
|
||||
sdio_writeb(func, reg | 0x3f, card->reg->host_int_rsr, &ret);
|
||||
if (ret < 0) {
|
||||
ret = -EIO;
|
||||
goto release_irq;
|
||||
}
|
||||
|
||||
reg = sdio_readb(func, card->reg->card_misc_cfg, &ret);
|
||||
if (ret < 0) {
|
||||
ret = -EIO;
|
||||
goto release_irq;
|
||||
}
|
||||
sdio_writeb(func, reg | 0x10, card->reg->card_misc_cfg, &ret);
|
||||
if (ret < 0) {
|
||||
ret = -EIO;
|
||||
goto release_irq;
|
||||
}
|
||||
}
|
||||
|
||||
sdio_set_drvdata(func, card);
|
||||
|
||||
sdio_release_host(func);
|
||||
|
|
|
@ -78,6 +78,9 @@ struct btmrvl_sdio_card_reg {
|
|||
u8 io_port_0;
|
||||
u8 io_port_1;
|
||||
u8 io_port_2;
|
||||
bool int_read_to_clear;
|
||||
u8 host_int_rsr;
|
||||
u8 card_misc_cfg;
|
||||
};
|
||||
|
||||
struct btmrvl_sdio_card {
|
||||
|
|
|
@ -55,13 +55,6 @@ struct h4_struct {
|
|||
struct sk_buff_head txq;
|
||||
};
|
||||
|
||||
/* H4 receiver States */
|
||||
#define H4_W4_PACKET_TYPE 0
|
||||
#define H4_W4_EVENT_HDR 1
|
||||
#define H4_W4_ACL_HDR 2
|
||||
#define H4_W4_SCO_HDR 3
|
||||
#define H4_W4_DATA 4
|
||||
|
||||
/* Initialize protocol */
|
||||
static int h4_open(struct hci_uart *hu)
|
||||
{
|
||||
|
|
|
@ -367,6 +367,7 @@ enum {
|
|||
#define HCI_ERROR_REMOTE_POWER_OFF 0x15
|
||||
#define HCI_ERROR_LOCAL_HOST_TERM 0x16
|
||||
#define HCI_ERROR_PAIRING_NOT_ALLOWED 0x18
|
||||
#define HCI_ERROR_ADVERTISING_TIMEOUT 0x3c
|
||||
|
||||
/* Flow control modes */
|
||||
#define HCI_FLOW_CTL_MODE_PACKET_BASED 0x00
|
||||
|
|
|
@ -68,6 +68,11 @@ struct discovery_state {
|
|||
struct list_head unknown; /* Name state not known */
|
||||
struct list_head resolve; /* Name needs to be resolved */
|
||||
__u32 timestamp;
|
||||
bdaddr_t last_adv_addr;
|
||||
u8 last_adv_addr_type;
|
||||
s8 last_adv_rssi;
|
||||
u8 last_adv_data[HCI_MAX_AD_LENGTH];
|
||||
u8 last_adv_data_len;
|
||||
};
|
||||
|
||||
struct hci_conn_hash {
|
||||
|
@ -194,6 +199,7 @@ struct hci_dev {
|
|||
__u16 le_scan_window;
|
||||
__u16 le_conn_min_interval;
|
||||
__u16 le_conn_max_interval;
|
||||
__u16 discov_interleaved_timeout;
|
||||
__u8 ssp_debug_mode;
|
||||
|
||||
__u16 devid_source;
|
||||
|
@ -1204,8 +1210,8 @@ void hci_sock_dev_event(struct hci_dev *hdev, int event);
|
|||
*/
|
||||
#define DISCOV_LE_SCAN_WIN 0x12
|
||||
#define DISCOV_LE_SCAN_INT 0x12
|
||||
#define DISCOV_LE_TIMEOUT msecs_to_jiffies(10240)
|
||||
#define DISCOV_INTERLEAVED_TIMEOUT msecs_to_jiffies(5120)
|
||||
#define DISCOV_LE_TIMEOUT 10240 /* msec */
|
||||
#define DISCOV_INTERLEAVED_TIMEOUT 5120 /* msec */
|
||||
#define DISCOV_INTERLEAVED_INQUIRY_LEN 0x04
|
||||
#define DISCOV_BREDR_INQUIRY_LEN 0x08
|
||||
|
||||
|
@ -1265,7 +1271,8 @@ void mgmt_read_local_oob_data_complete(struct hci_dev *hdev, u8 *hash192,
|
|||
u8 *randomizer256, u8 status);
|
||||
void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
|
||||
u8 addr_type, u8 *dev_class, s8 rssi, u8 cfm_name,
|
||||
u8 ssp, u8 *eir, u16 eir_len);
|
||||
u8 ssp, u8 *eir, u16 eir_len, u8 *scan_rsp,
|
||||
u8 scan_rsp_len);
|
||||
void mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
|
||||
u8 addr_type, s8 rssi, u8 *name, u8 name_len);
|
||||
void mgmt_discovering(struct hci_dev *hdev, u8 discovering);
|
||||
|
|
|
@ -367,9 +367,23 @@ static void le_conn_timeout(struct work_struct *work)
|
|||
{
|
||||
struct hci_conn *conn = container_of(work, struct hci_conn,
|
||||
le_conn_timeout.work);
|
||||
struct hci_dev *hdev = conn->hdev;
|
||||
|
||||
BT_DBG("");
|
||||
|
||||
/* We could end up here due to having done directed advertising,
|
||||
* so clean up the state if necessary. This should however only
|
||||
* happen with broken hardware or if low duty cycle was used
|
||||
* (which doesn't have a timeout of its own).
|
||||
*/
|
||||
if (test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
|
||||
u8 enable = 0x00;
|
||||
hci_send_cmd(hdev, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable),
|
||||
&enable);
|
||||
hci_le_conn_failed(conn, HCI_ERROR_ADVERTISING_TIMEOUT);
|
||||
return;
|
||||
}
|
||||
|
||||
hci_le_create_connection_cancel(conn);
|
||||
}
|
||||
|
||||
|
@ -401,6 +415,10 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst)
|
|||
case ACL_LINK:
|
||||
conn->pkt_type = hdev->pkt_type & ACL_PTYPE_MASK;
|
||||
break;
|
||||
case LE_LINK:
|
||||
/* conn->src should reflect the local identity address */
|
||||
hci_copy_identity_address(hdev, &conn->src, &conn->src_type);
|
||||
break;
|
||||
case SCO_LINK:
|
||||
if (lmp_esco_capable(hdev))
|
||||
conn->pkt_type = (hdev->esco_type & SCO_ESCO_MASK) |
|
||||
|
@ -545,6 +563,11 @@ void hci_le_conn_failed(struct hci_conn *conn, u8 status)
|
|||
* favor of connection establishment, we should restart it.
|
||||
*/
|
||||
hci_update_background_scan(hdev);
|
||||
|
||||
/* Re-enable advertising in case this was a failed connection
|
||||
* attempt as a peripheral.
|
||||
*/
|
||||
mgmt_reenable_advertising(hdev);
|
||||
}
|
||||
|
||||
static void create_le_conn_complete(struct hci_dev *hdev, u8 status)
|
||||
|
@ -605,6 +628,45 @@ static void hci_req_add_le_create_conn(struct hci_request *req,
|
|||
conn->state = BT_CONNECT;
|
||||
}
|
||||
|
||||
static void hci_req_directed_advertising(struct hci_request *req,
|
||||
struct hci_conn *conn)
|
||||
{
|
||||
struct hci_dev *hdev = req->hdev;
|
||||
struct hci_cp_le_set_adv_param cp;
|
||||
u8 own_addr_type;
|
||||
u8 enable;
|
||||
|
||||
enable = 0x00;
|
||||
hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable);
|
||||
|
||||
/* Clear the HCI_ADVERTISING bit temporarily so that the
|
||||
* hci_update_random_address knows that it's safe to go ahead
|
||||
* and write a new random address. The flag will be set back on
|
||||
* as soon as the SET_ADV_ENABLE HCI command completes.
|
||||
*/
|
||||
clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
|
||||
|
||||
/* Set require_privacy to false so that the remote device has a
|
||||
* chance of identifying us.
|
||||
*/
|
||||
if (hci_update_random_address(req, false, &own_addr_type) < 0)
|
||||
return;
|
||||
|
||||
memset(&cp, 0, sizeof(cp));
|
||||
cp.type = LE_ADV_DIRECT_IND;
|
||||
cp.own_address_type = own_addr_type;
|
||||
cp.direct_addr_type = conn->dst_type;
|
||||
bacpy(&cp.direct_addr, &conn->dst);
|
||||
cp.channel_map = hdev->le_adv_channel_map;
|
||||
|
||||
hci_req_add(req, HCI_OP_LE_SET_ADV_PARAM, sizeof(cp), &cp);
|
||||
|
||||
enable = 0x01;
|
||||
hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable);
|
||||
|
||||
conn->state = BT_CONNECT;
|
||||
}
|
||||
|
||||
struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst,
|
||||
u8 dst_type, u8 sec_level, u8 auth_type)
|
||||
{
|
||||
|
@ -614,9 +676,6 @@ struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst,
|
|||
struct hci_request req;
|
||||
int err;
|
||||
|
||||
if (test_bit(HCI_ADVERTISING, &hdev->flags))
|
||||
return ERR_PTR(-ENOTSUPP);
|
||||
|
||||
/* Some devices send ATT messages as soon as the physical link is
|
||||
* established. To be able to handle these ATT messages, the user-
|
||||
* space first establishes the connection and then starts the pairing
|
||||
|
@ -664,13 +723,20 @@ struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst,
|
|||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
conn->dst_type = dst_type;
|
||||
|
||||
conn->out = true;
|
||||
conn->link_mode |= HCI_LM_MASTER;
|
||||
conn->sec_level = BT_SECURITY_LOW;
|
||||
conn->pending_sec_level = sec_level;
|
||||
conn->auth_type = auth_type;
|
||||
|
||||
hci_req_init(&req, hdev);
|
||||
|
||||
if (test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
|
||||
hci_req_directed_advertising(&req, conn);
|
||||
goto create_conn;
|
||||
}
|
||||
|
||||
conn->out = true;
|
||||
conn->link_mode |= HCI_LM_MASTER;
|
||||
|
||||
params = hci_conn_params_lookup(hdev, &conn->dst, conn->dst_type);
|
||||
if (params) {
|
||||
conn->le_conn_min_interval = params->conn_min_interval;
|
||||
|
@ -680,8 +746,6 @@ struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst,
|
|||
conn->le_conn_max_interval = hdev->le_conn_max_interval;
|
||||
}
|
||||
|
||||
hci_req_init(&req, hdev);
|
||||
|
||||
/* If controller is scanning, we stop it since some controllers are
|
||||
* not able to scan and connect at the same time. Also set the
|
||||
* HCI_LE_SCAN_INTERRUPTED flag so that the command complete
|
||||
|
@ -695,6 +759,7 @@ struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst,
|
|||
|
||||
hci_req_add_le_create_conn(&req, conn);
|
||||
|
||||
create_conn:
|
||||
err = hci_req_run(&req, create_le_conn_complete);
|
||||
if (err) {
|
||||
hci_conn_del(conn);
|
||||
|
|
|
@ -955,14 +955,9 @@ static ssize_t le_auto_conn_write(struct file *file, const char __user *data,
|
|||
if (count < 3)
|
||||
return -EINVAL;
|
||||
|
||||
buf = kzalloc(count, GFP_KERNEL);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
if (copy_from_user(buf, data, count)) {
|
||||
err = -EFAULT;
|
||||
goto done;
|
||||
}
|
||||
buf = memdup_user(data, count);
|
||||
if (IS_ERR(buf))
|
||||
return PTR_ERR(buf);
|
||||
|
||||
if (memcmp(buf, "add", 3) == 0) {
|
||||
n = sscanf(&buf[4], "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx %hhu %hhu",
|
||||
|
@ -1828,6 +1823,9 @@ static int __hci_init(struct hci_dev *hdev)
|
|||
&lowpan_debugfs_fops);
|
||||
debugfs_create_file("le_auto_conn", 0644, hdev->debugfs, hdev,
|
||||
&le_auto_conn_fops);
|
||||
debugfs_create_u16("discov_interleaved_timeout", 0644,
|
||||
hdev->debugfs,
|
||||
&hdev->discov_interleaved_timeout);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -2033,12 +2031,11 @@ bool hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_data *data,
|
|||
|
||||
hci_remove_remote_oob_data(hdev, &data->bdaddr);
|
||||
|
||||
if (ssp)
|
||||
*ssp = data->ssp_mode;
|
||||
*ssp = data->ssp_mode;
|
||||
|
||||
ie = hci_inquiry_cache_lookup(hdev, &data->bdaddr);
|
||||
if (ie) {
|
||||
if (ie->data.ssp_mode && ssp)
|
||||
if (ie->data.ssp_mode)
|
||||
*ssp = true;
|
||||
|
||||
if (ie->name_state == NAME_NEEDED &&
|
||||
|
@ -3791,6 +3788,7 @@ struct hci_dev *hci_alloc_dev(void)
|
|||
hdev->le_conn_max_interval = 0x0038;
|
||||
|
||||
hdev->rpa_timeout = HCI_DEFAULT_RPA_TIMEOUT;
|
||||
hdev->discov_interleaved_timeout = DISCOV_INTERLEAVED_TIMEOUT;
|
||||
|
||||
mutex_init(&hdev->lock);
|
||||
mutex_init(&hdev->req_lock);
|
||||
|
|
|
@ -991,10 +991,25 @@ static void hci_cc_le_set_adv_enable(struct hci_dev *hdev, struct sk_buff *skb)
|
|||
if (!sent)
|
||||
return;
|
||||
|
||||
if (status)
|
||||
return;
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
|
||||
if (!status)
|
||||
mgmt_advertising(hdev, *sent);
|
||||
/* If we're doing connection initation as peripheral. Set a
|
||||
* timeout in case something goes wrong.
|
||||
*/
|
||||
if (*sent) {
|
||||
struct hci_conn *conn;
|
||||
|
||||
conn = hci_conn_hash_lookup_state(hdev, LE_LINK, BT_CONNECT);
|
||||
if (conn)
|
||||
queue_delayed_work(hdev->workqueue,
|
||||
&conn->le_conn_timeout,
|
||||
HCI_LE_CONN_TIMEOUT);
|
||||
}
|
||||
|
||||
mgmt_advertising(hdev, *sent);
|
||||
|
||||
hci_dev_unlock(hdev);
|
||||
}
|
||||
|
@ -1018,6 +1033,33 @@ static void hci_cc_le_set_scan_param(struct hci_dev *hdev, struct sk_buff *skb)
|
|||
hci_dev_unlock(hdev);
|
||||
}
|
||||
|
||||
static bool has_pending_adv_report(struct hci_dev *hdev)
|
||||
{
|
||||
struct discovery_state *d = &hdev->discovery;
|
||||
|
||||
return bacmp(&d->last_adv_addr, BDADDR_ANY);
|
||||
}
|
||||
|
||||
static void clear_pending_adv_report(struct hci_dev *hdev)
|
||||
{
|
||||
struct discovery_state *d = &hdev->discovery;
|
||||
|
||||
bacpy(&d->last_adv_addr, BDADDR_ANY);
|
||||
d->last_adv_data_len = 0;
|
||||
}
|
||||
|
||||
static void store_pending_adv_report(struct hci_dev *hdev, bdaddr_t *bdaddr,
|
||||
u8 bdaddr_type, s8 rssi, u8 *data, u8 len)
|
||||
{
|
||||
struct discovery_state *d = &hdev->discovery;
|
||||
|
||||
bacpy(&d->last_adv_addr, bdaddr);
|
||||
d->last_adv_addr_type = bdaddr_type;
|
||||
d->last_adv_rssi = rssi;
|
||||
memcpy(d->last_adv_data, data, len);
|
||||
d->last_adv_data_len = len;
|
||||
}
|
||||
|
||||
static void hci_cc_le_set_scan_enable(struct hci_dev *hdev,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
|
@ -1036,9 +1078,25 @@ static void hci_cc_le_set_scan_enable(struct hci_dev *hdev,
|
|||
switch (cp->enable) {
|
||||
case LE_SCAN_ENABLE:
|
||||
set_bit(HCI_LE_SCAN, &hdev->dev_flags);
|
||||
if (hdev->le_scan_type == LE_SCAN_ACTIVE)
|
||||
clear_pending_adv_report(hdev);
|
||||
break;
|
||||
|
||||
case LE_SCAN_DISABLE:
|
||||
/* We do this here instead of when setting DISCOVERY_STOPPED
|
||||
* since the latter would potentially require waiting for
|
||||
* inquiry to stop too.
|
||||
*/
|
||||
if (has_pending_adv_report(hdev)) {
|
||||
struct discovery_state *d = &hdev->discovery;
|
||||
|
||||
mgmt_device_found(hdev, &d->last_adv_addr, LE_LINK,
|
||||
d->last_adv_addr_type, NULL,
|
||||
d->last_adv_rssi, 0, 1,
|
||||
d->last_adv_data,
|
||||
d->last_adv_data_len, NULL, 0);
|
||||
}
|
||||
|
||||
/* Cancel this timer so that we don't try to disable scanning
|
||||
* when it's already disabled.
|
||||
*/
|
||||
|
@ -1827,7 +1885,7 @@ static void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
|||
name_known = hci_inquiry_cache_update(hdev, &data, false, &ssp);
|
||||
mgmt_device_found(hdev, &info->bdaddr, ACL_LINK, 0x00,
|
||||
info->dev_class, 0, !name_known, ssp, NULL,
|
||||
0);
|
||||
0, NULL, 0);
|
||||
}
|
||||
|
||||
hci_dev_unlock(hdev);
|
||||
|
@ -3102,7 +3160,7 @@ static void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev,
|
|||
false, &ssp);
|
||||
mgmt_device_found(hdev, &info->bdaddr, ACL_LINK, 0x00,
|
||||
info->dev_class, info->rssi,
|
||||
!name_known, ssp, NULL, 0);
|
||||
!name_known, ssp, NULL, 0, NULL, 0);
|
||||
}
|
||||
} else {
|
||||
struct inquiry_info_with_rssi *info = (void *) (skb->data + 1);
|
||||
|
@ -3120,7 +3178,7 @@ static void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev,
|
|||
false, &ssp);
|
||||
mgmt_device_found(hdev, &info->bdaddr, ACL_LINK, 0x00,
|
||||
info->dev_class, info->rssi,
|
||||
!name_known, ssp, NULL, 0);
|
||||
!name_known, ssp, NULL, 0, NULL, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3309,7 +3367,7 @@ static void hci_extended_inquiry_result_evt(struct hci_dev *hdev,
|
|||
eir_len = eir_get_length(info->data, sizeof(info->data));
|
||||
mgmt_device_found(hdev, &info->bdaddr, ACL_LINK, 0x00,
|
||||
info->dev_class, info->rssi, !name_known,
|
||||
ssp, info->data, eir_len);
|
||||
ssp, info->data, eir_len, NULL, 0);
|
||||
}
|
||||
|
||||
hci_dev_unlock(hdev);
|
||||
|
@ -3361,24 +3419,20 @@ static void hci_key_refresh_complete_evt(struct hci_dev *hdev,
|
|||
|
||||
static u8 hci_get_auth_req(struct hci_conn *conn)
|
||||
{
|
||||
/* If remote requests dedicated bonding follow that lead */
|
||||
if (conn->remote_auth == HCI_AT_DEDICATED_BONDING ||
|
||||
conn->remote_auth == HCI_AT_DEDICATED_BONDING_MITM) {
|
||||
/* If both remote and local IO capabilities allow MITM
|
||||
* protection then require it, otherwise don't */
|
||||
if (conn->remote_cap == HCI_IO_NO_INPUT_OUTPUT ||
|
||||
conn->io_capability == HCI_IO_NO_INPUT_OUTPUT)
|
||||
return HCI_AT_DEDICATED_BONDING;
|
||||
else
|
||||
return HCI_AT_DEDICATED_BONDING_MITM;
|
||||
}
|
||||
|
||||
/* If remote requests no-bonding follow that lead */
|
||||
if (conn->remote_auth == HCI_AT_NO_BONDING ||
|
||||
conn->remote_auth == HCI_AT_NO_BONDING_MITM)
|
||||
return conn->remote_auth | (conn->auth_type & 0x01);
|
||||
|
||||
return conn->auth_type;
|
||||
/* If both remote and local have enough IO capabilities, require
|
||||
* MITM protection
|
||||
*/
|
||||
if (conn->remote_cap != HCI_IO_NO_INPUT_OUTPUT &&
|
||||
conn->io_capability != HCI_IO_NO_INPUT_OUTPUT)
|
||||
return conn->remote_auth | 0x01;
|
||||
|
||||
/* No MITM protection possible so ignore remote requirement */
|
||||
return (conn->remote_auth & ~0x01) | (conn->auth_type & 0x01);
|
||||
}
|
||||
|
||||
static void hci_io_capa_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
|
@ -3408,8 +3462,21 @@ static void hci_io_capa_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
|||
* to DisplayYesNo as it is not supported by BT spec. */
|
||||
cp.capability = (conn->io_capability == 0x04) ?
|
||||
HCI_IO_DISPLAY_YESNO : conn->io_capability;
|
||||
conn->auth_type = hci_get_auth_req(conn);
|
||||
cp.authentication = conn->auth_type;
|
||||
|
||||
/* If we are initiators, there is no remote information yet */
|
||||
if (conn->remote_auth == 0xff) {
|
||||
cp.authentication = conn->auth_type;
|
||||
|
||||
/* Request MITM protection if our IO caps allow it
|
||||
* except for the no-bonding case
|
||||
*/
|
||||
if (conn->io_capability != HCI_IO_NO_INPUT_OUTPUT &&
|
||||
cp.authentication != HCI_AT_NO_BONDING)
|
||||
cp.authentication |= 0x01;
|
||||
} else {
|
||||
conn->auth_type = hci_get_auth_req(conn);
|
||||
cp.authentication = conn->auth_type;
|
||||
}
|
||||
|
||||
if (hci_find_remote_oob_data(hdev, &conn->dst) &&
|
||||
(conn->out || test_bit(HCI_CONN_REMOTE_OOB, &conn->flags)))
|
||||
|
@ -3477,12 +3544,9 @@ static void hci_user_confirm_request_evt(struct hci_dev *hdev,
|
|||
rem_mitm = (conn->remote_auth & 0x01);
|
||||
|
||||
/* If we require MITM but the remote device can't provide that
|
||||
* (it has NoInputNoOutput) then reject the confirmation
|
||||
* request. The only exception is when we're dedicated bonding
|
||||
* initiators (connect_cfm_cb set) since then we always have the MITM
|
||||
* bit set. */
|
||||
if (!conn->connect_cfm_cb && loc_mitm &&
|
||||
conn->remote_cap == HCI_IO_NO_INPUT_OUTPUT) {
|
||||
* (it has NoInputNoOutput) then reject the confirmation request
|
||||
*/
|
||||
if (loc_mitm && conn->remote_cap == HCI_IO_NO_INPUT_OUTPUT) {
|
||||
BT_DBG("Rejecting request: remote device can't provide MITM");
|
||||
hci_send_cmd(hdev, HCI_OP_USER_CONFIRM_NEG_REPLY,
|
||||
sizeof(ev->bdaddr), &ev->bdaddr);
|
||||
|
@ -3840,17 +3904,6 @@ static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
|||
|
||||
conn->dst_type = ev->bdaddr_type;
|
||||
|
||||
/* The advertising parameters for own address type
|
||||
* define which source address and source address
|
||||
* type this connections has.
|
||||
*/
|
||||
if (bacmp(&conn->src, BDADDR_ANY)) {
|
||||
conn->src_type = ADDR_LE_DEV_PUBLIC;
|
||||
} else {
|
||||
bacpy(&conn->src, &hdev->static_addr);
|
||||
conn->src_type = ADDR_LE_DEV_RANDOM;
|
||||
}
|
||||
|
||||
if (ev->role == LE_CONN_ROLE_MASTER) {
|
||||
conn->out = true;
|
||||
conn->link_mode |= HCI_LM_MASTER;
|
||||
|
@ -3875,27 +3928,24 @@ static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
|||
&conn->init_addr,
|
||||
&conn->init_addr_type);
|
||||
}
|
||||
} else {
|
||||
/* Set the responder (our side) address type based on
|
||||
* the advertising address type.
|
||||
*/
|
||||
conn->resp_addr_type = hdev->adv_addr_type;
|
||||
if (hdev->adv_addr_type == ADDR_LE_DEV_RANDOM)
|
||||
bacpy(&conn->resp_addr, &hdev->random_addr);
|
||||
else
|
||||
bacpy(&conn->resp_addr, &hdev->bdaddr);
|
||||
|
||||
conn->init_addr_type = ev->bdaddr_type;
|
||||
bacpy(&conn->init_addr, &ev->bdaddr);
|
||||
}
|
||||
} else {
|
||||
cancel_delayed_work(&conn->le_conn_timeout);
|
||||
}
|
||||
|
||||
/* Ensure that the hci_conn contains the identity address type
|
||||
* regardless of which address the connection was made with.
|
||||
*/
|
||||
hci_copy_identity_address(hdev, &conn->src, &conn->src_type);
|
||||
if (!conn->out) {
|
||||
/* Set the responder (our side) address type based on
|
||||
* the advertising address type.
|
||||
*/
|
||||
conn->resp_addr_type = hdev->adv_addr_type;
|
||||
if (hdev->adv_addr_type == ADDR_LE_DEV_RANDOM)
|
||||
bacpy(&conn->resp_addr, &hdev->random_addr);
|
||||
else
|
||||
bacpy(&conn->resp_addr, &hdev->bdaddr);
|
||||
|
||||
conn->init_addr_type = ev->bdaddr_type;
|
||||
bacpy(&conn->init_addr, &ev->bdaddr);
|
||||
}
|
||||
|
||||
/* Lookup the identity address from the stored connection
|
||||
* address and address type.
|
||||
|
@ -3975,25 +4025,97 @@ static void check_pending_le_conn(struct hci_dev *hdev, bdaddr_t *addr,
|
|||
}
|
||||
}
|
||||
|
||||
static void process_adv_report(struct hci_dev *hdev, u8 type, bdaddr_t *bdaddr,
|
||||
u8 bdaddr_type, s8 rssi, u8 *data, u8 len)
|
||||
{
|
||||
struct discovery_state *d = &hdev->discovery;
|
||||
bool match;
|
||||
|
||||
/* Passive scanning shouldn't trigger any device found events */
|
||||
if (hdev->le_scan_type == LE_SCAN_PASSIVE) {
|
||||
if (type == LE_ADV_IND || type == LE_ADV_DIRECT_IND)
|
||||
check_pending_le_conn(hdev, bdaddr, bdaddr_type);
|
||||
return;
|
||||
}
|
||||
|
||||
/* If there's nothing pending either store the data from this
|
||||
* event or send an immediate device found event if the data
|
||||
* should not be stored for later.
|
||||
*/
|
||||
if (!has_pending_adv_report(hdev)) {
|
||||
/* If the report will trigger a SCAN_REQ store it for
|
||||
* later merging.
|
||||
*/
|
||||
if (type == LE_ADV_IND || type == LE_ADV_SCAN_IND) {
|
||||
store_pending_adv_report(hdev, bdaddr, bdaddr_type,
|
||||
rssi, data, len);
|
||||
return;
|
||||
}
|
||||
|
||||
mgmt_device_found(hdev, bdaddr, LE_LINK, bdaddr_type, NULL,
|
||||
rssi, 0, 1, data, len, NULL, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Check if the pending report is for the same device as the new one */
|
||||
match = (!bacmp(bdaddr, &d->last_adv_addr) &&
|
||||
bdaddr_type == d->last_adv_addr_type);
|
||||
|
||||
/* If the pending data doesn't match this report or this isn't a
|
||||
* scan response (e.g. we got a duplicate ADV_IND) then force
|
||||
* sending of the pending data.
|
||||
*/
|
||||
if (type != LE_ADV_SCAN_RSP || !match) {
|
||||
/* Send out whatever is in the cache, but skip duplicates */
|
||||
if (!match)
|
||||
mgmt_device_found(hdev, &d->last_adv_addr, LE_LINK,
|
||||
d->last_adv_addr_type, NULL,
|
||||
d->last_adv_rssi, 0, 1,
|
||||
d->last_adv_data,
|
||||
d->last_adv_data_len, NULL, 0);
|
||||
|
||||
/* If the new report will trigger a SCAN_REQ store it for
|
||||
* later merging.
|
||||
*/
|
||||
if (type == LE_ADV_IND || type == LE_ADV_SCAN_IND) {
|
||||
store_pending_adv_report(hdev, bdaddr, bdaddr_type,
|
||||
rssi, data, len);
|
||||
return;
|
||||
}
|
||||
|
||||
/* The advertising reports cannot be merged, so clear
|
||||
* the pending report and send out a device found event.
|
||||
*/
|
||||
clear_pending_adv_report(hdev);
|
||||
mgmt_device_found(hdev, bdaddr, LE_LINK, bdaddr_type, NULL,
|
||||
rssi, 0, 1, data, len, NULL, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
/* If we get here we've got a pending ADV_IND or ADV_SCAN_IND and
|
||||
* the new event is a SCAN_RSP. We can therefore proceed with
|
||||
* sending a merged device found event.
|
||||
*/
|
||||
mgmt_device_found(hdev, &d->last_adv_addr, LE_LINK,
|
||||
d->last_adv_addr_type, NULL, rssi, 0, 1, data, len,
|
||||
d->last_adv_data, d->last_adv_data_len);
|
||||
clear_pending_adv_report(hdev);
|
||||
}
|
||||
|
||||
static void hci_le_adv_report_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
u8 num_reports = skb->data[0];
|
||||
void *ptr = &skb->data[1];
|
||||
s8 rssi;
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
|
||||
while (num_reports--) {
|
||||
struct hci_ev_le_advertising_info *ev = ptr;
|
||||
|
||||
if (ev->evt_type == LE_ADV_IND ||
|
||||
ev->evt_type == LE_ADV_DIRECT_IND)
|
||||
check_pending_le_conn(hdev, &ev->bdaddr,
|
||||
ev->bdaddr_type);
|
||||
s8 rssi;
|
||||
|
||||
rssi = ev->data[ev->length];
|
||||
mgmt_device_found(hdev, &ev->bdaddr, LE_LINK, ev->bdaddr_type,
|
||||
NULL, rssi, 0, 1, ev->data, ev->length);
|
||||
process_adv_report(hdev, ev->evt_type, &ev->bdaddr,
|
||||
ev->bdaddr_type, rssi, ev->data, ev->length);
|
||||
|
||||
ptr += sizeof(*ev) + ev->length + 1;
|
||||
}
|
||||
|
|
|
@ -524,16 +524,7 @@ static int hci_sock_bound_ioctl(struct sock *sk, unsigned int cmd,
|
|||
case HCISETRAW:
|
||||
if (!capable(CAP_NET_ADMIN))
|
||||
return -EPERM;
|
||||
|
||||
if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
|
||||
return -EPERM;
|
||||
|
||||
if (arg)
|
||||
set_bit(HCI_RAW, &hdev->flags);
|
||||
else
|
||||
clear_bit(HCI_RAW, &hdev->flags);
|
||||
|
||||
return 0;
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
case HCIGETCONNINFO:
|
||||
return hci_get_conn_info(hdev, (void __user *) arg);
|
||||
|
|
|
@ -58,6 +58,7 @@ int bt_to_errno(__u16 code)
|
|||
return EIO;
|
||||
|
||||
case 0x04:
|
||||
case 0x3c:
|
||||
return EHOSTDOWN;
|
||||
|
||||
case 0x05:
|
||||
|
|
|
@ -2850,10 +2850,7 @@ static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
|
|||
}
|
||||
|
||||
sec_level = BT_SECURITY_MEDIUM;
|
||||
if (cp->io_cap == 0x03)
|
||||
auth_type = HCI_AT_DEDICATED_BONDING;
|
||||
else
|
||||
auth_type = HCI_AT_DEDICATED_BONDING_MITM;
|
||||
auth_type = HCI_AT_DEDICATED_BONDING;
|
||||
|
||||
if (cp->addr.type == BDADDR_BREDR) {
|
||||
conn = hci_connect_acl(hdev, &cp->addr.bdaddr, sec_level,
|
||||
|
@ -3351,6 +3348,8 @@ static int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
|
|||
|
||||
static void start_discovery_complete(struct hci_dev *hdev, u8 status)
|
||||
{
|
||||
unsigned long timeout = 0;
|
||||
|
||||
BT_DBG("status %d", status);
|
||||
|
||||
if (status) {
|
||||
|
@ -3366,13 +3365,11 @@ static void start_discovery_complete(struct hci_dev *hdev, u8 status)
|
|||
|
||||
switch (hdev->discovery.type) {
|
||||
case DISCOV_TYPE_LE:
|
||||
queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
|
||||
DISCOV_LE_TIMEOUT);
|
||||
timeout = msecs_to_jiffies(DISCOV_LE_TIMEOUT);
|
||||
break;
|
||||
|
||||
case DISCOV_TYPE_INTERLEAVED:
|
||||
queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
|
||||
DISCOV_INTERLEAVED_TIMEOUT);
|
||||
timeout = msecs_to_jiffies(hdev->discov_interleaved_timeout);
|
||||
break;
|
||||
|
||||
case DISCOV_TYPE_BREDR:
|
||||
|
@ -3381,6 +3378,11 @@ static void start_discovery_complete(struct hci_dev *hdev, u8 status)
|
|||
default:
|
||||
BT_ERR("Invalid discovery type %d", hdev->discovery.type);
|
||||
}
|
||||
|
||||
if (!timeout)
|
||||
return;
|
||||
|
||||
queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable, timeout);
|
||||
}
|
||||
|
||||
static int start_discovery(struct sock *sk, struct hci_dev *hdev,
|
||||
|
@ -5668,8 +5670,9 @@ void mgmt_read_local_oob_data_complete(struct hci_dev *hdev, u8 *hash192,
|
|||
}
|
||||
|
||||
void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
|
||||
u8 addr_type, u8 *dev_class, s8 rssi, u8 cfm_name, u8
|
||||
ssp, u8 *eir, u16 eir_len)
|
||||
u8 addr_type, u8 *dev_class, s8 rssi, u8 cfm_name,
|
||||
u8 ssp, u8 *eir, u16 eir_len, u8 *scan_rsp,
|
||||
u8 scan_rsp_len)
|
||||
{
|
||||
char buf[512];
|
||||
struct mgmt_ev_device_found *ev = (void *) buf;
|
||||
|
@ -5679,8 +5682,10 @@ void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
|
|||
if (!hci_discovery_active(hdev))
|
||||
return;
|
||||
|
||||
/* Leave 5 bytes for a potential CoD field */
|
||||
if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
|
||||
/* Make sure that the buffer is big enough. The 5 extra bytes
|
||||
* are for the potential CoD field.
|
||||
*/
|
||||
if (sizeof(*ev) + eir_len + scan_rsp_len + 5 > sizeof(buf))
|
||||
return;
|
||||
|
||||
memset(buf, 0, sizeof(buf));
|
||||
|
@ -5707,8 +5712,11 @@ void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
|
|||
eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
|
||||
dev_class, 3);
|
||||
|
||||
ev->eir_len = cpu_to_le16(eir_len);
|
||||
ev_size = sizeof(*ev) + eir_len;
|
||||
if (scan_rsp_len > 0)
|
||||
memcpy(ev->eir + eir_len, scan_rsp, scan_rsp_len);
|
||||
|
||||
ev->eir_len = cpu_to_le16(eir_len + scan_rsp_len);
|
||||
ev_size = sizeof(*ev) + eir_len + scan_rsp_len;
|
||||
|
||||
mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue