Merge branch 'for-upstream' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next
This commit is contained in:
commit
d2ff5ee919
9 changed files with 204 additions and 29 deletions
|
@ -96,6 +96,7 @@ static struct usb_device_id btusb_table[] = {
|
|||
{ USB_DEVICE(0x0c10, 0x0000) },
|
||||
|
||||
/* Broadcom BCM20702A0 */
|
||||
{ USB_DEVICE(0x0b05, 0x17b5) },
|
||||
{ USB_DEVICE(0x04ca, 0x2003) },
|
||||
{ USB_DEVICE(0x0489, 0xe042) },
|
||||
{ USB_DEVICE(0x413c, 0x8197) },
|
||||
|
|
|
@ -154,7 +154,7 @@ enum {
|
|||
#define HCI_DISCONN_TIMEOUT msecs_to_jiffies(2000) /* 2 seconds */
|
||||
#define HCI_PAIRING_TIMEOUT msecs_to_jiffies(60000) /* 60 seconds */
|
||||
#define HCI_INIT_TIMEOUT msecs_to_jiffies(10000) /* 10 seconds */
|
||||
#define HCI_CMD_TIMEOUT msecs_to_jiffies(1000) /* 1 second */
|
||||
#define HCI_CMD_TIMEOUT msecs_to_jiffies(2000) /* 2 seconds */
|
||||
#define HCI_ACL_TX_TIMEOUT msecs_to_jiffies(45000) /* 45 seconds */
|
||||
#define HCI_AUTO_OFF_TIMEOUT msecs_to_jiffies(2000) /* 2 seconds */
|
||||
|
||||
|
@ -319,6 +319,9 @@ enum {
|
|||
#define HCI_FLOW_CTL_MODE_PACKET_BASED 0x00
|
||||
#define HCI_FLOW_CTL_MODE_BLOCK_BASED 0x01
|
||||
|
||||
/* The core spec defines 127 as the "not available" value */
|
||||
#define HCI_TX_POWER_INVALID 127
|
||||
|
||||
/* Extended Inquiry Response field types */
|
||||
#define EIR_FLAGS 0x01 /* flags */
|
||||
#define EIR_UUID16_SOME 0x02 /* 16-bit UUID, more available */
|
||||
|
@ -335,6 +338,13 @@ enum {
|
|||
#define EIR_SSP_RAND_R 0x0F /* Simple Pairing Randomizer R */
|
||||
#define EIR_DEVICE_ID 0x10 /* device ID */
|
||||
|
||||
/* Low Energy Advertising Flags */
|
||||
#define LE_AD_LIMITED 0x01 /* Limited Discoverable */
|
||||
#define LE_AD_GENERAL 0x02 /* General Discoverable */
|
||||
#define LE_AD_NO_BREDR 0x04 /* BR/EDR not supported */
|
||||
#define LE_AD_SIM_LE_BREDR_CTRL 0x08 /* Simultaneous LE & BR/EDR Controller */
|
||||
#define LE_AD_SIM_LE_BREDR_HOST 0x10 /* Simultaneous LE & BR/EDR Host */
|
||||
|
||||
/* ----- HCI Commands ---- */
|
||||
#define HCI_OP_NOP 0x0000
|
||||
|
||||
|
@ -939,6 +949,16 @@ struct hci_rp_le_read_adv_tx_power {
|
|||
__s8 tx_power;
|
||||
} __packed;
|
||||
|
||||
#define HCI_MAX_AD_LENGTH 31
|
||||
|
||||
#define HCI_OP_LE_SET_ADV_DATA 0x2008
|
||||
struct hci_cp_le_set_adv_data {
|
||||
__u8 length;
|
||||
__u8 data[HCI_MAX_AD_LENGTH];
|
||||
} __packed;
|
||||
|
||||
#define HCI_OP_LE_SET_ADV_ENABLE 0x200a
|
||||
|
||||
#define HCI_OP_LE_SET_SCAN_PARAM 0x200b
|
||||
struct hci_cp_le_set_scan_param {
|
||||
__u8 type;
|
||||
|
|
|
@ -279,6 +279,8 @@ struct hci_dev {
|
|||
struct le_scan_params le_scan_params;
|
||||
|
||||
__s8 adv_tx_power;
|
||||
__u8 adv_data[HCI_MAX_AD_LENGTH];
|
||||
__u8 adv_data_len;
|
||||
|
||||
int (*open)(struct hci_dev *hdev);
|
||||
int (*close)(struct hci_dev *hdev);
|
||||
|
@ -734,6 +736,8 @@ int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *hash,
|
|||
u8 *randomizer);
|
||||
int hci_remove_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr);
|
||||
|
||||
int hci_update_ad(struct hci_dev *hdev);
|
||||
|
||||
void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb);
|
||||
|
||||
int hci_recv_frame(struct sk_buff *skb);
|
||||
|
|
|
@ -811,6 +811,6 @@ void l2cap_send_conn_req(struct l2cap_chan *chan);
|
|||
void l2cap_move_start(struct l2cap_chan *chan);
|
||||
void l2cap_logical_cfm(struct l2cap_chan *chan, struct hci_chan *hchan,
|
||||
u8 status);
|
||||
void l2cap_physical_cfm(struct l2cap_chan *chan, int result);
|
||||
void __l2cap_physical_cfm(struct l2cap_chan *chan, int result);
|
||||
|
||||
#endif /* __L2CAP_H */
|
||||
|
|
|
@ -386,13 +386,17 @@ void amp_physical_cfm(struct hci_conn *bredr_hcon, struct hci_conn *hs_hcon)
|
|||
|
||||
bredr_chan = mgr->bredr_chan;
|
||||
|
||||
l2cap_chan_lock(bredr_chan);
|
||||
|
||||
set_bit(FLAG_EFS_ENABLE, &bredr_chan->flags);
|
||||
bredr_chan->remote_amp_id = hs_hcon->remote_id;
|
||||
bredr_chan->local_amp_id = hs_hcon->hdev->id;
|
||||
bredr_chan->hs_hcon = hs_hcon;
|
||||
bredr_chan->conn->mtu = hs_hcon->hdev->block_mtu;
|
||||
bredr_chan->fcs = L2CAP_FCS_NONE;
|
||||
|
||||
l2cap_physical_cfm(bredr_chan, 0);
|
||||
__l2cap_physical_cfm(bredr_chan, 0);
|
||||
|
||||
l2cap_chan_unlock(bredr_chan);
|
||||
|
||||
hci_dev_put(bredr_hdev);
|
||||
}
|
||||
|
|
|
@ -434,6 +434,8 @@ bool hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_data *data,
|
|||
|
||||
BT_DBG("cache %p, %pMR", cache, &data->bdaddr);
|
||||
|
||||
hci_remove_remote_oob_data(hdev, &data->bdaddr);
|
||||
|
||||
if (ssp)
|
||||
*ssp = data->ssp_mode;
|
||||
|
||||
|
@ -594,6 +596,99 @@ int hci_inquiry(void __user *arg)
|
|||
return err;
|
||||
}
|
||||
|
||||
static u8 create_ad(struct hci_dev *hdev, u8 *ptr)
|
||||
{
|
||||
u8 ad_len = 0, flags = 0;
|
||||
size_t name_len;
|
||||
|
||||
if (test_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags))
|
||||
flags |= LE_AD_GENERAL;
|
||||
|
||||
if (!lmp_bredr_capable(hdev))
|
||||
flags |= LE_AD_NO_BREDR;
|
||||
|
||||
if (lmp_le_br_capable(hdev))
|
||||
flags |= LE_AD_SIM_LE_BREDR_CTRL;
|
||||
|
||||
if (lmp_host_le_br_capable(hdev))
|
||||
flags |= LE_AD_SIM_LE_BREDR_HOST;
|
||||
|
||||
if (flags) {
|
||||
BT_DBG("adv flags 0x%02x", flags);
|
||||
|
||||
ptr[0] = 2;
|
||||
ptr[1] = EIR_FLAGS;
|
||||
ptr[2] = flags;
|
||||
|
||||
ad_len += 3;
|
||||
ptr += 3;
|
||||
}
|
||||
|
||||
if (hdev->adv_tx_power != HCI_TX_POWER_INVALID) {
|
||||
ptr[0] = 2;
|
||||
ptr[1] = EIR_TX_POWER;
|
||||
ptr[2] = (u8) hdev->adv_tx_power;
|
||||
|
||||
ad_len += 3;
|
||||
ptr += 3;
|
||||
}
|
||||
|
||||
name_len = strlen(hdev->dev_name);
|
||||
if (name_len > 0) {
|
||||
size_t max_len = HCI_MAX_AD_LENGTH - ad_len - 2;
|
||||
|
||||
if (name_len > max_len) {
|
||||
name_len = max_len;
|
||||
ptr[1] = EIR_NAME_SHORT;
|
||||
} else
|
||||
ptr[1] = EIR_NAME_COMPLETE;
|
||||
|
||||
ptr[0] = name_len + 1;
|
||||
|
||||
memcpy(ptr + 2, hdev->dev_name, name_len);
|
||||
|
||||
ad_len += (name_len + 2);
|
||||
ptr += (name_len + 2);
|
||||
}
|
||||
|
||||
return ad_len;
|
||||
}
|
||||
|
||||
int hci_update_ad(struct hci_dev *hdev)
|
||||
{
|
||||
struct hci_cp_le_set_adv_data cp;
|
||||
u8 len;
|
||||
int err;
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
|
||||
if (!lmp_le_capable(hdev)) {
|
||||
err = -EINVAL;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
memset(&cp, 0, sizeof(cp));
|
||||
|
||||
len = create_ad(hdev, cp.data);
|
||||
|
||||
if (hdev->adv_data_len == len &&
|
||||
memcmp(cp.data, hdev->adv_data, len) == 0) {
|
||||
err = 0;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
memcpy(hdev->adv_data, cp.data, sizeof(cp.data));
|
||||
hdev->adv_data_len = len;
|
||||
|
||||
cp.length = len;
|
||||
err = hci_send_cmd(hdev, HCI_OP_LE_SET_ADV_DATA, sizeof(cp), &cp);
|
||||
|
||||
unlock:
|
||||
hci_dev_unlock(hdev);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/* ---- HCI ioctl helpers ---- */
|
||||
|
||||
int hci_dev_open(__u16 dev)
|
||||
|
@ -651,6 +746,7 @@ int hci_dev_open(__u16 dev)
|
|||
hci_dev_hold(hdev);
|
||||
set_bit(HCI_UP, &hdev->flags);
|
||||
hci_notify(hdev, HCI_DEV_UP);
|
||||
hci_update_ad(hdev);
|
||||
if (!test_bit(HCI_SETUP, &hdev->dev_flags) &&
|
||||
mgmt_valid_hdev(hdev)) {
|
||||
hci_dev_lock(hdev);
|
||||
|
@ -1606,6 +1702,8 @@ struct hci_dev *hci_alloc_dev(void)
|
|||
hdev->esco_type = (ESCO_HV1);
|
||||
hdev->link_mode = (HCI_LM_ACCEPT);
|
||||
hdev->io_capability = 0x03; /* No Input No Output */
|
||||
hdev->inq_tx_power = HCI_TX_POWER_INVALID;
|
||||
hdev->adv_tx_power = HCI_TX_POWER_INVALID;
|
||||
|
||||
hdev->sniff_max_interval = 800;
|
||||
hdev->sniff_min_interval = 80;
|
||||
|
|
|
@ -202,6 +202,11 @@ static void hci_cc_reset(struct hci_dev *hdev, struct sk_buff *skb)
|
|||
BIT(HCI_PERIODIC_INQ));
|
||||
|
||||
hdev->discovery.state = DISCOVERY_STOPPED;
|
||||
hdev->inq_tx_power = HCI_TX_POWER_INVALID;
|
||||
hdev->adv_tx_power = HCI_TX_POWER_INVALID;
|
||||
|
||||
memset(hdev->adv_data, 0, sizeof(hdev->adv_data));
|
||||
hdev->adv_data_len = 0;
|
||||
}
|
||||
|
||||
static void hci_cc_write_local_name(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
|
@ -224,6 +229,9 @@ static void hci_cc_write_local_name(struct hci_dev *hdev, struct sk_buff *skb)
|
|||
|
||||
hci_dev_unlock(hdev);
|
||||
|
||||
if (!status && !test_bit(HCI_INIT, &hdev->flags))
|
||||
hci_update_ad(hdev);
|
||||
|
||||
hci_req_complete(hdev, HCI_OP_WRITE_LOCAL_NAME, status);
|
||||
}
|
||||
|
||||
|
@ -1089,8 +1097,11 @@ static void hci_cc_le_read_adv_tx_power(struct hci_dev *hdev,
|
|||
|
||||
BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
|
||||
|
||||
if (!rp->status)
|
||||
if (!rp->status) {
|
||||
hdev->adv_tx_power = rp->tx_power;
|
||||
if (!test_bit(HCI_INIT, &hdev->flags))
|
||||
hci_update_ad(hdev);
|
||||
}
|
||||
|
||||
hci_req_complete(hdev, HCI_OP_LE_READ_ADV_TX_POWER, rp->status);
|
||||
}
|
||||
|
@ -1179,6 +1190,33 @@ static void hci_cc_read_local_oob_data_reply(struct hci_dev *hdev,
|
|||
hci_dev_unlock(hdev);
|
||||
}
|
||||
|
||||
static void hci_cc_le_set_adv_enable(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
__u8 *sent, status = *((__u8 *) skb->data);
|
||||
|
||||
BT_DBG("%s status 0x%2.2x", hdev->name, status);
|
||||
|
||||
sent = hci_sent_cmd_data(hdev, HCI_OP_LE_SET_ADV_ENABLE);
|
||||
if (!sent)
|
||||
return;
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
|
||||
if (!status) {
|
||||
if (*sent)
|
||||
set_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags);
|
||||
else
|
||||
clear_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags);
|
||||
}
|
||||
|
||||
hci_dev_unlock(hdev);
|
||||
|
||||
if (!test_bit(HCI_INIT, &hdev->flags))
|
||||
hci_update_ad(hdev);
|
||||
|
||||
hci_req_complete(hdev, HCI_OP_LE_SET_ADV_ENABLE, status);
|
||||
}
|
||||
|
||||
static void hci_cc_le_set_scan_param(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
__u8 status = *((__u8 *) skb->data);
|
||||
|
@ -2574,6 +2612,10 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
|||
hci_cc_le_set_scan_param(hdev, skb);
|
||||
break;
|
||||
|
||||
case HCI_OP_LE_SET_ADV_ENABLE:
|
||||
hci_cc_le_set_adv_enable(hdev, skb);
|
||||
break;
|
||||
|
||||
case HCI_OP_LE_SET_SCAN_ENABLE:
|
||||
hci_cc_le_set_scan_enable(hdev, skb);
|
||||
break;
|
||||
|
|
|
@ -4284,9 +4284,9 @@ static int l2cap_create_channel_req(struct l2cap_conn *conn,
|
|||
|
||||
BT_DBG("mgr %p bredr_chan %p hs_hcon %p", mgr, chan, hs_hcon);
|
||||
|
||||
chan->local_amp_id = req->amp_id;
|
||||
mgr->bredr_chan = chan;
|
||||
chan->hs_hcon = hs_hcon;
|
||||
chan->fcs = L2CAP_FCS_NONE;
|
||||
conn->mtu = hdev->block_mtu;
|
||||
}
|
||||
|
||||
|
@ -4518,21 +4518,39 @@ void l2cap_move_start(struct l2cap_chan *chan)
|
|||
static void l2cap_do_create(struct l2cap_chan *chan, int result,
|
||||
u8 local_amp_id, u8 remote_amp_id)
|
||||
{
|
||||
if (!test_bit(CONF_CONNECT_PEND, &chan->conf_state)) {
|
||||
BT_DBG("chan %p state %s %u -> %u", chan, state_to_string(chan->state),
|
||||
local_amp_id, remote_amp_id);
|
||||
|
||||
chan->fcs = L2CAP_FCS_NONE;
|
||||
|
||||
/* Outgoing channel on AMP */
|
||||
if (chan->state == BT_CONNECT) {
|
||||
if (result == L2CAP_CR_SUCCESS) {
|
||||
chan->local_amp_id = local_amp_id;
|
||||
l2cap_send_create_chan_req(chan, remote_amp_id);
|
||||
} else {
|
||||
/* Revert to BR/EDR connect */
|
||||
l2cap_send_conn_req(chan);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* Incoming channel on AMP */
|
||||
if (__l2cap_no_conn_pending(chan)) {
|
||||
struct l2cap_conn_rsp rsp;
|
||||
char buf[128];
|
||||
rsp.scid = cpu_to_le16(chan->dcid);
|
||||
rsp.dcid = cpu_to_le16(chan->scid);
|
||||
|
||||
/* Incoming channel on AMP */
|
||||
if (result == L2CAP_CR_SUCCESS) {
|
||||
/* Send successful response */
|
||||
rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS);
|
||||
rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
|
||||
rsp.result = __constant_cpu_to_le16(L2CAP_CR_SUCCESS);
|
||||
rsp.status = __constant_cpu_to_le16(L2CAP_CS_NO_INFO);
|
||||
} else {
|
||||
/* Send negative response */
|
||||
rsp.result = cpu_to_le16(L2CAP_CR_NO_MEM);
|
||||
rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
|
||||
rsp.result = __constant_cpu_to_le16(L2CAP_CR_NO_MEM);
|
||||
rsp.status = __constant_cpu_to_le16(L2CAP_CS_NO_INFO);
|
||||
}
|
||||
|
||||
l2cap_send_cmd(chan->conn, chan->ident, L2CAP_CREATE_CHAN_RSP,
|
||||
|
@ -4546,15 +4564,6 @@ static void l2cap_do_create(struct l2cap_chan *chan, int result,
|
|||
l2cap_build_conf_req(chan, buf), buf);
|
||||
chan->num_conf_req++;
|
||||
}
|
||||
} else {
|
||||
/* Outgoing channel on AMP */
|
||||
if (result == L2CAP_CR_SUCCESS) {
|
||||
chan->local_amp_id = local_amp_id;
|
||||
l2cap_send_create_chan_req(chan, remote_amp_id);
|
||||
} else {
|
||||
/* Revert to BR/EDR connect */
|
||||
l2cap_send_conn_req(chan);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4612,7 +4621,8 @@ static void l2cap_do_move_cancel(struct l2cap_chan *chan, int result)
|
|||
l2cap_ertm_send(chan);
|
||||
}
|
||||
|
||||
void l2cap_physical_cfm(struct l2cap_chan *chan, int result)
|
||||
/* Invoke with locked chan */
|
||||
void __l2cap_physical_cfm(struct l2cap_chan *chan, int result)
|
||||
{
|
||||
u8 local_amp_id = chan->local_amp_id;
|
||||
u8 remote_amp_id = chan->remote_amp_id;
|
||||
|
@ -4620,8 +4630,6 @@ void l2cap_physical_cfm(struct l2cap_chan *chan, int result)
|
|||
BT_DBG("chan %p, result %d, local_amp_id %d, remote_amp_id %d",
|
||||
chan, result, local_amp_id, remote_amp_id);
|
||||
|
||||
l2cap_chan_lock(chan);
|
||||
|
||||
if (chan->state == BT_DISCONN || chan->state == BT_CLOSED) {
|
||||
l2cap_chan_unlock(chan);
|
||||
return;
|
||||
|
@ -4645,8 +4653,6 @@ void l2cap_physical_cfm(struct l2cap_chan *chan, int result)
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
l2cap_chan_unlock(chan);
|
||||
}
|
||||
|
||||
static inline int l2cap_move_channel_req(struct l2cap_conn *conn,
|
||||
|
@ -6086,7 +6092,7 @@ static int l2cap_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb)
|
|||
control->super);
|
||||
|
||||
if (len != 0) {
|
||||
BT_ERR("%d", len);
|
||||
BT_ERR("Trailing bytes: %d in sframe", len);
|
||||
l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
|
||||
goto drop;
|
||||
}
|
||||
|
@ -6380,7 +6386,7 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
|
|||
continue;
|
||||
}
|
||||
|
||||
if (test_bit(CONF_CONNECT_PEND, &chan->conf_state)) {
|
||||
if (!__l2cap_no_conn_pending(chan)) {
|
||||
l2cap_chan_unlock(chan);
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -485,7 +485,7 @@ static void create_eir(struct hci_dev *hdev, u8 *data)
|
|||
ptr += (name_len + 2);
|
||||
}
|
||||
|
||||
if (hdev->inq_tx_power) {
|
||||
if (hdev->inq_tx_power != HCI_TX_POWER_INVALID) {
|
||||
ptr[0] = 2;
|
||||
ptr[1] = EIR_TX_POWER;
|
||||
ptr[2] = (u8) hdev->inq_tx_power;
|
||||
|
|
Loading…
Reference in a new issue