Эх сурвалжийг харах

Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/padovan/bluetooth-next-2.6

John W. Linville 14 жил өмнө
parent
commit
f4f314bf6f

+ 279 - 0
drivers/bluetooth/ath3k.c

@@ -31,6 +31,30 @@
 
 
 #define VERSION "1.0"
 #define VERSION "1.0"
 
 
+#define ATH3K_DNLOAD				0x01
+#define ATH3K_GETSTATE				0x05
+#define ATH3K_SET_NORMAL_MODE			0x07
+#define ATH3K_GETVERSION			0x09
+#define USB_REG_SWITCH_VID_PID			0x0a
+
+#define ATH3K_MODE_MASK				0x3F
+#define ATH3K_NORMAL_MODE			0x0E
+
+#define ATH3K_PATCH_UPDATE			0x80
+#define ATH3K_SYSCFG_UPDATE			0x40
+
+#define ATH3K_XTAL_FREQ_26M			0x00
+#define ATH3K_XTAL_FREQ_40M			0x01
+#define ATH3K_XTAL_FREQ_19P2			0x02
+#define ATH3K_NAME_LEN				0xFF
+
+struct ath3k_version {
+	unsigned int	rom_version;
+	unsigned int	build_version;
+	unsigned int	ram_version;
+	unsigned char	ref_clock;
+	unsigned char	reserved[0x07];
+};
 
 
 static struct usb_device_id ath3k_table[] = {
 static struct usb_device_id ath3k_table[] = {
 	/* Atheros AR3011 */
 	/* Atheros AR3011 */
@@ -41,13 +65,29 @@ static struct usb_device_id ath3k_table[] = {
 
 
 	/* Atheros AR9285 Malbec with sflash firmware */
 	/* Atheros AR9285 Malbec with sflash firmware */
 	{ USB_DEVICE(0x03F0, 0x311D) },
 	{ USB_DEVICE(0x03F0, 0x311D) },
+
+	/* Atheros AR3012 with sflash firmware*/
+	{ USB_DEVICE(0x0CF3, 0x3004) },
+
 	{ }	/* Terminating entry */
 	{ }	/* Terminating entry */
 };
 };
 
 
 MODULE_DEVICE_TABLE(usb, ath3k_table);
 MODULE_DEVICE_TABLE(usb, ath3k_table);
 
 
+#define BTUSB_ATH3012		0x80
+/* This table is to load patch and sysconfig files
+ * for AR3012 */
+static struct usb_device_id ath3k_blist_tbl[] = {
+
+	/* Atheros AR3012 with sflash firmware*/
+	{ USB_DEVICE(0x0cf3, 0x3004), .driver_info = BTUSB_ATH3012 },
+
+	{ }	/* Terminating entry */
+};
+
 #define USB_REQ_DFU_DNLOAD	1
 #define USB_REQ_DFU_DNLOAD	1
 #define BULK_SIZE		4096
 #define BULK_SIZE		4096
+#define FW_HDR_SIZE		20
 
 
 static int ath3k_load_firmware(struct usb_device *udev,
 static int ath3k_load_firmware(struct usb_device *udev,
 				const struct firmware *firmware)
 				const struct firmware *firmware)
@@ -103,6 +143,215 @@ error:
 	return err;
 	return err;
 }
 }
 
 
+static int ath3k_get_state(struct usb_device *udev, unsigned char *state)
+{
+	int pipe = 0;
+
+	pipe = usb_rcvctrlpipe(udev, 0);
+	return usb_control_msg(udev, pipe, ATH3K_GETSTATE,
+			USB_TYPE_VENDOR | USB_DIR_IN, 0, 0,
+			state, 0x01, USB_CTRL_SET_TIMEOUT);
+}
+
+static int ath3k_get_version(struct usb_device *udev,
+			struct ath3k_version *version)
+{
+	int pipe = 0;
+
+	pipe = usb_rcvctrlpipe(udev, 0);
+	return usb_control_msg(udev, pipe, ATH3K_GETVERSION,
+			USB_TYPE_VENDOR | USB_DIR_IN, 0, 0, version,
+			sizeof(struct ath3k_version),
+			USB_CTRL_SET_TIMEOUT);
+}
+
+static int ath3k_load_fwfile(struct usb_device *udev,
+		const struct firmware *firmware)
+{
+	u8 *send_buf;
+	int err, pipe, len, size, count, sent = 0;
+	int ret;
+
+	count = firmware->size;
+
+	send_buf = kmalloc(BULK_SIZE, GFP_ATOMIC);
+	if (!send_buf) {
+		BT_ERR("Can't allocate memory chunk for firmware");
+		return -ENOMEM;
+	}
+
+	size = min_t(uint, count, FW_HDR_SIZE);
+	memcpy(send_buf, firmware->data, size);
+
+	pipe = usb_sndctrlpipe(udev, 0);
+	ret = usb_control_msg(udev, pipe, ATH3K_DNLOAD,
+			USB_TYPE_VENDOR, 0, 0, send_buf,
+			size, USB_CTRL_SET_TIMEOUT);
+	if (ret < 0) {
+		BT_ERR("Can't change to loading configuration err");
+		kfree(send_buf);
+		return ret;
+	}
+
+	sent += size;
+	count -= size;
+
+	while (count) {
+		size = min_t(uint, count, BULK_SIZE);
+		pipe = usb_sndbulkpipe(udev, 0x02);
+
+		memcpy(send_buf, firmware->data + sent, size);
+
+		err = usb_bulk_msg(udev, pipe, send_buf, size,
+					&len, 3000);
+		if (err || (len != size)) {
+			BT_ERR("Error in firmware loading err = %d,"
+				"len = %d, size = %d", err, len, size);
+			kfree(send_buf);
+			return err;
+		}
+		sent  += size;
+		count -= size;
+	}
+
+	kfree(send_buf);
+	return 0;
+}
+
+static int ath3k_switch_pid(struct usb_device *udev)
+{
+	int pipe = 0;
+
+	pipe = usb_sndctrlpipe(udev, 0);
+	return usb_control_msg(udev, pipe, USB_REG_SWITCH_VID_PID,
+			USB_TYPE_VENDOR, 0, 0,
+			NULL, 0, USB_CTRL_SET_TIMEOUT);
+}
+
+static int ath3k_set_normal_mode(struct usb_device *udev)
+{
+	unsigned char fw_state;
+	int pipe = 0, ret;
+
+	ret = ath3k_get_state(udev, &fw_state);
+	if (ret < 0) {
+		BT_ERR("Can't get state to change to normal mode err");
+		return ret;
+	}
+
+	if ((fw_state & ATH3K_MODE_MASK) == ATH3K_NORMAL_MODE) {
+		BT_DBG("firmware was already in normal mode");
+		return 0;
+	}
+
+	pipe = usb_sndctrlpipe(udev, 0);
+	return usb_control_msg(udev, pipe, ATH3K_SET_NORMAL_MODE,
+			USB_TYPE_VENDOR, 0, 0,
+			NULL, 0, USB_CTRL_SET_TIMEOUT);
+}
+
+static int ath3k_load_patch(struct usb_device *udev)
+{
+	unsigned char fw_state;
+	char filename[ATH3K_NAME_LEN] = {0};
+	const struct firmware *firmware;
+	struct ath3k_version fw_version, pt_version;
+	int ret;
+
+	ret = ath3k_get_state(udev, &fw_state);
+	if (ret < 0) {
+		BT_ERR("Can't get state to change to load ram patch err");
+		return ret;
+	}
+
+	if (fw_state & ATH3K_PATCH_UPDATE) {
+		BT_DBG("Patch was already downloaded");
+		return 0;
+	}
+
+	ret = ath3k_get_version(udev, &fw_version);
+	if (ret < 0) {
+		BT_ERR("Can't get version to change to load ram patch err");
+		return ret;
+	}
+
+	snprintf(filename, ATH3K_NAME_LEN, "ar3k/AthrBT_0x%08x.dfu",
+		fw_version.rom_version);
+
+	ret = request_firmware(&firmware, filename, &udev->dev);
+	if (ret < 0) {
+		BT_ERR("Patch file not found %s", filename);
+		return ret;
+	}
+
+	pt_version.rom_version = *(int *)(firmware->data + firmware->size - 8);
+	pt_version.build_version = *(int *)
+		(firmware->data + firmware->size - 4);
+
+	if ((pt_version.rom_version != fw_version.rom_version) ||
+		(pt_version.build_version <= fw_version.build_version)) {
+		BT_ERR("Patch file version did not match with firmware");
+		release_firmware(firmware);
+		return -EINVAL;
+	}
+
+	ret = ath3k_load_fwfile(udev, firmware);
+	release_firmware(firmware);
+
+	return ret;
+}
+
+static int ath3k_load_syscfg(struct usb_device *udev)
+{
+	unsigned char fw_state;
+	char filename[ATH3K_NAME_LEN] = {0};
+	const struct firmware *firmware;
+	struct ath3k_version fw_version;
+	int clk_value, ret;
+
+	ret = ath3k_get_state(udev, &fw_state);
+	if (ret < 0) {
+		BT_ERR("Can't get state to change to load configration err");
+		return -EBUSY;
+	}
+
+	ret = ath3k_get_version(udev, &fw_version);
+	if (ret < 0) {
+		BT_ERR("Can't get version to change to load ram patch err");
+		return ret;
+	}
+
+	switch (fw_version.ref_clock) {
+
+	case ATH3K_XTAL_FREQ_26M:
+		clk_value = 26;
+		break;
+	case ATH3K_XTAL_FREQ_40M:
+		clk_value = 40;
+		break;
+	case ATH3K_XTAL_FREQ_19P2:
+		clk_value = 19;
+		break;
+	default:
+		clk_value = 0;
+		break;
+	}
+
+	snprintf(filename, ATH3K_NAME_LEN, "ar3k/ramps_0x%08x_%d%s",
+		fw_version.rom_version, clk_value, ".dfu");
+
+	ret = request_firmware(&firmware, filename, &udev->dev);
+	if (ret < 0) {
+		BT_ERR("Configuration file not found %s", filename);
+		return ret;
+	}
+
+	ret = ath3k_load_fwfile(udev, firmware);
+	release_firmware(firmware);
+
+	return ret;
+}
+
 static int ath3k_probe(struct usb_interface *intf,
 static int ath3k_probe(struct usb_interface *intf,
 			const struct usb_device_id *id)
 			const struct usb_device_id *id)
 {
 {
@@ -115,7 +364,37 @@ static int ath3k_probe(struct usb_interface *intf,
 	if (intf->cur_altsetting->desc.bInterfaceNumber != 0)
 	if (intf->cur_altsetting->desc.bInterfaceNumber != 0)
 		return -ENODEV;
 		return -ENODEV;
 
 
+	/* match device ID in ath3k blacklist table */
+	if (!id->driver_info) {
+		const struct usb_device_id *match;
+		match = usb_match_id(intf, ath3k_blist_tbl);
+		if (match)
+			id = match;
+	}
+
+	/* load patch and sysconfig files for AR3012 */
+	if (id->driver_info & BTUSB_ATH3012) {
+		ret = ath3k_load_patch(udev);
+		if (ret < 0) {
+			BT_ERR("Loading patch file failed");
+			return ret;
+		}
+		ret = ath3k_load_syscfg(udev);
+		if (ret < 0) {
+			BT_ERR("Loading sysconfig file failed");
+			return ret;
+		}
+		ret = ath3k_set_normal_mode(udev);
+		if (ret < 0) {
+			BT_ERR("Set normal mode failed");
+			return ret;
+		}
+		ath3k_switch_pid(udev);
+		return 0;
+	}
+
 	if (request_firmware(&firmware, "ath3k-1.fw", &udev->dev) < 0) {
 	if (request_firmware(&firmware, "ath3k-1.fw", &udev->dev) < 0) {
+		BT_ERR("Error loading firmware");
 		return -EIO;
 		return -EIO;
 	}
 	}
 
 

+ 6 - 7
drivers/bluetooth/btusb.c

@@ -105,6 +105,9 @@ static struct usb_device_id blacklist_table[] = {
 	/* Atheros AR9285 Malbec with sflash firmware */
 	/* Atheros AR9285 Malbec with sflash firmware */
 	{ USB_DEVICE(0x03f0, 0x311d), .driver_info = BTUSB_IGNORE },
 	{ USB_DEVICE(0x03f0, 0x311d), .driver_info = BTUSB_IGNORE },
 
 
+	/* Atheros 3012 with sflash firmware */
+	{ USB_DEVICE(0x0cf3, 0x3004), .driver_info = BTUSB_IGNORE },
+
 	/* Broadcom BCM2035 */
 	/* Broadcom BCM2035 */
 	{ USB_DEVICE(0x0a5c, 0x2035), .driver_info = BTUSB_WRONG_SCO_MTU },
 	{ USB_DEVICE(0x0a5c, 0x2035), .driver_info = BTUSB_WRONG_SCO_MTU },
 	{ USB_DEVICE(0x0a5c, 0x200a), .driver_info = BTUSB_WRONG_SCO_MTU },
 	{ USB_DEVICE(0x0a5c, 0x200a), .driver_info = BTUSB_WRONG_SCO_MTU },
@@ -711,15 +714,11 @@ static int btusb_send_frame(struct sk_buff *skb)
 		pipe = usb_sndisocpipe(data->udev,
 		pipe = usb_sndisocpipe(data->udev,
 					data->isoc_tx_ep->bEndpointAddress);
 					data->isoc_tx_ep->bEndpointAddress);
 
 
-		urb->dev      = data->udev;
-		urb->pipe     = pipe;
-		urb->context  = skb;
-		urb->complete = btusb_isoc_tx_complete;
-		urb->interval = data->isoc_tx_ep->bInterval;
+		usb_fill_int_urb(urb, data->udev, pipe,
+				skb->data, skb->len, btusb_isoc_tx_complete,
+				skb, data->isoc_tx_ep->bInterval);
 
 
 		urb->transfer_flags  = URB_ISO_ASAP;
 		urb->transfer_flags  = URB_ISO_ASAP;
-		urb->transfer_buffer = skb->data;
-		urb->transfer_buffer_length = skb->len;
 
 
 		__fill_isoc_descriptor(urb, skb->len,
 		__fill_isoc_descriptor(urb, skb->len,
 				le16_to_cpu(data->isoc_tx_ep->wMaxPacketSize));
 				le16_to_cpu(data->isoc_tx_ep->wMaxPacketSize));

+ 1 - 0
drivers/bluetooth/hci_ldisc.c

@@ -398,6 +398,7 @@ static int hci_uart_register_dev(struct hci_uart *hu)
 	hdev->flush = hci_uart_flush;
 	hdev->flush = hci_uart_flush;
 	hdev->send  = hci_uart_send_frame;
 	hdev->send  = hci_uart_send_frame;
 	hdev->destruct = hci_uart_destruct;
 	hdev->destruct = hci_uart_destruct;
+	hdev->parent = hu->tty->dev;
 
 
 	hdev->owner = THIS_MODULE;
 	hdev->owner = THIS_MODULE;
 
 

+ 28 - 0
include/net/bluetooth/bluetooth.h

@@ -205,4 +205,32 @@ extern void bt_sysfs_cleanup(void);
 
 
 extern struct dentry *bt_debugfs;
 extern struct dentry *bt_debugfs;
 
 
+#ifdef CONFIG_BT_L2CAP
+int l2cap_init(void);
+void l2cap_exit(void);
+#else
+static inline int l2cap_init(void)
+{
+	return 0;
+}
+
+static inline void l2cap_exit(void)
+{
+}
+#endif
+
+#ifdef CONFIG_BT_SCO
+int sco_init(void);
+void sco_exit(void);
+#else
+static inline int sco_init(void)
+{
+	return 0;
+}
+
+static inline void sco_exit(void)
+{
+}
+#endif
+
 #endif /* __BLUETOOTH_H */
 #endif /* __BLUETOOTH_H */

+ 65 - 0
include/net/bluetooth/hci.h

@@ -119,6 +119,7 @@ enum {
 #define HCI_PAIRING_TIMEOUT	(60000)	/* 60 seconds */
 #define HCI_PAIRING_TIMEOUT	(60000)	/* 60 seconds */
 #define HCI_IDLE_TIMEOUT	(6000)	/* 6 seconds */
 #define HCI_IDLE_TIMEOUT	(6000)	/* 6 seconds */
 #define HCI_INIT_TIMEOUT	(10000)	/* 10 seconds */
 #define HCI_INIT_TIMEOUT	(10000)	/* 10 seconds */
+#define HCI_CMD_TIMEOUT		(1000)	/* 1 seconds */
 
 
 /* HCI data types */
 /* HCI data types */
 #define HCI_COMMAND_PKT		0x01
 #define HCI_COMMAND_PKT		0x01
@@ -168,6 +169,8 @@ enum {
 #define SCO_LINK	0x00
 #define SCO_LINK	0x00
 #define ACL_LINK	0x01
 #define ACL_LINK	0x01
 #define ESCO_LINK	0x02
 #define ESCO_LINK	0x02
+/* Low Energy links do not have defined link type. Use invented one */
+#define LE_LINK		0x80
 
 
 /* LMP features */
 /* LMP features */
 #define LMP_3SLOT	0x01
 #define LMP_3SLOT	0x01
@@ -242,6 +245,8 @@ enum {
 #define HCI_AT_GENERAL_BONDING_MITM	0x05
 #define HCI_AT_GENERAL_BONDING_MITM	0x05
 
 
 /* -----  HCI Commands ---- */
 /* -----  HCI Commands ---- */
+#define HCI_OP_NOP			0x0000
+
 #define HCI_OP_INQUIRY			0x0401
 #define HCI_OP_INQUIRY			0x0401
 struct hci_cp_inquiry {
 struct hci_cp_inquiry {
 	__u8     lap[3];
 	__u8     lap[3];
@@ -642,6 +647,47 @@ struct hci_rp_read_bd_addr {
 	bdaddr_t bdaddr;
 	bdaddr_t bdaddr;
 } __packed;
 } __packed;
 
 
+#define HCI_OP_LE_SET_EVENT_MASK	0x2001
+struct hci_cp_le_set_event_mask {
+	__u8     mask[8];
+} __packed;
+
+#define HCI_OP_LE_READ_BUFFER_SIZE	0x2002
+struct hci_rp_le_read_buffer_size {
+	__u8     status;
+	__le16   le_mtu;
+	__u8     le_max_pkt;
+} __packed;
+
+#define HCI_OP_LE_CREATE_CONN		0x200d
+struct hci_cp_le_create_conn {
+	__le16   scan_interval;
+	__le16   scan_window;
+	__u8     filter_policy;
+	__u8     peer_addr_type;
+	bdaddr_t peer_addr;
+	__u8     own_address_type;
+	__le16   conn_interval_min;
+	__le16   conn_interval_max;
+	__le16   conn_latency;
+	__le16   supervision_timeout;
+	__le16   min_ce_len;
+	__le16   max_ce_len;
+} __packed;
+
+#define HCI_OP_LE_CREATE_CONN_CANCEL	0x200e
+
+#define HCI_OP_LE_CONN_UPDATE		0x2013
+struct hci_cp_le_conn_update {
+	__le16   handle;
+	__le16   conn_interval_min;
+	__le16   conn_interval_max;
+	__le16   conn_latency;
+	__le16   supervision_timeout;
+	__le16   min_ce_len;
+	__le16   max_ce_len;
+} __packed;
+
 /* ---- HCI Events ---- */
 /* ---- HCI Events ---- */
 #define HCI_EV_INQUIRY_COMPLETE		0x01
 #define HCI_EV_INQUIRY_COMPLETE		0x01
 
 
@@ -902,6 +948,25 @@ struct hci_ev_remote_host_features {
 	__u8     features[8];
 	__u8     features[8];
 } __packed;
 } __packed;
 
 
+#define HCI_EV_LE_META			0x3e
+struct hci_ev_le_meta {
+	__u8     subevent;
+} __packed;
+
+/* Low energy meta events */
+#define HCI_EV_LE_CONN_COMPLETE		0x01
+struct hci_ev_le_conn_complete {
+	__u8     status;
+	__le16   handle;
+	__u8     role;
+	__u8     bdaddr_type;
+	bdaddr_t bdaddr;
+	__le16   interval;
+	__le16   latency;
+	__le16   supervision_timeout;
+	__u8     clk_accurancy;
+} __packed;
+
 /* Internal events generated by Bluetooth stack */
 /* Internal events generated by Bluetooth stack */
 #define HCI_EV_STACK_INTERNAL	0xfd
 #define HCI_EV_STACK_INTERNAL	0xfd
 struct hci_ev_stack_internal {
 struct hci_ev_stack_internal {

+ 58 - 34
include/net/bluetooth/hci_core.h

@@ -60,6 +60,7 @@ struct hci_conn_hash {
 	spinlock_t       lock;
 	spinlock_t       lock;
 	unsigned int     acl_num;
 	unsigned int     acl_num;
 	unsigned int     sco_num;
 	unsigned int     sco_num;
+	unsigned int     le_num;
 };
 };
 
 
 struct bdaddr_list {
 struct bdaddr_list {
@@ -122,15 +123,18 @@ struct hci_dev {
 	atomic_t	cmd_cnt;
 	atomic_t	cmd_cnt;
 	unsigned int	acl_cnt;
 	unsigned int	acl_cnt;
 	unsigned int	sco_cnt;
 	unsigned int	sco_cnt;
+	unsigned int	le_cnt;
 
 
 	unsigned int	acl_mtu;
 	unsigned int	acl_mtu;
 	unsigned int	sco_mtu;
 	unsigned int	sco_mtu;
+	unsigned int	le_mtu;
 	unsigned int	acl_pkts;
 	unsigned int	acl_pkts;
 	unsigned int	sco_pkts;
 	unsigned int	sco_pkts;
+	unsigned int	le_pkts;
 
 
-	unsigned long	cmd_last_tx;
 	unsigned long	acl_last_tx;
 	unsigned long	acl_last_tx;
 	unsigned long	sco_last_tx;
 	unsigned long	sco_last_tx;
+	unsigned long	le_last_tx;
 
 
 	struct workqueue_struct	*workqueue;
 	struct workqueue_struct	*workqueue;
 
 
@@ -138,6 +142,7 @@ struct hci_dev {
 	struct work_struct	power_off;
 	struct work_struct	power_off;
 	struct timer_list	off_timer;
 	struct timer_list	off_timer;
 
 
+	struct timer_list	cmd_timer;
 	struct tasklet_struct	cmd_task;
 	struct tasklet_struct	cmd_task;
 	struct tasklet_struct	rx_task;
 	struct tasklet_struct	rx_task;
 	struct tasklet_struct	tx_task;
 	struct tasklet_struct	tx_task;
@@ -194,37 +199,37 @@ struct hci_dev {
 struct hci_conn {
 struct hci_conn {
 	struct list_head list;
 	struct list_head list;
 
 
-	atomic_t	 refcnt;
-	spinlock_t	 lock;
-
-	bdaddr_t	 dst;
-	__u16		 handle;
-	__u16		 state;
-	__u8             mode;
-	__u8		 type;
-	__u8		 out;
-	__u8		 attempt;
-	__u8		 dev_class[3];
-	__u8             features[8];
-	__u8             ssp_mode;
-	__u16            interval;
-	__u16            pkt_type;
-	__u16            link_policy;
-	__u32		 link_mode;
-	__u8             auth_type;
-	__u8             sec_level;
-	__u8		 pending_sec_level;
-	__u8		 pin_length;
-	__u8		 io_capability;
-	__u8             power_save;
-	__u16            disc_timeout;
-	unsigned long	 pend;
+	atomic_t	refcnt;
+	spinlock_t	lock;
+
+	bdaddr_t	dst;
+	__u16		handle;
+	__u16		state;
+	__u8		mode;
+	__u8		type;
+	__u8		out;
+	__u8		attempt;
+	__u8		dev_class[3];
+	__u8		features[8];
+	__u8		ssp_mode;
+	__u16		interval;
+	__u16		pkt_type;
+	__u16		link_policy;
+	__u32		link_mode;
+	__u8		auth_type;
+	__u8		sec_level;
+	__u8		pending_sec_level;
+	__u8		pin_length;
+	__u8		io_capability;
+	__u8		power_save;
+	__u16		disc_timeout;
+	unsigned long	pend;
 
 
 	__u8		remote_cap;
 	__u8		remote_cap;
 	__u8		remote_oob;
 	__u8		remote_oob;
 	__u8		remote_auth;
 	__u8		remote_auth;
 
 
-	unsigned int	 sent;
+	unsigned int	sent;
 
 
 	struct sk_buff_head data_q;
 	struct sk_buff_head data_q;
 
 
@@ -309,24 +314,40 @@ static inline void hci_conn_hash_add(struct hci_dev *hdev, struct hci_conn *c)
 {
 {
 	struct hci_conn_hash *h = &hdev->conn_hash;
 	struct hci_conn_hash *h = &hdev->conn_hash;
 	list_add(&c->list, &h->list);
 	list_add(&c->list, &h->list);
-	if (c->type == ACL_LINK)
+	switch (c->type) {
+	case ACL_LINK:
 		h->acl_num++;
 		h->acl_num++;
-	else
+		break;
+	case LE_LINK:
+		h->le_num++;
+		break;
+	case SCO_LINK:
+	case ESCO_LINK:
 		h->sco_num++;
 		h->sco_num++;
+		break;
+	}
 }
 }
 
 
 static inline void hci_conn_hash_del(struct hci_dev *hdev, struct hci_conn *c)
 static inline void hci_conn_hash_del(struct hci_dev *hdev, struct hci_conn *c)
 {
 {
 	struct hci_conn_hash *h = &hdev->conn_hash;
 	struct hci_conn_hash *h = &hdev->conn_hash;
 	list_del(&c->list);
 	list_del(&c->list);
-	if (c->type == ACL_LINK)
+	switch (c->type) {
+	case ACL_LINK:
 		h->acl_num--;
 		h->acl_num--;
-	else
+		break;
+	case LE_LINK:
+		h->le_num--;
+		break;
+	case SCO_LINK:
+	case ESCO_LINK:
 		h->sco_num--;
 		h->sco_num--;
+		break;
+	}
 }
 }
 
 
 static inline struct hci_conn *hci_conn_hash_lookup_handle(struct hci_dev *hdev,
 static inline struct hci_conn *hci_conn_hash_lookup_handle(struct hci_dev *hdev,
-					__u16 handle)
+								__u16 handle)
 {
 {
 	struct hci_conn_hash *h = &hdev->conn_hash;
 	struct hci_conn_hash *h = &hdev->conn_hash;
 	struct list_head *p;
 	struct list_head *p;
@@ -341,7 +362,7 @@ static inline struct hci_conn *hci_conn_hash_lookup_handle(struct hci_dev *hdev,
 }
 }
 
 
 static inline struct hci_conn *hci_conn_hash_lookup_ba(struct hci_dev *hdev,
 static inline struct hci_conn *hci_conn_hash_lookup_ba(struct hci_dev *hdev,
-					__u8 type, bdaddr_t *ba)
+							__u8 type, bdaddr_t *ba)
 {
 {
 	struct hci_conn_hash *h = &hdev->conn_hash;
 	struct hci_conn_hash *h = &hdev->conn_hash;
 	struct list_head *p;
 	struct list_head *p;
@@ -356,7 +377,7 @@ static inline struct hci_conn *hci_conn_hash_lookup_ba(struct hci_dev *hdev,
 }
 }
 
 
 static inline struct hci_conn *hci_conn_hash_lookup_state(struct hci_dev *hdev,
 static inline struct hci_conn *hci_conn_hash_lookup_state(struct hci_dev *hdev,
-					__u8 type, __u16 state)
+							__u8 type, __u16 state)
 {
 {
 	struct hci_conn_hash *h = &hdev->conn_hash;
 	struct hci_conn_hash *h = &hdev->conn_hash;
 	struct list_head *p;
 	struct list_head *p;
@@ -504,6 +525,7 @@ void hci_conn_del_sysfs(struct hci_conn *conn);
 #define lmp_esco_capable(dev)      ((dev)->features[3] & LMP_ESCO)
 #define lmp_esco_capable(dev)      ((dev)->features[3] & LMP_ESCO)
 #define lmp_ssp_capable(dev)       ((dev)->features[6] & LMP_SIMPLE_PAIR)
 #define lmp_ssp_capable(dev)       ((dev)->features[6] & LMP_SIMPLE_PAIR)
 #define lmp_no_flush_capable(dev)  ((dev)->features[6] & LMP_NO_FLUSH)
 #define lmp_no_flush_capable(dev)  ((dev)->features[6] & LMP_NO_FLUSH)
+#define lmp_le_capable(dev)        ((dev)->features[4] & LMP_LE)
 
 
 /* ----- HCI protocols ----- */
 /* ----- HCI protocols ----- */
 struct hci_proto {
 struct hci_proto {
@@ -755,4 +777,6 @@ struct hci_sec_filter {
 
 
 void hci_req_complete(struct hci_dev *hdev, __u16 cmd, int result);
 void hci_req_complete(struct hci_dev *hdev, __u16 cmd, int result);
 
 
+void hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max,
+					u16 latency, u16 to_multiplier);
 #endif /* __HCI_CORE_H */
 #endif /* __HCI_CORE_H */

+ 21 - 2
include/net/bluetooth/l2cap.h

@@ -38,6 +38,7 @@
 #define L2CAP_DEFAULT_MAX_PDU_SIZE	1009    /* Sized for 3-DH5 packet */
 #define L2CAP_DEFAULT_MAX_PDU_SIZE	1009    /* Sized for 3-DH5 packet */
 #define L2CAP_DEFAULT_ACK_TO		200
 #define L2CAP_DEFAULT_ACK_TO		200
 #define L2CAP_LOCAL_BUSY_TRIES		12
 #define L2CAP_LOCAL_BUSY_TRIES		12
+#define L2CAP_LE_DEFAULT_MTU		23
 
 
 #define L2CAP_CONN_TIMEOUT	(40000) /* 40 seconds */
 #define L2CAP_CONN_TIMEOUT	(40000) /* 40 seconds */
 #define L2CAP_INFO_TIMEOUT	(4000)  /*  4 seconds */
 #define L2CAP_INFO_TIMEOUT	(4000)  /*  4 seconds */
@@ -88,6 +89,8 @@ struct l2cap_conninfo {
 #define L2CAP_ECHO_RSP		0x09
 #define L2CAP_ECHO_RSP		0x09
 #define L2CAP_INFO_REQ		0x0a
 #define L2CAP_INFO_REQ		0x0a
 #define L2CAP_INFO_RSP		0x0b
 #define L2CAP_INFO_RSP		0x0b
+#define L2CAP_CONN_PARAM_UPDATE_REQ	0x12
+#define L2CAP_CONN_PARAM_UPDATE_RSP	0x13
 
 
 /* L2CAP feature mask */
 /* L2CAP feature mask */
 #define L2CAP_FEAT_FLOWCTL	0x00000001
 #define L2CAP_FEAT_FLOWCTL	0x00000001
@@ -160,6 +163,9 @@ struct l2cap_conn_rsp {
 /* channel indentifier */
 /* channel indentifier */
 #define L2CAP_CID_SIGNALING	0x0001
 #define L2CAP_CID_SIGNALING	0x0001
 #define L2CAP_CID_CONN_LESS	0x0002
 #define L2CAP_CID_CONN_LESS	0x0002
+#define L2CAP_CID_LE_DATA	0x0004
+#define L2CAP_CID_LE_SIGNALING	0x0005
+#define L2CAP_CID_SMP		0x0006
 #define L2CAP_CID_DYN_START	0x0040
 #define L2CAP_CID_DYN_START	0x0040
 #define L2CAP_CID_DYN_END	0xffff
 #define L2CAP_CID_DYN_END	0xffff
 
 
@@ -255,6 +261,21 @@ struct l2cap_info_rsp {
 #define L2CAP_IR_SUCCESS    0x0000
 #define L2CAP_IR_SUCCESS    0x0000
 #define L2CAP_IR_NOTSUPP    0x0001
 #define L2CAP_IR_NOTSUPP    0x0001
 
 
+struct l2cap_conn_param_update_req {
+	__le16      min;
+	__le16      max;
+	__le16      latency;
+	__le16      to_multiplier;
+} __packed;
+
+struct l2cap_conn_param_update_rsp {
+	__le16      result;
+} __packed;
+
+/* Connection Parameters result */
+#define L2CAP_CONN_PARAM_ACCEPTED	0x0000
+#define L2CAP_CONN_PARAM_REJECTED	0x0001
+
 /* ----- L2CAP connections ----- */
 /* ----- L2CAP connections ----- */
 struct l2cap_chan_list {
 struct l2cap_chan_list {
 	struct sock	*head;
 	struct sock	*head;
@@ -455,6 +476,4 @@ void l2cap_send_disconn_req(struct l2cap_conn *conn, struct sock *sk, int err);
 void l2cap_chan_del(struct sock *sk, int err);
 void l2cap_chan_del(struct sock *sk, int err);
 int l2cap_do_connect(struct sock *sk);
 int l2cap_do_connect(struct sock *sk);
 
 
-void l2cap_load(void);
-
 #endif /* __L2CAP_H */
 #endif /* __L2CAP_H */

+ 76 - 0
include/net/bluetooth/smp.h

@@ -0,0 +1,76 @@
+#ifndef __SMP_H
+#define __SMP_H
+
+struct smp_command_hdr {
+	__u8	code;
+} __packed;
+
+#define SMP_CMD_PAIRING_REQ	0x01
+#define SMP_CMD_PAIRING_RSP	0x02
+struct smp_cmd_pairing {
+	__u8	io_capability;
+	__u8	oob_flag;
+	__u8	auth_req;
+	__u8	max_key_size;
+	__u8	init_key_dist;
+	__u8	resp_key_dist;
+} __packed;
+
+#define SMP_CMD_PAIRING_CONFIRM	0x03
+struct smp_cmd_pairing_confirm {
+	__u8	confirm_val[16];
+} __packed;
+
+#define SMP_CMD_PAIRING_RANDOM	0x04
+struct smp_cmd_pairing_random {
+	__u8	rand_val[16];
+} __packed;
+
+#define SMP_CMD_PAIRING_FAIL	0x05
+struct smp_cmd_pairing_fail {
+	__u8	reason;
+} __packed;
+
+#define SMP_CMD_ENCRYPT_INFO	0x06
+struct smp_cmd_encrypt_info {
+	__u8	ltk[16];
+} __packed;
+
+#define SMP_CMD_MASTER_IDENT	0x07
+struct smp_cmd_master_ident {
+	__u16	ediv;
+	__u8	rand[8];
+} __packed;
+
+#define SMP_CMD_IDENT_INFO	0x08
+struct smp_cmd_ident_info {
+	__u8	irk[16];
+} __packed;
+
+#define SMP_CMD_IDENT_ADDR_INFO	0x09
+struct smp_cmd_ident_addr_info {
+	__u8	addr_type;
+	bdaddr_t bdaddr;
+} __packed;
+
+#define SMP_CMD_SIGN_INFO	0x0a
+struct smp_cmd_sign_info {
+	__u8	csrk[16];
+} __packed;
+
+#define SMP_CMD_SECURITY_REQ	0x0b
+struct smp_cmd_security_req {
+	__u8	auth_req;
+} __packed;
+
+#define SMP_PASSKEY_ENTRY_FAILED	0x01
+#define SMP_OOB_NOT_AVAIL		0x02
+#define SMP_AUTH_REQUIREMENTS		0x03
+#define SMP_CONFIRM_FAILED		0x04
+#define SMP_PAIRING_NOTSUPP		0x05
+#define SMP_ENC_KEY_SIZE		0x06
+#define SMP_CMD_NOTSUPP		0x07
+#define SMP_UNSPECIFIED		0x08
+#define SMP_REPEATED_ATTEMPTS		0x09
+
+#endif /* __SMP_H */

+ 2 - 8
net/bluetooth/Kconfig

@@ -32,7 +32,7 @@ menuconfig BT
 	  more information, see <http://www.bluez.org/>.
 	  more information, see <http://www.bluez.org/>.
 
 
 config BT_L2CAP
 config BT_L2CAP
-	tristate "L2CAP protocol support"
+	bool "L2CAP protocol support"
 	depends on BT
 	depends on BT
 	select CRC16
 	select CRC16
 	help
 	help
@@ -40,19 +40,13 @@ config BT_L2CAP
 	  connection oriented and connection-less data transport.  L2CAP
 	  connection oriented and connection-less data transport.  L2CAP
 	  support is required for most Bluetooth applications.
 	  support is required for most Bluetooth applications.
 
 
-	  Say Y here to compile L2CAP support into the kernel or say M to
-	  compile it as module (l2cap).
-
 config BT_SCO
 config BT_SCO
-	tristate "SCO links support"
+	bool "SCO links support"
 	depends on BT
 	depends on BT
 	help
 	help
 	  SCO link provides voice transport over Bluetooth.  SCO support is
 	  SCO link provides voice transport over Bluetooth.  SCO support is
 	  required for voice applications like Headset and Audio.
 	  required for voice applications like Headset and Audio.
 
 
-	  Say Y here to compile SCO support into the kernel or say M to
-	  compile it as module (sco).
-
 source "net/bluetooth/rfcomm/Kconfig"
 source "net/bluetooth/rfcomm/Kconfig"
 
 
 source "net/bluetooth/bnep/Kconfig"
 source "net/bluetooth/bnep/Kconfig"

+ 2 - 3
net/bluetooth/Makefile

@@ -3,12 +3,11 @@
 #
 #
 
 
 obj-$(CONFIG_BT)	+= bluetooth.o
 obj-$(CONFIG_BT)	+= bluetooth.o
-obj-$(CONFIG_BT_L2CAP)	+= l2cap.o
-obj-$(CONFIG_BT_SCO)	+= sco.o
 obj-$(CONFIG_BT_RFCOMM)	+= rfcomm/
 obj-$(CONFIG_BT_RFCOMM)	+= rfcomm/
 obj-$(CONFIG_BT_BNEP)	+= bnep/
 obj-$(CONFIG_BT_BNEP)	+= bnep/
 obj-$(CONFIG_BT_CMTP)	+= cmtp/
 obj-$(CONFIG_BT_CMTP)	+= cmtp/
 obj-$(CONFIG_BT_HIDP)	+= hidp/
 obj-$(CONFIG_BT_HIDP)	+= hidp/
 
 
 bluetooth-y := af_bluetooth.o hci_core.o hci_conn.o hci_event.o mgmt.o hci_sock.o hci_sysfs.o lib.o
 bluetooth-y := af_bluetooth.o hci_core.o hci_conn.o hci_event.o mgmt.o hci_sock.o hci_sysfs.o lib.o
-l2cap-y := l2cap_core.o l2cap_sock.o
+bluetooth-$(CONFIG_BT_L2CAP)	+= l2cap_core.o l2cap_sock.o
+bluetooth-$(CONFIG_BT_SCO)	+= sco.o

+ 31 - 3
net/bluetooth/af_bluetooth.c

@@ -40,7 +40,7 @@
 
 
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/bluetooth.h>
 
 
-#define VERSION "2.15"
+#define VERSION "2.16"
 
 
 /* Bluetooth sockets */
 /* Bluetooth sockets */
 #define BT_MAX_PROTO	8
 #define BT_MAX_PROTO	8
@@ -397,7 +397,7 @@ static inline unsigned int bt_accept_poll(struct sock *parent)
 	return 0;
 	return 0;
 }
 }
 
 
-unsigned int bt_sock_poll(struct file * file, struct socket *sock, poll_table *wait)
+unsigned int bt_sock_poll(struct file *file, struct socket *sock, poll_table *wait)
 {
 {
 	struct sock *sk = sock->sk;
 	struct sock *sk = sock->sk;
 	unsigned int mask = 0;
 	unsigned int mask = 0;
@@ -545,13 +545,41 @@ static int __init bt_init(void)
 
 
 	BT_INFO("HCI device and connection manager initialized");
 	BT_INFO("HCI device and connection manager initialized");
 
 
-	hci_sock_init();
+	err = hci_sock_init();
+	if (err < 0)
+		goto error;
+
+	err = l2cap_init();
+	if (err < 0) {
+		hci_sock_cleanup();
+		goto sock_err;
+	}
+
+	err = sco_init();
+	if (err < 0) {
+		l2cap_exit();
+		goto sock_err;
+	}
 
 
 	return 0;
 	return 0;
+
+sock_err:
+	hci_sock_cleanup();
+
+error:
+	sock_unregister(PF_BLUETOOTH);
+	bt_sysfs_cleanup();
+
+	return err;
 }
 }
 
 
 static void __exit bt_exit(void)
 static void __exit bt_exit(void)
 {
 {
+
+	sco_exit();
+
+	l2cap_exit();
+
 	hci_sock_cleanup();
 	hci_sock_cleanup();
 
 
 	sock_unregister(PF_BLUETOOTH);
 	sock_unregister(PF_BLUETOOTH);

+ 0 - 2
net/bluetooth/bnep/core.c

@@ -708,8 +708,6 @@ static int __init bnep_init(void)
 {
 {
 	char flt[50] = "";
 	char flt[50] = "";
 
 
-	l2cap_load();
-
 #ifdef CONFIG_BT_BNEP_PROTO_FILTER
 #ifdef CONFIG_BT_BNEP_PROTO_FILTER
 	strcat(flt, "protocol ");
 	strcat(flt, "protocol ");
 #endif
 #endif

+ 1 - 0
net/bluetooth/bnep/sock.c

@@ -88,6 +88,7 @@ static int bnep_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long
 			sockfd_put(nsock);
 			sockfd_put(nsock);
 			return -EBADFD;
 			return -EBADFD;
 		}
 		}
+		ca.device[sizeof(ca.device)-1] = 0;
 
 
 		err = bnep_add_connection(&ca, nsock);
 		err = bnep_add_connection(&ca, nsock);
 		if (!err) {
 		if (!err) {

+ 0 - 2
net/bluetooth/cmtp/core.c

@@ -469,8 +469,6 @@ int cmtp_get_conninfo(struct cmtp_conninfo *ci)
 
 
 static int __init cmtp_init(void)
 static int __init cmtp_init(void)
 {
 {
-	l2cap_load();
-
 	BT_INFO("CMTP (CAPI Emulation) ver %s", VERSION);
 	BT_INFO("CMTP (CAPI Emulation) ver %s", VERSION);
 
 
 	cmtp_init_sockets();
 	cmtp_init_sockets();

+ 74 - 3
net/bluetooth/hci_conn.c

@@ -45,6 +45,33 @@
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci_core.h>
 #include <net/bluetooth/hci_core.h>
 
 
+static void hci_le_connect(struct hci_conn *conn)
+{
+	struct hci_dev *hdev = conn->hdev;
+	struct hci_cp_le_create_conn cp;
+
+	conn->state = BT_CONNECT;
+	conn->out = 1;
+	conn->link_mode |= HCI_LM_MASTER;
+
+	memset(&cp, 0, sizeof(cp));
+	cp.scan_interval = cpu_to_le16(0x0004);
+	cp.scan_window = cpu_to_le16(0x0004);
+	bacpy(&cp.peer_addr, &conn->dst);
+	cp.conn_interval_min = cpu_to_le16(0x0008);
+	cp.conn_interval_max = cpu_to_le16(0x0100);
+	cp.supervision_timeout = cpu_to_le16(0x0064);
+	cp.min_ce_len = cpu_to_le16(0x0001);
+	cp.max_ce_len = cpu_to_le16(0x0001);
+
+	hci_send_cmd(hdev, HCI_OP_LE_CREATE_CONN, sizeof(cp), &cp);
+}
+
+static void hci_le_connect_cancel(struct hci_conn *conn)
+{
+	hci_send_cmd(conn->hdev, HCI_OP_LE_CREATE_CONN_CANCEL, 0, NULL);
+}
+
 void hci_acl_connect(struct hci_conn *conn)
 void hci_acl_connect(struct hci_conn *conn)
 {
 {
 	struct hci_dev *hdev = conn->hdev;
 	struct hci_dev *hdev = conn->hdev;
@@ -156,6 +183,26 @@ void hci_setup_sync(struct hci_conn *conn, __u16 handle)
 	hci_send_cmd(hdev, HCI_OP_SETUP_SYNC_CONN, sizeof(cp), &cp);
 	hci_send_cmd(hdev, HCI_OP_SETUP_SYNC_CONN, sizeof(cp), &cp);
 }
 }
 
 
+void hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max,
+					u16 latency, u16 to_multiplier)
+{
+	struct hci_cp_le_conn_update cp;
+	struct hci_dev *hdev = conn->hdev;
+
+	memset(&cp, 0, sizeof(cp));
+
+	cp.handle		= cpu_to_le16(conn->handle);
+	cp.conn_interval_min	= cpu_to_le16(min);
+	cp.conn_interval_max	= cpu_to_le16(max);
+	cp.conn_latency		= cpu_to_le16(latency);
+	cp.supervision_timeout	= cpu_to_le16(to_multiplier);
+	cp.min_ce_len		= cpu_to_le16(0x0001);
+	cp.max_ce_len		= cpu_to_le16(0x0001);
+
+	hci_send_cmd(hdev, HCI_OP_LE_CONN_UPDATE, sizeof(cp), &cp);
+}
+EXPORT_SYMBOL(hci_le_conn_update);
+
 /* Device _must_ be locked */
 /* Device _must_ be locked */
 void hci_sco_setup(struct hci_conn *conn, __u8 status)
 void hci_sco_setup(struct hci_conn *conn, __u8 status)
 {
 {
@@ -193,8 +240,12 @@ static void hci_conn_timeout(unsigned long arg)
 	switch (conn->state) {
 	switch (conn->state) {
 	case BT_CONNECT:
 	case BT_CONNECT:
 	case BT_CONNECT2:
 	case BT_CONNECT2:
-		if (conn->type == ACL_LINK && conn->out)
-			hci_acl_connect_cancel(conn);
+		if (conn->out) {
+			if (conn->type == ACL_LINK)
+				hci_acl_connect_cancel(conn);
+			else if (conn->type == LE_LINK)
+				hci_le_connect_cancel(conn);
+		}
 		break;
 		break;
 	case BT_CONFIG:
 	case BT_CONFIG:
 	case BT_CONNECTED:
 	case BT_CONNECTED:
@@ -296,6 +347,11 @@ int hci_conn_del(struct hci_conn *conn)
 
 
 		/* Unacked frames */
 		/* Unacked frames */
 		hdev->acl_cnt += conn->sent;
 		hdev->acl_cnt += conn->sent;
+	} else if (conn->type == LE_LINK) {
+		if (hdev->le_pkts)
+			hdev->le_cnt += conn->sent;
+		else
+			hdev->acl_cnt += conn->sent;
 	} else {
 	} else {
 		struct hci_conn *acl = conn->link;
 		struct hci_conn *acl = conn->link;
 		if (acl) {
 		if (acl) {
@@ -361,15 +417,30 @@ struct hci_dev *hci_get_route(bdaddr_t *dst, bdaddr_t *src)
 }
 }
 EXPORT_SYMBOL(hci_get_route);
 EXPORT_SYMBOL(hci_get_route);
 
 
-/* Create SCO or ACL connection.
+/* Create SCO, ACL or LE connection.
  * Device _must_ be locked */
  * Device _must_ be locked */
 struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8 sec_level, __u8 auth_type)
 struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8 sec_level, __u8 auth_type)
 {
 {
 	struct hci_conn *acl;
 	struct hci_conn *acl;
 	struct hci_conn *sco;
 	struct hci_conn *sco;
+	struct hci_conn *le;
 
 
 	BT_DBG("%s dst %s", hdev->name, batostr(dst));
 	BT_DBG("%s dst %s", hdev->name, batostr(dst));
 
 
+	if (type == LE_LINK) {
+		le = hci_conn_hash_lookup_ba(hdev, LE_LINK, dst);
+		if (!le)
+			le = hci_conn_add(hdev, LE_LINK, dst);
+		if (!le)
+			return NULL;
+		if (le->state == BT_OPEN)
+			hci_le_connect(le);
+
+		hci_conn_hold(le);
+
+		return le;
+	}
+
 	acl = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst);
 	acl = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst);
 	if (!acl) {
 	if (!acl) {
 		acl = hci_conn_add(hdev, ACL_LINK, dst);
 		acl = hci_conn_add(hdev, ACL_LINK, dst);

+ 96 - 19
net/bluetooth/hci_core.c

@@ -41,6 +41,7 @@
 #include <linux/interrupt.h>
 #include <linux/interrupt.h>
 #include <linux/notifier.h>
 #include <linux/notifier.h>
 #include <linux/rfkill.h>
 #include <linux/rfkill.h>
+#include <linux/timer.h>
 #include <net/sock.h>
 #include <net/sock.h>
 
 
 #include <asm/system.h>
 #include <asm/system.h>
@@ -123,7 +124,7 @@ static void hci_req_cancel(struct hci_dev *hdev, int err)
 
 
 /* Execute request and wait for completion. */
 /* Execute request and wait for completion. */
 static int __hci_request(struct hci_dev *hdev, void (*req)(struct hci_dev *hdev, unsigned long opt),
 static int __hci_request(struct hci_dev *hdev, void (*req)(struct hci_dev *hdev, unsigned long opt),
-				unsigned long opt, __u32 timeout)
+					unsigned long opt, __u32 timeout)
 {
 {
 	DECLARE_WAITQUEUE(wait, current);
 	DECLARE_WAITQUEUE(wait, current);
 	int err = 0;
 	int err = 0;
@@ -165,7 +166,7 @@ static int __hci_request(struct hci_dev *hdev, void (*req)(struct hci_dev *hdev,
 }
 }
 
 
 static inline int hci_request(struct hci_dev *hdev, void (*req)(struct hci_dev *hdev, unsigned long opt),
 static inline int hci_request(struct hci_dev *hdev, void (*req)(struct hci_dev *hdev, unsigned long opt),
-				unsigned long opt, __u32 timeout)
+					unsigned long opt, __u32 timeout)
 {
 {
 	int ret;
 	int ret;
 
 
@@ -263,6 +264,14 @@ static void hci_init_req(struct hci_dev *hdev, unsigned long opt)
 	hci_send_cmd(hdev, HCI_OP_DELETE_STORED_LINK_KEY, sizeof(cp), &cp);
 	hci_send_cmd(hdev, HCI_OP_DELETE_STORED_LINK_KEY, sizeof(cp), &cp);
 }
 }
 
 
+static void hci_le_init_req(struct hci_dev *hdev, unsigned long opt)
+{
+	BT_DBG("%s", hdev->name);
+
+	/* Read LE buffer size */
+	hci_send_cmd(hdev, HCI_OP_LE_READ_BUFFER_SIZE, 0, NULL);
+}
+
 static void hci_scan_req(struct hci_dev *hdev, unsigned long opt)
 static void hci_scan_req(struct hci_dev *hdev, unsigned long opt)
 {
 {
 	__u8 scan = opt;
 	__u8 scan = opt;
@@ -456,7 +465,7 @@ int hci_inquiry(void __user *arg)
 	/* cache_dump can't sleep. Therefore we allocate temp buffer and then
 	/* cache_dump can't sleep. Therefore we allocate temp buffer and then
 	 * copy it to the user space.
 	 * copy it to the user space.
 	 */
 	 */
-	buf = kmalloc(sizeof(struct inquiry_info) *max_rsp, GFP_KERNEL);
+	buf = kmalloc(sizeof(struct inquiry_info) * max_rsp, GFP_KERNEL);
 	if (!buf) {
 	if (!buf) {
 		err = -ENOMEM;
 		err = -ENOMEM;
 		goto done;
 		goto done;
@@ -525,10 +534,13 @@ int hci_dev_open(__u16 dev)
 		set_bit(HCI_INIT, &hdev->flags);
 		set_bit(HCI_INIT, &hdev->flags);
 		hdev->init_last_cmd = 0;
 		hdev->init_last_cmd = 0;
 
 
-		//__hci_request(hdev, hci_reset_req, 0, HZ);
 		ret = __hci_request(hdev, hci_init_req, 0,
 		ret = __hci_request(hdev, hci_init_req, 0,
 					msecs_to_jiffies(HCI_INIT_TIMEOUT));
 					msecs_to_jiffies(HCI_INIT_TIMEOUT));
 
 
+		if (lmp_le_capable(hdev))
+			ret = __hci_request(hdev, hci_le_init_req, 0,
+					msecs_to_jiffies(HCI_INIT_TIMEOUT));
+
 		clear_bit(HCI_INIT, &hdev->flags);
 		clear_bit(HCI_INIT, &hdev->flags);
 	}
 	}
 
 
@@ -611,6 +623,7 @@ static int hci_dev_do_close(struct hci_dev *hdev)
 
 
 	/* Drop last sent command */
 	/* Drop last sent command */
 	if (hdev->sent_cmd) {
 	if (hdev->sent_cmd) {
+		del_timer_sync(&hdev->cmd_timer);
 		kfree_skb(hdev->sent_cmd);
 		kfree_skb(hdev->sent_cmd);
 		hdev->sent_cmd = NULL;
 		hdev->sent_cmd = NULL;
 	}
 	}
@@ -671,7 +684,7 @@ int hci_dev_reset(__u16 dev)
 		hdev->flush(hdev);
 		hdev->flush(hdev);
 
 
 	atomic_set(&hdev->cmd_cnt, 1);
 	atomic_set(&hdev->cmd_cnt, 1);
-	hdev->acl_cnt = 0; hdev->sco_cnt = 0;
+	hdev->acl_cnt = 0; hdev->sco_cnt = 0; hdev->le_cnt = 0;
 
 
 	if (!test_bit(HCI_RAW, &hdev->flags))
 	if (!test_bit(HCI_RAW, &hdev->flags))
 		ret = __hci_request(hdev, hci_reset_req, 0,
 		ret = __hci_request(hdev, hci_reset_req, 0,
@@ -1054,6 +1067,16 @@ int hci_remove_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr)
 	return 0;
 	return 0;
 }
 }
 
 
+/* HCI command timer function */
+static void hci_cmd_timer(unsigned long arg)
+{
+	struct hci_dev *hdev = (void *) arg;
+
+	BT_ERR("%s command tx timeout", hdev->name);
+	atomic_set(&hdev->cmd_cnt, 1);
+	tasklet_schedule(&hdev->cmd_task);
+}
+
 /* Register HCI device */
 /* Register HCI device */
 int hci_register_dev(struct hci_dev *hdev)
 int hci_register_dev(struct hci_dev *hdev)
 {
 {
@@ -1100,6 +1123,8 @@ int hci_register_dev(struct hci_dev *hdev)
 	skb_queue_head_init(&hdev->cmd_q);
 	skb_queue_head_init(&hdev->cmd_q);
 	skb_queue_head_init(&hdev->raw_q);
 	skb_queue_head_init(&hdev->raw_q);
 
 
+	setup_timer(&hdev->cmd_timer, hci_cmd_timer, (unsigned long) hdev);
+
 	for (i = 0; i < NUM_REASSEMBLY; i++)
 	for (i = 0; i < NUM_REASSEMBLY; i++)
 		hdev->reassembly[i] = NULL;
 		hdev->reassembly[i] = NULL;
 
 
@@ -1187,6 +1212,8 @@ int hci_unregister_dev(struct hci_dev *hdev)
 
 
 	hci_unregister_sysfs(hdev);
 	hci_unregister_sysfs(hdev);
 
 
+	hci_del_off_timer(hdev);
+
 	destroy_workqueue(hdev->workqueue);
 	destroy_workqueue(hdev->workqueue);
 
 
 	hci_dev_lock_bh(hdev);
 	hci_dev_lock_bh(hdev);
@@ -1672,8 +1699,25 @@ static inline struct hci_conn *hci_low_sent(struct hci_dev *hdev, __u8 type, int
 	}
 	}
 
 
 	if (conn) {
 	if (conn) {
-		int cnt = (type == ACL_LINK ? hdev->acl_cnt : hdev->sco_cnt);
-		int q = cnt / num;
+		int cnt, q;
+
+		switch (conn->type) {
+		case ACL_LINK:
+			cnt = hdev->acl_cnt;
+			break;
+		case SCO_LINK:
+		case ESCO_LINK:
+			cnt = hdev->sco_cnt;
+			break;
+		case LE_LINK:
+			cnt = hdev->le_mtu ? hdev->le_cnt : hdev->acl_cnt;
+			break;
+		default:
+			cnt = 0;
+			BT_ERR("Unknown link type");
+		}
+
+		q = cnt / num;
 		*quote = q ? q : 1;
 		*quote = q ? q : 1;
 	} else
 	} else
 		*quote = 0;
 		*quote = 0;
@@ -1682,19 +1726,19 @@ static inline struct hci_conn *hci_low_sent(struct hci_dev *hdev, __u8 type, int
 	return conn;
 	return conn;
 }
 }
 
 
-static inline void hci_acl_tx_to(struct hci_dev *hdev)
+static inline void hci_link_tx_to(struct hci_dev *hdev, __u8 type)
 {
 {
 	struct hci_conn_hash *h = &hdev->conn_hash;
 	struct hci_conn_hash *h = &hdev->conn_hash;
 	struct list_head *p;
 	struct list_head *p;
 	struct hci_conn  *c;
 	struct hci_conn  *c;
 
 
-	BT_ERR("%s ACL tx timeout", hdev->name);
+	BT_ERR("%s link tx timeout", hdev->name);
 
 
 	/* Kill stalled connections */
 	/* Kill stalled connections */
 	list_for_each(p, &h->list) {
 	list_for_each(p, &h->list) {
 		c = list_entry(p, struct hci_conn, list);
 		c = list_entry(p, struct hci_conn, list);
-		if (c->type == ACL_LINK && c->sent) {
-			BT_ERR("%s killing stalled ACL connection %s",
+		if (c->type == type && c->sent) {
+			BT_ERR("%s killing stalled connection %s",
 				hdev->name, batostr(&c->dst));
 				hdev->name, batostr(&c->dst));
 			hci_acl_disconn(c, 0x13);
 			hci_acl_disconn(c, 0x13);
 		}
 		}
@@ -1713,7 +1757,7 @@ static inline void hci_sched_acl(struct hci_dev *hdev)
 		/* ACL tx timeout must be longer than maximum
 		/* ACL tx timeout must be longer than maximum
 		 * link supervision timeout (40.9 seconds) */
 		 * link supervision timeout (40.9 seconds) */
 		if (!hdev->acl_cnt && time_after(jiffies, hdev->acl_last_tx + HZ * 45))
 		if (!hdev->acl_cnt && time_after(jiffies, hdev->acl_last_tx + HZ * 45))
-			hci_acl_tx_to(hdev);
+			hci_link_tx_to(hdev, ACL_LINK);
 	}
 	}
 
 
 	while (hdev->acl_cnt && (conn = hci_low_sent(hdev, ACL_LINK, &quote))) {
 	while (hdev->acl_cnt && (conn = hci_low_sent(hdev, ACL_LINK, &quote))) {
@@ -1772,6 +1816,40 @@ static inline void hci_sched_esco(struct hci_dev *hdev)
 	}
 	}
 }
 }
 
 
+static inline void hci_sched_le(struct hci_dev *hdev)
+{
+	struct hci_conn *conn;
+	struct sk_buff *skb;
+	int quote, cnt;
+
+	BT_DBG("%s", hdev->name);
+
+	if (!test_bit(HCI_RAW, &hdev->flags)) {
+		/* LE tx timeout must be longer than maximum
+		 * link supervision timeout (40.9 seconds) */
+		if (!hdev->le_cnt && hdev->le_pkts &&
+				time_after(jiffies, hdev->le_last_tx + HZ * 45))
+			hci_link_tx_to(hdev, LE_LINK);
+	}
+
+	cnt = hdev->le_pkts ? hdev->le_cnt : hdev->acl_cnt;
+	while (cnt && (conn = hci_low_sent(hdev, LE_LINK, &quote))) {
+		while (quote-- && (skb = skb_dequeue(&conn->data_q))) {
+			BT_DBG("skb %p len %d", skb, skb->len);
+
+			hci_send_frame(skb);
+			hdev->le_last_tx = jiffies;
+
+			cnt--;
+			conn->sent++;
+		}
+	}
+	if (hdev->le_pkts)
+		hdev->le_cnt = cnt;
+	else
+		hdev->acl_cnt = cnt;
+}
+
 static void hci_tx_task(unsigned long arg)
 static void hci_tx_task(unsigned long arg)
 {
 {
 	struct hci_dev *hdev = (struct hci_dev *) arg;
 	struct hci_dev *hdev = (struct hci_dev *) arg;
@@ -1779,7 +1857,8 @@ static void hci_tx_task(unsigned long arg)
 
 
 	read_lock(&hci_task_lock);
 	read_lock(&hci_task_lock);
 
 
-	BT_DBG("%s acl %d sco %d", hdev->name, hdev->acl_cnt, hdev->sco_cnt);
+	BT_DBG("%s acl %d sco %d le %d", hdev->name, hdev->acl_cnt,
+		hdev->sco_cnt, hdev->le_cnt);
 
 
 	/* Schedule queues and send stuff to HCI driver */
 	/* Schedule queues and send stuff to HCI driver */
 
 
@@ -1789,6 +1868,8 @@ static void hci_tx_task(unsigned long arg)
 
 
 	hci_sched_esco(hdev);
 	hci_sched_esco(hdev);
 
 
+	hci_sched_le(hdev);
+
 	/* Send next queued raw (unknown type) packet */
 	/* Send next queued raw (unknown type) packet */
 	while ((skb = skb_dequeue(&hdev->raw_q)))
 	while ((skb = skb_dequeue(&hdev->raw_q)))
 		hci_send_frame(skb);
 		hci_send_frame(skb);
@@ -1936,11 +2017,6 @@ static void hci_cmd_task(unsigned long arg)
 
 
 	BT_DBG("%s cmd %d", hdev->name, atomic_read(&hdev->cmd_cnt));
 	BT_DBG("%s cmd %d", hdev->name, atomic_read(&hdev->cmd_cnt));
 
 
-	if (!atomic_read(&hdev->cmd_cnt) && time_after(jiffies, hdev->cmd_last_tx + HZ)) {
-		BT_ERR("%s command tx timeout", hdev->name);
-		atomic_set(&hdev->cmd_cnt, 1);
-	}
-
 	/* Send queued commands */
 	/* Send queued commands */
 	if (atomic_read(&hdev->cmd_cnt)) {
 	if (atomic_read(&hdev->cmd_cnt)) {
 		skb = skb_dequeue(&hdev->cmd_q);
 		skb = skb_dequeue(&hdev->cmd_q);
@@ -1953,7 +2029,8 @@ static void hci_cmd_task(unsigned long arg)
 		if (hdev->sent_cmd) {
 		if (hdev->sent_cmd) {
 			atomic_dec(&hdev->cmd_cnt);
 			atomic_dec(&hdev->cmd_cnt);
 			hci_send_frame(skb);
 			hci_send_frame(skb);
-			hdev->cmd_last_tx = jiffies;
+			mod_timer(&hdev->cmd_timer,
+				  jiffies + msecs_to_jiffies(HCI_CMD_TIMEOUT));
 		} else {
 		} else {
 			skb_queue_head(&hdev->cmd_q, skb);
 			skb_queue_head(&hdev->cmd_q, skb);
 			tasklet_schedule(&hdev->cmd_task);
 			tasklet_schedule(&hdev->cmd_task);

+ 148 - 17
net/bluetooth/hci_event.c

@@ -776,6 +776,25 @@ static void hci_cc_pin_code_neg_reply(struct hci_dev *hdev, struct sk_buff *skb)
 		mgmt_pin_code_neg_reply_complete(hdev->id, &rp->bdaddr,
 		mgmt_pin_code_neg_reply_complete(hdev->id, &rp->bdaddr,
 								rp->status);
 								rp->status);
 }
 }
+static void hci_cc_le_read_buffer_size(struct hci_dev *hdev,
+				       struct sk_buff *skb)
+{
+	struct hci_rp_le_read_buffer_size *rp = (void *) skb->data;
+
+	BT_DBG("%s status 0x%x", hdev->name, rp->status);
+
+	if (rp->status)
+		return;
+
+	hdev->le_mtu = __le16_to_cpu(rp->le_mtu);
+	hdev->le_pkts = rp->le_max_pkt;
+
+	hdev->le_cnt = hdev->le_pkts;
+
+	BT_DBG("%s le mtu %d:%d", hdev->name, hdev->le_mtu, hdev->le_pkts);
+
+	hci_req_complete(hdev, HCI_OP_LE_READ_BUFFER_SIZE, rp->status);
+}
 
 
 static inline void hci_cs_inquiry(struct hci_dev *hdev, __u8 status)
 static inline void hci_cs_inquiry(struct hci_dev *hdev, __u8 status)
 {
 {
@@ -919,7 +938,7 @@ static void hci_cs_set_conn_encrypt(struct hci_dev *hdev, __u8 status)
 }
 }
 
 
 static int hci_outgoing_auth_needed(struct hci_dev *hdev,
 static int hci_outgoing_auth_needed(struct hci_dev *hdev,
-						struct hci_conn *conn)
+							struct hci_conn *conn)
 {
 {
 	if (conn->state != BT_CONFIG || !conn->out)
 	if (conn->state != BT_CONFIG || !conn->out)
 		return 0;
 		return 0;
@@ -1107,6 +1126,43 @@ static void hci_cs_exit_sniff_mode(struct hci_dev *hdev, __u8 status)
 	hci_dev_unlock(hdev);
 	hci_dev_unlock(hdev);
 }
 }
 
 
+static void hci_cs_le_create_conn(struct hci_dev *hdev, __u8 status)
+{
+	struct hci_cp_le_create_conn *cp;
+	struct hci_conn *conn;
+
+	BT_DBG("%s status 0x%x", hdev->name, status);
+
+	cp = hci_sent_cmd_data(hdev, HCI_OP_LE_CREATE_CONN);
+	if (!cp)
+		return;
+
+	hci_dev_lock(hdev);
+
+	conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->peer_addr);
+
+	BT_DBG("%s bdaddr %s conn %p", hdev->name, batostr(&cp->peer_addr),
+		conn);
+
+	if (status) {
+		if (conn && conn->state == BT_CONNECT) {
+			conn->state = BT_CLOSED;
+			hci_proto_connect_cfm(conn, status);
+			hci_conn_del(conn);
+		}
+	} else {
+		if (!conn) {
+			conn = hci_conn_add(hdev, LE_LINK, &cp->peer_addr);
+			if (conn)
+				conn->out = 1;
+			else
+				BT_ERR("No memory for new connection");
+		}
+	}
+
+	hci_dev_unlock(hdev);
+}
+
 static inline void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
 static inline void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
 {
 	__u8 status = *((__u8 *) skb->data);
 	__u8 status = *((__u8 *) skb->data);
@@ -1237,7 +1293,8 @@ static inline void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *sk
 
 
 	mask |= hci_proto_connect_ind(hdev, &ev->bdaddr, ev->link_type);
 	mask |= hci_proto_connect_ind(hdev, &ev->bdaddr, ev->link_type);
 
 
-	if ((mask & HCI_LM_ACCEPT) && !hci_blacklist_lookup(hdev, &ev->bdaddr)) {
+	if ((mask & HCI_LM_ACCEPT) &&
+			!hci_blacklist_lookup(hdev, &ev->bdaddr)) {
 		/* Connection accepted */
 		/* Connection accepted */
 		struct inquiry_entry *ie;
 		struct inquiry_entry *ie;
 		struct hci_conn *conn;
 		struct hci_conn *conn;
@@ -1667,11 +1724,18 @@ static inline void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *sk
 		hci_cc_pin_code_neg_reply(hdev, skb);
 		hci_cc_pin_code_neg_reply(hdev, skb);
 		break;
 		break;
 
 
+	case HCI_OP_LE_READ_BUFFER_SIZE:
+		hci_cc_le_read_buffer_size(hdev, skb);
+		break;
+
 	default:
 	default:
 		BT_DBG("%s opcode 0x%x", hdev->name, opcode);
 		BT_DBG("%s opcode 0x%x", hdev->name, opcode);
 		break;
 		break;
 	}
 	}
 
 
+	if (ev->opcode != HCI_OP_NOP)
+		del_timer(&hdev->cmd_timer);
+
 	if (ev->ncmd) {
 	if (ev->ncmd) {
 		atomic_set(&hdev->cmd_cnt, 1);
 		atomic_set(&hdev->cmd_cnt, 1);
 		if (!skb_queue_empty(&hdev->cmd_q))
 		if (!skb_queue_empty(&hdev->cmd_q))
@@ -1738,11 +1802,18 @@ static inline void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb)
 			mgmt_disconnect_failed(hdev->id);
 			mgmt_disconnect_failed(hdev->id);
 		break;
 		break;
 
 
+	case HCI_OP_LE_CREATE_CONN:
+		hci_cs_le_create_conn(hdev, ev->status);
+		break;
+
 	default:
 	default:
 		BT_DBG("%s opcode 0x%x", hdev->name, opcode);
 		BT_DBG("%s opcode 0x%x", hdev->name, opcode);
 		break;
 		break;
 	}
 	}
 
 
+	if (ev->opcode != HCI_OP_NOP)
+		del_timer(&hdev->cmd_timer);
+
 	if (ev->ncmd) {
 	if (ev->ncmd) {
 		atomic_set(&hdev->cmd_cnt, 1);
 		atomic_set(&hdev->cmd_cnt, 1);
 		if (!skb_queue_empty(&hdev->cmd_q))
 		if (!skb_queue_empty(&hdev->cmd_q))
@@ -1808,6 +1879,16 @@ static inline void hci_num_comp_pkts_evt(struct hci_dev *hdev, struct sk_buff *s
 				hdev->acl_cnt += count;
 				hdev->acl_cnt += count;
 				if (hdev->acl_cnt > hdev->acl_pkts)
 				if (hdev->acl_cnt > hdev->acl_pkts)
 					hdev->acl_cnt = hdev->acl_pkts;
 					hdev->acl_cnt = hdev->acl_pkts;
+			} else if (conn->type == LE_LINK) {
+				if (hdev->le_pkts) {
+					hdev->le_cnt += count;
+					if (hdev->le_cnt > hdev->le_pkts)
+						hdev->le_cnt = hdev->le_pkts;
+				} else {
+					hdev->acl_cnt += count;
+					if (hdev->acl_cnt > hdev->acl_pkts)
+						hdev->acl_cnt = hdev->acl_pkts;
+				}
 			} else {
 			} else {
 				hdev->sco_cnt += count;
 				hdev->sco_cnt += count;
 				if (hdev->sco_cnt > hdev->sco_pkts)
 				if (hdev->sco_cnt > hdev->sco_pkts)
@@ -2021,7 +2102,8 @@ static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct
 	hci_dev_lock(hdev);
 	hci_dev_lock(hdev);
 
 
 	if ((skb->len - 1) / num_rsp != sizeof(struct inquiry_info_with_rssi)) {
 	if ((skb->len - 1) / num_rsp != sizeof(struct inquiry_info_with_rssi)) {
-		struct inquiry_info_with_rssi_and_pscan_mode *info = (void *) (skb->data + 1);
+		struct inquiry_info_with_rssi_and_pscan_mode *info;
+		info = (void *) (skb->data + 1);
 
 
 		for (; num_rsp; num_rsp--) {
 		for (; num_rsp; num_rsp--) {
 			bacpy(&data.bdaddr, &info->bdaddr);
 			bacpy(&data.bdaddr, &info->bdaddr);
@@ -2162,17 +2244,8 @@ static inline void hci_sync_conn_changed_evt(struct hci_dev *hdev, struct sk_buf
 static inline void hci_sniff_subrate_evt(struct hci_dev *hdev, struct sk_buff *skb)
 static inline void hci_sniff_subrate_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
 {
 	struct hci_ev_sniff_subrate *ev = (void *) skb->data;
 	struct hci_ev_sniff_subrate *ev = (void *) skb->data;
-	struct hci_conn *conn;
 
 
 	BT_DBG("%s status %d", hdev->name, ev->status);
 	BT_DBG("%s status %d", hdev->name, ev->status);
-
-	hci_dev_lock(hdev);
-
-	conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle));
-	if (conn) {
-	}
-
-	hci_dev_unlock(hdev);
 }
 }
 
 
 static inline void hci_extended_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *skb)
 static inline void hci_extended_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *skb)
@@ -2190,12 +2263,12 @@ static inline void hci_extended_inquiry_result_evt(struct hci_dev *hdev, struct
 
 
 	for (; num_rsp; num_rsp--) {
 	for (; num_rsp; num_rsp--) {
 		bacpy(&data.bdaddr, &info->bdaddr);
 		bacpy(&data.bdaddr, &info->bdaddr);
-		data.pscan_rep_mode     = info->pscan_rep_mode;
-		data.pscan_period_mode  = info->pscan_period_mode;
-		data.pscan_mode         = 0x00;
+		data.pscan_rep_mode	= info->pscan_rep_mode;
+		data.pscan_period_mode	= info->pscan_period_mode;
+		data.pscan_mode		= 0x00;
 		memcpy(data.dev_class, info->dev_class, 3);
 		memcpy(data.dev_class, info->dev_class, 3);
-		data.clock_offset       = info->clock_offset;
-		data.rssi               = info->rssi;
+		data.clock_offset	= info->clock_offset;
+		data.rssi		= info->rssi;
 		data.ssp_mode		= 0x01;
 		data.ssp_mode		= 0x01;
 		info++;
 		info++;
 		hci_inquiry_cache_update(hdev, &data);
 		hci_inquiry_cache_update(hdev, &data);
@@ -2321,6 +2394,60 @@ static inline void hci_remote_host_features_evt(struct hci_dev *hdev, struct sk_
 	hci_dev_unlock(hdev);
 	hci_dev_unlock(hdev);
 }
 }
 
 
+static inline void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
+{
+	struct hci_ev_le_conn_complete *ev = (void *) skb->data;
+	struct hci_conn *conn;
+
+	BT_DBG("%s status %d", hdev->name, ev->status);
+
+	hci_dev_lock(hdev);
+
+	conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &ev->bdaddr);
+	if (!conn) {
+		conn = hci_conn_add(hdev, LE_LINK, &ev->bdaddr);
+		if (!conn) {
+			BT_ERR("No memory for new connection");
+			hci_dev_unlock(hdev);
+			return;
+		}
+	}
+
+	if (ev->status) {
+		hci_proto_connect_cfm(conn, ev->status);
+		conn->state = BT_CLOSED;
+		hci_conn_del(conn);
+		goto unlock;
+	}
+
+	conn->handle = __le16_to_cpu(ev->handle);
+	conn->state = BT_CONNECTED;
+
+	hci_conn_hold_device(conn);
+	hci_conn_add_sysfs(conn);
+
+	hci_proto_connect_cfm(conn, ev->status);
+
+unlock:
+	hci_dev_unlock(hdev);
+}
+
+static inline void hci_le_meta_evt(struct hci_dev *hdev, struct sk_buff *skb)
+{
+	struct hci_ev_le_meta *le_ev = (void *) skb->data;
+
+	skb_pull(skb, sizeof(*le_ev));
+
+	switch (le_ev->subevent) {
+	case HCI_EV_LE_CONN_COMPLETE:
+		hci_le_conn_complete_evt(hdev, skb);
+		break;
+
+	default:
+		break;
+	}
+}
+
 void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
 void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
 {
 {
 	struct hci_event_hdr *hdr = (void *) skb->data;
 	struct hci_event_hdr *hdr = (void *) skb->data;
@@ -2461,6 +2588,10 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
 		hci_remote_host_features_evt(hdev, skb);
 		hci_remote_host_features_evt(hdev, skb);
 		break;
 		break;
 
 
+	case HCI_EV_LE_META:
+		hci_le_meta_evt(hdev, skb);
+		break;
+
 	default:
 	default:
 		BT_DBG("%s event 0x%x", hdev->name, event);
 		BT_DBG("%s event 0x%x", hdev->name, event);
 		break;
 		break;

+ 3 - 3
net/bluetooth/hci_sysfs.c

@@ -11,7 +11,7 @@
 
 
 static struct class *bt_class;
 static struct class *bt_class;
 
 
-struct dentry *bt_debugfs = NULL;
+struct dentry *bt_debugfs;
 EXPORT_SYMBOL_GPL(bt_debugfs);
 EXPORT_SYMBOL_GPL(bt_debugfs);
 
 
 static inline char *link_typetostr(int type)
 static inline char *link_typetostr(int type)
@@ -51,8 +51,8 @@ static ssize_t show_link_features(struct device *dev, struct device_attribute *a
 				conn->features[6], conn->features[7]);
 				conn->features[6], conn->features[7]);
 }
 }
 
 
-#define LINK_ATTR(_name,_mode,_show,_store) \
-struct device_attribute link_attr_##_name = __ATTR(_name,_mode,_show,_store)
+#define LINK_ATTR(_name, _mode, _show, _store) \
+struct device_attribute link_attr_##_name = __ATTR(_name, _mode, _show, _store)
 
 
 static LINK_ATTR(type, S_IRUGO, show_link_type, NULL);
 static LINK_ATTR(type, S_IRUGO, show_link_type, NULL);
 static LINK_ATTR(address, S_IRUGO, show_link_address, NULL);
 static LINK_ATTR(address, S_IRUGO, show_link_address, NULL);

+ 0 - 2
net/bluetooth/hidp/core.c

@@ -1019,8 +1019,6 @@ static int __init hidp_init(void)
 {
 {
 	int ret;
 	int ret;
 
 
-	l2cap_load();
-
 	BT_INFO("HIDP (Human Interface Emulation) ver %s", VERSION);
 	BT_INFO("HIDP (Human Interface Emulation) ver %s", VERSION);
 
 
 	ret = hid_register_driver(&hidp_driver);
 	ret = hid_register_driver(&hidp_driver);

+ 268 - 87
net/bluetooth/l2cap_core.c

@@ -55,8 +55,6 @@
 #include <net/bluetooth/hci_core.h>
 #include <net/bluetooth/hci_core.h>
 #include <net/bluetooth/l2cap.h>
 #include <net/bluetooth/l2cap.h>
 
 
-#define VERSION "2.15"
-
 int disable_ertm;
 int disable_ertm;
 
 
 static u32 l2cap_feat_mask = L2CAP_FEAT_FIXED_CHAN;
 static u32 l2cap_feat_mask = L2CAP_FEAT_FIXED_CHAN;
@@ -183,8 +181,16 @@ static void __l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct so
 	l2cap_pi(sk)->conn = conn;
 	l2cap_pi(sk)->conn = conn;
 
 
 	if (sk->sk_type == SOCK_SEQPACKET || sk->sk_type == SOCK_STREAM) {
 	if (sk->sk_type == SOCK_SEQPACKET || sk->sk_type == SOCK_STREAM) {
-		/* Alloc CID for connection-oriented socket */
-		l2cap_pi(sk)->scid = l2cap_alloc_cid(l);
+		if (conn->hcon->type == LE_LINK) {
+			/* LE connection */
+			l2cap_pi(sk)->omtu = L2CAP_LE_DEFAULT_MTU;
+			l2cap_pi(sk)->scid = L2CAP_CID_LE_DATA;
+			l2cap_pi(sk)->dcid = L2CAP_CID_LE_DATA;
+		} else {
+			/* Alloc CID for connection-oriented socket */
+			l2cap_pi(sk)->scid = l2cap_alloc_cid(l);
+			l2cap_pi(sk)->omtu = L2CAP_DEFAULT_MTU;
+		}
 	} else if (sk->sk_type == SOCK_DGRAM) {
 	} else if (sk->sk_type == SOCK_DGRAM) {
 		/* Connectionless socket */
 		/* Connectionless socket */
 		l2cap_pi(sk)->scid = L2CAP_CID_CONN_LESS;
 		l2cap_pi(sk)->scid = L2CAP_CID_CONN_LESS;
@@ -583,6 +589,82 @@ static void l2cap_conn_start(struct l2cap_conn *conn)
 	}
 	}
 }
 }
 
 
+/* Find socket with cid and source bdaddr.
+ * Returns closest match, locked.
+ */
+static struct sock *l2cap_get_sock_by_scid(int state, __le16 cid, bdaddr_t *src)
+{
+	struct sock *s, *sk = NULL, *sk1 = NULL;
+	struct hlist_node *node;
+
+	read_lock(&l2cap_sk_list.lock);
+
+	sk_for_each(sk, node, &l2cap_sk_list.head) {
+		if (state && sk->sk_state != state)
+			continue;
+
+		if (l2cap_pi(sk)->scid == cid) {
+			/* Exact match. */
+			if (!bacmp(&bt_sk(sk)->src, src))
+				break;
+
+			/* Closest match */
+			if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY))
+				sk1 = sk;
+		}
+	}
+	s = node ? sk : sk1;
+	if (s)
+		bh_lock_sock(s);
+	read_unlock(&l2cap_sk_list.lock);
+
+	return s;
+}
+
+static void l2cap_le_conn_ready(struct l2cap_conn *conn)
+{
+	struct l2cap_chan_list *list = &conn->chan_list;
+	struct sock *parent, *uninitialized_var(sk);
+
+	BT_DBG("");
+
+	/* Check if we have socket listening on cid */
+	parent = l2cap_get_sock_by_scid(BT_LISTEN, L2CAP_CID_LE_DATA,
+							conn->src);
+	if (!parent)
+		return;
+
+	/* Check for backlog size */
+	if (sk_acceptq_is_full(parent)) {
+		BT_DBG("backlog full %d", parent->sk_ack_backlog);
+		goto clean;
+	}
+
+	sk = l2cap_sock_alloc(sock_net(parent), NULL, BTPROTO_L2CAP, GFP_ATOMIC);
+	if (!sk)
+		goto clean;
+
+	write_lock_bh(&list->lock);
+
+	hci_conn_hold(conn->hcon);
+
+	l2cap_sock_init(sk, parent);
+	bacpy(&bt_sk(sk)->src, conn->src);
+	bacpy(&bt_sk(sk)->dst, conn->dst);
+
+	__l2cap_chan_add(conn, sk, parent);
+
+	l2cap_sock_set_timer(sk, sk->sk_sndtimeo);
+
+	sk->sk_state = BT_CONNECTED;
+	parent->sk_data_ready(parent, 0);
+
+	write_unlock_bh(&list->lock);
+
+clean:
+	bh_unlock_sock(parent);
+}
+
 static void l2cap_conn_ready(struct l2cap_conn *conn)
 static void l2cap_conn_ready(struct l2cap_conn *conn)
 {
 {
 	struct l2cap_chan_list *l = &conn->chan_list;
 	struct l2cap_chan_list *l = &conn->chan_list;
@@ -590,11 +672,20 @@ static void l2cap_conn_ready(struct l2cap_conn *conn)
 
 
 	BT_DBG("conn %p", conn);
 	BT_DBG("conn %p", conn);
 
 
+	if (!conn->hcon->out && conn->hcon->type == LE_LINK)
+		l2cap_le_conn_ready(conn);
+
 	read_lock(&l->lock);
 	read_lock(&l->lock);
 
 
 	for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) {
 	for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) {
 		bh_lock_sock(sk);
 		bh_lock_sock(sk);
 
 
+		if (conn->hcon->type == LE_LINK) {
+			l2cap_sock_clear_timer(sk);
+			sk->sk_state = BT_CONNECTED;
+			sk->sk_state_change(sk);
+		}
+
 		if (sk->sk_type != SOCK_SEQPACKET &&
 		if (sk->sk_type != SOCK_SEQPACKET &&
 				sk->sk_type != SOCK_STREAM) {
 				sk->sk_type != SOCK_STREAM) {
 			l2cap_sock_clear_timer(sk);
 			l2cap_sock_clear_timer(sk);
@@ -653,7 +744,11 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status)
 
 
 	BT_DBG("hcon %p conn %p", hcon, conn);
 	BT_DBG("hcon %p conn %p", hcon, conn);
 
 
-	conn->mtu = hcon->hdev->acl_mtu;
+	if (hcon->hdev->le_mtu && hcon->type == LE_LINK)
+		conn->mtu = hcon->hdev->le_mtu;
+	else
+		conn->mtu = hcon->hdev->acl_mtu;
+
 	conn->src = &hcon->hdev->bdaddr;
 	conn->src = &hcon->hdev->bdaddr;
 	conn->dst = &hcon->dst;
 	conn->dst = &hcon->dst;
 
 
@@ -662,7 +757,8 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status)
 	spin_lock_init(&conn->lock);
 	spin_lock_init(&conn->lock);
 	rwlock_init(&conn->chan_list.lock);
 	rwlock_init(&conn->chan_list.lock);
 
 
-	setup_timer(&conn->info_timer, l2cap_info_timeout,
+	if (hcon->type != LE_LINK)
+		setup_timer(&conn->info_timer, l2cap_info_timeout,
 						(unsigned long) conn);
 						(unsigned long) conn);
 
 
 	conn->disc_reason = 0x13;
 	conn->disc_reason = 0x13;
@@ -760,8 +856,13 @@ int l2cap_do_connect(struct sock *sk)
 
 
 	auth_type = l2cap_get_auth_type(sk);
 	auth_type = l2cap_get_auth_type(sk);
 
 
-	hcon = hci_connect(hdev, ACL_LINK, dst,
+	if (l2cap_pi(sk)->dcid == L2CAP_CID_LE_DATA)
+		hcon = hci_connect(hdev, LE_LINK, dst,
 					l2cap_pi(sk)->sec_level, auth_type);
 					l2cap_pi(sk)->sec_level, auth_type);
+	else
+		hcon = hci_connect(hdev, ACL_LINK, dst,
+					l2cap_pi(sk)->sec_level, auth_type);
+
 	if (!hcon)
 	if (!hcon)
 		goto done;
 		goto done;
 
 
@@ -1327,7 +1428,11 @@ static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn,
 
 
 	lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
 	lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
 	lh->len = cpu_to_le16(L2CAP_CMD_HDR_SIZE + dlen);
 	lh->len = cpu_to_le16(L2CAP_CMD_HDR_SIZE + dlen);
-	lh->cid = cpu_to_le16(L2CAP_CID_SIGNALING);
+
+	if (conn->hcon->type == LE_LINK)
+		lh->cid = cpu_to_le16(L2CAP_CID_LE_SIGNALING);
+	else
+		lh->cid = cpu_to_le16(L2CAP_CID_SIGNALING);
 
 
 	cmd = (struct l2cap_cmd_hdr *) skb_put(skb, L2CAP_CMD_HDR_SIZE);
 	cmd = (struct l2cap_cmd_hdr *) skb_put(skb, L2CAP_CMD_HDR_SIZE);
 	cmd->code  = code;
 	cmd->code  = code;
@@ -1566,10 +1671,6 @@ done:
 		break;
 		break;
 	}
 	}
 
 
-	/* FIXME: Need actual value of the flush timeout */
-	//if (flush_to != L2CAP_DEFAULT_FLUSH_TO)
-	//   l2cap_add_conf_opt(&ptr, L2CAP_CONF_FLUSH_TO, 2, pi->flush_to);
-
 	req->dcid  = cpu_to_le16(pi->dcid);
 	req->dcid  = cpu_to_le16(pi->dcid);
 	req->flags = cpu_to_le16(0);
 	req->flags = cpu_to_le16(0);
 
 
@@ -2396,12 +2497,153 @@ static inline int l2cap_information_rsp(struct l2cap_conn *conn, struct l2cap_cm
 	return 0;
 	return 0;
 }
 }
 
 
-static inline void l2cap_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb)
+static inline int l2cap_check_conn_param(u16 min, u16 max, u16 latency,
+							u16 to_multiplier)
+{
+	u16 max_latency;
+
+	if (min > max || min < 6 || max > 3200)
+		return -EINVAL;
+
+	if (to_multiplier < 10 || to_multiplier > 3200)
+		return -EINVAL;
+
+	if (max >= to_multiplier * 8)
+		return -EINVAL;
+
+	max_latency = (to_multiplier * 8 / max) - 1;
+	if (latency > 499 || latency > max_latency)
+		return -EINVAL;
+
+	return 0;
+}
+
+static inline int l2cap_conn_param_update_req(struct l2cap_conn *conn,
+					struct l2cap_cmd_hdr *cmd, u8 *data)
+{
+	struct hci_conn *hcon = conn->hcon;
+	struct l2cap_conn_param_update_req *req;
+	struct l2cap_conn_param_update_rsp rsp;
+	u16 min, max, latency, to_multiplier, cmd_len;
+	int err;
+
+	if (!(hcon->link_mode & HCI_LM_MASTER))
+		return -EINVAL;
+
+	cmd_len = __le16_to_cpu(cmd->len);
+	if (cmd_len != sizeof(struct l2cap_conn_param_update_req))
+		return -EPROTO;
+
+	req = (struct l2cap_conn_param_update_req *) data;
+	min		= __le16_to_cpu(req->min);
+	max		= __le16_to_cpu(req->max);
+	latency		= __le16_to_cpu(req->latency);
+	to_multiplier	= __le16_to_cpu(req->to_multiplier);
+
+	BT_DBG("min 0x%4.4x max 0x%4.4x latency: 0x%4.4x Timeout: 0x%4.4x",
+						min, max, latency, to_multiplier);
+
+	memset(&rsp, 0, sizeof(rsp));
+
+	err = l2cap_check_conn_param(min, max, latency, to_multiplier);
+	if (err)
+		rsp.result = cpu_to_le16(L2CAP_CONN_PARAM_REJECTED);
+	else
+		rsp.result = cpu_to_le16(L2CAP_CONN_PARAM_ACCEPTED);
+
+	l2cap_send_cmd(conn, cmd->ident, L2CAP_CONN_PARAM_UPDATE_RSP,
+							sizeof(rsp), &rsp);
+
+	if (!err)
+		hci_le_conn_update(hcon, min, max, latency, to_multiplier);
+
+	return 0;
+}
+
+static inline int l2cap_bredr_sig_cmd(struct l2cap_conn *conn,
+			struct l2cap_cmd_hdr *cmd, u16 cmd_len, u8 *data)
+{
+	int err = 0;
+
+	switch (cmd->code) {
+	case L2CAP_COMMAND_REJ:
+		l2cap_command_rej(conn, cmd, data);
+		break;
+
+	case L2CAP_CONN_REQ:
+		err = l2cap_connect_req(conn, cmd, data);
+		break;
+
+	case L2CAP_CONN_RSP:
+		err = l2cap_connect_rsp(conn, cmd, data);
+		break;
+
+	case L2CAP_CONF_REQ:
+		err = l2cap_config_req(conn, cmd, cmd_len, data);
+		break;
+
+	case L2CAP_CONF_RSP:
+		err = l2cap_config_rsp(conn, cmd, data);
+		break;
+
+	case L2CAP_DISCONN_REQ:
+		err = l2cap_disconnect_req(conn, cmd, data);
+		break;
+
+	case L2CAP_DISCONN_RSP:
+		err = l2cap_disconnect_rsp(conn, cmd, data);
+		break;
+
+	case L2CAP_ECHO_REQ:
+		l2cap_send_cmd(conn, cmd->ident, L2CAP_ECHO_RSP, cmd_len, data);
+		break;
+
+	case L2CAP_ECHO_RSP:
+		break;
+
+	case L2CAP_INFO_REQ:
+		err = l2cap_information_req(conn, cmd, data);
+		break;
+
+	case L2CAP_INFO_RSP:
+		err = l2cap_information_rsp(conn, cmd, data);
+		break;
+
+	default:
+		BT_ERR("Unknown BR/EDR signaling command 0x%2.2x", cmd->code);
+		err = -EINVAL;
+		break;
+	}
+
+	return err;
+}
+
+static inline int l2cap_le_sig_cmd(struct l2cap_conn *conn,
+					struct l2cap_cmd_hdr *cmd, u8 *data)
+{
+	switch (cmd->code) {
+	case L2CAP_COMMAND_REJ:
+		return 0;
+
+	case L2CAP_CONN_PARAM_UPDATE_REQ:
+		return l2cap_conn_param_update_req(conn, cmd, data);
+
+	case L2CAP_CONN_PARAM_UPDATE_RSP:
+		return 0;
+
+	default:
+		BT_ERR("Unknown LE signaling command 0x%2.2x", cmd->code);
+		return -EINVAL;
+	}
+}
+
+static inline void l2cap_sig_channel(struct l2cap_conn *conn,
+							struct sk_buff *skb)
 {
 {
 	u8 *data = skb->data;
 	u8 *data = skb->data;
 	int len = skb->len;
 	int len = skb->len;
 	struct l2cap_cmd_hdr cmd;
 	struct l2cap_cmd_hdr cmd;
-	int err = 0;
+	int err;
 
 
 	l2cap_raw_recv(conn, skb);
 	l2cap_raw_recv(conn, skb);
 
 
@@ -2420,55 +2662,10 @@ static inline void l2cap_sig_channel(struct l2cap_conn *conn, struct sk_buff *sk
 			break;
 			break;
 		}
 		}
 
 
-		switch (cmd.code) {
-		case L2CAP_COMMAND_REJ:
-			l2cap_command_rej(conn, &cmd, data);
-			break;
-
-		case L2CAP_CONN_REQ:
-			err = l2cap_connect_req(conn, &cmd, data);
-			break;
-
-		case L2CAP_CONN_RSP:
-			err = l2cap_connect_rsp(conn, &cmd, data);
-			break;
-
-		case L2CAP_CONF_REQ:
-			err = l2cap_config_req(conn, &cmd, cmd_len, data);
-			break;
-
-		case L2CAP_CONF_RSP:
-			err = l2cap_config_rsp(conn, &cmd, data);
-			break;
-
-		case L2CAP_DISCONN_REQ:
-			err = l2cap_disconnect_req(conn, &cmd, data);
-			break;
-
-		case L2CAP_DISCONN_RSP:
-			err = l2cap_disconnect_rsp(conn, &cmd, data);
-			break;
-
-		case L2CAP_ECHO_REQ:
-			l2cap_send_cmd(conn, cmd.ident, L2CAP_ECHO_RSP, cmd_len, data);
-			break;
-
-		case L2CAP_ECHO_RSP:
-			break;
-
-		case L2CAP_INFO_REQ:
-			err = l2cap_information_req(conn, &cmd, data);
-			break;
-
-		case L2CAP_INFO_RSP:
-			err = l2cap_information_rsp(conn, &cmd, data);
-			break;
-
-		default:
-			BT_ERR("Unknown signaling command 0x%2.2x", cmd.code);
-			err = -EINVAL;
-			break;
-		}
+		if (conn->hcon->type == LE_LINK)
+			err = l2cap_le_sig_cmd(conn, &cmd, data);
+		else
+			err = l2cap_bredr_sig_cmd(conn, &cmd, cmd_len, data);
 
 
 		if (err) {
 		if (err) {
 			struct l2cap_cmd_rej rej;
 			struct l2cap_cmd_rej rej;
@@ -3465,6 +3662,7 @@ static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb)
 	BT_DBG("len %d, cid 0x%4.4x", len, cid);
 	BT_DBG("len %d, cid 0x%4.4x", len, cid);
 
 
 	switch (cid) {
 	switch (cid) {
+	case L2CAP_CID_LE_SIGNALING:
 	case L2CAP_CID_SIGNALING:
 	case L2CAP_CID_SIGNALING:
 		l2cap_sig_channel(conn, skb);
 		l2cap_sig_channel(conn, skb);
 		break;
 		break;
@@ -3522,7 +3720,7 @@ static int l2cap_connect_cfm(struct hci_conn *hcon, u8 status)
 
 
 	BT_DBG("hcon %p bdaddr %s status %d", hcon, batostr(&hcon->dst), status);
 	BT_DBG("hcon %p bdaddr %s status %d", hcon, batostr(&hcon->dst), status);
 
 
-	if (hcon->type != ACL_LINK)
+	if (!(hcon->type == ACL_LINK || hcon->type == LE_LINK))
 		return -EINVAL;
 		return -EINVAL;
 
 
 	if (!status) {
 	if (!status) {
@@ -3551,7 +3749,7 @@ static int l2cap_disconn_cfm(struct hci_conn *hcon, u8 reason)
 {
 {
 	BT_DBG("hcon %p reason %d", hcon, reason);
 	BT_DBG("hcon %p reason %d", hcon, reason);
 
 
-	if (hcon->type != ACL_LINK)
+	if (!(hcon->type == ACL_LINK || hcon->type == LE_LINK))
 		return -EINVAL;
 		return -EINVAL;
 
 
 	l2cap_conn_del(hcon, bt_err(reason));
 	l2cap_conn_del(hcon, bt_err(reason));
@@ -3768,12 +3966,13 @@ static int l2cap_debugfs_show(struct seq_file *f, void *p)
 	sk_for_each(sk, node, &l2cap_sk_list.head) {
 	sk_for_each(sk, node, &l2cap_sk_list.head) {
 		struct l2cap_pinfo *pi = l2cap_pi(sk);
 		struct l2cap_pinfo *pi = l2cap_pi(sk);
 
 
-		seq_printf(f, "%s %s %d %d 0x%4.4x 0x%4.4x %d %d %d\n",
+		seq_printf(f, "%s %s %d %d 0x%4.4x 0x%4.4x %d %d %d %d\n",
 					batostr(&bt_sk(sk)->src),
 					batostr(&bt_sk(sk)->src),
 					batostr(&bt_sk(sk)->dst),
 					batostr(&bt_sk(sk)->dst),
 					sk->sk_state, __le16_to_cpu(pi->psm),
 					sk->sk_state, __le16_to_cpu(pi->psm),
 					pi->scid, pi->dcid,
 					pi->scid, pi->dcid,
-					pi->imtu, pi->omtu, pi->sec_level);
+					pi->imtu, pi->omtu, pi->sec_level,
+					pi->mode);
 	}
 	}
 
 
 	read_unlock_bh(&l2cap_sk_list.lock);
 	read_unlock_bh(&l2cap_sk_list.lock);
@@ -3806,7 +4005,7 @@ static struct hci_proto l2cap_hci_proto = {
 	.recv_acldata	= l2cap_recv_acldata
 	.recv_acldata	= l2cap_recv_acldata
 };
 };
 
 
-static int __init l2cap_init(void)
+int __init l2cap_init(void)
 {
 {
 	int err;
 	int err;
 
 
@@ -3834,7 +4033,6 @@ static int __init l2cap_init(void)
 			BT_ERR("Failed to create L2CAP debug file");
 			BT_ERR("Failed to create L2CAP debug file");
 	}
 	}
 
 
-	BT_INFO("L2CAP ver %s", VERSION);
 	BT_INFO("L2CAP socket layer initialized");
 	BT_INFO("L2CAP socket layer initialized");
 
 
 	return 0;
 	return 0;
@@ -3845,7 +4043,7 @@ error:
 	return err;
 	return err;
 }
 }
 
 
-static void __exit l2cap_exit(void)
+void l2cap_exit(void)
 {
 {
 	debugfs_remove(l2cap_debugfs);
 	debugfs_remove(l2cap_debugfs);
 
 
@@ -3858,22 +4056,5 @@ static void __exit l2cap_exit(void)
 	l2cap_cleanup_sockets();
 	l2cap_cleanup_sockets();
 }
 }
 
 
-void l2cap_load(void)
-{
-	/* Dummy function to trigger automatic L2CAP module loading by
-	 * other modules that use L2CAP sockets but don't use any other
-	 * symbols from it. */
-}
-EXPORT_SYMBOL(l2cap_load);
-
-module_init(l2cap_init);
-module_exit(l2cap_exit);
-
 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_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
-MODULE_DESCRIPTION("Bluetooth L2CAP ver " VERSION);
-MODULE_VERSION(VERSION);
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("bt-proto-0");

+ 33 - 27
net/bluetooth/l2cap_sock.c

@@ -103,7 +103,7 @@ static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen)
 	len = min_t(unsigned int, sizeof(la), alen);
 	len = min_t(unsigned int, sizeof(la), alen);
 	memcpy(&la, addr, len);
 	memcpy(&la, addr, len);
 
 
-	if (la.l2_cid)
+	if (la.l2_cid && la.l2_psm)
 		return -EINVAL;
 		return -EINVAL;
 
 
 	lock_sock(sk);
 	lock_sock(sk);
@@ -145,6 +145,9 @@ static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen)
 			l2cap_pi(sk)->sec_level = BT_SECURITY_SDP;
 			l2cap_pi(sk)->sec_level = BT_SECURITY_SDP;
 	}
 	}
 
 
+	if (la.l2_cid)
+		l2cap_pi(sk)->scid = la.l2_cid;
+
 	write_unlock_bh(&l2cap_sk_list.lock);
 	write_unlock_bh(&l2cap_sk_list.lock);
 
 
 done:
 done:
@@ -168,13 +171,13 @@ static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int al
 	len = min_t(unsigned int, sizeof(la), alen);
 	len = min_t(unsigned int, sizeof(la), alen);
 	memcpy(&la, addr, len);
 	memcpy(&la, addr, len);
 
 
-	if (la.l2_cid)
+	if (la.l2_cid && la.l2_psm)
 		return -EINVAL;
 		return -EINVAL;
 
 
 	lock_sock(sk);
 	lock_sock(sk);
 
 
 	if ((sk->sk_type == SOCK_SEQPACKET || sk->sk_type == SOCK_STREAM)
 	if ((sk->sk_type == SOCK_SEQPACKET || sk->sk_type == SOCK_STREAM)
-			&& !la.l2_psm) {
+			&& !(la.l2_psm || la.l2_cid)) {
 		err = -EINVAL;
 		err = -EINVAL;
 		goto done;
 		goto done;
 	}
 	}
@@ -216,7 +219,7 @@ static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int al
 
 
 	/* PSM must be odd and lsb of upper byte must be 0 */
 	/* PSM must be odd and lsb of upper byte must be 0 */
 	if ((__le16_to_cpu(la.l2_psm) & 0x0101) != 0x0001 &&
 	if ((__le16_to_cpu(la.l2_psm) & 0x0101) != 0x0001 &&
-		sk->sk_type != SOCK_RAW) {
+				sk->sk_type != SOCK_RAW && !la.l2_cid) {
 		err = -EINVAL;
 		err = -EINVAL;
 		goto done;
 		goto done;
 	}
 	}
@@ -224,6 +227,7 @@ static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int al
 	/* Set destination address and psm */
 	/* Set destination address and psm */
 	bacpy(&bt_sk(sk)->dst, &la.l2_bdaddr);
 	bacpy(&bt_sk(sk)->dst, &la.l2_bdaddr);
 	l2cap_pi(sk)->psm = la.l2_psm;
 	l2cap_pi(sk)->psm = la.l2_psm;
+	l2cap_pi(sk)->dcid = la.l2_cid;
 
 
 	err = l2cap_do_connect(sk);
 	err = l2cap_do_connect(sk);
 	if (err)
 	if (err)
@@ -265,7 +269,7 @@ static int l2cap_sock_listen(struct socket *sock, int backlog)
 		goto done;
 		goto done;
 	}
 	}
 
 
-	if (!l2cap_pi(sk)->psm) {
+	if (!l2cap_pi(sk)->psm && !l2cap_pi(sk)->dcid) {
 		bdaddr_t *src = &bt_sk(sk)->src;
 		bdaddr_t *src = &bt_sk(sk)->src;
 		u16 psm;
 		u16 psm;
 
 
@@ -392,6 +396,7 @@ static int l2cap_sock_getsockopt_old(struct socket *sock, int optname, char __us
 
 
 	switch (optname) {
 	switch (optname) {
 	case L2CAP_OPTIONS:
 	case L2CAP_OPTIONS:
+		memset(&opts, 0, sizeof(opts));
 		opts.imtu     = l2cap_pi(sk)->imtu;
 		opts.imtu     = l2cap_pi(sk)->imtu;
 		opts.omtu     = l2cap_pi(sk)->omtu;
 		opts.omtu     = l2cap_pi(sk)->omtu;
 		opts.flush_to = l2cap_pi(sk)->flush_to;
 		opts.flush_to = l2cap_pi(sk)->flush_to;
@@ -880,6 +885,8 @@ static void l2cap_sock_cleanup_listen(struct sock *parent)
 
 
 void __l2cap_sock_close(struct sock *sk, int reason)
 void __l2cap_sock_close(struct sock *sk, int reason)
 {
 {
+	struct l2cap_conn *conn = l2cap_pi(sk)->conn;
+
 	BT_DBG("sk %p state %d socket %p", sk, sk->sk_state, sk->sk_socket);
 	BT_DBG("sk %p state %d socket %p", sk, sk->sk_state, sk->sk_socket);
 
 
 	switch (sk->sk_state) {
 	switch (sk->sk_state) {
@@ -889,10 +896,9 @@ void __l2cap_sock_close(struct sock *sk, int reason)
 
 
 	case BT_CONNECTED:
 	case BT_CONNECTED:
 	case BT_CONFIG:
 	case BT_CONFIG:
-		if (sk->sk_type == SOCK_SEQPACKET ||
-				sk->sk_type == SOCK_STREAM) {
-			struct l2cap_conn *conn = l2cap_pi(sk)->conn;
-
+		if ((sk->sk_type == SOCK_SEQPACKET ||
+					sk->sk_type == SOCK_STREAM) &&
+					conn->hcon->type == ACL_LINK) {
 			l2cap_sock_set_timer(sk, sk->sk_sndtimeo);
 			l2cap_sock_set_timer(sk, sk->sk_sndtimeo);
 			l2cap_send_disconn_req(conn, sk, reason);
 			l2cap_send_disconn_req(conn, sk, reason);
 		} else
 		} else
@@ -900,9 +906,9 @@ void __l2cap_sock_close(struct sock *sk, int reason)
 		break;
 		break;
 
 
 	case BT_CONNECT2:
 	case BT_CONNECT2:
-		if (sk->sk_type == SOCK_SEQPACKET ||
-				sk->sk_type == SOCK_STREAM) {
-			struct l2cap_conn *conn = l2cap_pi(sk)->conn;
+		if ((sk->sk_type == SOCK_SEQPACKET ||
+					sk->sk_type == SOCK_STREAM) &&
+					conn->hcon->type == ACL_LINK) {
 			struct l2cap_conn_rsp rsp;
 			struct l2cap_conn_rsp rsp;
 			__u16 result;
 			__u16 result;
 
 
@@ -1121,30 +1127,30 @@ static const struct net_proto_family l2cap_sock_family_ops = {
 
 
 int __init l2cap_init_sockets(void)
 int __init l2cap_init_sockets(void)
 {
 {
-       int err;
+	int err;
 
 
-       err = proto_register(&l2cap_proto, 0);
-       if (err < 0)
-               return err;
+	err = proto_register(&l2cap_proto, 0);
+	if (err < 0)
+		return err;
 
 
-       err = bt_sock_register(BTPROTO_L2CAP, &l2cap_sock_family_ops);
-       if (err < 0)
-               goto error;
+	err = bt_sock_register(BTPROTO_L2CAP, &l2cap_sock_family_ops);
+	if (err < 0)
+		goto error;
 
 
-       BT_INFO("L2CAP socket layer initialized");
+	BT_INFO("L2CAP socket layer initialized");
 
 
-       return 0;
+	return 0;
 
 
 error:
 error:
-       BT_ERR("L2CAP socket registration failed");
-       proto_unregister(&l2cap_proto);
-       return err;
+	BT_ERR("L2CAP socket registration failed");
+	proto_unregister(&l2cap_proto);
+	return err;
 }
 }
 
 
 void l2cap_cleanup_sockets(void)
 void l2cap_cleanup_sockets(void)
 {
 {
-       if (bt_sock_unregister(BTPROTO_L2CAP) < 0)
-               BT_ERR("L2CAP socket unregistration failed");
+	if (bt_sock_unregister(BTPROTO_L2CAP) < 0)
+		BT_ERR("L2CAP socket unregistration failed");
 
 
-       proto_unregister(&l2cap_proto);
+	proto_unregister(&l2cap_proto);
 }
 }

+ 1 - 1
net/bluetooth/mgmt.c

@@ -22,7 +22,7 @@
 
 
 /* Bluetooth HCI Management interface */
 /* Bluetooth HCI Management interface */
 
 
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
 #include <asm/unaligned.h>
 #include <asm/unaligned.h>
 
 
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/bluetooth.h>

+ 0 - 2
net/bluetooth/rfcomm/core.c

@@ -2154,8 +2154,6 @@ static int __init rfcomm_init(void)
 {
 {
 	int err;
 	int err;
 
 
-	l2cap_load();
-
 	hci_register_cb(&rfcomm_cb);
 	hci_register_cb(&rfcomm_cb);
 
 
 	rfcomm_thread = kthread_run(rfcomm_run, NULL, "krfcommd");
 	rfcomm_thread = kthread_run(rfcomm_run, NULL, "krfcommd");

+ 3 - 14
net/bluetooth/sco.c

@@ -50,8 +50,6 @@
 #include <net/bluetooth/hci_core.h>
 #include <net/bluetooth/hci_core.h>
 #include <net/bluetooth/sco.h>
 #include <net/bluetooth/sco.h>
 
 
-#define VERSION "0.6"
-
 static int disable_esco;
 static int disable_esco;
 
 
 static const struct proto_ops sco_sock_ops;
 static const struct proto_ops sco_sock_ops;
@@ -703,6 +701,7 @@ static int sco_sock_getsockopt_old(struct socket *sock, int optname, char __user
 			break;
 			break;
 		}
 		}
 
 
+		memset(&cinfo, 0, sizeof(cinfo));
 		cinfo.hci_handle = sco_pi(sk)->conn->hcon->handle;
 		cinfo.hci_handle = sco_pi(sk)->conn->hcon->handle;
 		memcpy(cinfo.dev_class, sco_pi(sk)->conn->hcon->dev_class, 3);
 		memcpy(cinfo.dev_class, sco_pi(sk)->conn->hcon->dev_class, 3);
 
 
@@ -1023,7 +1022,7 @@ static struct hci_proto sco_hci_proto = {
 	.recv_scodata	= sco_recv_scodata
 	.recv_scodata	= sco_recv_scodata
 };
 };
 
 
-static int __init sco_init(void)
+int __init sco_init(void)
 {
 {
 	int err;
 	int err;
 
 
@@ -1051,7 +1050,6 @@ static int __init sco_init(void)
 			BT_ERR("Failed to create SCO debug file");
 			BT_ERR("Failed to create SCO debug file");
 	}
 	}
 
 
-	BT_INFO("SCO (Voice Link) ver %s", VERSION);
 	BT_INFO("SCO socket layer initialized");
 	BT_INFO("SCO socket layer initialized");
 
 
 	return 0;
 	return 0;
@@ -1061,7 +1059,7 @@ error:
 	return err;
 	return err;
 }
 }
 
 
-static void __exit sco_exit(void)
+void __exit sco_exit(void)
 {
 {
 	debugfs_remove(sco_debugfs);
 	debugfs_remove(sco_debugfs);
 
 
@@ -1074,14 +1072,5 @@ static void __exit sco_exit(void)
 	proto_unregister(&sco_proto);
 	proto_unregister(&sco_proto);
 }
 }
 
 
-module_init(sco_init);
-module_exit(sco_exit);
-
 module_param(disable_esco, bool, 0644);
 module_param(disable_esco, bool, 0644);
 MODULE_PARM_DESC(disable_esco, "Disable eSCO connection creation");
 MODULE_PARM_DESC(disable_esco, "Disable eSCO connection creation");
-
-MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
-MODULE_DESCRIPTION("Bluetooth SCO ver " VERSION);
-MODULE_VERSION(VERSION);
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("bt-proto-2");