Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/padovan/bluetooth-next
This commit is contained in:
commit
5f779bbd47
18 changed files with 881 additions and 282 deletions
|
@ -188,7 +188,7 @@ config BT_MRVL
|
|||
The core driver to support Marvell Bluetooth devices.
|
||||
|
||||
This driver is required if you want to support
|
||||
Marvell Bluetooth devices, such as 8688/8787.
|
||||
Marvell Bluetooth devices, such as 8688/8787/8797.
|
||||
|
||||
Say Y here to compile Marvell Bluetooth driver
|
||||
into the kernel or say M to compile it as module.
|
||||
|
@ -201,8 +201,8 @@ config BT_MRVL_SDIO
|
|||
The driver for Marvell Bluetooth chipsets with SDIO interface.
|
||||
|
||||
This driver is required if you want to use Marvell Bluetooth
|
||||
devices with SDIO interface. Currently SD8688/SD8787 chipsets are
|
||||
supported.
|
||||
devices with SDIO interface. Currently SD8688/SD8787/SD8797
|
||||
chipsets are supported.
|
||||
|
||||
Say Y here to compile support for Marvell BT-over-SDIO driver
|
||||
into the kernel or say M to compile it as module.
|
||||
|
|
|
@ -65,7 +65,7 @@ static const struct btmrvl_sdio_card_reg btmrvl_reg_8688 = {
|
|||
.io_port_1 = 0x01,
|
||||
.io_port_2 = 0x02,
|
||||
};
|
||||
static const struct btmrvl_sdio_card_reg btmrvl_reg_8787 = {
|
||||
static const struct btmrvl_sdio_card_reg btmrvl_reg_87xx = {
|
||||
.cfg = 0x00,
|
||||
.host_int_mask = 0x02,
|
||||
.host_intstatus = 0x03,
|
||||
|
@ -92,7 +92,14 @@ static const struct btmrvl_sdio_device btmrvl_sdio_sd8688 = {
|
|||
static const struct btmrvl_sdio_device btmrvl_sdio_sd8787 = {
|
||||
.helper = NULL,
|
||||
.firmware = "mrvl/sd8787_uapsta.bin",
|
||||
.reg = &btmrvl_reg_8787,
|
||||
.reg = &btmrvl_reg_87xx,
|
||||
.sd_blksz_fw_dl = 256,
|
||||
};
|
||||
|
||||
static const struct btmrvl_sdio_device btmrvl_sdio_sd8797 = {
|
||||
.helper = NULL,
|
||||
.firmware = "mrvl/sd8797_uapsta.bin",
|
||||
.reg = &btmrvl_reg_87xx,
|
||||
.sd_blksz_fw_dl = 256,
|
||||
};
|
||||
|
||||
|
@ -103,6 +110,9 @@ static const struct sdio_device_id btmrvl_sdio_ids[] = {
|
|||
/* Marvell SD8787 Bluetooth device */
|
||||
{ SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x911A),
|
||||
.driver_data = (unsigned long) &btmrvl_sdio_sd8787 },
|
||||
/* Marvell SD8797 Bluetooth device */
|
||||
{ SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x912A),
|
||||
.driver_data = (unsigned long) &btmrvl_sdio_sd8797 },
|
||||
|
||||
{ } /* Terminating entry */
|
||||
};
|
||||
|
@ -1076,3 +1086,4 @@ MODULE_LICENSE("GPL v2");
|
|||
MODULE_FIRMWARE("sd8688_helper.bin");
|
||||
MODULE_FIRMWARE("sd8688.bin");
|
||||
MODULE_FIRMWARE("mrvl/sd8787_uapsta.bin");
|
||||
MODULE_FIRMWARE("mrvl/sd8797_uapsta.bin");
|
||||
|
|
|
@ -785,9 +785,8 @@ static int btusb_send_frame(struct sk_buff *skb)
|
|||
usb_mark_last_busy(data->udev);
|
||||
}
|
||||
|
||||
usb_free_urb(urb);
|
||||
|
||||
done:
|
||||
usb_free_urb(urb);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
|
|
@ -41,6 +41,8 @@
|
|||
|
||||
#define VERSION "1.3"
|
||||
|
||||
static bool amp;
|
||||
|
||||
struct vhci_data {
|
||||
struct hci_dev *hdev;
|
||||
|
||||
|
@ -239,6 +241,9 @@ static int vhci_open(struct inode *inode, struct file *file)
|
|||
hdev->bus = HCI_VIRTUAL;
|
||||
hdev->driver_data = data;
|
||||
|
||||
if (amp)
|
||||
hdev->dev_type = HCI_AMP;
|
||||
|
||||
hdev->open = vhci_open_dev;
|
||||
hdev->close = vhci_close_dev;
|
||||
hdev->flush = vhci_flush;
|
||||
|
@ -303,6 +308,9 @@ static void __exit vhci_exit(void)
|
|||
module_init(vhci_init);
|
||||
module_exit(vhci_exit);
|
||||
|
||||
module_param(amp, bool, 0644);
|
||||
MODULE_PARM_DESC(amp, "Create AMP controller device");
|
||||
|
||||
MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
|
||||
MODULE_DESCRIPTION("Bluetooth virtual HCI driver ver " VERSION);
|
||||
MODULE_VERSION(VERSION);
|
||||
|
|
|
@ -36,6 +36,11 @@
|
|||
#define PF_BLUETOOTH AF_BLUETOOTH
|
||||
#endif
|
||||
|
||||
/* Bluetooth versions */
|
||||
#define BLUETOOTH_VER_1_1 1
|
||||
#define BLUETOOTH_VER_1_2 2
|
||||
#define BLUETOOTH_VER_2_0 3
|
||||
|
||||
/* Reserv for core and drivers use */
|
||||
#define BT_SKB_RESERVE 8
|
||||
|
||||
|
|
|
@ -88,6 +88,14 @@ enum {
|
|||
HCI_RESET,
|
||||
};
|
||||
|
||||
/*
|
||||
* BR/EDR and/or LE controller flags: the flags defined here should represent
|
||||
* states from the controller.
|
||||
*/
|
||||
enum {
|
||||
HCI_LE_SCAN,
|
||||
};
|
||||
|
||||
/* HCI ioctl defines */
|
||||
#define HCIDEVUP _IOW('H', 201, int)
|
||||
#define HCIDEVDOWN _IOW('H', 202, int)
|
||||
|
@ -453,6 +461,14 @@ struct hci_rp_user_confirm_reply {
|
|||
|
||||
#define HCI_OP_USER_CONFIRM_NEG_REPLY 0x042d
|
||||
|
||||
#define HCI_OP_USER_PASSKEY_REPLY 0x042e
|
||||
struct hci_cp_user_passkey_reply {
|
||||
bdaddr_t bdaddr;
|
||||
__le32 passkey;
|
||||
} __packed;
|
||||
|
||||
#define HCI_OP_USER_PASSKEY_NEG_REPLY 0x042f
|
||||
|
||||
#define HCI_OP_REMOTE_OOB_DATA_REPLY 0x0430
|
||||
struct hci_cp_remote_oob_data_reply {
|
||||
bdaddr_t bdaddr;
|
||||
|
@ -669,6 +685,12 @@ struct hci_rp_read_local_oob_data {
|
|||
|
||||
#define HCI_OP_READ_INQ_RSP_TX_POWER 0x0c58
|
||||
|
||||
#define HCI_OP_READ_FLOW_CONTROL_MODE 0x0c66
|
||||
struct hci_rp_read_flow_control_mode {
|
||||
__u8 status;
|
||||
__u8 mode;
|
||||
} __packed;
|
||||
|
||||
#define HCI_OP_WRITE_LE_HOST_SUPPORTED 0x0c6d
|
||||
struct hci_cp_write_le_host_supported {
|
||||
__u8 le;
|
||||
|
@ -760,6 +782,15 @@ struct hci_rp_le_read_buffer_size {
|
|||
__u8 le_max_pkt;
|
||||
} __packed;
|
||||
|
||||
#define HCI_OP_LE_SET_SCAN_PARAM 0x200b
|
||||
struct hci_cp_le_set_scan_param {
|
||||
__u8 type;
|
||||
__le16 interval;
|
||||
__le16 window;
|
||||
__u8 own_address_type;
|
||||
__u8 filter_policy;
|
||||
} __packed;
|
||||
|
||||
#define HCI_OP_LE_SET_SCAN_ENABLE 0x200c
|
||||
struct hci_cp_le_set_scan_enable {
|
||||
__u8 enable;
|
||||
|
@ -1076,6 +1107,11 @@ struct hci_ev_user_confirm_req {
|
|||
__le32 passkey;
|
||||
} __packed;
|
||||
|
||||
#define HCI_EV_USER_PASSKEY_REQUEST 0x34
|
||||
struct hci_ev_user_passkey_req {
|
||||
bdaddr_t bdaddr;
|
||||
} __packed;
|
||||
|
||||
#define HCI_EV_REMOTE_OOB_DATA_REQUEST 0x35
|
||||
struct hci_ev_remote_oob_data_request {
|
||||
bdaddr_t bdaddr;
|
||||
|
@ -1331,4 +1367,6 @@ struct hci_inquiry_req {
|
|||
};
|
||||
#define IREQ_CACHE_FLUSH 0x0001
|
||||
|
||||
extern int enable_hs;
|
||||
|
||||
#endif /* __HCI_H */
|
||||
|
|
|
@ -170,6 +170,8 @@ struct hci_dev {
|
|||
__u32 amp_max_flush_to;
|
||||
__u32 amp_be_flush_to;
|
||||
|
||||
__u8 flow_ctl_mode;
|
||||
|
||||
unsigned int auto_accept_delay;
|
||||
|
||||
unsigned long quirks;
|
||||
|
@ -250,6 +252,8 @@ struct hci_dev {
|
|||
|
||||
struct module *owner;
|
||||
|
||||
unsigned long dev_flags;
|
||||
|
||||
int (*open)(struct hci_dev *hdev);
|
||||
int (*close)(struct hci_dev *hdev);
|
||||
int (*flush)(struct hci_dev *hdev);
|
||||
|
@ -917,11 +921,13 @@ int mgmt_connectable(struct hci_dev *hdev, u8 connectable);
|
|||
int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status);
|
||||
int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
|
||||
u8 persistent);
|
||||
int mgmt_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type);
|
||||
int mgmt_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type);
|
||||
int mgmt_disconnect_failed(struct hci_dev *hdev);
|
||||
int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type,
|
||||
u8 status);
|
||||
int mgmt_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
|
||||
u8 addr_type);
|
||||
int mgmt_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
|
||||
u8 addr_type);
|
||||
int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 status);
|
||||
int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
|
||||
u8 addr_type, u8 status);
|
||||
int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure);
|
||||
int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
|
||||
u8 status);
|
||||
|
@ -933,14 +939,20 @@ int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
|
|||
u8 status);
|
||||
int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev,
|
||||
bdaddr_t *bdaddr, u8 status);
|
||||
int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr);
|
||||
int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
|
||||
u8 status);
|
||||
int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev,
|
||||
bdaddr_t *bdaddr, u8 status);
|
||||
int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 status);
|
||||
int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status);
|
||||
int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
|
||||
u8 *randomizer, u8 status);
|
||||
int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type,
|
||||
u8 *dev_class, s8 rssi, u8 *eir);
|
||||
int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
|
||||
u8 addr_type, u8 *dev_class, s8 rssi, u8 *eir);
|
||||
int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *name);
|
||||
int mgmt_inquiry_failed(struct hci_dev *hdev, u8 status);
|
||||
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_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr);
|
||||
int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr);
|
||||
|
|
|
@ -792,7 +792,6 @@ static inline __u8 __ctrl_size(struct l2cap_chan *chan)
|
|||
}
|
||||
|
||||
extern int disable_ertm;
|
||||
extern int enable_hs;
|
||||
|
||||
int l2cap_init_sockets(void);
|
||||
void l2cap_cleanup_sockets(void);
|
||||
|
@ -810,5 +809,6 @@ int l2cap_chan_connect(struct l2cap_chan *chan);
|
|||
int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len,
|
||||
u32 priority);
|
||||
void l2cap_chan_busy(struct l2cap_chan *chan, int busy);
|
||||
int l2cap_chan_check_security(struct l2cap_chan *chan);
|
||||
|
||||
#endif /* __L2CAP_H */
|
||||
|
|
|
@ -23,6 +23,23 @@
|
|||
|
||||
#define MGMT_INDEX_NONE 0xFFFF
|
||||
|
||||
#define MGMT_STATUS_SUCCESS 0x00
|
||||
#define MGMT_STATUS_UNKNOWN_COMMAND 0x01
|
||||
#define MGMT_STATUS_NOT_CONNECTED 0x02
|
||||
#define MGMT_STATUS_FAILED 0x03
|
||||
#define MGMT_STATUS_CONNECT_FAILED 0x04
|
||||
#define MGMT_STATUS_AUTH_FAILED 0x05
|
||||
#define MGMT_STATUS_NOT_PAIRED 0x06
|
||||
#define MGMT_STATUS_NO_RESOURCES 0x07
|
||||
#define MGMT_STATUS_TIMEOUT 0x08
|
||||
#define MGMT_STATUS_ALREADY_CONNECTED 0x09
|
||||
#define MGMT_STATUS_BUSY 0x0a
|
||||
#define MGMT_STATUS_REJECTED 0x0b
|
||||
#define MGMT_STATUS_NOT_SUPPORTED 0x0c
|
||||
#define MGMT_STATUS_INVALID_PARAMS 0x0d
|
||||
#define MGMT_STATUS_DISCONNECTED 0x0e
|
||||
#define MGMT_STATUS_NOT_POWERED 0x0f
|
||||
|
||||
struct mgmt_hdr {
|
||||
__le16 opcode;
|
||||
__le16 index;
|
||||
|
@ -119,6 +136,10 @@ struct mgmt_cp_remove_keys {
|
|||
bdaddr_t bdaddr;
|
||||
__u8 disconnect;
|
||||
} __packed;
|
||||
struct mgmt_rp_remove_keys {
|
||||
bdaddr_t bdaddr;
|
||||
__u8 status;
|
||||
};
|
||||
|
||||
#define MGMT_OP_DISCONNECT 0x000F
|
||||
struct mgmt_cp_disconnect {
|
||||
|
@ -126,11 +147,12 @@ struct mgmt_cp_disconnect {
|
|||
} __packed;
|
||||
struct mgmt_rp_disconnect {
|
||||
bdaddr_t bdaddr;
|
||||
__u8 status;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_ADDR_BREDR 0x00
|
||||
#define MGMT_ADDR_LE 0x01
|
||||
#define MGMT_ADDR_BREDR_LE 0x02
|
||||
#define MGMT_ADDR_LE_PUBLIC 0x01
|
||||
#define MGMT_ADDR_LE_RANDOM 0x02
|
||||
#define MGMT_ADDR_INVALID 0xff
|
||||
|
||||
struct mgmt_addr_info {
|
||||
|
@ -167,11 +189,11 @@ struct mgmt_cp_set_io_capability {
|
|||
|
||||
#define MGMT_OP_PAIR_DEVICE 0x0014
|
||||
struct mgmt_cp_pair_device {
|
||||
bdaddr_t bdaddr;
|
||||
struct mgmt_addr_info addr;
|
||||
__u8 io_cap;
|
||||
} __packed;
|
||||
struct mgmt_rp_pair_device {
|
||||
bdaddr_t bdaddr;
|
||||
struct mgmt_addr_info addr;
|
||||
__u8 status;
|
||||
} __packed;
|
||||
|
||||
|
@ -210,6 +232,9 @@ struct mgmt_cp_remove_remote_oob_data {
|
|||
} __packed;
|
||||
|
||||
#define MGMT_OP_START_DISCOVERY 0x001B
|
||||
struct mgmt_cp_start_discovery {
|
||||
__u8 type;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_STOP_DISCOVERY 0x001C
|
||||
|
||||
|
@ -228,6 +253,17 @@ struct mgmt_cp_set_fast_connectable {
|
|||
__u8 enable;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_USER_PASSKEY_REPLY 0x0020
|
||||
struct mgmt_cp_user_passkey_reply {
|
||||
bdaddr_t bdaddr;
|
||||
__le32 passkey;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_USER_PASSKEY_NEG_REPLY 0x0021
|
||||
struct mgmt_cp_user_passkey_neg_reply {
|
||||
bdaddr_t bdaddr;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_EV_CMD_COMPLETE 0x0001
|
||||
struct mgmt_ev_cmd_complete {
|
||||
__le16 opcode;
|
||||
|
@ -322,3 +358,8 @@ struct mgmt_ev_device_blocked {
|
|||
struct mgmt_ev_device_unblocked {
|
||||
bdaddr_t bdaddr;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_EV_USER_PASSKEY_REQUEST 0x0017
|
||||
struct mgmt_ev_user_passkey_request {
|
||||
bdaddr_t bdaddr;
|
||||
} __packed;
|
||||
|
|
|
@ -77,17 +77,12 @@ static struct bnep_session *__bnep_get_session(u8 *dst)
|
|||
|
||||
static void __bnep_link_session(struct bnep_session *s)
|
||||
{
|
||||
/* It's safe to call __module_get() here because sessions are added
|
||||
by the socket layer which has to hold the reference to this module.
|
||||
*/
|
||||
__module_get(THIS_MODULE);
|
||||
list_add(&s->list, &bnep_session_list);
|
||||
}
|
||||
|
||||
static void __bnep_unlink_session(struct bnep_session *s)
|
||||
{
|
||||
list_del(&s->list);
|
||||
module_put(THIS_MODULE);
|
||||
}
|
||||
|
||||
static int bnep_send(struct bnep_session *s, void *data, size_t len)
|
||||
|
@ -528,6 +523,7 @@ static int bnep_session(void *arg)
|
|||
|
||||
up_write(&bnep_session_sem);
|
||||
free_netdev(dev);
|
||||
module_put_and_exit(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -614,9 +610,11 @@ int bnep_add_connection(struct bnep_connadd_req *req, struct socket *sock)
|
|||
|
||||
__bnep_link_session(s);
|
||||
|
||||
__module_get(THIS_MODULE);
|
||||
s->task = kthread_run(bnep_session, s, "kbnepd %s", dev->name);
|
||||
if (IS_ERR(s->task)) {
|
||||
/* Session thread start failed, gotta cleanup. */
|
||||
module_put(THIS_MODULE);
|
||||
unregister_netdev(dev);
|
||||
__bnep_unlink_session(s);
|
||||
err = PTR_ERR(s->task);
|
||||
|
|
|
@ -65,14 +65,12 @@ static struct cmtp_session *__cmtp_get_session(bdaddr_t *bdaddr)
|
|||
|
||||
static void __cmtp_link_session(struct cmtp_session *session)
|
||||
{
|
||||
__module_get(THIS_MODULE);
|
||||
list_add(&session->list, &cmtp_session_list);
|
||||
}
|
||||
|
||||
static void __cmtp_unlink_session(struct cmtp_session *session)
|
||||
{
|
||||
list_del(&session->list);
|
||||
module_put(THIS_MODULE);
|
||||
}
|
||||
|
||||
static void __cmtp_copy_session(struct cmtp_session *session, struct cmtp_conninfo *ci)
|
||||
|
@ -325,6 +323,7 @@ static int cmtp_session(void *arg)
|
|||
up_write(&cmtp_session_sem);
|
||||
|
||||
kfree(session);
|
||||
module_put_and_exit(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -374,9 +373,11 @@ int cmtp_add_connection(struct cmtp_connadd_req *req, struct socket *sock)
|
|||
|
||||
__cmtp_link_session(session);
|
||||
|
||||
__module_get(THIS_MODULE);
|
||||
session->task = kthread_run(cmtp_session, session, "kcmtpd_ctr_%d",
|
||||
session->num);
|
||||
if (IS_ERR(session->task)) {
|
||||
module_put(THIS_MODULE);
|
||||
err = PTR_ERR(session->task);
|
||||
goto unlink;
|
||||
}
|
||||
|
|
|
@ -123,7 +123,7 @@ static void hci_acl_connect_cancel(struct hci_conn *conn)
|
|||
|
||||
BT_DBG("%p", conn);
|
||||
|
||||
if (conn->hdev->hci_ver < 2)
|
||||
if (conn->hdev->hci_ver < BLUETOOTH_VER_1_2)
|
||||
return;
|
||||
|
||||
bacpy(&cp.bdaddr, &conn->dst);
|
||||
|
|
|
@ -54,6 +54,8 @@
|
|||
|
||||
#define AUTO_OFF_TIMEOUT 2000
|
||||
|
||||
int enable_hs;
|
||||
|
||||
static void hci_cmd_task(unsigned long arg);
|
||||
static void hci_rx_task(unsigned long arg);
|
||||
static void hci_tx_task(unsigned long arg);
|
||||
|
@ -228,18 +230,6 @@ static void hci_init_req(struct hci_dev *hdev, unsigned long opt)
|
|||
/* Read Buffer Size (ACL mtu, max pkt, etc.) */
|
||||
hci_send_cmd(hdev, HCI_OP_READ_BUFFER_SIZE, 0, NULL);
|
||||
|
||||
#if 0
|
||||
/* Host buffer size */
|
||||
{
|
||||
struct hci_cp_host_buffer_size cp;
|
||||
cp.acl_mtu = cpu_to_le16(HCI_MAX_ACL_SIZE);
|
||||
cp.sco_mtu = HCI_MAX_SCO_SIZE;
|
||||
cp.acl_max_pkt = cpu_to_le16(0xffff);
|
||||
cp.sco_max_pkt = cpu_to_le16(0xffff);
|
||||
hci_send_cmd(hdev, HCI_OP_HOST_BUFFER_SIZE, sizeof(cp), &cp);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Read BD Address */
|
||||
hci_send_cmd(hdev, HCI_OP_READ_BD_ADDR, 0, NULL);
|
||||
|
||||
|
@ -521,8 +511,9 @@ int hci_dev_open(__u16 dev)
|
|||
if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
|
||||
set_bit(HCI_RAW, &hdev->flags);
|
||||
|
||||
/* Treat all non BR/EDR controllers as raw devices for now */
|
||||
if (hdev->dev_type != HCI_BREDR)
|
||||
/* Treat all non BR/EDR controllers as raw devices if
|
||||
enable_hs is not set */
|
||||
if (hdev->dev_type != HCI_BREDR && !enable_hs)
|
||||
set_bit(HCI_RAW, &hdev->flags);
|
||||
|
||||
if (hdev->open(hdev)) {
|
||||
|
@ -1336,14 +1327,12 @@ int hci_blacklist_del(struct hci_dev *hdev, bdaddr_t *bdaddr)
|
|||
{
|
||||
struct bdaddr_list *entry;
|
||||
|
||||
if (bacmp(bdaddr, BDADDR_ANY) == 0) {
|
||||
if (bacmp(bdaddr, BDADDR_ANY) == 0)
|
||||
return hci_blacklist_clear(hdev);
|
||||
}
|
||||
|
||||
entry = hci_blacklist_lookup(hdev, bdaddr);
|
||||
if (!entry) {
|
||||
if (!entry)
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
list_del(&entry->list);
|
||||
kfree(entry);
|
||||
|
@ -1451,12 +1440,13 @@ int hci_register_dev(struct hci_dev *hdev)
|
|||
|
||||
sprintf(hdev->name, "hci%d", id);
|
||||
hdev->id = id;
|
||||
list_add(&hdev->list, head);
|
||||
list_add_tail(&hdev->list, head);
|
||||
|
||||
atomic_set(&hdev->refcnt, 1);
|
||||
spin_lock_init(&hdev->lock);
|
||||
|
||||
hdev->flags = 0;
|
||||
hdev->dev_flags = 0;
|
||||
hdev->pkt_type = (HCI_DM1 | HCI_DH1 | HCI_HV1);
|
||||
hdev->esco_type = (ESCO_HV1);
|
||||
hdev->link_mode = (HCI_LM_ACCEPT);
|
||||
|
@ -2614,3 +2604,6 @@ int hci_cancel_inquiry(struct hci_dev *hdev)
|
|||
|
||||
return hci_send_cmd(hdev, HCI_OP_INQUIRY_CANCEL, 0, NULL);
|
||||
}
|
||||
|
||||
module_param(enable_hs, bool, 0644);
|
||||
MODULE_PARM_DESC(enable_hs, "Enable High Speed");
|
||||
|
|
|
@ -55,8 +55,12 @@ static void hci_cc_inquiry_cancel(struct hci_dev *hdev, struct sk_buff *skb)
|
|||
|
||||
BT_DBG("%s status 0x%x", hdev->name, status);
|
||||
|
||||
if (status)
|
||||
if (status) {
|
||||
hci_dev_lock(hdev);
|
||||
mgmt_stop_discovery_failed(hdev, status);
|
||||
hci_dev_unlock(hdev);
|
||||
return;
|
||||
}
|
||||
|
||||
clear_bit(HCI_INQUIRY, &hdev->flags);
|
||||
|
||||
|
@ -190,6 +194,8 @@ static void hci_cc_reset(struct hci_dev *hdev, struct sk_buff *skb)
|
|||
clear_bit(HCI_RESET, &hdev->flags);
|
||||
|
||||
hci_req_complete(hdev, HCI_OP_RESET, status);
|
||||
|
||||
hdev->dev_flags = 0;
|
||||
}
|
||||
|
||||
static void hci_cc_write_local_name(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
|
@ -494,7 +500,7 @@ static void hci_setup_event_mask(struct hci_dev *hdev)
|
|||
|
||||
/* CSR 1.1 dongles does not accept any bitfield so don't try to set
|
||||
* any event mask for pre 1.2 devices */
|
||||
if (hdev->lmp_ver <= 1)
|
||||
if (hdev->hci_ver < BLUETOOTH_VER_1_2)
|
||||
return;
|
||||
|
||||
events[4] |= 0x01; /* Flow Specification Complete */
|
||||
|
@ -558,7 +564,7 @@ static void hci_setup(struct hci_dev *hdev)
|
|||
{
|
||||
hci_setup_event_mask(hdev);
|
||||
|
||||
if (hdev->lmp_ver > 1)
|
||||
if (hdev->hci_ver > BLUETOOTH_VER_1_1)
|
||||
hci_send_cmd(hdev, HCI_OP_READ_LOCAL_COMMANDS, 0, NULL);
|
||||
|
||||
if (hdev->features[6] & LMP_SIMPLE_PAIR) {
|
||||
|
@ -713,6 +719,21 @@ static void hci_cc_read_local_ext_features(struct hci_dev *hdev,
|
|||
hci_req_complete(hdev, HCI_OP_READ_LOCAL_EXT_FEATURES, rp->status);
|
||||
}
|
||||
|
||||
static void hci_cc_read_flow_control_mode(struct hci_dev *hdev,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct hci_rp_read_flow_control_mode *rp = (void *) skb->data;
|
||||
|
||||
BT_DBG("%s status 0x%x", hdev->name, rp->status);
|
||||
|
||||
if (rp->status)
|
||||
return;
|
||||
|
||||
hdev->flow_ctl_mode = rp->mode;
|
||||
|
||||
hci_req_complete(hdev, HCI_OP_READ_FLOW_CONTROL_MODE, rp->status);
|
||||
}
|
||||
|
||||
static void hci_cc_read_buffer_size(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
struct hci_rp_read_buffer_size *rp = (void *) skb->data;
|
||||
|
@ -927,6 +948,37 @@ static void hci_cc_user_confirm_neg_reply(struct hci_dev *hdev,
|
|||
hci_dev_unlock(hdev);
|
||||
}
|
||||
|
||||
static void hci_cc_user_passkey_reply(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
struct hci_rp_user_confirm_reply *rp = (void *) skb->data;
|
||||
|
||||
BT_DBG("%s status 0x%x", hdev->name, rp->status);
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
|
||||
if (test_bit(HCI_MGMT, &hdev->flags))
|
||||
mgmt_user_passkey_reply_complete(hdev, &rp->bdaddr,
|
||||
rp->status);
|
||||
|
||||
hci_dev_unlock(hdev);
|
||||
}
|
||||
|
||||
static void hci_cc_user_passkey_neg_reply(struct hci_dev *hdev,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct hci_rp_user_confirm_reply *rp = (void *) skb->data;
|
||||
|
||||
BT_DBG("%s status 0x%x", hdev->name, rp->status);
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
|
||||
if (test_bit(HCI_MGMT, &hdev->flags))
|
||||
mgmt_user_passkey_neg_reply_complete(hdev, &rp->bdaddr,
|
||||
rp->status);
|
||||
|
||||
hci_dev_unlock(hdev);
|
||||
}
|
||||
|
||||
static void hci_cc_read_local_oob_data_reply(struct hci_dev *hdev,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
|
@ -940,6 +992,13 @@ static void hci_cc_read_local_oob_data_reply(struct hci_dev *hdev,
|
|||
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%x", hdev->name, status);
|
||||
}
|
||||
|
||||
static void hci_cc_le_set_scan_enable(struct hci_dev *hdev,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
|
@ -956,12 +1015,16 @@ static void hci_cc_le_set_scan_enable(struct hci_dev *hdev,
|
|||
return;
|
||||
|
||||
if (cp->enable == 0x01) {
|
||||
set_bit(HCI_LE_SCAN, &hdev->dev_flags);
|
||||
|
||||
del_timer(&hdev->adv_timer);
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
hci_adv_entries_clear(hdev);
|
||||
hci_dev_unlock(hdev);
|
||||
} else if (cp->enable == 0x00) {
|
||||
clear_bit(HCI_LE_SCAN, &hdev->dev_flags);
|
||||
|
||||
mod_timer(&hdev->adv_timer, jiffies + ADV_CLEAR_TIMEOUT);
|
||||
}
|
||||
}
|
||||
|
@ -1014,7 +1077,7 @@ static inline void hci_cs_inquiry(struct hci_dev *hdev, __u8 status)
|
|||
hci_conn_check_pending(hdev);
|
||||
hci_dev_lock(hdev);
|
||||
if (test_bit(HCI_MGMT, &hdev->flags))
|
||||
mgmt_inquiry_failed(hdev, status);
|
||||
mgmt_start_discovery_failed(hdev, status);
|
||||
hci_dev_unlock(hdev);
|
||||
return;
|
||||
}
|
||||
|
@ -1437,7 +1500,7 @@ static inline void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *
|
|||
data.rssi = 0x00;
|
||||
data.ssp_mode = 0x00;
|
||||
hci_inquiry_cache_update(hdev, &data);
|
||||
mgmt_device_found(hdev, &info->bdaddr, ACL_LINK,
|
||||
mgmt_device_found(hdev, &info->bdaddr, ACL_LINK, 0x00,
|
||||
info->dev_class, 0, NULL);
|
||||
}
|
||||
|
||||
|
@ -1472,7 +1535,8 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s
|
|||
conn->state = BT_CONFIG;
|
||||
hci_conn_hold(conn);
|
||||
conn->disc_timeout = HCI_DISCONN_TIMEOUT;
|
||||
mgmt_connected(hdev, &ev->bdaddr, conn->type);
|
||||
mgmt_connected(hdev, &ev->bdaddr, conn->type,
|
||||
conn->dst_type);
|
||||
} else
|
||||
conn->state = BT_CONNECTED;
|
||||
|
||||
|
@ -1494,7 +1558,7 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s
|
|||
}
|
||||
|
||||
/* Set packet type for incoming connection */
|
||||
if (!conn->out && hdev->hci_ver < 3) {
|
||||
if (!conn->out && hdev->hci_ver < BLUETOOTH_VER_2_0) {
|
||||
struct hci_cp_change_conn_ptype cp;
|
||||
cp.handle = ev->handle;
|
||||
cp.pkt_type = cpu_to_le16(conn->pkt_type);
|
||||
|
@ -1505,7 +1569,7 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s
|
|||
conn->state = BT_CLOSED;
|
||||
if (conn->type == ACL_LINK)
|
||||
mgmt_connect_failed(hdev, &ev->bdaddr, conn->type,
|
||||
ev->status);
|
||||
conn->dst_type, ev->status);
|
||||
}
|
||||
|
||||
if (conn->type == ACL_LINK)
|
||||
|
@ -1604,26 +1668,27 @@ static inline void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff
|
|||
|
||||
BT_DBG("%s status %d", hdev->name, ev->status);
|
||||
|
||||
if (ev->status) {
|
||||
hci_dev_lock(hdev);
|
||||
mgmt_disconnect_failed(hdev);
|
||||
hci_dev_unlock(hdev);
|
||||
return;
|
||||
}
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
|
||||
conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle));
|
||||
if (!conn)
|
||||
goto unlock;
|
||||
|
||||
if (ev->status == 0)
|
||||
conn->state = BT_CLOSED;
|
||||
|
||||
if (conn->type == ACL_LINK || conn->type == LE_LINK)
|
||||
mgmt_disconnected(hdev, &conn->dst, conn->type);
|
||||
if (conn->type == ACL_LINK || conn->type == LE_LINK) {
|
||||
if (ev->status != 0)
|
||||
mgmt_disconnect_failed(hdev, &conn->dst, ev->status);
|
||||
else
|
||||
mgmt_disconnected(hdev, &conn->dst, conn->type,
|
||||
conn->dst_type);
|
||||
}
|
||||
|
||||
if (ev->status == 0) {
|
||||
hci_proto_disconn_cfm(conn, ev->reason);
|
||||
hci_conn_del(conn);
|
||||
}
|
||||
|
||||
unlock:
|
||||
hci_dev_unlock(hdev);
|
||||
|
@ -1961,6 +2026,10 @@ static inline void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *sk
|
|||
hci_cc_write_ca_timeout(hdev, skb);
|
||||
break;
|
||||
|
||||
case HCI_OP_READ_FLOW_CONTROL_MODE:
|
||||
hci_cc_read_flow_control_mode(hdev, skb);
|
||||
break;
|
||||
|
||||
case HCI_OP_READ_LOCAL_AMP_INFO:
|
||||
hci_cc_read_local_amp_info(hdev, skb);
|
||||
break;
|
||||
|
@ -2009,6 +2078,17 @@ static inline void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *sk
|
|||
hci_cc_user_confirm_neg_reply(hdev, skb);
|
||||
break;
|
||||
|
||||
case HCI_OP_USER_PASSKEY_REPLY:
|
||||
hci_cc_user_passkey_reply(hdev, skb);
|
||||
break;
|
||||
|
||||
case HCI_OP_USER_PASSKEY_NEG_REPLY:
|
||||
hci_cc_user_passkey_neg_reply(hdev, skb);
|
||||
|
||||
case HCI_OP_LE_SET_SCAN_PARAM:
|
||||
hci_cc_le_set_scan_param(hdev, skb);
|
||||
break;
|
||||
|
||||
case HCI_OP_LE_SET_SCAN_ENABLE:
|
||||
hci_cc_le_set_scan_enable(hdev, skb);
|
||||
break;
|
||||
|
@ -2096,7 +2176,7 @@ static inline void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
|||
|
||||
case HCI_OP_DISCONNECT:
|
||||
if (ev->status != 0)
|
||||
mgmt_disconnect_failed(hdev);
|
||||
mgmt_disconnect_failed(hdev, NULL, ev->status);
|
||||
break;
|
||||
|
||||
case HCI_OP_LE_CREATE_CONN:
|
||||
|
@ -2444,7 +2524,7 @@ static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct
|
|||
data.rssi = info->rssi;
|
||||
data.ssp_mode = 0x00;
|
||||
hci_inquiry_cache_update(hdev, &data);
|
||||
mgmt_device_found(hdev, &info->bdaddr, ACL_LINK,
|
||||
mgmt_device_found(hdev, &info->bdaddr, ACL_LINK, 0x00,
|
||||
info->dev_class, info->rssi,
|
||||
NULL);
|
||||
}
|
||||
|
@ -2461,7 +2541,7 @@ static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct
|
|||
data.rssi = info->rssi;
|
||||
data.ssp_mode = 0x00;
|
||||
hci_inquiry_cache_update(hdev, &data);
|
||||
mgmt_device_found(hdev, &info->bdaddr, ACL_LINK,
|
||||
mgmt_device_found(hdev, &info->bdaddr, ACL_LINK, 0x00,
|
||||
info->dev_class, info->rssi,
|
||||
NULL);
|
||||
}
|
||||
|
@ -2604,7 +2684,7 @@ static inline void hci_extended_inquiry_result_evt(struct hci_dev *hdev, struct
|
|||
data.rssi = info->rssi;
|
||||
data.ssp_mode = 0x01;
|
||||
hci_inquiry_cache_update(hdev, &data);
|
||||
mgmt_device_found(hdev, &info->bdaddr, ACL_LINK,
|
||||
mgmt_device_found(hdev, &info->bdaddr, ACL_LINK, 0x00,
|
||||
info->dev_class, info->rssi, info->data);
|
||||
}
|
||||
|
||||
|
@ -2768,6 +2848,21 @@ static inline void hci_user_confirm_request_evt(struct hci_dev *hdev,
|
|||
hci_dev_unlock(hdev);
|
||||
}
|
||||
|
||||
static inline void hci_user_passkey_request_evt(struct hci_dev *hdev,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct hci_ev_user_passkey_req *ev = (void *) skb->data;
|
||||
|
||||
BT_DBG("%s", hdev->name);
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
|
||||
if (test_bit(HCI_MGMT, &hdev->flags))
|
||||
mgmt_user_passkey_request(hdev, &ev->bdaddr);
|
||||
|
||||
hci_dev_unlock(hdev);
|
||||
}
|
||||
|
||||
static inline void hci_simple_pair_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
struct hci_ev_simple_pair_complete *ev = (void *) skb->data;
|
||||
|
@ -2868,14 +2963,15 @@ static inline void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff
|
|||
}
|
||||
|
||||
if (ev->status) {
|
||||
mgmt_connect_failed(hdev, &ev->bdaddr, conn->type, ev->status);
|
||||
mgmt_connect_failed(hdev, &ev->bdaddr, conn->type,
|
||||
conn->dst_type, ev->status);
|
||||
hci_proto_connect_cfm(conn, ev->status);
|
||||
conn->state = BT_CLOSED;
|
||||
hci_conn_del(conn);
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
mgmt_connected(hdev, &ev->bdaddr, conn->type);
|
||||
mgmt_connected(hdev, &ev->bdaddr, conn->type, conn->dst_type);
|
||||
|
||||
conn->sec_level = BT_SECURITY_LOW;
|
||||
conn->handle = __le16_to_cpu(ev->handle);
|
||||
|
@ -3106,6 +3202,10 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
|
|||
hci_user_confirm_request_evt(hdev, skb);
|
||||
break;
|
||||
|
||||
case HCI_EV_USER_PASSKEY_REQUEST:
|
||||
hci_user_passkey_request_evt(hdev, skb);
|
||||
break;
|
||||
|
||||
case HCI_EV_SIMPLE_PAIR_COMPLETE:
|
||||
hci_simple_pair_complete_evt(hdev, skb);
|
||||
break;
|
||||
|
|
|
@ -57,7 +57,6 @@
|
|||
#include <net/bluetooth/smp.h>
|
||||
|
||||
int disable_ertm;
|
||||
int enable_hs;
|
||||
|
||||
static u32 l2cap_feat_mask = L2CAP_FEAT_FIXED_CHAN;
|
||||
static u8 l2cap_fixed_chan[8] = { L2CAP_FC_L2CAP, };
|
||||
|
@ -97,7 +96,6 @@ static struct l2cap_chan *__l2cap_get_chan_by_dcid(struct l2cap_conn *conn, u16
|
|||
return c;
|
||||
}
|
||||
return NULL;
|
||||
|
||||
}
|
||||
|
||||
static struct l2cap_chan *__l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16 cid)
|
||||
|
@ -154,13 +152,10 @@ static struct l2cap_chan *__l2cap_global_chan_by_addr(__le16 psm, bdaddr_t *src)
|
|||
|
||||
list_for_each_entry(c, &chan_list, global_l) {
|
||||
if (c->sport == psm && !bacmp(&bt_sk(c->sk)->src, src))
|
||||
goto found;
|
||||
}
|
||||
|
||||
c = NULL;
|
||||
found:
|
||||
return c;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int l2cap_add_psm(struct l2cap_chan *chan, bdaddr_t *src, __le16 psm)
|
||||
{
|
||||
|
@ -234,8 +229,37 @@ static void l2cap_clear_timer(struct l2cap_chan *chan, struct timer_list *timer)
|
|||
chan_put(chan);
|
||||
}
|
||||
|
||||
static char *state_to_string(int state)
|
||||
{
|
||||
switch(state) {
|
||||
case BT_CONNECTED:
|
||||
return "BT_CONNECTED";
|
||||
case BT_OPEN:
|
||||
return "BT_OPEN";
|
||||
case BT_BOUND:
|
||||
return "BT_BOUND";
|
||||
case BT_LISTEN:
|
||||
return "BT_LISTEN";
|
||||
case BT_CONNECT:
|
||||
return "BT_CONNECT";
|
||||
case BT_CONNECT2:
|
||||
return "BT_CONNECT2";
|
||||
case BT_CONFIG:
|
||||
return "BT_CONFIG";
|
||||
case BT_DISCONN:
|
||||
return "BT_DISCONN";
|
||||
case BT_CLOSED:
|
||||
return "BT_CLOSED";
|
||||
}
|
||||
|
||||
return "invalid state";
|
||||
}
|
||||
|
||||
static void l2cap_state_change(struct l2cap_chan *chan, int state)
|
||||
{
|
||||
BT_DBG("%p %s -> %s", chan, state_to_string(chan->state),
|
||||
state_to_string(state));
|
||||
|
||||
chan->state = state;
|
||||
chan->ops->state_change(chan->data, state);
|
||||
}
|
||||
|
@ -518,7 +542,7 @@ static inline u8 l2cap_get_auth_type(struct l2cap_chan *chan)
|
|||
}
|
||||
|
||||
/* Service level security */
|
||||
static inline int l2cap_check_security(struct l2cap_chan *chan)
|
||||
int l2cap_chan_check_security(struct l2cap_chan *chan)
|
||||
{
|
||||
struct l2cap_conn *conn = chan->conn;
|
||||
__u8 auth_type;
|
||||
|
@ -664,7 +688,7 @@ static void l2cap_do_start(struct l2cap_chan *chan)
|
|||
if (!(conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE))
|
||||
return;
|
||||
|
||||
if (l2cap_check_security(chan) &&
|
||||
if (l2cap_chan_check_security(chan) &&
|
||||
__l2cap_no_conn_pending(chan)) {
|
||||
struct l2cap_conn_req req;
|
||||
req.scid = cpu_to_le16(chan->scid);
|
||||
|
@ -754,7 +778,7 @@ static void l2cap_conn_start(struct l2cap_conn *conn)
|
|||
if (chan->state == BT_CONNECT) {
|
||||
struct l2cap_conn_req req;
|
||||
|
||||
if (!l2cap_check_security(chan) ||
|
||||
if (!l2cap_chan_check_security(chan) ||
|
||||
!__l2cap_no_conn_pending(chan)) {
|
||||
bh_unlock_sock(sk);
|
||||
continue;
|
||||
|
@ -787,7 +811,7 @@ static void l2cap_conn_start(struct l2cap_conn *conn)
|
|||
rsp.scid = cpu_to_le16(chan->dcid);
|
||||
rsp.dcid = cpu_to_le16(chan->scid);
|
||||
|
||||
if (l2cap_check_security(chan)) {
|
||||
if (l2cap_chan_check_security(chan)) {
|
||||
if (bt_sk(sk)->defer_setup) {
|
||||
struct sock *parent = bt_sk(sk)->parent;
|
||||
rsp.result = cpu_to_le16(L2CAP_CR_PEND);
|
||||
|
@ -1181,7 +1205,7 @@ int l2cap_chan_connect(struct l2cap_chan *chan)
|
|||
if (hcon->state == BT_CONNECTED) {
|
||||
if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
|
||||
__clear_chan_timer(chan);
|
||||
if (l2cap_check_security(chan))
|
||||
if (l2cap_chan_check_security(chan))
|
||||
l2cap_state_change(chan, BT_CONNECTED);
|
||||
} else
|
||||
l2cap_do_start(chan);
|
||||
|
@ -1318,14 +1342,12 @@ static void l2cap_retransmit_one_frame(struct l2cap_chan *chan, u16 tx_seq)
|
|||
if (!skb)
|
||||
return;
|
||||
|
||||
do {
|
||||
if (bt_cb(skb)->tx_seq == tx_seq)
|
||||
break;
|
||||
|
||||
while (bt_cb(skb)->tx_seq != tx_seq) {
|
||||
if (skb_queue_is_last(&chan->tx_q, skb))
|
||||
return;
|
||||
|
||||
} while ((skb = skb_queue_next(&chan->tx_q, skb)));
|
||||
skb = skb_queue_next(&chan->tx_q, skb);
|
||||
}
|
||||
|
||||
if (chan->remote_max_tx &&
|
||||
bt_cb(skb)->retries == chan->remote_max_tx) {
|
||||
|
@ -2606,7 +2628,7 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd
|
|||
chan->ident = cmd->ident;
|
||||
|
||||
if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE) {
|
||||
if (l2cap_check_security(chan)) {
|
||||
if (l2cap_chan_check_security(chan)) {
|
||||
if (bt_sk(sk)->defer_setup) {
|
||||
l2cap_state_change(chan, BT_CONNECT2);
|
||||
result = L2CAP_CR_PEND;
|
||||
|
@ -3562,14 +3584,10 @@ static int l2cap_add_to_srej_queue(struct l2cap_chan *chan, struct sk_buff *skb,
|
|||
bt_cb(skb)->sar = sar;
|
||||
|
||||
next_skb = skb_peek(&chan->srej_q);
|
||||
if (!next_skb) {
|
||||
__skb_queue_tail(&chan->srej_q, skb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
tx_seq_offset = __seq_offset(chan, tx_seq, chan->buffer_seq);
|
||||
|
||||
do {
|
||||
while (next_skb) {
|
||||
if (bt_cb(next_skb)->tx_seq == tx_seq)
|
||||
return -EINVAL;
|
||||
|
||||
|
@ -3582,9 +3600,10 @@ static int l2cap_add_to_srej_queue(struct l2cap_chan *chan, struct sk_buff *skb,
|
|||
}
|
||||
|
||||
if (skb_queue_is_last(&chan->srej_q, next_skb))
|
||||
break;
|
||||
|
||||
} while ((next_skb = skb_queue_next(&chan->srej_q, next_skb)));
|
||||
next_skb = NULL;
|
||||
else
|
||||
next_skb = skb_queue_next(&chan->srej_q, next_skb);
|
||||
}
|
||||
|
||||
__skb_queue_tail(&chan->srej_q, skb);
|
||||
|
||||
|
@ -3788,7 +3807,7 @@ static void l2cap_resend_srejframe(struct l2cap_chan *chan, u16 tx_seq)
|
|||
}
|
||||
}
|
||||
|
||||
static void l2cap_send_srejframe(struct l2cap_chan *chan, u16 tx_seq)
|
||||
static int l2cap_send_srejframe(struct l2cap_chan *chan, u16 tx_seq)
|
||||
{
|
||||
struct srej_list *new;
|
||||
u32 control;
|
||||
|
@ -3799,6 +3818,9 @@ static void l2cap_send_srejframe(struct l2cap_chan *chan, u16 tx_seq)
|
|||
l2cap_send_sframe(chan, control);
|
||||
|
||||
new = kzalloc(sizeof(struct srej_list), GFP_ATOMIC);
|
||||
if (!new)
|
||||
return -ENOMEM;
|
||||
|
||||
new->tx_seq = chan->expected_tx_seq;
|
||||
|
||||
chan->expected_tx_seq = __next_seq(chan, chan->expected_tx_seq);
|
||||
|
@ -3807,6 +3829,8 @@ static void l2cap_send_srejframe(struct l2cap_chan *chan, u16 tx_seq)
|
|||
}
|
||||
|
||||
chan->expected_tx_seq = __next_seq(chan, chan->expected_tx_seq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u32 rx_control, struct sk_buff *skb)
|
||||
|
@ -3877,7 +3901,12 @@ static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u32 rx_cont
|
|||
return 0;
|
||||
}
|
||||
}
|
||||
l2cap_send_srejframe(chan, tx_seq);
|
||||
|
||||
err = l2cap_send_srejframe(chan, tx_seq);
|
||||
if (err < 0) {
|
||||
l2cap_send_disconn_req(chan->conn, chan, -err);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
expected_tx_seq_offset = __seq_offset(chan,
|
||||
|
@ -3899,7 +3928,11 @@ static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u32 rx_cont
|
|||
|
||||
set_bit(CONN_SEND_PBIT, &chan->conn_state);
|
||||
|
||||
l2cap_send_srejframe(chan, tx_seq);
|
||||
err = l2cap_send_srejframe(chan, tx_seq);
|
||||
if (err < 0) {
|
||||
l2cap_send_disconn_req(chan->conn, chan, -err);
|
||||
return err;
|
||||
}
|
||||
|
||||
__clear_ack_timer(chan);
|
||||
}
|
||||
|
@ -3928,11 +3961,12 @@ static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u32 rx_cont
|
|||
l2cap_retransmit_frames(chan);
|
||||
}
|
||||
|
||||
__set_ack_timer(chan);
|
||||
|
||||
chan->num_acked = (chan->num_acked + 1) % num_to_ack;
|
||||
if (chan->num_acked == num_to_ack - 1)
|
||||
l2cap_send_ack(chan);
|
||||
else
|
||||
__set_ack_timer(chan);
|
||||
|
||||
return 0;
|
||||
|
||||
|
@ -4768,6 +4802,3 @@ void l2cap_exit(void)
|
|||
|
||||
module_param(disable_ertm, bool, 0644);
|
||||
MODULE_PARM_DESC(disable_ertm, "Disable enhanced retransmission mode");
|
||||
|
||||
module_param(enable_hs, bool, 0644);
|
||||
MODULE_PARM_DESC(enable_hs, "Enable High Speed");
|
||||
|
|
|
@ -626,8 +626,13 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch
|
|||
|
||||
chan->sec_level = sec.level;
|
||||
|
||||
if (!chan->conn)
|
||||
break;
|
||||
|
||||
conn = chan->conn;
|
||||
if (conn && chan->scid == L2CAP_CID_LE_DATA) {
|
||||
|
||||
/*change security for LE channels */
|
||||
if (chan->scid == L2CAP_CID_LE_DATA) {
|
||||
if (!conn->hcon->out) {
|
||||
err = -EINVAL;
|
||||
break;
|
||||
|
@ -635,9 +640,14 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch
|
|||
|
||||
if (smp_conn_security(conn, sec.level))
|
||||
break;
|
||||
|
||||
err = 0;
|
||||
sk->sk_state = BT_CONFIG;
|
||||
|
||||
/* or for ACL link, under defer_setup time */
|
||||
} else if (sk->sk_state == BT_CONNECT2 &&
|
||||
bt_sk(sk)->defer_setup) {
|
||||
err = l2cap_chan_check_security(chan);
|
||||
} else {
|
||||
err = -EINVAL;
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -232,6 +232,18 @@ static u8 check_enc_key_size(struct l2cap_conn *conn, __u8 max_key_size)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void smp_failure(struct l2cap_conn *conn, u8 reason, u8 send)
|
||||
{
|
||||
if (send)
|
||||
smp_send_cmd(conn, SMP_CMD_PAIRING_FAIL, sizeof(reason),
|
||||
&reason);
|
||||
|
||||
clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->hcon->pend);
|
||||
mgmt_auth_failed(conn->hcon->hdev, conn->dst, reason);
|
||||
del_timer(&conn->security_timer);
|
||||
smp_chan_destroy(conn);
|
||||
}
|
||||
|
||||
static void confirm_work(struct work_struct *work)
|
||||
{
|
||||
struct smp_chan *smp = container_of(work, struct smp_chan, confirm);
|
||||
|
@ -270,8 +282,7 @@ static void confirm_work(struct work_struct *work)
|
|||
return;
|
||||
|
||||
error:
|
||||
smp_send_cmd(conn, SMP_CMD_PAIRING_FAIL, sizeof(reason), &reason);
|
||||
smp_chan_destroy(conn);
|
||||
smp_failure(conn, reason, 1);
|
||||
}
|
||||
|
||||
static void random_work(struct work_struct *work)
|
||||
|
@ -354,8 +365,7 @@ static void random_work(struct work_struct *work)
|
|||
return;
|
||||
|
||||
error:
|
||||
smp_send_cmd(conn, SMP_CMD_PAIRING_FAIL, sizeof(reason), &reason);
|
||||
smp_chan_destroy(conn);
|
||||
smp_failure(conn, reason, 1);
|
||||
}
|
||||
|
||||
static struct smp_chan *smp_chan_create(struct l2cap_conn *conn)
|
||||
|
@ -379,7 +389,15 @@ static struct smp_chan *smp_chan_create(struct l2cap_conn *conn)
|
|||
|
||||
void smp_chan_destroy(struct l2cap_conn *conn)
|
||||
{
|
||||
kfree(conn->smp_chan);
|
||||
struct smp_chan *smp = conn->smp_chan;
|
||||
|
||||
clear_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->pend);
|
||||
|
||||
if (smp->tfm)
|
||||
crypto_free_blkcipher(smp->tfm);
|
||||
|
||||
kfree(smp);
|
||||
conn->smp_chan = NULL;
|
||||
hci_conn_put(conn->hcon);
|
||||
}
|
||||
|
||||
|
@ -647,6 +665,7 @@ int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb)
|
|||
break;
|
||||
|
||||
case SMP_CMD_PAIRING_FAIL:
|
||||
smp_failure(conn, skb->data[0], 0);
|
||||
reason = 0;
|
||||
err = -EPERM;
|
||||
break;
|
||||
|
@ -692,8 +711,7 @@ int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb)
|
|||
|
||||
done:
|
||||
if (reason)
|
||||
smp_send_cmd(conn, SMP_CMD_PAIRING_FAIL, sizeof(reason),
|
||||
&reason);
|
||||
smp_failure(conn, reason, 1);
|
||||
|
||||
kfree_skb(skb);
|
||||
return err;
|
||||
|
|
Loading…
Reference in a new issue