Merge branch 'for-upstream' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next
This commit is contained in:
commit
b7fd76d114
16 changed files with 1485 additions and 192 deletions
|
@ -46,5 +46,9 @@ void amp_accept_phylink(struct hci_dev *hdev, struct amp_mgr *mgr,
|
|||
struct hci_conn *hcon);
|
||||
void amp_write_remote_assoc(struct hci_dev *hdev, u8 handle);
|
||||
void amp_write_rem_assoc_continue(struct hci_dev *hdev, u8 handle);
|
||||
void amp_physical_cfm(struct hci_conn *bredr_hcon, struct hci_conn *hs_hcon);
|
||||
void amp_create_logical_link(struct l2cap_chan *chan);
|
||||
void amp_disconnect_logical_link(struct hci_chan *hchan);
|
||||
void amp_destroy_logical_link(struct hci_chan *hchan, u8 reason);
|
||||
|
||||
#endif /* __AMP_H */
|
||||
|
|
|
@ -115,6 +115,7 @@ enum {
|
|||
HCI_SSP_ENABLED,
|
||||
HCI_HS_ENABLED,
|
||||
HCI_LE_ENABLED,
|
||||
HCI_LE_PERIPHERAL,
|
||||
HCI_CONNECTABLE,
|
||||
HCI_DISCOVERABLE,
|
||||
HCI_LINK_SECURITY,
|
||||
|
@ -932,6 +933,12 @@ struct hci_rp_le_read_buffer_size {
|
|||
__u8 le_max_pkt;
|
||||
} __packed;
|
||||
|
||||
#define HCI_OP_LE_READ_ADV_TX_POWER 0x2007
|
||||
struct hci_rp_le_read_adv_tx_power {
|
||||
__u8 status;
|
||||
__s8 tx_power;
|
||||
} __packed;
|
||||
|
||||
#define HCI_OP_LE_SET_SCAN_PARAM 0x200b
|
||||
struct hci_cp_le_set_scan_param {
|
||||
__u8 type;
|
||||
|
|
|
@ -278,6 +278,8 @@ struct hci_dev {
|
|||
struct work_struct le_scan;
|
||||
struct le_scan_params le_scan_params;
|
||||
|
||||
__s8 adv_tx_power;
|
||||
|
||||
int (*open)(struct hci_dev *hdev);
|
||||
int (*close)(struct hci_dev *hdev);
|
||||
int (*flush)(struct hci_dev *hdev);
|
||||
|
@ -355,6 +357,7 @@ struct hci_chan {
|
|||
struct hci_conn *conn;
|
||||
struct sk_buff_head data_q;
|
||||
unsigned int sent;
|
||||
__u8 state;
|
||||
};
|
||||
|
||||
extern struct list_head hci_dev_list;
|
||||
|
@ -682,7 +685,7 @@ static inline uint8_t __hci_num_ctrl(void)
|
|||
}
|
||||
|
||||
struct hci_dev *hci_dev_get(int index);
|
||||
struct hci_dev *hci_get_route(bdaddr_t *src, bdaddr_t *dst);
|
||||
struct hci_dev *hci_get_route(bdaddr_t *dst, bdaddr_t *src);
|
||||
|
||||
struct hci_dev *hci_alloc_dev(void);
|
||||
void hci_free_dev(struct hci_dev *hdev);
|
||||
|
@ -747,18 +750,29 @@ void hci_conn_del_sysfs(struct hci_conn *conn);
|
|||
#define SET_HCIDEV_DEV(hdev, pdev) ((hdev)->dev.parent = (pdev))
|
||||
|
||||
/* ----- LMP capabilities ----- */
|
||||
#define lmp_rswitch_capable(dev) ((dev)->features[0] & LMP_RSWITCH)
|
||||
#define lmp_encrypt_capable(dev) ((dev)->features[0] & LMP_ENCRYPT)
|
||||
#define lmp_rswitch_capable(dev) ((dev)->features[0] & LMP_RSWITCH)
|
||||
#define lmp_hold_capable(dev) ((dev)->features[0] & LMP_HOLD)
|
||||
#define lmp_sniff_capable(dev) ((dev)->features[0] & LMP_SNIFF)
|
||||
#define lmp_sniffsubr_capable(dev) ((dev)->features[5] & LMP_SNIFF_SUBR)
|
||||
#define lmp_park_capable(dev) ((dev)->features[1] & LMP_PARK)
|
||||
#define lmp_inq_rssi_capable(dev) ((dev)->features[3] & LMP_RSSI_INQ)
|
||||
#define lmp_esco_capable(dev) ((dev)->features[3] & LMP_ESCO)
|
||||
#define lmp_bredr_capable(dev) (!((dev)->features[4] & LMP_NO_BREDR))
|
||||
#define lmp_le_capable(dev) ((dev)->features[4] & LMP_LE)
|
||||
#define lmp_sniffsubr_capable(dev) ((dev)->features[5] & LMP_SNIFF_SUBR)
|
||||
#define lmp_pause_enc_capable(dev) ((dev)->features[5] & LMP_PAUSE_ENC)
|
||||
#define lmp_ext_inq_capable(dev) ((dev)->features[6] & LMP_EXT_INQ)
|
||||
#define lmp_le_br_capable(dev) ((dev)->features[6] & LMP_SIMUL_LE_BR)
|
||||
#define lmp_ssp_capable(dev) ((dev)->features[6] & LMP_SIMPLE_PAIR)
|
||||
#define lmp_no_flush_capable(dev) ((dev)->features[6] & LMP_NO_FLUSH)
|
||||
#define lmp_le_capable(dev) ((dev)->features[4] & LMP_LE)
|
||||
#define lmp_bredr_capable(dev) (!((dev)->features[4] & LMP_NO_BREDR))
|
||||
#define lmp_lsto_capable(dev) ((dev)->features[7] & LMP_LSTO)
|
||||
#define lmp_inq_tx_pwr_capable(dev) ((dev)->features[7] & LMP_INQ_TX_PWR)
|
||||
#define lmp_ext_feat_capable(dev) ((dev)->features[7] & LMP_EXTFEATURES)
|
||||
|
||||
/* ----- Extended LMP capabilities ----- */
|
||||
#define lmp_host_ssp_capable(dev) ((dev)->host_features[0] & LMP_HOST_SSP)
|
||||
#define lmp_host_le_capable(dev) ((dev)->host_features[0] & LMP_HOST_LE)
|
||||
#define lmp_host_le_br_capable(dev) ((dev)->host_features[0] & LMP_HOST_LE_BREDR)
|
||||
|
||||
/* ----- HCI protocols ----- */
|
||||
static inline int hci_proto_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr,
|
||||
|
@ -877,7 +891,7 @@ struct hci_cb {
|
|||
|
||||
static inline void hci_auth_cfm(struct hci_conn *conn, __u8 status)
|
||||
{
|
||||
struct list_head *p;
|
||||
struct hci_cb *cb;
|
||||
__u8 encrypt;
|
||||
|
||||
hci_proto_auth_cfm(conn, status);
|
||||
|
@ -888,8 +902,7 @@ static inline void hci_auth_cfm(struct hci_conn *conn, __u8 status)
|
|||
encrypt = (conn->link_mode & HCI_LM_ENCRYPT) ? 0x01 : 0x00;
|
||||
|
||||
read_lock(&hci_cb_list_lock);
|
||||
list_for_each(p, &hci_cb_list) {
|
||||
struct hci_cb *cb = list_entry(p, struct hci_cb, list);
|
||||
list_for_each_entry(cb, &hci_cb_list, list) {
|
||||
if (cb->security_cfm)
|
||||
cb->security_cfm(conn, status, encrypt);
|
||||
}
|
||||
|
@ -899,7 +912,7 @@ static inline void hci_auth_cfm(struct hci_conn *conn, __u8 status)
|
|||
static inline void hci_encrypt_cfm(struct hci_conn *conn, __u8 status,
|
||||
__u8 encrypt)
|
||||
{
|
||||
struct list_head *p;
|
||||
struct hci_cb *cb;
|
||||
|
||||
if (conn->sec_level == BT_SECURITY_SDP)
|
||||
conn->sec_level = BT_SECURITY_LOW;
|
||||
|
@ -910,8 +923,7 @@ static inline void hci_encrypt_cfm(struct hci_conn *conn, __u8 status,
|
|||
hci_proto_encrypt_cfm(conn, status, encrypt);
|
||||
|
||||
read_lock(&hci_cb_list_lock);
|
||||
list_for_each(p, &hci_cb_list) {
|
||||
struct hci_cb *cb = list_entry(p, struct hci_cb, list);
|
||||
list_for_each_entry(cb, &hci_cb_list, list) {
|
||||
if (cb->security_cfm)
|
||||
cb->security_cfm(conn, status, encrypt);
|
||||
}
|
||||
|
@ -920,11 +932,10 @@ static inline void hci_encrypt_cfm(struct hci_conn *conn, __u8 status,
|
|||
|
||||
static inline void hci_key_change_cfm(struct hci_conn *conn, __u8 status)
|
||||
{
|
||||
struct list_head *p;
|
||||
struct hci_cb *cb;
|
||||
|
||||
read_lock(&hci_cb_list_lock);
|
||||
list_for_each(p, &hci_cb_list) {
|
||||
struct hci_cb *cb = list_entry(p, struct hci_cb, list);
|
||||
list_for_each_entry(cb, &hci_cb_list, list) {
|
||||
if (cb->key_change_cfm)
|
||||
cb->key_change_cfm(conn, status);
|
||||
}
|
||||
|
@ -934,11 +945,10 @@ static inline void hci_key_change_cfm(struct hci_conn *conn, __u8 status)
|
|||
static inline void hci_role_switch_cfm(struct hci_conn *conn, __u8 status,
|
||||
__u8 role)
|
||||
{
|
||||
struct list_head *p;
|
||||
struct hci_cb *cb;
|
||||
|
||||
read_lock(&hci_cb_list_lock);
|
||||
list_for_each(p, &hci_cb_list) {
|
||||
struct hci_cb *cb = list_entry(p, struct hci_cb, list);
|
||||
list_for_each_entry(cb, &hci_cb_list, list) {
|
||||
if (cb->role_switch_cfm)
|
||||
cb->role_switch_cfm(conn, status, role);
|
||||
}
|
||||
|
|
|
@ -52,6 +52,8 @@
|
|||
#define L2CAP_ENC_TIMEOUT msecs_to_jiffies(5000)
|
||||
#define L2CAP_CONN_TIMEOUT msecs_to_jiffies(40000)
|
||||
#define L2CAP_INFO_TIMEOUT msecs_to_jiffies(4000)
|
||||
#define L2CAP_MOVE_TIMEOUT msecs_to_jiffies(4000)
|
||||
#define L2CAP_MOVE_ERTX_TIMEOUT msecs_to_jiffies(60000)
|
||||
|
||||
#define L2CAP_A2MP_DEFAULT_MTU 670
|
||||
|
||||
|
@ -434,6 +436,8 @@ struct l2cap_chan {
|
|||
struct sock *sk;
|
||||
|
||||
struct l2cap_conn *conn;
|
||||
struct hci_conn *hs_hcon;
|
||||
struct hci_chan *hs_hchan;
|
||||
struct kref kref;
|
||||
|
||||
__u8 state;
|
||||
|
@ -477,6 +481,12 @@ struct l2cap_chan {
|
|||
unsigned long conn_state;
|
||||
unsigned long flags;
|
||||
|
||||
__u8 remote_amp_id;
|
||||
__u8 local_amp_id;
|
||||
__u8 move_id;
|
||||
__u8 move_state;
|
||||
__u8 move_role;
|
||||
|
||||
__u16 next_tx_seq;
|
||||
__u16 expected_ack_seq;
|
||||
__u16 expected_tx_seq;
|
||||
|
@ -509,8 +519,6 @@ struct l2cap_chan {
|
|||
__u32 remote_acc_lat;
|
||||
__u32 remote_flush_to;
|
||||
|
||||
__u8 ctrl_id;
|
||||
|
||||
struct delayed_work chan_timer;
|
||||
struct delayed_work retrans_timer;
|
||||
struct delayed_work monitor_timer;
|
||||
|
@ -644,6 +652,9 @@ enum {
|
|||
enum {
|
||||
L2CAP_RX_STATE_RECV,
|
||||
L2CAP_RX_STATE_SREJ_SENT,
|
||||
L2CAP_RX_STATE_MOVE,
|
||||
L2CAP_RX_STATE_WAIT_P,
|
||||
L2CAP_RX_STATE_WAIT_F,
|
||||
};
|
||||
|
||||
enum {
|
||||
|
@ -674,6 +685,25 @@ enum {
|
|||
L2CAP_EV_RECV_FRAME,
|
||||
};
|
||||
|
||||
enum {
|
||||
L2CAP_MOVE_ROLE_NONE,
|
||||
L2CAP_MOVE_ROLE_INITIATOR,
|
||||
L2CAP_MOVE_ROLE_RESPONDER,
|
||||
};
|
||||
|
||||
enum {
|
||||
L2CAP_MOVE_STABLE,
|
||||
L2CAP_MOVE_WAIT_REQ,
|
||||
L2CAP_MOVE_WAIT_RSP,
|
||||
L2CAP_MOVE_WAIT_RSP_SUCCESS,
|
||||
L2CAP_MOVE_WAIT_CONFIRM,
|
||||
L2CAP_MOVE_WAIT_CONFIRM_RSP,
|
||||
L2CAP_MOVE_WAIT_LOGICAL_COMP,
|
||||
L2CAP_MOVE_WAIT_LOGICAL_CFM,
|
||||
L2CAP_MOVE_WAIT_LOCAL_BUSY,
|
||||
L2CAP_MOVE_WAIT_PREPARE,
|
||||
};
|
||||
|
||||
void l2cap_chan_hold(struct l2cap_chan *c);
|
||||
void l2cap_chan_put(struct l2cap_chan *c);
|
||||
|
||||
|
@ -778,5 +808,9 @@ void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan);
|
|||
void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan);
|
||||
void l2cap_chan_del(struct l2cap_chan *chan, int err);
|
||||
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);
|
||||
|
||||
#endif /* __L2CAP_H */
|
||||
|
|
|
@ -48,4 +48,3 @@ source "net/bluetooth/cmtp/Kconfig"
|
|||
source "net/bluetooth/hidp/Kconfig"
|
||||
|
||||
source "drivers/bluetooth/Kconfig"
|
||||
|
||||
|
|
|
@ -423,7 +423,7 @@ static int a2mp_getampassoc_rsp(struct amp_mgr *mgr, struct sk_buff *skb,
|
|||
|
||||
BT_DBG("Created hcon %p: loc:%d -> rem:%d", hcon, hdev->id, rsp->id);
|
||||
|
||||
mgr->bredr_chan->ctrl_id = rsp->id;
|
||||
mgr->bredr_chan->remote_amp_id = rsp->id;
|
||||
|
||||
amp_create_phylink(hdev, mgr, hcon);
|
||||
|
||||
|
@ -939,7 +939,7 @@ void a2mp_send_create_phy_link_req(struct hci_dev *hdev, u8 status)
|
|||
goto clean;
|
||||
|
||||
req->local_id = hdev->id;
|
||||
req->remote_id = bredr_chan->ctrl_id;
|
||||
req->remote_id = bredr_chan->remote_amp_id;
|
||||
memcpy(req->amp_assoc, loc_assoc->data, loc_assoc->len);
|
||||
|
||||
a2mp_send(mgr, A2MP_CREATEPHYSLINK_REQ, __next_ident(mgr), len, req);
|
||||
|
|
|
@ -372,3 +372,96 @@ void amp_accept_phylink(struct hci_dev *hdev, struct amp_mgr *mgr,
|
|||
|
||||
hci_send_cmd(hdev, HCI_OP_ACCEPT_PHY_LINK, sizeof(cp), &cp);
|
||||
}
|
||||
|
||||
void amp_physical_cfm(struct hci_conn *bredr_hcon, struct hci_conn *hs_hcon)
|
||||
{
|
||||
struct hci_dev *bredr_hdev = hci_dev_hold(bredr_hcon->hdev);
|
||||
struct amp_mgr *mgr = hs_hcon->amp_mgr;
|
||||
struct l2cap_chan *bredr_chan;
|
||||
|
||||
BT_DBG("bredr_hcon %p hs_hcon %p mgr %p", bredr_hcon, hs_hcon, mgr);
|
||||
|
||||
if (!bredr_hdev || !mgr || !mgr->bredr_chan)
|
||||
return;
|
||||
|
||||
bredr_chan = mgr->bredr_chan;
|
||||
|
||||
set_bit(FLAG_EFS_ENABLE, &bredr_chan->flags);
|
||||
bredr_chan->remote_amp_id = hs_hcon->remote_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);
|
||||
|
||||
hci_dev_put(bredr_hdev);
|
||||
}
|
||||
|
||||
void amp_create_logical_link(struct l2cap_chan *chan)
|
||||
{
|
||||
struct hci_cp_create_accept_logical_link cp;
|
||||
struct hci_conn *hcon;
|
||||
struct hci_dev *hdev;
|
||||
|
||||
BT_DBG("chan %p", chan);
|
||||
|
||||
if (!chan->hs_hcon)
|
||||
return;
|
||||
|
||||
hdev = hci_dev_hold(chan->hs_hcon->hdev);
|
||||
if (!hdev)
|
||||
return;
|
||||
|
||||
BT_DBG("chan %p dst %pMR", chan, chan->conn->dst);
|
||||
|
||||
hcon = hci_conn_hash_lookup_ba(hdev, AMP_LINK, chan->conn->dst);
|
||||
if (!hcon)
|
||||
goto done;
|
||||
|
||||
cp.phy_handle = hcon->handle;
|
||||
|
||||
cp.tx_flow_spec.id = chan->local_id;
|
||||
cp.tx_flow_spec.stype = chan->local_stype;
|
||||
cp.tx_flow_spec.msdu = cpu_to_le16(chan->local_msdu);
|
||||
cp.tx_flow_spec.sdu_itime = cpu_to_le32(chan->local_sdu_itime);
|
||||
cp.tx_flow_spec.acc_lat = cpu_to_le32(chan->local_acc_lat);
|
||||
cp.tx_flow_spec.flush_to = cpu_to_le32(chan->local_flush_to);
|
||||
|
||||
cp.rx_flow_spec.id = chan->remote_id;
|
||||
cp.rx_flow_spec.stype = chan->remote_stype;
|
||||
cp.rx_flow_spec.msdu = cpu_to_le16(chan->remote_msdu);
|
||||
cp.rx_flow_spec.sdu_itime = cpu_to_le32(chan->remote_sdu_itime);
|
||||
cp.rx_flow_spec.acc_lat = cpu_to_le32(chan->remote_acc_lat);
|
||||
cp.rx_flow_spec.flush_to = cpu_to_le32(chan->remote_flush_to);
|
||||
|
||||
if (hcon->out)
|
||||
hci_send_cmd(hdev, HCI_OP_CREATE_LOGICAL_LINK, sizeof(cp),
|
||||
&cp);
|
||||
else
|
||||
hci_send_cmd(hdev, HCI_OP_ACCEPT_LOGICAL_LINK, sizeof(cp),
|
||||
&cp);
|
||||
|
||||
done:
|
||||
hci_dev_put(hdev);
|
||||
}
|
||||
|
||||
void amp_disconnect_logical_link(struct hci_chan *hchan)
|
||||
{
|
||||
struct hci_conn *hcon = hchan->conn;
|
||||
struct hci_cp_disconn_logical_link cp;
|
||||
|
||||
if (hcon->state != BT_CONNECTED) {
|
||||
BT_DBG("hchan %p not connected", hchan);
|
||||
return;
|
||||
}
|
||||
|
||||
cp.log_handle = cpu_to_le16(hchan->handle);
|
||||
hci_send_cmd(hcon->hdev, HCI_OP_DISCONN_LOGICAL_LINK, sizeof(cp), &cp);
|
||||
}
|
||||
|
||||
void amp_destroy_logical_link(struct hci_chan *hchan, u8 reason)
|
||||
{
|
||||
BT_DBG("hchan %p", hchan);
|
||||
|
||||
hci_chan_del(hchan);
|
||||
}
|
||||
|
|
|
@ -25,7 +25,6 @@
|
|||
SOFTWARE IS DISCLAIMED.
|
||||
*/
|
||||
|
||||
#include <linux/export.h>
|
||||
#include <linux/etherdevice.h>
|
||||
|
||||
#include <net/bluetooth/bluetooth.h>
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
SOFTWARE IS DISCLAIMED.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/types.h>
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
SOFTWARE IS DISCLAIMED.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/export.h>
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/capability.h>
|
||||
|
|
|
@ -502,6 +502,9 @@ static struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst,
|
|||
{
|
||||
struct hci_conn *le;
|
||||
|
||||
if (test_bit(HCI_LE_PERIPHERAL, &hdev->flags))
|
||||
return ERR_PTR(-ENOTSUPP);
|
||||
|
||||
le = hci_conn_hash_lookup_ba(hdev, LE_LINK, dst);
|
||||
if (!le) {
|
||||
le = hci_conn_hash_lookup_state(hdev, LE_LINK, BT_CONNECT);
|
||||
|
@ -959,6 +962,7 @@ struct hci_chan *hci_chan_create(struct hci_conn *conn)
|
|||
|
||||
chan->conn = conn;
|
||||
skb_queue_head_init(&chan->data_q);
|
||||
chan->state = BT_CONNECTED;
|
||||
|
||||
list_add_rcu(&chan->list, &conn->chan_list);
|
||||
|
||||
|
@ -976,6 +980,8 @@ void hci_chan_del(struct hci_chan *chan)
|
|||
|
||||
synchronize_rcu();
|
||||
|
||||
hci_conn_put(conn);
|
||||
|
||||
skb_queue_purge(&chan->data_q);
|
||||
kfree(chan);
|
||||
}
|
||||
|
|
|
@ -178,48 +178,13 @@ static void hci_reset_req(struct hci_dev *hdev, unsigned long opt)
|
|||
|
||||
static void bredr_init(struct hci_dev *hdev)
|
||||
{
|
||||
struct hci_cp_delete_stored_link_key cp;
|
||||
__le16 param;
|
||||
__u8 flt_type;
|
||||
|
||||
hdev->flow_ctl_mode = HCI_FLOW_CTL_MODE_PACKET_BASED;
|
||||
|
||||
/* Mandatory initialization */
|
||||
|
||||
/* Read Local Supported Features */
|
||||
hci_send_cmd(hdev, HCI_OP_READ_LOCAL_FEATURES, 0, NULL);
|
||||
|
||||
/* Read Local Version */
|
||||
hci_send_cmd(hdev, HCI_OP_READ_LOCAL_VERSION, 0, NULL);
|
||||
|
||||
/* Read Buffer Size (ACL mtu, max pkt, etc.) */
|
||||
hci_send_cmd(hdev, HCI_OP_READ_BUFFER_SIZE, 0, NULL);
|
||||
|
||||
/* Read BD Address */
|
||||
hci_send_cmd(hdev, HCI_OP_READ_BD_ADDR, 0, NULL);
|
||||
|
||||
/* Read Class of Device */
|
||||
hci_send_cmd(hdev, HCI_OP_READ_CLASS_OF_DEV, 0, NULL);
|
||||
|
||||
/* Read Local Name */
|
||||
hci_send_cmd(hdev, HCI_OP_READ_LOCAL_NAME, 0, NULL);
|
||||
|
||||
/* Read Voice Setting */
|
||||
hci_send_cmd(hdev, HCI_OP_READ_VOICE_SETTING, 0, NULL);
|
||||
|
||||
/* Optional initialization */
|
||||
|
||||
/* Clear Event Filters */
|
||||
flt_type = HCI_FLT_CLEAR_ALL;
|
||||
hci_send_cmd(hdev, HCI_OP_SET_EVENT_FLT, 1, &flt_type);
|
||||
|
||||
/* Connection accept timeout ~20 secs */
|
||||
param = __constant_cpu_to_le16(0x7d00);
|
||||
hci_send_cmd(hdev, HCI_OP_WRITE_CA_TIMEOUT, 2, ¶m);
|
||||
|
||||
bacpy(&cp.bdaddr, BDADDR_ANY);
|
||||
cp.delete_all = 1;
|
||||
hci_send_cmd(hdev, HCI_OP_DELETE_STORED_LINK_KEY, sizeof(cp), &cp);
|
||||
}
|
||||
|
||||
static void amp_init(struct hci_dev *hdev)
|
||||
|
@ -273,14 +238,6 @@ static void hci_init_req(struct hci_dev *hdev, unsigned long opt)
|
|||
}
|
||||
}
|
||||
|
||||
static void hci_le_init_req(struct hci_dev *hdev, unsigned long opt)
|
||||
{
|
||||
BT_DBG("%s", hdev->name);
|
||||
|
||||
/* Read LE buffer size */
|
||||
hci_send_cmd(hdev, HCI_OP_LE_READ_BUFFER_SIZE, 0, NULL);
|
||||
}
|
||||
|
||||
static void hci_scan_req(struct hci_dev *hdev, unsigned long opt)
|
||||
{
|
||||
__u8 scan = opt;
|
||||
|
@ -687,10 +644,6 @@ int hci_dev_open(__u16 dev)
|
|||
|
||||
ret = __hci_request(hdev, hci_init_req, 0, HCI_INIT_TIMEOUT);
|
||||
|
||||
if (lmp_host_le_capable(hdev))
|
||||
ret = __hci_request(hdev, hci_le_init_req, 0,
|
||||
HCI_INIT_TIMEOUT);
|
||||
|
||||
clear_bit(HCI_INIT, &hdev->flags);
|
||||
}
|
||||
|
||||
|
@ -1039,10 +992,17 @@ int hci_get_dev_info(void __user *arg)
|
|||
di.type = (hdev->bus & 0x0f) | (hdev->dev_type << 4);
|
||||
di.flags = hdev->flags;
|
||||
di.pkt_type = hdev->pkt_type;
|
||||
di.acl_mtu = hdev->acl_mtu;
|
||||
di.acl_pkts = hdev->acl_pkts;
|
||||
di.sco_mtu = hdev->sco_mtu;
|
||||
di.sco_pkts = hdev->sco_pkts;
|
||||
if (lmp_bredr_capable(hdev)) {
|
||||
di.acl_mtu = hdev->acl_mtu;
|
||||
di.acl_pkts = hdev->acl_pkts;
|
||||
di.sco_mtu = hdev->sco_mtu;
|
||||
di.sco_pkts = hdev->sco_pkts;
|
||||
} else {
|
||||
di.acl_mtu = hdev->le_mtu;
|
||||
di.acl_pkts = hdev->le_pkts;
|
||||
di.sco_mtu = 0;
|
||||
di.sco_pkts = 0;
|
||||
}
|
||||
di.link_policy = hdev->link_policy;
|
||||
di.link_mode = hdev->link_mode;
|
||||
|
||||
|
@ -1617,6 +1577,9 @@ int hci_le_scan(struct hci_dev *hdev, u8 type, u16 interval, u16 window,
|
|||
|
||||
BT_DBG("%s", hdev->name);
|
||||
|
||||
if (test_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags))
|
||||
return -ENOTSUPP;
|
||||
|
||||
if (work_busy(&hdev->le_scan))
|
||||
return -EINPROGRESS;
|
||||
|
||||
|
|
|
@ -24,7 +24,6 @@
|
|||
|
||||
/* Bluetooth HCI event handling. */
|
||||
|
||||
#include <linux/export.h>
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
#include <net/bluetooth/bluetooth.h>
|
||||
|
@ -440,7 +439,7 @@ static void hci_cc_host_buffer_size(struct hci_dev *hdev, struct sk_buff *skb)
|
|||
static void hci_cc_write_ssp_mode(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
__u8 status = *((__u8 *) skb->data);
|
||||
void *sent;
|
||||
struct hci_cp_write_ssp_mode *sent;
|
||||
|
||||
BT_DBG("%s status 0x%2.2x", hdev->name, status);
|
||||
|
||||
|
@ -448,10 +447,17 @@ static void hci_cc_write_ssp_mode(struct hci_dev *hdev, struct sk_buff *skb)
|
|||
if (!sent)
|
||||
return;
|
||||
|
||||
if (!status) {
|
||||
if (sent->mode)
|
||||
hdev->host_features[0] |= LMP_HOST_SSP;
|
||||
else
|
||||
hdev->host_features[0] &= ~LMP_HOST_SSP;
|
||||
}
|
||||
|
||||
if (test_bit(HCI_MGMT, &hdev->dev_flags))
|
||||
mgmt_ssp_enable_complete(hdev, *((u8 *) sent), status);
|
||||
mgmt_ssp_enable_complete(hdev, sent->mode, status);
|
||||
else if (!status) {
|
||||
if (*((u8 *) sent))
|
||||
if (sent->mode)
|
||||
set_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
|
||||
else
|
||||
clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
|
||||
|
@ -460,10 +466,10 @@ static void hci_cc_write_ssp_mode(struct hci_dev *hdev, struct sk_buff *skb)
|
|||
|
||||
static u8 hci_get_inquiry_mode(struct hci_dev *hdev)
|
||||
{
|
||||
if (hdev->features[6] & LMP_EXT_INQ)
|
||||
if (lmp_ext_inq_capable(hdev))
|
||||
return 2;
|
||||
|
||||
if (hdev->features[3] & LMP_RSSI_INQ)
|
||||
if (lmp_inq_rssi_capable(hdev))
|
||||
return 1;
|
||||
|
||||
if (hdev->manufacturer == 11 && hdev->hci_rev == 0x00 &&
|
||||
|
@ -507,28 +513,30 @@ static void hci_setup_event_mask(struct hci_dev *hdev)
|
|||
if (hdev->hci_ver < BLUETOOTH_VER_1_2)
|
||||
return;
|
||||
|
||||
events[4] |= 0x01; /* Flow Specification Complete */
|
||||
events[4] |= 0x02; /* Inquiry Result with RSSI */
|
||||
events[4] |= 0x04; /* Read Remote Extended Features Complete */
|
||||
events[5] |= 0x08; /* Synchronous Connection Complete */
|
||||
events[5] |= 0x10; /* Synchronous Connection Changed */
|
||||
if (lmp_bredr_capable(hdev)) {
|
||||
events[4] |= 0x01; /* Flow Specification Complete */
|
||||
events[4] |= 0x02; /* Inquiry Result with RSSI */
|
||||
events[4] |= 0x04; /* Read Remote Extended Features Complete */
|
||||
events[5] |= 0x08; /* Synchronous Connection Complete */
|
||||
events[5] |= 0x10; /* Synchronous Connection Changed */
|
||||
}
|
||||
|
||||
if (hdev->features[3] & LMP_RSSI_INQ)
|
||||
if (lmp_inq_rssi_capable(hdev))
|
||||
events[4] |= 0x02; /* Inquiry Result with RSSI */
|
||||
|
||||
if (lmp_sniffsubr_capable(hdev))
|
||||
events[5] |= 0x20; /* Sniff Subrating */
|
||||
|
||||
if (hdev->features[5] & LMP_PAUSE_ENC)
|
||||
if (lmp_pause_enc_capable(hdev))
|
||||
events[5] |= 0x80; /* Encryption Key Refresh Complete */
|
||||
|
||||
if (hdev->features[6] & LMP_EXT_INQ)
|
||||
if (lmp_ext_inq_capable(hdev))
|
||||
events[5] |= 0x40; /* Extended Inquiry Result */
|
||||
|
||||
if (lmp_no_flush_capable(hdev))
|
||||
events[7] |= 0x01; /* Enhanced Flush Complete */
|
||||
|
||||
if (hdev->features[7] & LMP_LSTO)
|
||||
if (lmp_lsto_capable(hdev))
|
||||
events[6] |= 0x80; /* Link Supervision Timeout Changed */
|
||||
|
||||
if (lmp_ssp_capable(hdev)) {
|
||||
|
@ -548,6 +556,53 @@ static void hci_setup_event_mask(struct hci_dev *hdev)
|
|||
events[7] |= 0x20; /* LE Meta-Event */
|
||||
|
||||
hci_send_cmd(hdev, HCI_OP_SET_EVENT_MASK, sizeof(events), events);
|
||||
|
||||
if (lmp_le_capable(hdev)) {
|
||||
memset(events, 0, sizeof(events));
|
||||
events[0] = 0x1f;
|
||||
hci_send_cmd(hdev, HCI_OP_LE_SET_EVENT_MASK,
|
||||
sizeof(events), events);
|
||||
}
|
||||
}
|
||||
|
||||
static void bredr_setup(struct hci_dev *hdev)
|
||||
{
|
||||
struct hci_cp_delete_stored_link_key cp;
|
||||
__le16 param;
|
||||
__u8 flt_type;
|
||||
|
||||
/* Read Buffer Size (ACL mtu, max pkt, etc.) */
|
||||
hci_send_cmd(hdev, HCI_OP_READ_BUFFER_SIZE, 0, NULL);
|
||||
|
||||
/* Read Class of Device */
|
||||
hci_send_cmd(hdev, HCI_OP_READ_CLASS_OF_DEV, 0, NULL);
|
||||
|
||||
/* Read Local Name */
|
||||
hci_send_cmd(hdev, HCI_OP_READ_LOCAL_NAME, 0, NULL);
|
||||
|
||||
/* Read Voice Setting */
|
||||
hci_send_cmd(hdev, HCI_OP_READ_VOICE_SETTING, 0, NULL);
|
||||
|
||||
/* Clear Event Filters */
|
||||
flt_type = HCI_FLT_CLEAR_ALL;
|
||||
hci_send_cmd(hdev, HCI_OP_SET_EVENT_FLT, 1, &flt_type);
|
||||
|
||||
/* Connection accept timeout ~20 secs */
|
||||
param = __constant_cpu_to_le16(0x7d00);
|
||||
hci_send_cmd(hdev, HCI_OP_WRITE_CA_TIMEOUT, 2, ¶m);
|
||||
|
||||
bacpy(&cp.bdaddr, BDADDR_ANY);
|
||||
cp.delete_all = 1;
|
||||
hci_send_cmd(hdev, HCI_OP_DELETE_STORED_LINK_KEY, sizeof(cp), &cp);
|
||||
}
|
||||
|
||||
static void le_setup(struct hci_dev *hdev)
|
||||
{
|
||||
/* Read LE Buffer Size */
|
||||
hci_send_cmd(hdev, HCI_OP_LE_READ_BUFFER_SIZE, 0, NULL);
|
||||
|
||||
/* Read LE Advertising Channel TX Power */
|
||||
hci_send_cmd(hdev, HCI_OP_LE_READ_ADV_TX_POWER, 0, NULL);
|
||||
}
|
||||
|
||||
static void hci_setup(struct hci_dev *hdev)
|
||||
|
@ -555,6 +610,15 @@ static void hci_setup(struct hci_dev *hdev)
|
|||
if (hdev->dev_type != HCI_BREDR)
|
||||
return;
|
||||
|
||||
/* Read BD Address */
|
||||
hci_send_cmd(hdev, HCI_OP_READ_BD_ADDR, 0, NULL);
|
||||
|
||||
if (lmp_bredr_capable(hdev))
|
||||
bredr_setup(hdev);
|
||||
|
||||
if (lmp_le_capable(hdev))
|
||||
le_setup(hdev);
|
||||
|
||||
hci_setup_event_mask(hdev);
|
||||
|
||||
if (hdev->hci_ver > BLUETOOTH_VER_1_1)
|
||||
|
@ -575,13 +639,13 @@ static void hci_setup(struct hci_dev *hdev)
|
|||
}
|
||||
}
|
||||
|
||||
if (hdev->features[3] & LMP_RSSI_INQ)
|
||||
if (lmp_inq_rssi_capable(hdev))
|
||||
hci_setup_inquiry_mode(hdev);
|
||||
|
||||
if (hdev->features[7] & LMP_INQ_TX_PWR)
|
||||
if (lmp_inq_tx_pwr_capable(hdev))
|
||||
hci_send_cmd(hdev, HCI_OP_READ_INQ_RSP_TX_POWER, 0, NULL);
|
||||
|
||||
if (hdev->features[7] & LMP_EXTFEATURES) {
|
||||
if (lmp_ext_feat_capable(hdev)) {
|
||||
struct hci_cp_read_local_ext_features cp;
|
||||
|
||||
cp.page = 0x01;
|
||||
|
@ -628,11 +692,11 @@ static void hci_setup_link_policy(struct hci_dev *hdev)
|
|||
|
||||
if (lmp_rswitch_capable(hdev))
|
||||
link_policy |= HCI_LP_RSWITCH;
|
||||
if (hdev->features[0] & LMP_HOLD)
|
||||
if (lmp_hold_capable(hdev))
|
||||
link_policy |= HCI_LP_HOLD;
|
||||
if (lmp_sniff_capable(hdev))
|
||||
link_policy |= HCI_LP_SNIFF;
|
||||
if (hdev->features[1] & LMP_PARK)
|
||||
if (lmp_park_capable(hdev))
|
||||
link_policy |= HCI_LP_PARK;
|
||||
|
||||
cp.policy = cpu_to_le16(link_policy);
|
||||
|
@ -722,10 +786,10 @@ static void hci_set_le_support(struct hci_dev *hdev)
|
|||
|
||||
if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
|
||||
cp.le = 1;
|
||||
cp.simul = !!(hdev->features[6] & LMP_SIMUL_LE_BR);
|
||||
cp.simul = !!lmp_le_br_capable(hdev);
|
||||
}
|
||||
|
||||
if (cp.le != !!(hdev->host_features[0] & LMP_HOST_LE))
|
||||
if (cp.le != !!lmp_host_le_capable(hdev))
|
||||
hci_send_cmd(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(cp),
|
||||
&cp);
|
||||
}
|
||||
|
@ -1018,6 +1082,28 @@ static void hci_cc_le_read_buffer_size(struct hci_dev *hdev,
|
|||
hci_req_complete(hdev, HCI_OP_LE_READ_BUFFER_SIZE, rp->status);
|
||||
}
|
||||
|
||||
static void hci_cc_le_read_adv_tx_power(struct hci_dev *hdev,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct hci_rp_le_read_adv_tx_power *rp = (void *) skb->data;
|
||||
|
||||
BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
|
||||
|
||||
if (!rp->status)
|
||||
hdev->adv_tx_power = rp->tx_power;
|
||||
|
||||
hci_req_complete(hdev, HCI_OP_LE_READ_ADV_TX_POWER, rp->status);
|
||||
}
|
||||
|
||||
static void hci_cc_le_set_event_mask(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
__u8 status = *((__u8 *) skb->data);
|
||||
|
||||
BT_DBG("%s status 0x%2.2x", hdev->name, status);
|
||||
|
||||
hci_req_complete(hdev, HCI_OP_LE_SET_EVENT_MASK, status);
|
||||
}
|
||||
|
||||
static void hci_cc_user_confirm_reply(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
struct hci_rp_user_confirm_reply *rp = (void *) skb->data;
|
||||
|
@ -1207,6 +1293,11 @@ static void hci_cc_write_le_host_supported(struct hci_dev *hdev,
|
|||
hdev->host_features[0] |= LMP_HOST_LE;
|
||||
else
|
||||
hdev->host_features[0] &= ~LMP_HOST_LE;
|
||||
|
||||
if (sent->simul)
|
||||
hdev->host_features[0] |= LMP_HOST_LE_BREDR;
|
||||
else
|
||||
hdev->host_features[0] &= ~LMP_HOST_LE_BREDR;
|
||||
}
|
||||
|
||||
if (test_bit(HCI_MGMT, &hdev->dev_flags) &&
|
||||
|
@ -1718,14 +1809,23 @@ static void hci_cs_create_phylink(struct hci_dev *hdev, u8 status)
|
|||
|
||||
BT_DBG("%s status 0x%2.2x", hdev->name, status);
|
||||
|
||||
if (status)
|
||||
return;
|
||||
|
||||
cp = hci_sent_cmd_data(hdev, HCI_OP_CREATE_PHY_LINK);
|
||||
if (!cp)
|
||||
return;
|
||||
|
||||
amp_write_remote_assoc(hdev, cp->phy_handle);
|
||||
hci_dev_lock(hdev);
|
||||
|
||||
if (status) {
|
||||
struct hci_conn *hcon;
|
||||
|
||||
hcon = hci_conn_hash_lookup_handle(hdev, cp->phy_handle);
|
||||
if (hcon)
|
||||
hci_conn_del(hcon);
|
||||
} else {
|
||||
amp_write_remote_assoc(hdev, cp->phy_handle);
|
||||
}
|
||||
|
||||
hci_dev_unlock(hdev);
|
||||
}
|
||||
|
||||
static void hci_cs_accept_phylink(struct hci_dev *hdev, u8 status)
|
||||
|
@ -1744,6 +1844,11 @@ static void hci_cs_accept_phylink(struct hci_dev *hdev, u8 status)
|
|||
amp_write_remote_assoc(hdev, cp->phy_handle);
|
||||
}
|
||||
|
||||
static void hci_cs_create_logical_link(struct hci_dev *hdev, u8 status)
|
||||
{
|
||||
BT_DBG("%s status 0x%2.2x", hdev->name, status);
|
||||
}
|
||||
|
||||
static void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
__u8 status = *((__u8 *) skb->data);
|
||||
|
@ -2441,6 +2546,14 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
|||
hci_cc_le_read_buffer_size(hdev, skb);
|
||||
break;
|
||||
|
||||
case HCI_OP_LE_READ_ADV_TX_POWER:
|
||||
hci_cc_le_read_adv_tx_power(hdev, skb);
|
||||
break;
|
||||
|
||||
case HCI_OP_LE_SET_EVENT_MASK:
|
||||
hci_cc_le_set_event_mask(hdev, skb);
|
||||
break;
|
||||
|
||||
case HCI_OP_USER_CONFIRM_REPLY:
|
||||
hci_cc_user_confirm_reply(hdev, skb);
|
||||
break;
|
||||
|
@ -2570,6 +2683,10 @@ static void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
|||
hci_cs_accept_phylink(hdev, ev->status);
|
||||
break;
|
||||
|
||||
case HCI_OP_CREATE_LOGICAL_LINK:
|
||||
hci_cs_create_logical_link(hdev, ev->status);
|
||||
break;
|
||||
|
||||
default:
|
||||
BT_DBG("%s opcode 0x%4.4x", hdev->name, opcode);
|
||||
break;
|
||||
|
@ -3544,6 +3661,130 @@ static void hci_remote_oob_data_request_evt(struct hci_dev *hdev,
|
|||
hci_dev_unlock(hdev);
|
||||
}
|
||||
|
||||
static void hci_phy_link_complete_evt(struct hci_dev *hdev,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct hci_ev_phy_link_complete *ev = (void *) skb->data;
|
||||
struct hci_conn *hcon, *bredr_hcon;
|
||||
|
||||
BT_DBG("%s handle 0x%2.2x status 0x%2.2x", hdev->name, ev->phy_handle,
|
||||
ev->status);
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
|
||||
hcon = hci_conn_hash_lookup_handle(hdev, ev->phy_handle);
|
||||
if (!hcon) {
|
||||
hci_dev_unlock(hdev);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ev->status) {
|
||||
hci_conn_del(hcon);
|
||||
hci_dev_unlock(hdev);
|
||||
return;
|
||||
}
|
||||
|
||||
bredr_hcon = hcon->amp_mgr->l2cap_conn->hcon;
|
||||
|
||||
hcon->state = BT_CONNECTED;
|
||||
bacpy(&hcon->dst, &bredr_hcon->dst);
|
||||
|
||||
hci_conn_hold(hcon);
|
||||
hcon->disc_timeout = HCI_DISCONN_TIMEOUT;
|
||||
hci_conn_put(hcon);
|
||||
|
||||
hci_conn_hold_device(hcon);
|
||||
hci_conn_add_sysfs(hcon);
|
||||
|
||||
amp_physical_cfm(bredr_hcon, hcon);
|
||||
|
||||
hci_dev_unlock(hdev);
|
||||
}
|
||||
|
||||
static void hci_loglink_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
struct hci_ev_logical_link_complete *ev = (void *) skb->data;
|
||||
struct hci_conn *hcon;
|
||||
struct hci_chan *hchan;
|
||||
struct amp_mgr *mgr;
|
||||
|
||||
BT_DBG("%s log_handle 0x%4.4x phy_handle 0x%2.2x status 0x%2.2x",
|
||||
hdev->name, le16_to_cpu(ev->handle), ev->phy_handle,
|
||||
ev->status);
|
||||
|
||||
hcon = hci_conn_hash_lookup_handle(hdev, ev->phy_handle);
|
||||
if (!hcon)
|
||||
return;
|
||||
|
||||
/* Create AMP hchan */
|
||||
hchan = hci_chan_create(hcon);
|
||||
if (!hchan)
|
||||
return;
|
||||
|
||||
hchan->handle = le16_to_cpu(ev->handle);
|
||||
|
||||
BT_DBG("hcon %p mgr %p hchan %p", hcon, hcon->amp_mgr, hchan);
|
||||
|
||||
mgr = hcon->amp_mgr;
|
||||
if (mgr && mgr->bredr_chan) {
|
||||
struct l2cap_chan *bredr_chan = mgr->bredr_chan;
|
||||
|
||||
l2cap_chan_lock(bredr_chan);
|
||||
|
||||
bredr_chan->conn->mtu = hdev->block_mtu;
|
||||
l2cap_logical_cfm(bredr_chan, hchan, 0);
|
||||
hci_conn_hold(hcon);
|
||||
|
||||
l2cap_chan_unlock(bredr_chan);
|
||||
}
|
||||
}
|
||||
|
||||
static void hci_disconn_loglink_complete_evt(struct hci_dev *hdev,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct hci_ev_disconn_logical_link_complete *ev = (void *) skb->data;
|
||||
struct hci_chan *hchan;
|
||||
|
||||
BT_DBG("%s log handle 0x%4.4x status 0x%2.2x", hdev->name,
|
||||
le16_to_cpu(ev->handle), ev->status);
|
||||
|
||||
if (ev->status)
|
||||
return;
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
|
||||
hchan = hci_chan_lookup_handle(hdev, le16_to_cpu(ev->handle));
|
||||
if (!hchan)
|
||||
goto unlock;
|
||||
|
||||
amp_destroy_logical_link(hchan, ev->reason);
|
||||
|
||||
unlock:
|
||||
hci_dev_unlock(hdev);
|
||||
}
|
||||
|
||||
static void hci_disconn_phylink_complete_evt(struct hci_dev *hdev,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct hci_ev_disconn_phy_link_complete *ev = (void *) skb->data;
|
||||
struct hci_conn *hcon;
|
||||
|
||||
BT_DBG("%s status 0x%2.2x", hdev->name, ev->status);
|
||||
|
||||
if (ev->status)
|
||||
return;
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
|
||||
hcon = hci_conn_hash_lookup_handle(hdev, ev->phy_handle);
|
||||
if (hcon) {
|
||||
hcon->state = BT_CLOSED;
|
||||
hci_conn_del(hcon);
|
||||
}
|
||||
|
||||
hci_dev_unlock(hdev);
|
||||
}
|
||||
|
||||
static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
struct hci_ev_le_conn_complete *ev = (void *) skb->data;
|
||||
|
@ -3871,6 +4112,22 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
|
|||
hci_remote_oob_data_request_evt(hdev, skb);
|
||||
break;
|
||||
|
||||
case HCI_EV_PHY_LINK_COMPLETE:
|
||||
hci_phy_link_complete_evt(hdev, skb);
|
||||
break;
|
||||
|
||||
case HCI_EV_LOGICAL_LINK_COMPLETE:
|
||||
hci_loglink_complete_evt(hdev, skb);
|
||||
break;
|
||||
|
||||
case HCI_EV_DISCONN_LOGICAL_LINK_COMPLETE:
|
||||
hci_disconn_loglink_complete_evt(hdev, skb);
|
||||
break;
|
||||
|
||||
case HCI_EV_DISCONN_PHY_LINK_COMPLETE:
|
||||
hci_disconn_phylink_complete_evt(hdev, skb);
|
||||
break;
|
||||
|
||||
case HCI_EV_NUM_COMP_BLOCKS:
|
||||
hci_num_comp_blocks_evt(hdev, skb);
|
||||
break;
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -736,6 +736,11 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname,
|
|||
}
|
||||
|
||||
chan->chan_policy = (u8) opt;
|
||||
|
||||
if (sk->sk_state == BT_CONNECTED &&
|
||||
chan->move_role == L2CAP_MOVE_ROLE_NONE)
|
||||
l2cap_move_start(chan);
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
|
|
|
@ -222,7 +222,7 @@ static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
|
|||
|
||||
hdr = (void *) skb_put(skb, sizeof(*hdr));
|
||||
|
||||
hdr->opcode = cpu_to_le16(MGMT_EV_CMD_STATUS);
|
||||
hdr->opcode = __constant_cpu_to_le16(MGMT_EV_CMD_STATUS);
|
||||
hdr->index = cpu_to_le16(index);
|
||||
hdr->len = cpu_to_le16(sizeof(*ev));
|
||||
|
||||
|
@ -253,7 +253,7 @@ static int cmd_complete(struct sock *sk, u16 index, u16 cmd, u8 status,
|
|||
|
||||
hdr = (void *) skb_put(skb, sizeof(*hdr));
|
||||
|
||||
hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE);
|
||||
hdr->opcode = __constant_cpu_to_le16(MGMT_EV_CMD_COMPLETE);
|
||||
hdr->index = cpu_to_le16(index);
|
||||
hdr->len = cpu_to_le16(sizeof(*ev) + rp_len);
|
||||
|
||||
|
@ -376,15 +376,15 @@ static u32 get_supported_settings(struct hci_dev *hdev)
|
|||
u32 settings = 0;
|
||||
|
||||
settings |= MGMT_SETTING_POWERED;
|
||||
settings |= MGMT_SETTING_CONNECTABLE;
|
||||
settings |= MGMT_SETTING_FAST_CONNECTABLE;
|
||||
settings |= MGMT_SETTING_DISCOVERABLE;
|
||||
settings |= MGMT_SETTING_PAIRABLE;
|
||||
|
||||
if (lmp_ssp_capable(hdev))
|
||||
settings |= MGMT_SETTING_SSP;
|
||||
|
||||
if (lmp_bredr_capable(hdev)) {
|
||||
settings |= MGMT_SETTING_CONNECTABLE;
|
||||
settings |= MGMT_SETTING_FAST_CONNECTABLE;
|
||||
settings |= MGMT_SETTING_DISCOVERABLE;
|
||||
settings |= MGMT_SETTING_BREDR;
|
||||
settings |= MGMT_SETTING_LINK_SECURITY;
|
||||
}
|
||||
|
@ -565,7 +565,7 @@ static int update_eir(struct hci_dev *hdev)
|
|||
if (!hdev_is_powered(hdev))
|
||||
return 0;
|
||||
|
||||
if (!(hdev->features[6] & LMP_EXT_INQ))
|
||||
if (!lmp_ext_inq_capable(hdev))
|
||||
return 0;
|
||||
|
||||
if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
|
||||
|
@ -832,7 +832,7 @@ static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, u16 data_len,
|
|||
if (hdev)
|
||||
hdr->index = cpu_to_le16(hdev->id);
|
||||
else
|
||||
hdr->index = cpu_to_le16(MGMT_INDEX_NONE);
|
||||
hdr->index = __constant_cpu_to_le16(MGMT_INDEX_NONE);
|
||||
hdr->len = cpu_to_le16(data_len);
|
||||
|
||||
if (data)
|
||||
|
@ -867,6 +867,10 @@ static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
|
|||
|
||||
BT_DBG("request for %s", hdev->name);
|
||||
|
||||
if (!lmp_bredr_capable(hdev))
|
||||
return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
|
||||
MGMT_STATUS_NOT_SUPPORTED);
|
||||
|
||||
timeout = __le16_to_cpu(cp->timeout);
|
||||
if (!cp->val && timeout > 0)
|
||||
return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
|
||||
|
@ -962,6 +966,10 @@ static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
|
|||
|
||||
BT_DBG("request for %s", hdev->name);
|
||||
|
||||
if (!lmp_bredr_capable(hdev))
|
||||
return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
|
||||
MGMT_STATUS_NOT_SUPPORTED);
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
|
||||
if (!hdev_is_powered(hdev)) {
|
||||
|
@ -1060,6 +1068,10 @@ static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data,
|
|||
|
||||
BT_DBG("request for %s", hdev->name);
|
||||
|
||||
if (!lmp_bredr_capable(hdev))
|
||||
return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
|
||||
MGMT_STATUS_NOT_SUPPORTED);
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
|
||||
if (!hdev_is_powered(hdev)) {
|
||||
|
@ -1213,7 +1225,7 @@ static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
|
|||
}
|
||||
|
||||
val = !!cp->val;
|
||||
enabled = !!(hdev->host_features[0] & LMP_HOST_LE);
|
||||
enabled = !!lmp_host_le_capable(hdev);
|
||||
|
||||
if (!hdev_is_powered(hdev) || val == enabled) {
|
||||
bool changed = false;
|
||||
|
@ -1249,7 +1261,7 @@ static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
|
|||
|
||||
if (val) {
|
||||
hci_cp.le = val;
|
||||
hci_cp.simul = !!(hdev->features[6] & LMP_SIMUL_LE_BR);
|
||||
hci_cp.simul = !!lmp_le_br_capable(hdev);
|
||||
}
|
||||
|
||||
err = hci_send_cmd(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp),
|
||||
|
@ -2594,6 +2606,10 @@ static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
|
|||
|
||||
BT_DBG("%s", hdev->name);
|
||||
|
||||
if (!lmp_bredr_capable(hdev))
|
||||
return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
|
||||
MGMT_STATUS_NOT_SUPPORTED);
|
||||
|
||||
if (!hdev_is_powered(hdev))
|
||||
return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
|
||||
MGMT_STATUS_NOT_POWERED);
|
||||
|
@ -2871,6 +2887,21 @@ static void settings_rsp(struct pending_cmd *cmd, void *data)
|
|||
mgmt_pending_free(cmd);
|
||||
}
|
||||
|
||||
static int set_bredr_scan(struct hci_dev *hdev)
|
||||
{
|
||||
u8 scan = 0;
|
||||
|
||||
if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
|
||||
scan |= SCAN_PAGE;
|
||||
if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
|
||||
scan |= SCAN_INQUIRY;
|
||||
|
||||
if (!scan)
|
||||
return 0;
|
||||
|
||||
return hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
|
||||
}
|
||||
|
||||
int mgmt_powered(struct hci_dev *hdev, u8 powered)
|
||||
{
|
||||
struct cmd_lookup match = { NULL, hdev };
|
||||
|
@ -2882,17 +2913,8 @@ int mgmt_powered(struct hci_dev *hdev, u8 powered)
|
|||
mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
|
||||
|
||||
if (powered) {
|
||||
u8 scan = 0;
|
||||
|
||||
if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
|
||||
scan |= SCAN_PAGE;
|
||||
if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
|
||||
scan |= SCAN_INQUIRY;
|
||||
|
||||
if (scan)
|
||||
hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
|
||||
|
||||
if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
|
||||
if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) &&
|
||||
!lmp_host_ssp_capable(hdev)) {
|
||||
u8 ssp = 1;
|
||||
|
||||
hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, 1, &ssp);
|
||||
|
@ -2902,15 +2924,24 @@ int mgmt_powered(struct hci_dev *hdev, u8 powered)
|
|||
struct hci_cp_write_le_host_supported cp;
|
||||
|
||||
cp.le = 1;
|
||||
cp.simul = !!(hdev->features[6] & LMP_SIMUL_LE_BR);
|
||||
cp.simul = !!lmp_le_br_capable(hdev);
|
||||
|
||||
hci_send_cmd(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED,
|
||||
sizeof(cp), &cp);
|
||||
/* Check first if we already have the right
|
||||
* host state (host features set)
|
||||
*/
|
||||
if (cp.le != !!lmp_host_le_capable(hdev) ||
|
||||
cp.simul != !!lmp_host_le_br_capable(hdev))
|
||||
hci_send_cmd(hdev,
|
||||
HCI_OP_WRITE_LE_HOST_SUPPORTED,
|
||||
sizeof(cp), &cp);
|
||||
}
|
||||
|
||||
update_class(hdev);
|
||||
update_name(hdev, hdev->dev_name);
|
||||
update_eir(hdev);
|
||||
if (lmp_bredr_capable(hdev)) {
|
||||
set_bredr_scan(hdev);
|
||||
update_class(hdev);
|
||||
update_name(hdev, hdev->dev_name);
|
||||
update_eir(hdev);
|
||||
}
|
||||
} else {
|
||||
u8 status = MGMT_STATUS_NOT_POWERED;
|
||||
mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
|
||||
|
@ -3359,7 +3390,7 @@ static int clear_eir(struct hci_dev *hdev)
|
|||
{
|
||||
struct hci_cp_write_eir cp;
|
||||
|
||||
if (!(hdev->features[6] & LMP_EXT_INQ))
|
||||
if (!lmp_ext_inq_capable(hdev))
|
||||
return 0;
|
||||
|
||||
memset(hdev->eir, 0, sizeof(hdev->eir));
|
||||
|
@ -3491,7 +3522,12 @@ int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
|
|||
err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev,
|
||||
sizeof(ev), cmd ? cmd->sk : NULL);
|
||||
|
||||
update_eir(hdev);
|
||||
/* EIR is taken care of separately when powering on the
|
||||
* adapter so only update them here if this is a name change
|
||||
* unrelated to power on.
|
||||
*/
|
||||
if (!test_bit(HCI_INIT, &hdev->flags))
|
||||
update_eir(hdev);
|
||||
|
||||
failed:
|
||||
if (cmd)
|
||||
|
@ -3586,9 +3622,9 @@ int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
|
|||
ev->addr.type = link_to_bdaddr(link_type, addr_type);
|
||||
ev->rssi = rssi;
|
||||
if (cfm_name)
|
||||
ev->flags |= cpu_to_le32(MGMT_DEV_FOUND_CONFIRM_NAME);
|
||||
ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_CONFIRM_NAME);
|
||||
if (!ssp)
|
||||
ev->flags |= cpu_to_le32(MGMT_DEV_FOUND_LEGACY_PAIRING);
|
||||
ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_LEGACY_PAIRING);
|
||||
|
||||
if (eir_len > 0)
|
||||
memcpy(ev->eir, eir, eir_len);
|
||||
|
|
Loading…
Reference in a new issue