Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/padovan/bluetooth-next
This commit is contained in:
commit
5f779bbd47
|
@ -188,7 +188,7 @@ config BT_MRVL
|
||||||
The core driver to support Marvell Bluetooth devices.
|
The core driver to support Marvell Bluetooth devices.
|
||||||
|
|
||||||
This driver is required if you want to support
|
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
|
Say Y here to compile Marvell Bluetooth driver
|
||||||
into the kernel or say M to compile it as module.
|
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.
|
The driver for Marvell Bluetooth chipsets with SDIO interface.
|
||||||
|
|
||||||
This driver is required if you want to use Marvell Bluetooth
|
This driver is required if you want to use Marvell Bluetooth
|
||||||
devices with SDIO interface. Currently SD8688/SD8787 chipsets are
|
devices with SDIO interface. Currently SD8688/SD8787/SD8797
|
||||||
supported.
|
chipsets are supported.
|
||||||
|
|
||||||
Say Y here to compile support for Marvell BT-over-SDIO driver
|
Say Y here to compile support for Marvell BT-over-SDIO driver
|
||||||
into the kernel or say M to compile it as module.
|
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_1 = 0x01,
|
||||||
.io_port_2 = 0x02,
|
.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,
|
.cfg = 0x00,
|
||||||
.host_int_mask = 0x02,
|
.host_int_mask = 0x02,
|
||||||
.host_intstatus = 0x03,
|
.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 = {
|
static const struct btmrvl_sdio_device btmrvl_sdio_sd8787 = {
|
||||||
.helper = NULL,
|
.helper = NULL,
|
||||||
.firmware = "mrvl/sd8787_uapsta.bin",
|
.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,
|
.sd_blksz_fw_dl = 256,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -103,6 +110,9 @@ static const struct sdio_device_id btmrvl_sdio_ids[] = {
|
||||||
/* Marvell SD8787 Bluetooth device */
|
/* Marvell SD8787 Bluetooth device */
|
||||||
{ SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x911A),
|
{ SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x911A),
|
||||||
.driver_data = (unsigned long) &btmrvl_sdio_sd8787 },
|
.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 */
|
{ } /* Terminating entry */
|
||||||
};
|
};
|
||||||
|
@ -1076,3 +1086,4 @@ MODULE_LICENSE("GPL v2");
|
||||||
MODULE_FIRMWARE("sd8688_helper.bin");
|
MODULE_FIRMWARE("sd8688_helper.bin");
|
||||||
MODULE_FIRMWARE("sd8688.bin");
|
MODULE_FIRMWARE("sd8688.bin");
|
||||||
MODULE_FIRMWARE("mrvl/sd8787_uapsta.bin");
|
MODULE_FIRMWARE("mrvl/sd8787_uapsta.bin");
|
||||||
|
MODULE_FIRMWARE("mrvl/sd8797_uapsta.bin");
|
||||||
|
|
|
@ -785,9 +785,8 @@ skip_waking:
|
||||||
usb_mark_last_busy(data->udev);
|
usb_mark_last_busy(data->udev);
|
||||||
}
|
}
|
||||||
|
|
||||||
usb_free_urb(urb);
|
|
||||||
|
|
||||||
done:
|
done:
|
||||||
|
usb_free_urb(urb);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -41,6 +41,8 @@
|
||||||
|
|
||||||
#define VERSION "1.3"
|
#define VERSION "1.3"
|
||||||
|
|
||||||
|
static bool amp;
|
||||||
|
|
||||||
struct vhci_data {
|
struct vhci_data {
|
||||||
struct hci_dev *hdev;
|
struct hci_dev *hdev;
|
||||||
|
|
||||||
|
@ -239,6 +241,9 @@ static int vhci_open(struct inode *inode, struct file *file)
|
||||||
hdev->bus = HCI_VIRTUAL;
|
hdev->bus = HCI_VIRTUAL;
|
||||||
hdev->driver_data = data;
|
hdev->driver_data = data;
|
||||||
|
|
||||||
|
if (amp)
|
||||||
|
hdev->dev_type = HCI_AMP;
|
||||||
|
|
||||||
hdev->open = vhci_open_dev;
|
hdev->open = vhci_open_dev;
|
||||||
hdev->close = vhci_close_dev;
|
hdev->close = vhci_close_dev;
|
||||||
hdev->flush = vhci_flush;
|
hdev->flush = vhci_flush;
|
||||||
|
@ -303,6 +308,9 @@ static void __exit vhci_exit(void)
|
||||||
module_init(vhci_init);
|
module_init(vhci_init);
|
||||||
module_exit(vhci_exit);
|
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_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
|
||||||
MODULE_DESCRIPTION("Bluetooth virtual HCI driver ver " VERSION);
|
MODULE_DESCRIPTION("Bluetooth virtual HCI driver ver " VERSION);
|
||||||
MODULE_VERSION(VERSION);
|
MODULE_VERSION(VERSION);
|
||||||
|
|
|
@ -36,6 +36,11 @@
|
||||||
#define PF_BLUETOOTH AF_BLUETOOTH
|
#define PF_BLUETOOTH AF_BLUETOOTH
|
||||||
#endif
|
#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 */
|
/* Reserv for core and drivers use */
|
||||||
#define BT_SKB_RESERVE 8
|
#define BT_SKB_RESERVE 8
|
||||||
|
|
||||||
|
|
|
@ -88,6 +88,14 @@ enum {
|
||||||
HCI_RESET,
|
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 */
|
/* HCI ioctl defines */
|
||||||
#define HCIDEVUP _IOW('H', 201, int)
|
#define HCIDEVUP _IOW('H', 201, int)
|
||||||
#define HCIDEVDOWN _IOW('H', 202, 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_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
|
#define HCI_OP_REMOTE_OOB_DATA_REPLY 0x0430
|
||||||
struct hci_cp_remote_oob_data_reply {
|
struct hci_cp_remote_oob_data_reply {
|
||||||
bdaddr_t bdaddr;
|
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_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
|
#define HCI_OP_WRITE_LE_HOST_SUPPORTED 0x0c6d
|
||||||
struct hci_cp_write_le_host_supported {
|
struct hci_cp_write_le_host_supported {
|
||||||
__u8 le;
|
__u8 le;
|
||||||
|
@ -760,6 +782,15 @@ struct hci_rp_le_read_buffer_size {
|
||||||
__u8 le_max_pkt;
|
__u8 le_max_pkt;
|
||||||
} __packed;
|
} __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
|
#define HCI_OP_LE_SET_SCAN_ENABLE 0x200c
|
||||||
struct hci_cp_le_set_scan_enable {
|
struct hci_cp_le_set_scan_enable {
|
||||||
__u8 enable;
|
__u8 enable;
|
||||||
|
@ -1076,6 +1107,11 @@ struct hci_ev_user_confirm_req {
|
||||||
__le32 passkey;
|
__le32 passkey;
|
||||||
} __packed;
|
} __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
|
#define HCI_EV_REMOTE_OOB_DATA_REQUEST 0x35
|
||||||
struct hci_ev_remote_oob_data_request {
|
struct hci_ev_remote_oob_data_request {
|
||||||
bdaddr_t bdaddr;
|
bdaddr_t bdaddr;
|
||||||
|
@ -1331,4 +1367,6 @@ struct hci_inquiry_req {
|
||||||
};
|
};
|
||||||
#define IREQ_CACHE_FLUSH 0x0001
|
#define IREQ_CACHE_FLUSH 0x0001
|
||||||
|
|
||||||
|
extern int enable_hs;
|
||||||
|
|
||||||
#endif /* __HCI_H */
|
#endif /* __HCI_H */
|
||||||
|
|
|
@ -170,6 +170,8 @@ struct hci_dev {
|
||||||
__u32 amp_max_flush_to;
|
__u32 amp_max_flush_to;
|
||||||
__u32 amp_be_flush_to;
|
__u32 amp_be_flush_to;
|
||||||
|
|
||||||
|
__u8 flow_ctl_mode;
|
||||||
|
|
||||||
unsigned int auto_accept_delay;
|
unsigned int auto_accept_delay;
|
||||||
|
|
||||||
unsigned long quirks;
|
unsigned long quirks;
|
||||||
|
@ -250,6 +252,8 @@ struct hci_dev {
|
||||||
|
|
||||||
struct module *owner;
|
struct module *owner;
|
||||||
|
|
||||||
|
unsigned long dev_flags;
|
||||||
|
|
||||||
int (*open)(struct hci_dev *hdev);
|
int (*open)(struct hci_dev *hdev);
|
||||||
int (*close)(struct hci_dev *hdev);
|
int (*close)(struct hci_dev *hdev);
|
||||||
int (*flush)(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_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status);
|
||||||
int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
|
int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
|
||||||
u8 persistent);
|
u8 persistent);
|
||||||
int mgmt_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type);
|
int mgmt_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
|
||||||
int mgmt_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type);
|
u8 addr_type);
|
||||||
int mgmt_disconnect_failed(struct hci_dev *hdev);
|
int mgmt_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
|
||||||
int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type,
|
u8 addr_type);
|
||||||
u8 status);
|
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_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure);
|
||||||
int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
|
int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
|
||||||
u8 status);
|
u8 status);
|
||||||
|
@ -933,14 +939,20 @@ int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
|
||||||
u8 status);
|
u8 status);
|
||||||
int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev,
|
int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev,
|
||||||
bdaddr_t *bdaddr, u8 status);
|
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_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_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,
|
int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
|
||||||
u8 *randomizer, u8 status);
|
u8 *randomizer, u8 status);
|
||||||
int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type,
|
int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
|
||||||
u8 *dev_class, s8 rssi, u8 *eir);
|
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_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_discovering(struct hci_dev *hdev, u8 discovering);
|
||||||
int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr);
|
int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr);
|
||||||
int mgmt_device_unblocked(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 disable_ertm;
|
||||||
extern int enable_hs;
|
|
||||||
|
|
||||||
int l2cap_init_sockets(void);
|
int l2cap_init_sockets(void);
|
||||||
void l2cap_cleanup_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,
|
int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len,
|
||||||
u32 priority);
|
u32 priority);
|
||||||
void l2cap_chan_busy(struct l2cap_chan *chan, int busy);
|
void l2cap_chan_busy(struct l2cap_chan *chan, int busy);
|
||||||
|
int l2cap_chan_check_security(struct l2cap_chan *chan);
|
||||||
|
|
||||||
#endif /* __L2CAP_H */
|
#endif /* __L2CAP_H */
|
||||||
|
|
|
@ -23,6 +23,23 @@
|
||||||
|
|
||||||
#define MGMT_INDEX_NONE 0xFFFF
|
#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 {
|
struct mgmt_hdr {
|
||||||
__le16 opcode;
|
__le16 opcode;
|
||||||
__le16 index;
|
__le16 index;
|
||||||
|
@ -119,6 +136,10 @@ struct mgmt_cp_remove_keys {
|
||||||
bdaddr_t bdaddr;
|
bdaddr_t bdaddr;
|
||||||
__u8 disconnect;
|
__u8 disconnect;
|
||||||
} __packed;
|
} __packed;
|
||||||
|
struct mgmt_rp_remove_keys {
|
||||||
|
bdaddr_t bdaddr;
|
||||||
|
__u8 status;
|
||||||
|
};
|
||||||
|
|
||||||
#define MGMT_OP_DISCONNECT 0x000F
|
#define MGMT_OP_DISCONNECT 0x000F
|
||||||
struct mgmt_cp_disconnect {
|
struct mgmt_cp_disconnect {
|
||||||
|
@ -126,11 +147,12 @@ struct mgmt_cp_disconnect {
|
||||||
} __packed;
|
} __packed;
|
||||||
struct mgmt_rp_disconnect {
|
struct mgmt_rp_disconnect {
|
||||||
bdaddr_t bdaddr;
|
bdaddr_t bdaddr;
|
||||||
|
__u8 status;
|
||||||
} __packed;
|
} __packed;
|
||||||
|
|
||||||
#define MGMT_ADDR_BREDR 0x00
|
#define MGMT_ADDR_BREDR 0x00
|
||||||
#define MGMT_ADDR_LE 0x01
|
#define MGMT_ADDR_LE_PUBLIC 0x01
|
||||||
#define MGMT_ADDR_BREDR_LE 0x02
|
#define MGMT_ADDR_LE_RANDOM 0x02
|
||||||
#define MGMT_ADDR_INVALID 0xff
|
#define MGMT_ADDR_INVALID 0xff
|
||||||
|
|
||||||
struct mgmt_addr_info {
|
struct mgmt_addr_info {
|
||||||
|
@ -167,11 +189,11 @@ struct mgmt_cp_set_io_capability {
|
||||||
|
|
||||||
#define MGMT_OP_PAIR_DEVICE 0x0014
|
#define MGMT_OP_PAIR_DEVICE 0x0014
|
||||||
struct mgmt_cp_pair_device {
|
struct mgmt_cp_pair_device {
|
||||||
bdaddr_t bdaddr;
|
struct mgmt_addr_info addr;
|
||||||
__u8 io_cap;
|
__u8 io_cap;
|
||||||
} __packed;
|
} __packed;
|
||||||
struct mgmt_rp_pair_device {
|
struct mgmt_rp_pair_device {
|
||||||
bdaddr_t bdaddr;
|
struct mgmt_addr_info addr;
|
||||||
__u8 status;
|
__u8 status;
|
||||||
} __packed;
|
} __packed;
|
||||||
|
|
||||||
|
@ -210,6 +232,9 @@ struct mgmt_cp_remove_remote_oob_data {
|
||||||
} __packed;
|
} __packed;
|
||||||
|
|
||||||
#define MGMT_OP_START_DISCOVERY 0x001B
|
#define MGMT_OP_START_DISCOVERY 0x001B
|
||||||
|
struct mgmt_cp_start_discovery {
|
||||||
|
__u8 type;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
#define MGMT_OP_STOP_DISCOVERY 0x001C
|
#define MGMT_OP_STOP_DISCOVERY 0x001C
|
||||||
|
|
||||||
|
@ -228,6 +253,17 @@ struct mgmt_cp_set_fast_connectable {
|
||||||
__u8 enable;
|
__u8 enable;
|
||||||
} __packed;
|
} __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
|
#define MGMT_EV_CMD_COMPLETE 0x0001
|
||||||
struct mgmt_ev_cmd_complete {
|
struct mgmt_ev_cmd_complete {
|
||||||
__le16 opcode;
|
__le16 opcode;
|
||||||
|
@ -322,3 +358,8 @@ struct mgmt_ev_device_blocked {
|
||||||
struct mgmt_ev_device_unblocked {
|
struct mgmt_ev_device_unblocked {
|
||||||
bdaddr_t bdaddr;
|
bdaddr_t bdaddr;
|
||||||
} __packed;
|
} __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)
|
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);
|
list_add(&s->list, &bnep_session_list);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __bnep_unlink_session(struct bnep_session *s)
|
static void __bnep_unlink_session(struct bnep_session *s)
|
||||||
{
|
{
|
||||||
list_del(&s->list);
|
list_del(&s->list);
|
||||||
module_put(THIS_MODULE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int bnep_send(struct bnep_session *s, void *data, size_t len)
|
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);
|
up_write(&bnep_session_sem);
|
||||||
free_netdev(dev);
|
free_netdev(dev);
|
||||||
|
module_put_and_exit(0);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -614,9 +610,11 @@ int bnep_add_connection(struct bnep_connadd_req *req, struct socket *sock)
|
||||||
|
|
||||||
__bnep_link_session(s);
|
__bnep_link_session(s);
|
||||||
|
|
||||||
|
__module_get(THIS_MODULE);
|
||||||
s->task = kthread_run(bnep_session, s, "kbnepd %s", dev->name);
|
s->task = kthread_run(bnep_session, s, "kbnepd %s", dev->name);
|
||||||
if (IS_ERR(s->task)) {
|
if (IS_ERR(s->task)) {
|
||||||
/* Session thread start failed, gotta cleanup. */
|
/* Session thread start failed, gotta cleanup. */
|
||||||
|
module_put(THIS_MODULE);
|
||||||
unregister_netdev(dev);
|
unregister_netdev(dev);
|
||||||
__bnep_unlink_session(s);
|
__bnep_unlink_session(s);
|
||||||
err = PTR_ERR(s->task);
|
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)
|
static void __cmtp_link_session(struct cmtp_session *session)
|
||||||
{
|
{
|
||||||
__module_get(THIS_MODULE);
|
|
||||||
list_add(&session->list, &cmtp_session_list);
|
list_add(&session->list, &cmtp_session_list);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __cmtp_unlink_session(struct cmtp_session *session)
|
static void __cmtp_unlink_session(struct cmtp_session *session)
|
||||||
{
|
{
|
||||||
list_del(&session->list);
|
list_del(&session->list);
|
||||||
module_put(THIS_MODULE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __cmtp_copy_session(struct cmtp_session *session, struct cmtp_conninfo *ci)
|
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);
|
up_write(&cmtp_session_sem);
|
||||||
|
|
||||||
kfree(session);
|
kfree(session);
|
||||||
|
module_put_and_exit(0);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -374,9 +373,11 @@ int cmtp_add_connection(struct cmtp_connadd_req *req, struct socket *sock)
|
||||||
|
|
||||||
__cmtp_link_session(session);
|
__cmtp_link_session(session);
|
||||||
|
|
||||||
|
__module_get(THIS_MODULE);
|
||||||
session->task = kthread_run(cmtp_session, session, "kcmtpd_ctr_%d",
|
session->task = kthread_run(cmtp_session, session, "kcmtpd_ctr_%d",
|
||||||
session->num);
|
session->num);
|
||||||
if (IS_ERR(session->task)) {
|
if (IS_ERR(session->task)) {
|
||||||
|
module_put(THIS_MODULE);
|
||||||
err = PTR_ERR(session->task);
|
err = PTR_ERR(session->task);
|
||||||
goto unlink;
|
goto unlink;
|
||||||
}
|
}
|
||||||
|
|
|
@ -123,7 +123,7 @@ static void hci_acl_connect_cancel(struct hci_conn *conn)
|
||||||
|
|
||||||
BT_DBG("%p", conn);
|
BT_DBG("%p", conn);
|
||||||
|
|
||||||
if (conn->hdev->hci_ver < 2)
|
if (conn->hdev->hci_ver < BLUETOOTH_VER_1_2)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
bacpy(&cp.bdaddr, &conn->dst);
|
bacpy(&cp.bdaddr, &conn->dst);
|
||||||
|
|
|
@ -54,6 +54,8 @@
|
||||||
|
|
||||||
#define AUTO_OFF_TIMEOUT 2000
|
#define AUTO_OFF_TIMEOUT 2000
|
||||||
|
|
||||||
|
int enable_hs;
|
||||||
|
|
||||||
static void hci_cmd_task(unsigned long arg);
|
static void hci_cmd_task(unsigned long arg);
|
||||||
static void hci_rx_task(unsigned long arg);
|
static void hci_rx_task(unsigned long arg);
|
||||||
static void hci_tx_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.) */
|
/* Read Buffer Size (ACL mtu, max pkt, etc.) */
|
||||||
hci_send_cmd(hdev, HCI_OP_READ_BUFFER_SIZE, 0, NULL);
|
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 */
|
/* Read BD Address */
|
||||||
hci_send_cmd(hdev, HCI_OP_READ_BD_ADDR, 0, NULL);
|
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))
|
if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
|
||||||
set_bit(HCI_RAW, &hdev->flags);
|
set_bit(HCI_RAW, &hdev->flags);
|
||||||
|
|
||||||
/* Treat all non BR/EDR controllers as raw devices for now */
|
/* Treat all non BR/EDR controllers as raw devices if
|
||||||
if (hdev->dev_type != HCI_BREDR)
|
enable_hs is not set */
|
||||||
|
if (hdev->dev_type != HCI_BREDR && !enable_hs)
|
||||||
set_bit(HCI_RAW, &hdev->flags);
|
set_bit(HCI_RAW, &hdev->flags);
|
||||||
|
|
||||||
if (hdev->open(hdev)) {
|
if (hdev->open(hdev)) {
|
||||||
|
@ -1336,14 +1327,12 @@ int hci_blacklist_del(struct hci_dev *hdev, bdaddr_t *bdaddr)
|
||||||
{
|
{
|
||||||
struct bdaddr_list *entry;
|
struct bdaddr_list *entry;
|
||||||
|
|
||||||
if (bacmp(bdaddr, BDADDR_ANY) == 0) {
|
if (bacmp(bdaddr, BDADDR_ANY) == 0)
|
||||||
return hci_blacklist_clear(hdev);
|
return hci_blacklist_clear(hdev);
|
||||||
}
|
|
||||||
|
|
||||||
entry = hci_blacklist_lookup(hdev, bdaddr);
|
entry = hci_blacklist_lookup(hdev, bdaddr);
|
||||||
if (!entry) {
|
if (!entry)
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
}
|
|
||||||
|
|
||||||
list_del(&entry->list);
|
list_del(&entry->list);
|
||||||
kfree(entry);
|
kfree(entry);
|
||||||
|
@ -1451,12 +1440,13 @@ int hci_register_dev(struct hci_dev *hdev)
|
||||||
|
|
||||||
sprintf(hdev->name, "hci%d", id);
|
sprintf(hdev->name, "hci%d", id);
|
||||||
hdev->id = id;
|
hdev->id = id;
|
||||||
list_add(&hdev->list, head);
|
list_add_tail(&hdev->list, head);
|
||||||
|
|
||||||
atomic_set(&hdev->refcnt, 1);
|
atomic_set(&hdev->refcnt, 1);
|
||||||
spin_lock_init(&hdev->lock);
|
spin_lock_init(&hdev->lock);
|
||||||
|
|
||||||
hdev->flags = 0;
|
hdev->flags = 0;
|
||||||
|
hdev->dev_flags = 0;
|
||||||
hdev->pkt_type = (HCI_DM1 | HCI_DH1 | HCI_HV1);
|
hdev->pkt_type = (HCI_DM1 | HCI_DH1 | HCI_HV1);
|
||||||
hdev->esco_type = (ESCO_HV1);
|
hdev->esco_type = (ESCO_HV1);
|
||||||
hdev->link_mode = (HCI_LM_ACCEPT);
|
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);
|
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);
|
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;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
clear_bit(HCI_INQUIRY, &hdev->flags);
|
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);
|
clear_bit(HCI_RESET, &hdev->flags);
|
||||||
|
|
||||||
hci_req_complete(hdev, HCI_OP_RESET, status);
|
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)
|
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
|
/* CSR 1.1 dongles does not accept any bitfield so don't try to set
|
||||||
* any event mask for pre 1.2 devices */
|
* any event mask for pre 1.2 devices */
|
||||||
if (hdev->lmp_ver <= 1)
|
if (hdev->hci_ver < BLUETOOTH_VER_1_2)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
events[4] |= 0x01; /* Flow Specification Complete */
|
events[4] |= 0x01; /* Flow Specification Complete */
|
||||||
|
@ -558,7 +564,7 @@ static void hci_setup(struct hci_dev *hdev)
|
||||||
{
|
{
|
||||||
hci_setup_event_mask(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);
|
hci_send_cmd(hdev, HCI_OP_READ_LOCAL_COMMANDS, 0, NULL);
|
||||||
|
|
||||||
if (hdev->features[6] & LMP_SIMPLE_PAIR) {
|
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);
|
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)
|
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;
|
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);
|
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,
|
static void hci_cc_read_local_oob_data_reply(struct hci_dev *hdev,
|
||||||
struct sk_buff *skb)
|
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);
|
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,
|
static void hci_cc_le_set_scan_enable(struct hci_dev *hdev,
|
||||||
struct sk_buff *skb)
|
struct sk_buff *skb)
|
||||||
{
|
{
|
||||||
|
@ -956,12 +1015,16 @@ static void hci_cc_le_set_scan_enable(struct hci_dev *hdev,
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (cp->enable == 0x01) {
|
if (cp->enable == 0x01) {
|
||||||
|
set_bit(HCI_LE_SCAN, &hdev->dev_flags);
|
||||||
|
|
||||||
del_timer(&hdev->adv_timer);
|
del_timer(&hdev->adv_timer);
|
||||||
|
|
||||||
hci_dev_lock(hdev);
|
hci_dev_lock(hdev);
|
||||||
hci_adv_entries_clear(hdev);
|
hci_adv_entries_clear(hdev);
|
||||||
hci_dev_unlock(hdev);
|
hci_dev_unlock(hdev);
|
||||||
} else if (cp->enable == 0x00) {
|
} else if (cp->enable == 0x00) {
|
||||||
|
clear_bit(HCI_LE_SCAN, &hdev->dev_flags);
|
||||||
|
|
||||||
mod_timer(&hdev->adv_timer, jiffies + ADV_CLEAR_TIMEOUT);
|
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_conn_check_pending(hdev);
|
||||||
hci_dev_lock(hdev);
|
hci_dev_lock(hdev);
|
||||||
if (test_bit(HCI_MGMT, &hdev->flags))
|
if (test_bit(HCI_MGMT, &hdev->flags))
|
||||||
mgmt_inquiry_failed(hdev, status);
|
mgmt_start_discovery_failed(hdev, status);
|
||||||
hci_dev_unlock(hdev);
|
hci_dev_unlock(hdev);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1437,7 +1500,7 @@ static inline void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *
|
||||||
data.rssi = 0x00;
|
data.rssi = 0x00;
|
||||||
data.ssp_mode = 0x00;
|
data.ssp_mode = 0x00;
|
||||||
hci_inquiry_cache_update(hdev, &data);
|
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);
|
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;
|
conn->state = BT_CONFIG;
|
||||||
hci_conn_hold(conn);
|
hci_conn_hold(conn);
|
||||||
conn->disc_timeout = HCI_DISCONN_TIMEOUT;
|
conn->disc_timeout = HCI_DISCONN_TIMEOUT;
|
||||||
mgmt_connected(hdev, &ev->bdaddr, conn->type);
|
mgmt_connected(hdev, &ev->bdaddr, conn->type,
|
||||||
|
conn->dst_type);
|
||||||
} else
|
} else
|
||||||
conn->state = BT_CONNECTED;
|
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 */
|
/* 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;
|
struct hci_cp_change_conn_ptype cp;
|
||||||
cp.handle = ev->handle;
|
cp.handle = ev->handle;
|
||||||
cp.pkt_type = cpu_to_le16(conn->pkt_type);
|
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;
|
conn->state = BT_CLOSED;
|
||||||
if (conn->type == ACL_LINK)
|
if (conn->type == ACL_LINK)
|
||||||
mgmt_connect_failed(hdev, &ev->bdaddr, conn->type,
|
mgmt_connect_failed(hdev, &ev->bdaddr, conn->type,
|
||||||
ev->status);
|
conn->dst_type, ev->status);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (conn->type == ACL_LINK)
|
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);
|
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);
|
hci_dev_lock(hdev);
|
||||||
|
|
||||||
conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle));
|
conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle));
|
||||||
if (!conn)
|
if (!conn)
|
||||||
goto unlock;
|
goto unlock;
|
||||||
|
|
||||||
conn->state = BT_CLOSED;
|
if (ev->status == 0)
|
||||||
|
conn->state = BT_CLOSED;
|
||||||
|
|
||||||
if (conn->type == ACL_LINK || conn->type == LE_LINK)
|
if (conn->type == ACL_LINK || conn->type == LE_LINK) {
|
||||||
mgmt_disconnected(hdev, &conn->dst, conn->type);
|
if (ev->status != 0)
|
||||||
|
mgmt_disconnect_failed(hdev, &conn->dst, ev->status);
|
||||||
|
else
|
||||||
|
mgmt_disconnected(hdev, &conn->dst, conn->type,
|
||||||
|
conn->dst_type);
|
||||||
|
}
|
||||||
|
|
||||||
hci_proto_disconn_cfm(conn, ev->reason);
|
if (ev->status == 0) {
|
||||||
hci_conn_del(conn);
|
hci_proto_disconn_cfm(conn, ev->reason);
|
||||||
|
hci_conn_del(conn);
|
||||||
|
}
|
||||||
|
|
||||||
unlock:
|
unlock:
|
||||||
hci_dev_unlock(hdev);
|
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);
|
hci_cc_write_ca_timeout(hdev, skb);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case HCI_OP_READ_FLOW_CONTROL_MODE:
|
||||||
|
hci_cc_read_flow_control_mode(hdev, skb);
|
||||||
|
break;
|
||||||
|
|
||||||
case HCI_OP_READ_LOCAL_AMP_INFO:
|
case HCI_OP_READ_LOCAL_AMP_INFO:
|
||||||
hci_cc_read_local_amp_info(hdev, skb);
|
hci_cc_read_local_amp_info(hdev, skb);
|
||||||
break;
|
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);
|
hci_cc_user_confirm_neg_reply(hdev, skb);
|
||||||
break;
|
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:
|
case HCI_OP_LE_SET_SCAN_ENABLE:
|
||||||
hci_cc_le_set_scan_enable(hdev, skb);
|
hci_cc_le_set_scan_enable(hdev, skb);
|
||||||
break;
|
break;
|
||||||
|
@ -2096,7 +2176,7 @@ static inline void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||||
|
|
||||||
case HCI_OP_DISCONNECT:
|
case HCI_OP_DISCONNECT:
|
||||||
if (ev->status != 0)
|
if (ev->status != 0)
|
||||||
mgmt_disconnect_failed(hdev);
|
mgmt_disconnect_failed(hdev, NULL, ev->status);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case HCI_OP_LE_CREATE_CONN:
|
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.rssi = info->rssi;
|
||||||
data.ssp_mode = 0x00;
|
data.ssp_mode = 0x00;
|
||||||
hci_inquiry_cache_update(hdev, &data);
|
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->dev_class, info->rssi,
|
||||||
NULL);
|
NULL);
|
||||||
}
|
}
|
||||||
|
@ -2461,7 +2541,7 @@ static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct
|
||||||
data.rssi = info->rssi;
|
data.rssi = info->rssi;
|
||||||
data.ssp_mode = 0x00;
|
data.ssp_mode = 0x00;
|
||||||
hci_inquiry_cache_update(hdev, &data);
|
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->dev_class, info->rssi,
|
||||||
NULL);
|
NULL);
|
||||||
}
|
}
|
||||||
|
@ -2604,7 +2684,7 @@ static inline void hci_extended_inquiry_result_evt(struct hci_dev *hdev, struct
|
||||||
data.rssi = info->rssi;
|
data.rssi = info->rssi;
|
||||||
data.ssp_mode = 0x01;
|
data.ssp_mode = 0x01;
|
||||||
hci_inquiry_cache_update(hdev, &data);
|
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);
|
info->dev_class, info->rssi, info->data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2768,6 +2848,21 @@ unlock:
|
||||||
hci_dev_unlock(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)
|
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;
|
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) {
|
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);
|
hci_proto_connect_cfm(conn, ev->status);
|
||||||
conn->state = BT_CLOSED;
|
conn->state = BT_CLOSED;
|
||||||
hci_conn_del(conn);
|
hci_conn_del(conn);
|
||||||
goto unlock;
|
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->sec_level = BT_SECURITY_LOW;
|
||||||
conn->handle = __le16_to_cpu(ev->handle);
|
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);
|
hci_user_confirm_request_evt(hdev, skb);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case HCI_EV_USER_PASSKEY_REQUEST:
|
||||||
|
hci_user_passkey_request_evt(hdev, skb);
|
||||||
|
break;
|
||||||
|
|
||||||
case HCI_EV_SIMPLE_PAIR_COMPLETE:
|
case HCI_EV_SIMPLE_PAIR_COMPLETE:
|
||||||
hci_simple_pair_complete_evt(hdev, skb);
|
hci_simple_pair_complete_evt(hdev, skb);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -57,7 +57,6 @@
|
||||||
#include <net/bluetooth/smp.h>
|
#include <net/bluetooth/smp.h>
|
||||||
|
|
||||||
int disable_ertm;
|
int disable_ertm;
|
||||||
int enable_hs;
|
|
||||||
|
|
||||||
static u32 l2cap_feat_mask = L2CAP_FEAT_FIXED_CHAN;
|
static u32 l2cap_feat_mask = L2CAP_FEAT_FIXED_CHAN;
|
||||||
static u8 l2cap_fixed_chan[8] = { L2CAP_FC_L2CAP, };
|
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 c;
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct l2cap_chan *__l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16 cid)
|
static struct l2cap_chan *__l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16 cid)
|
||||||
|
@ -154,12 +152,9 @@ static struct l2cap_chan *__l2cap_global_chan_by_addr(__le16 psm, bdaddr_t *src)
|
||||||
|
|
||||||
list_for_each_entry(c, &chan_list, global_l) {
|
list_for_each_entry(c, &chan_list, global_l) {
|
||||||
if (c->sport == psm && !bacmp(&bt_sk(c->sk)->src, src))
|
if (c->sport == psm && !bacmp(&bt_sk(c->sk)->src, src))
|
||||||
goto found;
|
return c;
|
||||||
}
|
}
|
||||||
|
return NULL;
|
||||||
c = NULL;
|
|
||||||
found:
|
|
||||||
return c;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int l2cap_add_psm(struct l2cap_chan *chan, bdaddr_t *src, __le16 psm)
|
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);
|
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)
|
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->state = state;
|
||||||
chan->ops->state_change(chan->data, 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 */
|
/* 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;
|
struct l2cap_conn *conn = chan->conn;
|
||||||
__u8 auth_type;
|
__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))
|
if (!(conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (l2cap_check_security(chan) &&
|
if (l2cap_chan_check_security(chan) &&
|
||||||
__l2cap_no_conn_pending(chan)) {
|
__l2cap_no_conn_pending(chan)) {
|
||||||
struct l2cap_conn_req req;
|
struct l2cap_conn_req req;
|
||||||
req.scid = cpu_to_le16(chan->scid);
|
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) {
|
if (chan->state == BT_CONNECT) {
|
||||||
struct l2cap_conn_req req;
|
struct l2cap_conn_req req;
|
||||||
|
|
||||||
if (!l2cap_check_security(chan) ||
|
if (!l2cap_chan_check_security(chan) ||
|
||||||
!__l2cap_no_conn_pending(chan)) {
|
!__l2cap_no_conn_pending(chan)) {
|
||||||
bh_unlock_sock(sk);
|
bh_unlock_sock(sk);
|
||||||
continue;
|
continue;
|
||||||
|
@ -787,7 +811,7 @@ static void l2cap_conn_start(struct l2cap_conn *conn)
|
||||||
rsp.scid = cpu_to_le16(chan->dcid);
|
rsp.scid = cpu_to_le16(chan->dcid);
|
||||||
rsp.dcid = cpu_to_le16(chan->scid);
|
rsp.dcid = cpu_to_le16(chan->scid);
|
||||||
|
|
||||||
if (l2cap_check_security(chan)) {
|
if (l2cap_chan_check_security(chan)) {
|
||||||
if (bt_sk(sk)->defer_setup) {
|
if (bt_sk(sk)->defer_setup) {
|
||||||
struct sock *parent = bt_sk(sk)->parent;
|
struct sock *parent = bt_sk(sk)->parent;
|
||||||
rsp.result = cpu_to_le16(L2CAP_CR_PEND);
|
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 (hcon->state == BT_CONNECTED) {
|
||||||
if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
|
if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
|
||||||
__clear_chan_timer(chan);
|
__clear_chan_timer(chan);
|
||||||
if (l2cap_check_security(chan))
|
if (l2cap_chan_check_security(chan))
|
||||||
l2cap_state_change(chan, BT_CONNECTED);
|
l2cap_state_change(chan, BT_CONNECTED);
|
||||||
} else
|
} else
|
||||||
l2cap_do_start(chan);
|
l2cap_do_start(chan);
|
||||||
|
@ -1318,14 +1342,12 @@ static void l2cap_retransmit_one_frame(struct l2cap_chan *chan, u16 tx_seq)
|
||||||
if (!skb)
|
if (!skb)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
do {
|
while (bt_cb(skb)->tx_seq != tx_seq) {
|
||||||
if (bt_cb(skb)->tx_seq == tx_seq)
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (skb_queue_is_last(&chan->tx_q, skb))
|
if (skb_queue_is_last(&chan->tx_q, skb))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
} while ((skb = skb_queue_next(&chan->tx_q, skb)));
|
skb = skb_queue_next(&chan->tx_q, skb);
|
||||||
|
}
|
||||||
|
|
||||||
if (chan->remote_max_tx &&
|
if (chan->remote_max_tx &&
|
||||||
bt_cb(skb)->retries == chan->remote_max_tx) {
|
bt_cb(skb)->retries == chan->remote_max_tx) {
|
||||||
|
@ -1906,7 +1928,7 @@ static void l2cap_add_opt_efs(void **ptr, struct l2cap_chan *chan)
|
||||||
{
|
{
|
||||||
struct l2cap_conf_efs efs;
|
struct l2cap_conf_efs efs;
|
||||||
|
|
||||||
switch(chan->mode) {
|
switch (chan->mode) {
|
||||||
case L2CAP_MODE_ERTM:
|
case L2CAP_MODE_ERTM:
|
||||||
efs.id = chan->local_id;
|
efs.id = chan->local_id;
|
||||||
efs.stype = chan->local_stype;
|
efs.stype = chan->local_stype;
|
||||||
|
@ -2606,7 +2628,7 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd
|
||||||
chan->ident = cmd->ident;
|
chan->ident = cmd->ident;
|
||||||
|
|
||||||
if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE) {
|
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) {
|
if (bt_sk(sk)->defer_setup) {
|
||||||
l2cap_state_change(chan, BT_CONNECT2);
|
l2cap_state_change(chan, BT_CONNECT2);
|
||||||
result = L2CAP_CR_PEND;
|
result = L2CAP_CR_PEND;
|
||||||
|
@ -3019,7 +3041,7 @@ static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, struct l2cap_cmd
|
||||||
|
|
||||||
/* don't delete l2cap channel if sk is owned by user */
|
/* don't delete l2cap channel if sk is owned by user */
|
||||||
if (sock_owned_by_user(sk)) {
|
if (sock_owned_by_user(sk)) {
|
||||||
l2cap_state_change(chan,BT_DISCONN);
|
l2cap_state_change(chan, BT_DISCONN);
|
||||||
__clear_chan_timer(chan);
|
__clear_chan_timer(chan);
|
||||||
__set_chan_timer(chan, L2CAP_DISC_TIMEOUT);
|
__set_chan_timer(chan, L2CAP_DISC_TIMEOUT);
|
||||||
bh_unlock_sock(sk);
|
bh_unlock_sock(sk);
|
||||||
|
@ -3562,14 +3584,10 @@ static int l2cap_add_to_srej_queue(struct l2cap_chan *chan, struct sk_buff *skb,
|
||||||
bt_cb(skb)->sar = sar;
|
bt_cb(skb)->sar = sar;
|
||||||
|
|
||||||
next_skb = skb_peek(&chan->srej_q);
|
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);
|
tx_seq_offset = __seq_offset(chan, tx_seq, chan->buffer_seq);
|
||||||
|
|
||||||
do {
|
while (next_skb) {
|
||||||
if (bt_cb(next_skb)->tx_seq == tx_seq)
|
if (bt_cb(next_skb)->tx_seq == tx_seq)
|
||||||
return -EINVAL;
|
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))
|
if (skb_queue_is_last(&chan->srej_q, next_skb))
|
||||||
break;
|
next_skb = NULL;
|
||||||
|
else
|
||||||
} while ((next_skb = skb_queue_next(&chan->srej_q, next_skb)));
|
next_skb = skb_queue_next(&chan->srej_q, next_skb);
|
||||||
|
}
|
||||||
|
|
||||||
__skb_queue_tail(&chan->srej_q, 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;
|
struct srej_list *new;
|
||||||
u32 control;
|
u32 control;
|
||||||
|
@ -3799,6 +3818,9 @@ static void l2cap_send_srejframe(struct l2cap_chan *chan, u16 tx_seq)
|
||||||
l2cap_send_sframe(chan, control);
|
l2cap_send_sframe(chan, control);
|
||||||
|
|
||||||
new = kzalloc(sizeof(struct srej_list), GFP_ATOMIC);
|
new = kzalloc(sizeof(struct srej_list), GFP_ATOMIC);
|
||||||
|
if (!new)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
new->tx_seq = chan->expected_tx_seq;
|
new->tx_seq = chan->expected_tx_seq;
|
||||||
|
|
||||||
chan->expected_tx_seq = __next_seq(chan, 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);
|
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)
|
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;
|
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 {
|
} else {
|
||||||
expected_tx_seq_offset = __seq_offset(chan,
|
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);
|
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);
|
__clear_ack_timer(chan);
|
||||||
}
|
}
|
||||||
|
@ -3928,11 +3961,12 @@ expected:
|
||||||
l2cap_retransmit_frames(chan);
|
l2cap_retransmit_frames(chan);
|
||||||
}
|
}
|
||||||
|
|
||||||
__set_ack_timer(chan);
|
|
||||||
|
|
||||||
chan->num_acked = (chan->num_acked + 1) % num_to_ack;
|
chan->num_acked = (chan->num_acked + 1) % num_to_ack;
|
||||||
if (chan->num_acked == num_to_ack - 1)
|
if (chan->num_acked == num_to_ack - 1)
|
||||||
l2cap_send_ack(chan);
|
l2cap_send_ack(chan);
|
||||||
|
else
|
||||||
|
__set_ack_timer(chan);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
@ -4768,6 +4802,3 @@ void l2cap_exit(void)
|
||||||
|
|
||||||
module_param(disable_ertm, bool, 0644);
|
module_param(disable_ertm, bool, 0644);
|
||||||
MODULE_PARM_DESC(disable_ertm, "Disable enhanced retransmission mode");
|
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;
|
chan->sec_level = sec.level;
|
||||||
|
|
||||||
|
if (!chan->conn)
|
||||||
|
break;
|
||||||
|
|
||||||
conn = chan->conn;
|
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) {
|
if (!conn->hcon->out) {
|
||||||
err = -EINVAL;
|
err = -EINVAL;
|
||||||
break;
|
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))
|
if (smp_conn_security(conn, sec.level))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
err = 0;
|
|
||||||
sk->sk_state = BT_CONFIG;
|
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;
|
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;
|
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)
|
static void confirm_work(struct work_struct *work)
|
||||||
{
|
{
|
||||||
struct smp_chan *smp = container_of(work, struct smp_chan, confirm);
|
struct smp_chan *smp = container_of(work, struct smp_chan, confirm);
|
||||||
|
@ -270,8 +282,7 @@ static void confirm_work(struct work_struct *work)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
smp_send_cmd(conn, SMP_CMD_PAIRING_FAIL, sizeof(reason), &reason);
|
smp_failure(conn, reason, 1);
|
||||||
smp_chan_destroy(conn);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void random_work(struct work_struct *work)
|
static void random_work(struct work_struct *work)
|
||||||
|
@ -354,8 +365,7 @@ static void random_work(struct work_struct *work)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
smp_send_cmd(conn, SMP_CMD_PAIRING_FAIL, sizeof(reason), &reason);
|
smp_failure(conn, reason, 1);
|
||||||
smp_chan_destroy(conn);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct smp_chan *smp_chan_create(struct l2cap_conn *conn)
|
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)
|
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);
|
hci_conn_put(conn->hcon);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -647,6 +665,7 @@ int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SMP_CMD_PAIRING_FAIL:
|
case SMP_CMD_PAIRING_FAIL:
|
||||||
|
smp_failure(conn, skb->data[0], 0);
|
||||||
reason = 0;
|
reason = 0;
|
||||||
err = -EPERM;
|
err = -EPERM;
|
||||||
break;
|
break;
|
||||||
|
@ -692,8 +711,7 @@ int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb)
|
||||||
|
|
||||||
done:
|
done:
|
||||||
if (reason)
|
if (reason)
|
||||||
smp_send_cmd(conn, SMP_CMD_PAIRING_FAIL, sizeof(reason),
|
smp_failure(conn, reason, 1);
|
||||||
&reason);
|
|
||||||
|
|
||||||
kfree_skb(skb);
|
kfree_skb(skb);
|
||||||
return err;
|
return err;
|
||||||
|
|
Loading…
Reference in New Issue