1
0
Fork 0

Merge branch 'for-upstream' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next

hifive-unleashed-5.1
John W. Linville 2013-06-24 14:45:50 -04:00
commit 9fbdc75116
10 changed files with 327 additions and 349 deletions

View File

@ -1619,6 +1619,7 @@ static struct usb_driver btusb_driver = {
#ifdef CONFIG_PM
.suspend = btusb_suspend,
.resume = btusb_resume,
.reset_resume = btusb_resume,
#endif
.id_table = btusb_table,
.supports_autosuspend = 1,

View File

@ -107,7 +107,6 @@ enum {
HCI_MGMT,
HCI_PAIRABLE,
HCI_SERVICE_CACHE,
HCI_LINK_KEYS,
HCI_DEBUG_KEYS,
HCI_UNREGISTER,

View File

@ -117,13 +117,6 @@ struct oob_data {
u8 randomizer[16];
};
struct le_scan_params {
u8 type;
u16 interval;
u16 window;
int timeout;
};
#define HCI_MAX_SHORT_NAME_LENGTH 10
struct amp_assoc {
@ -283,9 +276,6 @@ struct hci_dev {
struct delayed_work le_scan_disable;
struct work_struct le_scan;
struct le_scan_params le_scan_params;
__s8 adv_tx_power;
__u8 adv_data[HCI_MAX_AD_LENGTH];
__u8 adv_data_len;
@ -432,6 +422,7 @@ void hci_inquiry_cache_update_resolve(struct hci_dev *hdev,
struct inquiry_entry *ie);
bool hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_data *data,
bool name_known, bool *ssp);
void hci_inquiry_cache_flush(struct hci_dev *hdev);
/* ----- HCI Connections ----- */
enum {
@ -1114,6 +1105,16 @@ void hci_sock_dev_event(struct hci_dev *hdev, int event);
BIT(BDADDR_LE_PUBLIC) | \
BIT(BDADDR_LE_RANDOM))
/* These LE scan and inquiry parameters were chosen according to LE General
* Discovery Procedure specification.
*/
#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_INTERLEAVED_INQUIRY_LEN 0x04
#define DISCOV_BREDR_INQUIRY_LEN 0x08
int mgmt_control(struct sock *sk, struct msghdr *msg, size_t len);
int mgmt_index_added(struct hci_dev *hdev);
int mgmt_index_removed(struct hci_dev *hdev);
@ -1169,10 +1170,7 @@ int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
u8 ssp, u8 *eir, u16 eir_len);
int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
u8 addr_type, s8 rssi, u8 *name, u8 name_len);
int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status);
int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status);
int mgmt_discovering(struct hci_dev *hdev, u8 discovering);
int mgmt_interleaved_discovery(struct hci_dev *hdev);
int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type);
int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type);
bool mgmt_valid_hdev(struct hci_dev *hdev);
@ -1212,11 +1210,6 @@ void hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max,
u16 latency, u16 to_multiplier);
void hci_le_start_enc(struct hci_conn *conn, __le16 ediv, __u8 rand[8],
__u8 ltk[16]);
int hci_do_inquiry(struct hci_dev *hdev, u8 length);
int hci_cancel_inquiry(struct hci_dev *hdev);
int hci_le_scan(struct hci_dev *hdev, u8 type, u16 interval, u16 window,
int timeout);
int hci_cancel_le_scan(struct hci_dev *hdev);
u8 bdaddr_to_le(u8 bdaddr_type);

View File

@ -242,7 +242,7 @@ struct l2cap_conn_rsp {
#define L2CAP_CID_SIGNALING 0x0001
#define L2CAP_CID_CONN_LESS 0x0002
#define L2CAP_CID_A2MP 0x0003
#define L2CAP_CID_LE_DATA 0x0004
#define L2CAP_CID_ATT 0x0004
#define L2CAP_CID_LE_SIGNALING 0x0005
#define L2CAP_CID_SMP 0x0006
#define L2CAP_CID_DYN_START 0x0040

View File

@ -597,7 +597,15 @@ static void hci_init3_req(struct hci_request *req, unsigned long opt)
struct hci_dev *hdev = req->hdev;
u8 p;
/* Only send HCI_Delete_Stored_Link_Key if it is supported */
/* Some Broadcom based Bluetooth controllers do not support the
* Delete Stored Link Key command. They are clearly indicating its
* absence in the bit mask of supported commands.
*
* Check the supported commands and only if the the command is marked
* as supported send it. If not supported assume that the controller
* does not have actual support for stored link keys which makes this
* command redundant anyway.
*/
if (hdev->commands[6] & 0x80) {
struct hci_cp_delete_stored_link_key cp;
@ -751,7 +759,7 @@ void hci_discovery_set_state(struct hci_dev *hdev, int state)
hdev->discovery.state = state;
}
static void inquiry_cache_flush(struct hci_dev *hdev)
void hci_inquiry_cache_flush(struct hci_dev *hdev)
{
struct discovery_state *cache = &hdev->discovery;
struct inquiry_entry *p, *n;
@ -964,7 +972,7 @@ int hci_inquiry(void __user *arg)
hci_dev_lock(hdev);
if (inquiry_cache_age(hdev) > INQUIRY_CACHE_AGE_MAX ||
inquiry_cache_empty(hdev) || ir.flags & IREQ_CACHE_FLUSH) {
inquiry_cache_flush(hdev);
hci_inquiry_cache_flush(hdev);
do_inquiry = 1;
}
hci_dev_unlock(hdev);
@ -1201,8 +1209,6 @@ static int hci_dev_do_close(struct hci_dev *hdev)
{
BT_DBG("%s %p", hdev->name, hdev);
cancel_work_sync(&hdev->le_scan);
cancel_delayed_work(&hdev->power_off);
hci_req_cancel(hdev, ENODEV);
@ -1230,7 +1236,7 @@ static int hci_dev_do_close(struct hci_dev *hdev)
cancel_delayed_work_sync(&hdev->le_scan_disable);
hci_dev_lock(hdev);
inquiry_cache_flush(hdev);
hci_inquiry_cache_flush(hdev);
hci_conn_hash_flush(hdev);
hci_dev_unlock(hdev);
@ -1331,7 +1337,7 @@ int hci_dev_reset(__u16 dev)
skb_queue_purge(&hdev->cmd_q);
hci_dev_lock(hdev);
inquiry_cache_flush(hdev);
hci_inquiry_cache_flush(hdev);
hci_conn_hash_flush(hdev);
hci_dev_unlock(hdev);
@ -1991,80 +1997,59 @@ int hci_blacklist_del(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
return mgmt_device_unblocked(hdev, bdaddr, type);
}
static void le_scan_param_req(struct hci_request *req, unsigned long opt)
static void inquiry_complete(struct hci_dev *hdev, u8 status)
{
struct le_scan_params *param = (struct le_scan_params *) opt;
struct hci_cp_le_set_scan_param cp;
if (status) {
BT_ERR("Failed to start inquiry: status %d", status);
memset(&cp, 0, sizeof(cp));
cp.type = param->type;
cp.interval = cpu_to_le16(param->interval);
cp.window = cpu_to_le16(param->window);
hci_req_add(req, HCI_OP_LE_SET_SCAN_PARAM, sizeof(cp), &cp);
hci_dev_lock(hdev);
hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
hci_dev_unlock(hdev);
return;
}
}
static void le_scan_enable_req(struct hci_request *req, unsigned long opt)
static void le_scan_disable_work_complete(struct hci_dev *hdev, u8 status)
{
struct hci_cp_le_set_scan_enable cp;
memset(&cp, 0, sizeof(cp));
cp.enable = LE_SCAN_ENABLE;
cp.filter_dup = LE_SCAN_FILTER_DUP_ENABLE;
hci_req_add(req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(cp), &cp);
}
static int hci_do_le_scan(struct hci_dev *hdev, u8 type, u16 interval,
u16 window, int timeout)
{
long timeo = msecs_to_jiffies(3000);
struct le_scan_params param;
/* General inquiry access code (GIAC) */
u8 lap[3] = { 0x33, 0x8b, 0x9e };
struct hci_request req;
struct hci_cp_inquiry cp;
int err;
BT_DBG("%s", hdev->name);
if (test_bit(HCI_LE_SCAN, &hdev->dev_flags))
return -EINPROGRESS;
param.type = type;
param.interval = interval;
param.window = window;
hci_req_lock(hdev);
err = __hci_req_sync(hdev, le_scan_param_req, (unsigned long) &param,
timeo);
if (!err)
err = __hci_req_sync(hdev, le_scan_enable_req, 0, timeo);
hci_req_unlock(hdev);
if (err < 0)
return err;
queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
timeout);
return 0;
}
int hci_cancel_le_scan(struct hci_dev *hdev)
{
BT_DBG("%s", hdev->name);
if (!test_bit(HCI_LE_SCAN, &hdev->dev_flags))
return -EALREADY;
if (cancel_delayed_work(&hdev->le_scan_disable)) {
struct hci_cp_le_set_scan_enable cp;
/* Send HCI command to disable LE Scan */
memset(&cp, 0, sizeof(cp));
hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(cp), &cp);
if (status) {
BT_ERR("Failed to disable LE scanning: status %d", status);
return;
}
return 0;
switch (hdev->discovery.type) {
case DISCOV_TYPE_LE:
hci_dev_lock(hdev);
hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
hci_dev_unlock(hdev);
break;
case DISCOV_TYPE_INTERLEAVED:
hci_req_init(&req, hdev);
memset(&cp, 0, sizeof(cp));
memcpy(&cp.lap, lap, sizeof(cp.lap));
cp.length = DISCOV_INTERLEAVED_INQUIRY_LEN;
hci_req_add(&req, HCI_OP_INQUIRY, sizeof(cp), &cp);
hci_dev_lock(hdev);
hci_inquiry_cache_flush(hdev);
err = hci_req_run(&req, inquiry_complete);
if (err) {
BT_ERR("Inquiry request failed: err %d", err);
hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
}
hci_dev_unlock(hdev);
break;
}
}
static void le_scan_disable_work(struct work_struct *work)
@ -2072,46 +2057,20 @@ static void le_scan_disable_work(struct work_struct *work)
struct hci_dev *hdev = container_of(work, struct hci_dev,
le_scan_disable.work);
struct hci_cp_le_set_scan_enable cp;
struct hci_request req;
int err;
BT_DBG("%s", hdev->name);
hci_req_init(&req, hdev);
memset(&cp, 0, sizeof(cp));
cp.enable = LE_SCAN_DISABLE;
hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(cp), &cp);
hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(cp), &cp);
}
static void le_scan_work(struct work_struct *work)
{
struct hci_dev *hdev = container_of(work, struct hci_dev, le_scan);
struct le_scan_params *param = &hdev->le_scan_params;
BT_DBG("%s", hdev->name);
hci_do_le_scan(hdev, param->type, param->interval, param->window,
param->timeout);
}
int hci_le_scan(struct hci_dev *hdev, u8 type, u16 interval, u16 window,
int timeout)
{
struct le_scan_params *param = &hdev->le_scan_params;
BT_DBG("%s", hdev->name);
if (test_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags))
return -ENOTSUPP;
if (work_busy(&hdev->le_scan))
return -EINPROGRESS;
param->type = type;
param->interval = interval;
param->window = window;
param->timeout = timeout;
queue_work(system_long_wq, &hdev->le_scan);
return 0;
err = hci_req_run(&req, le_scan_disable_work_complete);
if (err)
BT_ERR("Disable LE scanning request failed: err %d", err);
}
/* Alloc HCI device */
@ -2148,7 +2107,6 @@ struct hci_dev *hci_alloc_dev(void)
INIT_WORK(&hdev->cmd_work, hci_cmd_work);
INIT_WORK(&hdev->tx_work, hci_tx_work);
INIT_WORK(&hdev->power_on, hci_power_on);
INIT_WORK(&hdev->le_scan, le_scan_work);
INIT_DELAYED_WORK(&hdev->power_off, hci_power_off);
INIT_DELAYED_WORK(&hdev->discov_off, hci_discov_off);
@ -3551,36 +3509,6 @@ static void hci_cmd_work(struct work_struct *work)
}
}
int hci_do_inquiry(struct hci_dev *hdev, u8 length)
{
/* General inquiry access code (GIAC) */
u8 lap[3] = { 0x33, 0x8b, 0x9e };
struct hci_cp_inquiry cp;
BT_DBG("%s", hdev->name);
if (test_bit(HCI_INQUIRY, &hdev->flags))
return -EINPROGRESS;
inquiry_cache_flush(hdev);
memset(&cp, 0, sizeof(cp));
memcpy(&cp.lap, lap, sizeof(cp.lap));
cp.length = length;
return hci_send_cmd(hdev, HCI_OP_INQUIRY, sizeof(cp), &cp);
}
int hci_cancel_inquiry(struct hci_dev *hdev)
{
BT_DBG("%s", hdev->name);
if (!test_bit(HCI_INQUIRY, &hdev->flags))
return -EALREADY;
return hci_send_cmd(hdev, HCI_OP_INQUIRY_CANCEL, 0, NULL);
}
u8 bdaddr_to_le(u8 bdaddr_type)
{
switch (bdaddr_type) {

View File

@ -40,21 +40,13 @@ static void hci_cc_inquiry_cancel(struct hci_dev *hdev, struct sk_buff *skb)
BT_DBG("%s status 0x%2.2x", hdev->name, status);
if (status) {
hci_dev_lock(hdev);
mgmt_stop_discovery_failed(hdev, status);
hci_dev_unlock(hdev);
if (status)
return;
}
clear_bit(HCI_INQUIRY, &hdev->flags);
smp_mb__after_clear_bit(); /* wake_up_bit advises about this barrier */
wake_up_bit(&hdev->flags, HCI_INQUIRY);
hci_dev_lock(hdev);
hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
hci_dev_unlock(hdev);
hci_conn_check_pending(hdev);
}
@ -937,20 +929,6 @@ static void hci_cc_le_set_adv_enable(struct hci_dev *hdev, struct sk_buff *skb)
hci_dev_unlock(hdev);
}
static void hci_cc_le_set_scan_param(struct hci_dev *hdev, struct sk_buff *skb)
{
__u8 status = *((__u8 *) skb->data);
BT_DBG("%s status 0x%2.2x", hdev->name, status);
if (status) {
hci_dev_lock(hdev);
mgmt_start_discovery_failed(hdev, status);
hci_dev_unlock(hdev);
return;
}
}
static void hci_cc_le_set_scan_enable(struct hci_dev *hdev,
struct sk_buff *skb)
{
@ -963,41 +941,16 @@ static void hci_cc_le_set_scan_enable(struct hci_dev *hdev,
if (!cp)
return;
if (status)
return;
switch (cp->enable) {
case LE_SCAN_ENABLE:
if (status) {
hci_dev_lock(hdev);
mgmt_start_discovery_failed(hdev, status);
hci_dev_unlock(hdev);
return;
}
set_bit(HCI_LE_SCAN, &hdev->dev_flags);
hci_dev_lock(hdev);
hci_discovery_set_state(hdev, DISCOVERY_FINDING);
hci_dev_unlock(hdev);
break;
case LE_SCAN_DISABLE:
if (status) {
hci_dev_lock(hdev);
mgmt_stop_discovery_failed(hdev, status);
hci_dev_unlock(hdev);
return;
}
clear_bit(HCI_LE_SCAN, &hdev->dev_flags);
if (hdev->discovery.type == DISCOV_TYPE_INTERLEAVED &&
hdev->discovery.state == DISCOVERY_FINDING) {
mgmt_interleaved_discovery(hdev);
} else {
hci_dev_lock(hdev);
hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
hci_dev_unlock(hdev);
}
break;
default:
@ -1077,18 +1030,10 @@ static void hci_cs_inquiry(struct hci_dev *hdev, __u8 status)
if (status) {
hci_conn_check_pending(hdev);
hci_dev_lock(hdev);
if (test_bit(HCI_MGMT, &hdev->dev_flags))
mgmt_start_discovery_failed(hdev, status);
hci_dev_unlock(hdev);
return;
}
set_bit(HCI_INQUIRY, &hdev->flags);
hci_dev_lock(hdev);
hci_discovery_set_state(hdev, DISCOVERY_FINDING);
hci_dev_unlock(hdev);
}
static void hci_cs_create_conn(struct hci_dev *hdev, __u8 status)
@ -2298,10 +2243,6 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
hci_cc_user_passkey_neg_reply(hdev, skb);
break;
case HCI_OP_LE_SET_SCAN_PARAM:
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;
@ -2670,7 +2611,7 @@ static void hci_link_key_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
BT_DBG("%s", hdev->name);
if (!test_bit(HCI_LINK_KEYS, &hdev->dev_flags))
if (!test_bit(HCI_MGMT, &hdev->dev_flags))
return;
hci_dev_lock(hdev);
@ -2746,7 +2687,7 @@ static void hci_link_key_notify_evt(struct hci_dev *hdev, struct sk_buff *skb)
hci_conn_drop(conn);
}
if (test_bit(HCI_LINK_KEYS, &hdev->dev_flags))
if (test_bit(HCI_MGMT, &hdev->dev_flags))
hci_add_link_key(hdev, conn, 1, &ev->bdaddr, ev->link_key,
ev->key_type, pin_len);

View File

@ -76,25 +76,19 @@ static void hidp_copy_session(struct hidp_session *session, struct hidp_conninfo
ci->flags = session->flags;
ci->state = BT_CONNECTED;
ci->vendor = 0x0000;
ci->product = 0x0000;
ci->version = 0x0000;
if (session->input) {
ci->vendor = session->input->id.vendor;
ci->product = session->input->id.product;
ci->version = session->input->id.version;
if (session->input->name)
strncpy(ci->name, session->input->name, 128);
strlcpy(ci->name, session->input->name, 128);
else
strncpy(ci->name, "HID Boot Device", 128);
}
if (session->hid) {
strlcpy(ci->name, "HID Boot Device", 128);
} else if (session->hid) {
ci->vendor = session->hid->vendor;
ci->product = session->hid->product;
ci->version = session->hid->version;
strncpy(ci->name, session->hid->name, 128);
strlcpy(ci->name, session->hid->name, 128);
}
}

View File

@ -504,8 +504,10 @@ void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
if (conn->hcon->type == LE_LINK) {
/* LE connection */
chan->omtu = L2CAP_DEFAULT_MTU;
chan->scid = L2CAP_CID_LE_DATA;
chan->dcid = L2CAP_CID_LE_DATA;
if (chan->dcid == L2CAP_CID_ATT)
chan->scid = L2CAP_CID_ATT;
else
chan->scid = l2cap_alloc_cid(conn);
} else {
/* Alloc CID for connection-oriented socket */
chan->scid = l2cap_alloc_cid(conn);
@ -543,6 +545,8 @@ void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
l2cap_chan_hold(chan);
hci_conn_hold(conn->hcon);
list_add(&chan->list, &conn->chan_l);
}
@ -1338,17 +1342,21 @@ static struct l2cap_chan *l2cap_global_chan_by_scid(int state, u16 cid,
static void l2cap_le_conn_ready(struct l2cap_conn *conn)
{
struct sock *parent, *sk;
struct sock *parent;
struct l2cap_chan *chan, *pchan;
BT_DBG("");
/* Check if we have socket listening on cid */
pchan = l2cap_global_chan_by_scid(BT_LISTEN, L2CAP_CID_LE_DATA,
pchan = l2cap_global_chan_by_scid(BT_LISTEN, L2CAP_CID_ATT,
conn->src, conn->dst);
if (!pchan)
return;
/* Client ATT sockets should override the server one */
if (__l2cap_get_chan_by_dcid(conn, L2CAP_CID_ATT))
return;
parent = pchan->sk;
lock_sock(parent);
@ -1357,17 +1365,12 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn)
if (!chan)
goto clean;
sk = chan->sk;
chan->dcid = L2CAP_CID_ATT;
hci_conn_hold(conn->hcon);
conn->hcon->disc_timeout = HCI_DISCONN_TIMEOUT;
bacpy(&bt_sk(chan->sk)->src, conn->src);
bacpy(&bt_sk(chan->sk)->dst, conn->dst);
bacpy(&bt_sk(sk)->src, conn->src);
bacpy(&bt_sk(sk)->dst, conn->dst);
l2cap_chan_add(conn, chan);
l2cap_chan_ready(chan);
__l2cap_chan_add(conn, chan);
clean:
release_sock(parent);
@ -1380,14 +1383,17 @@ static void l2cap_conn_ready(struct l2cap_conn *conn)
BT_DBG("conn %p", conn);
if (!hcon->out && hcon->type == LE_LINK)
l2cap_le_conn_ready(conn);
/* For outgoing pairing which doesn't necessarily have an
* associated socket (e.g. mgmt_pair_device).
*/
if (hcon->out && hcon->type == LE_LINK)
smp_conn_security(hcon, hcon->pending_sec_level);
mutex_lock(&conn->chan_lock);
if (hcon->type == LE_LINK)
l2cap_le_conn_ready(conn);
list_for_each_entry(chan, &conn->chan_l, list) {
l2cap_chan_lock(chan);
@ -1792,7 +1798,7 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid,
auth_type = l2cap_get_auth_type(chan);
if (chan->dcid == L2CAP_CID_LE_DATA)
if (bdaddr_type_is_le(dst_type))
hcon = hci_connect(hdev, LE_LINK, dst, dst_type,
chan->sec_level, auth_type);
else
@ -1811,16 +1817,10 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid,
goto done;
}
if (hcon->type == LE_LINK) {
err = 0;
if (!list_empty(&conn->chan_l)) {
err = -EBUSY;
hci_conn_drop(hcon);
}
if (err)
goto done;
if (cid && __l2cap_get_chan_by_dcid(conn, cid)) {
hci_conn_drop(hcon);
err = -EBUSY;
goto done;
}
/* Update source addr of the socket */
@ -1830,6 +1830,9 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid,
l2cap_chan_add(conn, chan);
l2cap_chan_lock(chan);
/* l2cap_chan_add takes its own ref so we can drop this one */
hci_conn_drop(hcon);
l2cap_state_change(chan, BT_CONNECT);
__set_chan_timer(chan, sk->sk_sndtimeo);
@ -3751,8 +3754,6 @@ static struct l2cap_chan *l2cap_connect(struct l2cap_conn *conn,
sk = chan->sk;
hci_conn_hold(conn->hcon);
bacpy(&bt_sk(sk)->src, conn->src);
bacpy(&bt_sk(sk)->dst, conn->dst);
chan->psm = psm;
@ -5292,6 +5293,51 @@ static inline int l2cap_le_sig_cmd(struct l2cap_conn *conn,
}
}
static inline void l2cap_le_sig_channel(struct l2cap_conn *conn,
struct sk_buff *skb)
{
u8 *data = skb->data;
int len = skb->len;
struct l2cap_cmd_hdr cmd;
int err;
l2cap_raw_recv(conn, skb);
while (len >= L2CAP_CMD_HDR_SIZE) {
u16 cmd_len;
memcpy(&cmd, data, L2CAP_CMD_HDR_SIZE);
data += L2CAP_CMD_HDR_SIZE;
len -= L2CAP_CMD_HDR_SIZE;
cmd_len = le16_to_cpu(cmd.len);
BT_DBG("code 0x%2.2x len %d id 0x%2.2x", cmd.code, cmd_len,
cmd.ident);
if (cmd_len > len || !cmd.ident) {
BT_DBG("corrupted command");
break;
}
err = l2cap_le_sig_cmd(conn, &cmd, data);
if (err) {
struct l2cap_cmd_rej_unk rej;
BT_ERR("Wrong link type (%d)", err);
/* FIXME: Map err to a valid reason */
rej.reason = __constant_cpu_to_le16(L2CAP_REJ_NOT_UNDERSTOOD);
l2cap_send_cmd(conn, cmd.ident, L2CAP_COMMAND_REJ,
sizeof(rej), &rej);
}
data += cmd_len;
len -= cmd_len;
}
kfree_skb(skb);
}
static inline void l2cap_sig_channel(struct l2cap_conn *conn,
struct sk_buff *skb)
{
@ -5318,11 +5364,7 @@ static inline void l2cap_sig_channel(struct l2cap_conn *conn,
break;
}
if (conn->hcon->type == LE_LINK)
err = l2cap_le_sig_cmd(conn, &cmd, data);
else
err = l2cap_bredr_sig_cmd(conn, &cmd, cmd_len, data);
err = l2cap_bredr_sig_cmd(conn, &cmd, cmd_len, data);
if (err) {
struct l2cap_cmd_rej_unk rej;
@ -6356,16 +6398,13 @@ static void l2cap_att_channel(struct l2cap_conn *conn,
{
struct l2cap_chan *chan;
chan = l2cap_global_chan_by_scid(0, L2CAP_CID_LE_DATA,
chan = l2cap_global_chan_by_scid(BT_CONNECTED, L2CAP_CID_ATT,
conn->src, conn->dst);
if (!chan)
goto drop;
BT_DBG("chan %p, len %d", chan, skb->len);
if (chan->state != BT_BOUND && chan->state != BT_CONNECTED)
goto drop;
if (chan->imtu < skb->len)
goto drop;
@ -6395,6 +6434,8 @@ static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb)
switch (cid) {
case L2CAP_CID_LE_SIGNALING:
l2cap_le_sig_channel(conn, skb);
break;
case L2CAP_CID_SIGNALING:
l2cap_sig_channel(conn, skb);
break;
@ -6405,7 +6446,7 @@ static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb)
l2cap_conless_channel(conn, psm, skb);
break;
case L2CAP_CID_LE_DATA:
case L2CAP_CID_ATT:
l2cap_att_channel(conn, skb);
break;
@ -6531,7 +6572,7 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
continue;
}
if (chan->scid == L2CAP_CID_LE_DATA) {
if (chan->scid == L2CAP_CID_ATT) {
if (!status && encrypt) {
chan->sec_level = hcon->sec_level;
l2cap_chan_ready(chan);

View File

@ -466,7 +466,7 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname,
static bool l2cap_valid_mtu(struct l2cap_chan *chan, u16 mtu)
{
switch (chan->scid) {
case L2CAP_CID_LE_DATA:
case L2CAP_CID_ATT:
if (mtu < L2CAP_LE_MIN_MTU)
return false;
break;
@ -630,7 +630,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname,
conn = chan->conn;
/*change security for LE channels */
if (chan->scid == L2CAP_CID_LE_DATA) {
if (chan->scid == L2CAP_CID_ATT) {
if (!conn->hcon->out) {
err = -EINVAL;
break;

View File

@ -102,18 +102,6 @@ static const u16 mgmt_events[] = {
MGMT_EV_PASSKEY_NOTIFY,
};
/*
* These LE scan and inquiry parameters were chosen according to LE General
* Discovery Procedure specification.
*/
#define LE_SCAN_WIN 0x12
#define LE_SCAN_INT 0x12
#define LE_SCAN_TIMEOUT_LE_ONLY msecs_to_jiffies(10240)
#define LE_SCAN_TIMEOUT_BREDR_LE msecs_to_jiffies(5120)
#define INQUIRY_LEN_BREDR 0x08 /* TGAP(100) */
#define INQUIRY_LEN_BREDR_LE 0x04 /* TGAP(100)/2 */
#define CACHE_TIMEOUT msecs_to_jiffies(2 * 1000)
#define hdev_is_powered(hdev) (test_bit(HCI_UP, &hdev->flags) && \
@ -1748,8 +1736,6 @@ static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
hci_link_keys_clear(hdev);
set_bit(HCI_LINK_KEYS, &hdev->dev_flags);
if (cp->debug_keys)
set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
else
@ -2633,28 +2619,72 @@ static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
return err;
}
int mgmt_interleaved_discovery(struct hci_dev *hdev)
static int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
{
struct pending_cmd *cmd;
u8 type;
int err;
BT_DBG("%s", hdev->name);
hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
hci_dev_lock(hdev);
cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
if (!cmd)
return -ENOENT;
err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR_LE);
if (err < 0)
hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
type = hdev->discovery.type;
hci_dev_unlock(hdev);
err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
&type, sizeof(type));
mgmt_pending_remove(cmd);
return err;
}
static void start_discovery_complete(struct hci_dev *hdev, u8 status)
{
BT_DBG("status %d", status);
if (status) {
hci_dev_lock(hdev);
mgmt_start_discovery_failed(hdev, status);
hci_dev_unlock(hdev);
return;
}
hci_dev_lock(hdev);
hci_discovery_set_state(hdev, DISCOVERY_FINDING);
hci_dev_unlock(hdev);
switch (hdev->discovery.type) {
case DISCOV_TYPE_LE:
queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
DISCOV_LE_TIMEOUT);
break;
case DISCOV_TYPE_INTERLEAVED:
queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
DISCOV_INTERLEAVED_TIMEOUT);
break;
case DISCOV_TYPE_BREDR:
break;
default:
BT_ERR("Invalid discovery type %d", hdev->discovery.type);
}
}
static int start_discovery(struct sock *sk, struct hci_dev *hdev,
void *data, u16 len)
{
struct mgmt_cp_start_discovery *cp = data;
struct pending_cmd *cmd;
struct hci_cp_le_set_scan_param param_cp;
struct hci_cp_le_set_scan_enable enable_cp;
struct hci_cp_inquiry inq_cp;
struct hci_request req;
/* General inquiry access code (GIAC) */
u8 lap[3] = { 0x33, 0x8b, 0x9e };
int err;
BT_DBG("%s", hdev->name);
@ -2687,6 +2717,8 @@ static int start_discovery(struct sock *sk, struct hci_dev *hdev,
hdev->discovery.type = cp->type;
hci_req_init(&req, hdev);
switch (hdev->discovery.type) {
case DISCOV_TYPE_BREDR:
if (!lmp_bredr_capable(hdev)) {
@ -2696,10 +2728,23 @@ static int start_discovery(struct sock *sk, struct hci_dev *hdev,
goto failed;
}
err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
if (test_bit(HCI_INQUIRY, &hdev->flags)) {
err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
MGMT_STATUS_BUSY);
mgmt_pending_remove(cmd);
goto failed;
}
hci_inquiry_cache_flush(hdev);
memset(&inq_cp, 0, sizeof(inq_cp));
memcpy(&inq_cp.lap, lap, sizeof(inq_cp.lap));
inq_cp.length = DISCOV_BREDR_INQUIRY_LEN;
hci_req_add(&req, HCI_OP_INQUIRY, sizeof(inq_cp), &inq_cp);
break;
case DISCOV_TYPE_LE:
case DISCOV_TYPE_INTERLEAVED:
if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
MGMT_STATUS_NOT_SUPPORTED);
@ -2707,20 +2752,40 @@ static int start_discovery(struct sock *sk, struct hci_dev *hdev,
goto failed;
}
err = hci_le_scan(hdev, LE_SCAN_ACTIVE, LE_SCAN_INT,
LE_SCAN_WIN, LE_SCAN_TIMEOUT_LE_ONLY);
break;
case DISCOV_TYPE_INTERLEAVED:
if (!lmp_host_le_capable(hdev) || !lmp_bredr_capable(hdev)) {
if (hdev->discovery.type == DISCOV_TYPE_INTERLEAVED &&
!lmp_bredr_capable(hdev)) {
err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
MGMT_STATUS_NOT_SUPPORTED);
mgmt_pending_remove(cmd);
goto failed;
}
err = hci_le_scan(hdev, LE_SCAN_ACTIVE, LE_SCAN_INT,
LE_SCAN_WIN, LE_SCAN_TIMEOUT_BREDR_LE);
if (test_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags)) {
err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
MGMT_STATUS_REJECTED);
mgmt_pending_remove(cmd);
goto failed;
}
if (test_bit(HCI_LE_SCAN, &hdev->dev_flags)) {
err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
MGMT_STATUS_BUSY);
mgmt_pending_remove(cmd);
goto failed;
}
memset(&param_cp, 0, sizeof(param_cp));
param_cp.type = LE_SCAN_ACTIVE;
param_cp.interval = cpu_to_le16(DISCOV_LE_SCAN_INT);
param_cp.window = cpu_to_le16(DISCOV_LE_SCAN_WIN);
hci_req_add(&req, HCI_OP_LE_SET_SCAN_PARAM, sizeof(param_cp),
&param_cp);
memset(&enable_cp, 0, sizeof(enable_cp));
enable_cp.enable = LE_SCAN_ENABLE;
enable_cp.filter_dup = LE_SCAN_FILTER_DUP_ENABLE;
hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(enable_cp),
&enable_cp);
break;
default:
@ -2730,6 +2795,7 @@ static int start_discovery(struct sock *sk, struct hci_dev *hdev,
goto failed;
}
err = hci_req_run(&req, start_discovery_complete);
if (err < 0)
mgmt_pending_remove(cmd);
else
@ -2740,6 +2806,39 @@ failed:
return err;
}
static int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
{
struct pending_cmd *cmd;
int err;
cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
if (!cmd)
return -ENOENT;
err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
&hdev->discovery.type, sizeof(hdev->discovery.type));
mgmt_pending_remove(cmd);
return err;
}
static void stop_discovery_complete(struct hci_dev *hdev, u8 status)
{
BT_DBG("status %d", status);
hci_dev_lock(hdev);
if (status) {
mgmt_stop_discovery_failed(hdev, status);
goto unlock;
}
hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
unlock:
hci_dev_unlock(hdev);
}
static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
u16 len)
{
@ -2747,6 +2846,8 @@ static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
struct pending_cmd *cmd;
struct hci_cp_remote_name_req_cancel cp;
struct inquiry_entry *e;
struct hci_request req;
struct hci_cp_le_set_scan_enable enable_cp;
int err;
BT_DBG("%s", hdev->name);
@ -2773,12 +2874,20 @@ static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
goto unlock;
}
hci_req_init(&req, hdev);
switch (hdev->discovery.state) {
case DISCOVERY_FINDING:
if (test_bit(HCI_INQUIRY, &hdev->flags))
err = hci_cancel_inquiry(hdev);
else
err = hci_cancel_le_scan(hdev);
if (test_bit(HCI_INQUIRY, &hdev->flags)) {
hci_req_add(&req, HCI_OP_INQUIRY_CANCEL, 0, NULL);
} else {
cancel_delayed_work(&hdev->le_scan_disable);
memset(&enable_cp, 0, sizeof(enable_cp));
enable_cp.enable = LE_SCAN_DISABLE;
hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE,
sizeof(enable_cp), &enable_cp);
}
break;
@ -2796,16 +2905,22 @@ static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
}
bacpy(&cp.bdaddr, &e->data.bdaddr);
err = hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ_CANCEL,
sizeof(cp), &cp);
hci_req_add(&req, HCI_OP_REMOTE_NAME_REQ_CANCEL, sizeof(cp),
&cp);
break;
default:
BT_DBG("unknown discovery state %u", hdev->discovery.state);
err = -EFAULT;
mgmt_pending_remove(cmd);
err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
MGMT_STATUS_FAILED, &mgmt_cp->type,
sizeof(mgmt_cp->type));
goto unlock;
}
err = hci_req_run(&req, stop_discovery_complete);
if (err < 0)
mgmt_pending_remove(cmd);
else
@ -4063,6 +4178,9 @@ int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
struct mgmt_ev_device_found *ev = (void *) buf;
size_t ev_size;
if (!hci_discovery_active(hdev))
return -EPERM;
/* Leave 5 bytes for a potential CoD field */
if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
return -EINVAL;
@ -4114,43 +4232,6 @@ int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
sizeof(*ev) + eir_len, NULL);
}
int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
{
struct pending_cmd *cmd;
u8 type;
int err;
hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
if (!cmd)
return -ENOENT;
type = hdev->discovery.type;
err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
&type, sizeof(type));
mgmt_pending_remove(cmd);
return err;
}
int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
{
struct pending_cmd *cmd;
int err;
cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
if (!cmd)
return -ENOENT;
err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
&hdev->discovery.type, sizeof(hdev->discovery.type));
mgmt_pending_remove(cmd);
return err;
}
int mgmt_discovering(struct hci_dev *hdev, u8 discovering)
{
struct mgmt_ev_discovering ev;