Browse Source

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

David S. Miller 13 years ago
parent
commit
0111ad823e
41 changed files with 4327 additions and 2332 deletions
  1. 3 0
      drivers/bluetooth/ath3k.c
  2. 6 17
      drivers/bluetooth/bfusb.c
  3. 6 14
      drivers/bluetooth/bluecard_cs.c
  4. 12 23
      drivers/bluetooth/bpa10x.c
  5. 3 11
      drivers/bluetooth/bt3c_cs.c
  6. 14 16
      drivers/bluetooth/btmrvl_debugfs.c
  7. 6 11
      drivers/bluetooth/btmrvl_main.c
  8. 6 17
      drivers/bluetooth/btsdio.c
  9. 3 11
      drivers/bluetooth/btuart_cs.c
  10. 18 31
      drivers/bluetooth/btusb.c
  11. 4 14
      drivers/bluetooth/btwilink.c
  12. 6 28
      drivers/bluetooth/dtl1_cs.c
  13. 1 1
      drivers/bluetooth/hci_ath.c
  14. 1 1
      drivers/bluetooth/hci_bcsp.c
  15. 1 1
      drivers/bluetooth/hci_h4.c
  16. 12 22
      drivers/bluetooth/hci_ldisc.c
  17. 1 1
      drivers/bluetooth/hci_ll.c
  18. 2 0
      drivers/bluetooth/hci_uart.h
  19. 5 12
      drivers/bluetooth/hci_vhci.c
  20. 34 6
      include/net/bluetooth/bluetooth.h
  21. 59 17
      include/net/bluetooth/hci.h
  22. 203 98
      include/net/bluetooth/hci_core.h
  23. 51 0
      include/net/bluetooth/hci_mon.h
  24. 54 33
      include/net/bluetooth/l2cap.h
  25. 205 133
      include/net/bluetooth/mgmt.h
  26. 1 1
      include/net/bluetooth/smp.h
  27. 0 1
      net/bluetooth/Kconfig
  28. 3 3
      net/bluetooth/bnep/sock.c
  29. 3 3
      net/bluetooth/cmtp/sock.c
  30. 33 40
      net/bluetooth/hci_conn.c
  31. 497 148
      net/bluetooth/hci_core.c
  32. 441 190
      net/bluetooth/hci_event.c
  33. 383 86
      net/bluetooth/hci_sock.c
  34. 26 27
      net/bluetooth/hci_sysfs.c
  35. 3 3
      net/bluetooth/hidp/sock.c
  36. 347 294
      net/bluetooth/l2cap_core.c
  37. 45 9
      net/bluetooth/l2cap_sock.c
  38. 24 3
      net/bluetooth/lib.c
  39. 1742 955
      net/bluetooth/mgmt.c
  40. 3 3
      net/bluetooth/rfcomm/tty.c
  41. 60 48
      net/bluetooth/smp.c

+ 3 - 0
drivers/bluetooth/ath3k.c

@@ -65,12 +65,14 @@ static struct usb_device_id ath3k_table[] = {
 	{ USB_DEVICE(0x0CF3, 0x3002) },
 	{ USB_DEVICE(0x0CF3, 0x3002) },
 	{ USB_DEVICE(0x13d3, 0x3304) },
 	{ USB_DEVICE(0x13d3, 0x3304) },
 	{ USB_DEVICE(0x0930, 0x0215) },
 	{ USB_DEVICE(0x0930, 0x0215) },
+	{ USB_DEVICE(0x0489, 0xE03D) },
 
 
 	/* 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*/
 	/* Atheros AR3012 with sflash firmware*/
 	{ USB_DEVICE(0x0CF3, 0x3004) },
 	{ USB_DEVICE(0x0CF3, 0x3004) },
+	{ USB_DEVICE(0x13d3, 0x3375) },
 
 
 	/* Atheros AR5BBU12 with sflash firmware */
 	/* Atheros AR5BBU12 with sflash firmware */
 	{ USB_DEVICE(0x0489, 0xE02C) },
 	{ USB_DEVICE(0x0489, 0xE02C) },
@@ -87,6 +89,7 @@ static struct usb_device_id ath3k_blist_tbl[] = {
 
 
 	/* Atheros AR3012 with sflash firmware*/
 	/* Atheros AR3012 with sflash firmware*/
 	{ USB_DEVICE(0x0cf3, 0x3004), .driver_info = BTUSB_ATH3012 },
 	{ USB_DEVICE(0x0cf3, 0x3004), .driver_info = BTUSB_ATH3012 },
+	{ USB_DEVICE(0x13d3, 0x3375), .driver_info = BTUSB_ATH3012 },
 
 
 	{ }	/* Terminating entry */
 	{ }	/* Terminating entry */
 };
 };

+ 6 - 17
drivers/bluetooth/bfusb.c

@@ -411,7 +411,7 @@ unlock:
 
 
 static int bfusb_open(struct hci_dev *hdev)
 static int bfusb_open(struct hci_dev *hdev)
 {
 {
-	struct bfusb_data *data = hdev->driver_data;
+	struct bfusb_data *data = hci_get_drvdata(hdev);
 	unsigned long flags;
 	unsigned long flags;
 	int i, err;
 	int i, err;
 
 
@@ -437,7 +437,7 @@ static int bfusb_open(struct hci_dev *hdev)
 
 
 static int bfusb_flush(struct hci_dev *hdev)
 static int bfusb_flush(struct hci_dev *hdev)
 {
 {
-	struct bfusb_data *data = hdev->driver_data;
+	struct bfusb_data *data = hci_get_drvdata(hdev);
 
 
 	BT_DBG("hdev %p bfusb %p", hdev, data);
 	BT_DBG("hdev %p bfusb %p", hdev, data);
 
 
@@ -448,7 +448,7 @@ static int bfusb_flush(struct hci_dev *hdev)
 
 
 static int bfusb_close(struct hci_dev *hdev)
 static int bfusb_close(struct hci_dev *hdev)
 {
 {
-	struct bfusb_data *data = hdev->driver_data;
+	struct bfusb_data *data = hci_get_drvdata(hdev);
 	unsigned long flags;
 	unsigned long flags;
 
 
 	BT_DBG("hdev %p bfusb %p", hdev, data);
 	BT_DBG("hdev %p bfusb %p", hdev, data);
@@ -483,7 +483,7 @@ static int bfusb_send_frame(struct sk_buff *skb)
 	if (!test_bit(HCI_RUNNING, &hdev->flags))
 	if (!test_bit(HCI_RUNNING, &hdev->flags))
 		return -EBUSY;
 		return -EBUSY;
 
 
-	data = hdev->driver_data;
+	data = hci_get_drvdata(hdev);
 
 
 	switch (bt_cb(skb)->pkt_type) {
 	switch (bt_cb(skb)->pkt_type) {
 	case HCI_COMMAND_PKT:
 	case HCI_COMMAND_PKT:
@@ -544,15 +544,6 @@ static int bfusb_send_frame(struct sk_buff *skb)
 	return 0;
 	return 0;
 }
 }
 
 
-static void bfusb_destruct(struct hci_dev *hdev)
-{
-	struct bfusb_data *data = hdev->driver_data;
-
-	BT_DBG("hdev %p bfusb %p", hdev, data);
-
-	kfree(data);
-}
-
 static int bfusb_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned long arg)
 static int bfusb_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned long arg)
 {
 {
 	return -ENOIOCTLCMD;
 	return -ENOIOCTLCMD;
@@ -705,18 +696,15 @@ static int bfusb_probe(struct usb_interface *intf, const struct usb_device_id *i
 	data->hdev = hdev;
 	data->hdev = hdev;
 
 
 	hdev->bus = HCI_USB;
 	hdev->bus = HCI_USB;
-	hdev->driver_data = data;
+	hci_set_drvdata(hdev, data);
 	SET_HCIDEV_DEV(hdev, &intf->dev);
 	SET_HCIDEV_DEV(hdev, &intf->dev);
 
 
 	hdev->open     = bfusb_open;
 	hdev->open     = bfusb_open;
 	hdev->close    = bfusb_close;
 	hdev->close    = bfusb_close;
 	hdev->flush    = bfusb_flush;
 	hdev->flush    = bfusb_flush;
 	hdev->send     = bfusb_send_frame;
 	hdev->send     = bfusb_send_frame;
-	hdev->destruct = bfusb_destruct;
 	hdev->ioctl    = bfusb_ioctl;
 	hdev->ioctl    = bfusb_ioctl;
 
 
-	hdev->owner = THIS_MODULE;
-
 	if (hci_register_dev(hdev) < 0) {
 	if (hci_register_dev(hdev) < 0) {
 		BT_ERR("Can't register HCI device");
 		BT_ERR("Can't register HCI device");
 		hci_free_dev(hdev);
 		hci_free_dev(hdev);
@@ -753,6 +741,7 @@ static void bfusb_disconnect(struct usb_interface *intf)
 
 
 	hci_unregister_dev(hdev);
 	hci_unregister_dev(hdev);
 	hci_free_dev(hdev);
 	hci_free_dev(hdev);
+	kfree(data);
 }
 }
 
 
 static struct usb_driver bfusb_driver = {
 static struct usb_driver bfusb_driver = {

+ 6 - 14
drivers/bluetooth/bluecard_cs.c

@@ -561,7 +561,7 @@ static irqreturn_t bluecard_interrupt(int irq, void *dev_inst)
 
 
 static int bluecard_hci_set_baud_rate(struct hci_dev *hdev, int baud)
 static int bluecard_hci_set_baud_rate(struct hci_dev *hdev, int baud)
 {
 {
-	bluecard_info_t *info = (bluecard_info_t *)(hdev->driver_data);
+	bluecard_info_t *info = hci_get_drvdata(hdev);
 	struct sk_buff *skb;
 	struct sk_buff *skb;
 
 
 	/* Ericsson baud rate command */
 	/* Ericsson baud rate command */
@@ -609,7 +609,7 @@ static int bluecard_hci_set_baud_rate(struct hci_dev *hdev, int baud)
 
 
 static int bluecard_hci_flush(struct hci_dev *hdev)
 static int bluecard_hci_flush(struct hci_dev *hdev)
 {
 {
-	bluecard_info_t *info = (bluecard_info_t *)(hdev->driver_data);
+	bluecard_info_t *info = hci_get_drvdata(hdev);
 
 
 	/* Drop TX queue */
 	/* Drop TX queue */
 	skb_queue_purge(&(info->txq));
 	skb_queue_purge(&(info->txq));
@@ -620,7 +620,7 @@ static int bluecard_hci_flush(struct hci_dev *hdev)
 
 
 static int bluecard_hci_open(struct hci_dev *hdev)
 static int bluecard_hci_open(struct hci_dev *hdev)
 {
 {
-	bluecard_info_t *info = (bluecard_info_t *)(hdev->driver_data);
+	bluecard_info_t *info = hci_get_drvdata(hdev);
 	unsigned int iobase = info->p_dev->resource[0]->start;
 	unsigned int iobase = info->p_dev->resource[0]->start;
 
 
 	if (test_bit(CARD_HAS_PCCARD_ID, &(info->hw_state)))
 	if (test_bit(CARD_HAS_PCCARD_ID, &(info->hw_state)))
@@ -640,7 +640,7 @@ static int bluecard_hci_open(struct hci_dev *hdev)
 
 
 static int bluecard_hci_close(struct hci_dev *hdev)
 static int bluecard_hci_close(struct hci_dev *hdev)
 {
 {
-	bluecard_info_t *info = (bluecard_info_t *)(hdev->driver_data);
+	bluecard_info_t *info = hci_get_drvdata(hdev);
 	unsigned int iobase = info->p_dev->resource[0]->start;
 	unsigned int iobase = info->p_dev->resource[0]->start;
 
 
 	if (!test_and_clear_bit(HCI_RUNNING, &(hdev->flags)))
 	if (!test_and_clear_bit(HCI_RUNNING, &(hdev->flags)))
@@ -667,7 +667,7 @@ static int bluecard_hci_send_frame(struct sk_buff *skb)
 		return -ENODEV;
 		return -ENODEV;
 	}
 	}
 
 
-	info = (bluecard_info_t *)(hdev->driver_data);
+	info = hci_get_drvdata(hdev);
 
 
 	switch (bt_cb(skb)->pkt_type) {
 	switch (bt_cb(skb)->pkt_type) {
 	case HCI_COMMAND_PKT:
 	case HCI_COMMAND_PKT:
@@ -691,11 +691,6 @@ static int bluecard_hci_send_frame(struct sk_buff *skb)
 }
 }
 
 
 
 
-static void bluecard_hci_destruct(struct hci_dev *hdev)
-{
-}
-
-
 static int bluecard_hci_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned long arg)
 static int bluecard_hci_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned long arg)
 {
 {
 	return -ENOIOCTLCMD;
 	return -ENOIOCTLCMD;
@@ -734,18 +729,15 @@ static int bluecard_open(bluecard_info_t *info)
 	info->hdev = hdev;
 	info->hdev = hdev;
 
 
 	hdev->bus = HCI_PCCARD;
 	hdev->bus = HCI_PCCARD;
-	hdev->driver_data = info;
+	hci_set_drvdata(hdev, info);
 	SET_HCIDEV_DEV(hdev, &info->p_dev->dev);
 	SET_HCIDEV_DEV(hdev, &info->p_dev->dev);
 
 
 	hdev->open     = bluecard_hci_open;
 	hdev->open     = bluecard_hci_open;
 	hdev->close    = bluecard_hci_close;
 	hdev->close    = bluecard_hci_close;
 	hdev->flush    = bluecard_hci_flush;
 	hdev->flush    = bluecard_hci_flush;
 	hdev->send     = bluecard_hci_send_frame;
 	hdev->send     = bluecard_hci_send_frame;
-	hdev->destruct = bluecard_hci_destruct;
 	hdev->ioctl    = bluecard_hci_ioctl;
 	hdev->ioctl    = bluecard_hci_ioctl;
 
 
-	hdev->owner = THIS_MODULE;
-
 	id = inb(iobase + 0x30);
 	id = inb(iobase + 0x30);
 
 
 	if ((id & 0x0f) == 0x02)
 	if ((id & 0x0f) == 0x02)

+ 12 - 23
drivers/bluetooth/bpa10x.c

@@ -66,7 +66,7 @@ struct hci_vendor_hdr {
 
 
 static int bpa10x_recv(struct hci_dev *hdev, int queue, void *buf, int count)
 static int bpa10x_recv(struct hci_dev *hdev, int queue, void *buf, int count)
 {
 {
-	struct bpa10x_data *data = hdev->driver_data;
+	struct bpa10x_data *data = hci_get_drvdata(hdev);
 
 
 	BT_DBG("%s queue %d buffer %p count %d", hdev->name,
 	BT_DBG("%s queue %d buffer %p count %d", hdev->name,
 							queue, buf, count);
 							queue, buf, count);
@@ -189,7 +189,7 @@ done:
 static void bpa10x_rx_complete(struct urb *urb)
 static void bpa10x_rx_complete(struct urb *urb)
 {
 {
 	struct hci_dev *hdev = urb->context;
 	struct hci_dev *hdev = urb->context;
-	struct bpa10x_data *data = hdev->driver_data;
+	struct bpa10x_data *data = hci_get_drvdata(hdev);
 	int err;
 	int err;
 
 
 	BT_DBG("%s urb %p status %d count %d", hdev->name,
 	BT_DBG("%s urb %p status %d count %d", hdev->name,
@@ -219,7 +219,7 @@ static void bpa10x_rx_complete(struct urb *urb)
 
 
 static inline int bpa10x_submit_intr_urb(struct hci_dev *hdev)
 static inline int bpa10x_submit_intr_urb(struct hci_dev *hdev)
 {
 {
-	struct bpa10x_data *data = hdev->driver_data;
+	struct bpa10x_data *data = hci_get_drvdata(hdev);
 	struct urb *urb;
 	struct urb *urb;
 	unsigned char *buf;
 	unsigned char *buf;
 	unsigned int pipe;
 	unsigned int pipe;
@@ -260,7 +260,7 @@ static inline int bpa10x_submit_intr_urb(struct hci_dev *hdev)
 
 
 static inline int bpa10x_submit_bulk_urb(struct hci_dev *hdev)
 static inline int bpa10x_submit_bulk_urb(struct hci_dev *hdev)
 {
 {
-	struct bpa10x_data *data = hdev->driver_data;
+	struct bpa10x_data *data = hci_get_drvdata(hdev);
 	struct urb *urb;
 	struct urb *urb;
 	unsigned char *buf;
 	unsigned char *buf;
 	unsigned int pipe;
 	unsigned int pipe;
@@ -301,7 +301,7 @@ static inline int bpa10x_submit_bulk_urb(struct hci_dev *hdev)
 
 
 static int bpa10x_open(struct hci_dev *hdev)
 static int bpa10x_open(struct hci_dev *hdev)
 {
 {
-	struct bpa10x_data *data = hdev->driver_data;
+	struct bpa10x_data *data = hci_get_drvdata(hdev);
 	int err;
 	int err;
 
 
 	BT_DBG("%s", hdev->name);
 	BT_DBG("%s", hdev->name);
@@ -329,7 +329,7 @@ error:
 
 
 static int bpa10x_close(struct hci_dev *hdev)
 static int bpa10x_close(struct hci_dev *hdev)
 {
 {
-	struct bpa10x_data *data = hdev->driver_data;
+	struct bpa10x_data *data = hci_get_drvdata(hdev);
 
 
 	BT_DBG("%s", hdev->name);
 	BT_DBG("%s", hdev->name);
 
 
@@ -343,7 +343,7 @@ static int bpa10x_close(struct hci_dev *hdev)
 
 
 static int bpa10x_flush(struct hci_dev *hdev)
 static int bpa10x_flush(struct hci_dev *hdev)
 {
 {
-	struct bpa10x_data *data = hdev->driver_data;
+	struct bpa10x_data *data = hci_get_drvdata(hdev);
 
 
 	BT_DBG("%s", hdev->name);
 	BT_DBG("%s", hdev->name);
 
 
@@ -355,7 +355,7 @@ static int bpa10x_flush(struct hci_dev *hdev)
 static int bpa10x_send_frame(struct sk_buff *skb)
 static int bpa10x_send_frame(struct sk_buff *skb)
 {
 {
 	struct hci_dev *hdev = (struct hci_dev *) skb->dev;
 	struct hci_dev *hdev = (struct hci_dev *) skb->dev;
-	struct bpa10x_data *data = hdev->driver_data;
+	struct bpa10x_data *data = hci_get_drvdata(hdev);
 	struct usb_ctrlrequest *dr;
 	struct usb_ctrlrequest *dr;
 	struct urb *urb;
 	struct urb *urb;
 	unsigned int pipe;
 	unsigned int pipe;
@@ -432,17 +432,6 @@ static int bpa10x_send_frame(struct sk_buff *skb)
 	return 0;
 	return 0;
 }
 }
 
 
-static void bpa10x_destruct(struct hci_dev *hdev)
-{
-	struct bpa10x_data *data = hdev->driver_data;
-
-	BT_DBG("%s", hdev->name);
-
-	kfree_skb(data->rx_skb[0]);
-	kfree_skb(data->rx_skb[1]);
-	kfree(data);
-}
-
 static int bpa10x_probe(struct usb_interface *intf, const struct usb_device_id *id)
 static int bpa10x_probe(struct usb_interface *intf, const struct usb_device_id *id)
 {
 {
 	struct bpa10x_data *data;
 	struct bpa10x_data *data;
@@ -470,7 +459,7 @@ static int bpa10x_probe(struct usb_interface *intf, const struct usb_device_id *
 	}
 	}
 
 
 	hdev->bus = HCI_USB;
 	hdev->bus = HCI_USB;
-	hdev->driver_data = data;
+	hci_set_drvdata(hdev, data);
 
 
 	data->hdev = hdev;
 	data->hdev = hdev;
 
 
@@ -480,9 +469,6 @@ static int bpa10x_probe(struct usb_interface *intf, const struct usb_device_id *
 	hdev->close    = bpa10x_close;
 	hdev->close    = bpa10x_close;
 	hdev->flush    = bpa10x_flush;
 	hdev->flush    = bpa10x_flush;
 	hdev->send     = bpa10x_send_frame;
 	hdev->send     = bpa10x_send_frame;
-	hdev->destruct = bpa10x_destruct;
-
-	hdev->owner = THIS_MODULE;
 
 
 	set_bit(HCI_QUIRK_NO_RESET, &hdev->quirks);
 	set_bit(HCI_QUIRK_NO_RESET, &hdev->quirks);
 
 
@@ -512,6 +498,9 @@ static void bpa10x_disconnect(struct usb_interface *intf)
 	hci_unregister_dev(data->hdev);
 	hci_unregister_dev(data->hdev);
 
 
 	hci_free_dev(data->hdev);
 	hci_free_dev(data->hdev);
+	kfree_skb(data->rx_skb[0]);
+	kfree_skb(data->rx_skb[1]);
+	kfree(data);
 }
 }
 
 
 static struct usb_driver bpa10x_driver = {
 static struct usb_driver bpa10x_driver = {

+ 3 - 11
drivers/bluetooth/bt3c_cs.c

@@ -389,7 +389,7 @@ static irqreturn_t bt3c_interrupt(int irq, void *dev_inst)
 
 
 static int bt3c_hci_flush(struct hci_dev *hdev)
 static int bt3c_hci_flush(struct hci_dev *hdev)
 {
 {
-	bt3c_info_t *info = (bt3c_info_t *)(hdev->driver_data);
+	bt3c_info_t *info = hci_get_drvdata(hdev);
 
 
 	/* Drop TX queue */
 	/* Drop TX queue */
 	skb_queue_purge(&(info->txq));
 	skb_queue_purge(&(info->txq));
@@ -428,7 +428,7 @@ static int bt3c_hci_send_frame(struct sk_buff *skb)
 		return -ENODEV;
 		return -ENODEV;
 	}
 	}
 
 
-	info = (bt3c_info_t *) (hdev->driver_data);
+	info = hci_get_drvdata(hdev);
 
 
 	switch (bt_cb(skb)->pkt_type) {
 	switch (bt_cb(skb)->pkt_type) {
 	case HCI_COMMAND_PKT:
 	case HCI_COMMAND_PKT:
@@ -456,11 +456,6 @@ static int bt3c_hci_send_frame(struct sk_buff *skb)
 }
 }
 
 
 
 
-static void bt3c_hci_destruct(struct hci_dev *hdev)
-{
-}
-
-
 static int bt3c_hci_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned long arg)
 static int bt3c_hci_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned long arg)
 {
 {
 	return -ENOIOCTLCMD;
 	return -ENOIOCTLCMD;
@@ -580,18 +575,15 @@ static int bt3c_open(bt3c_info_t *info)
 	info->hdev = hdev;
 	info->hdev = hdev;
 
 
 	hdev->bus = HCI_PCCARD;
 	hdev->bus = HCI_PCCARD;
-	hdev->driver_data = info;
+	hci_set_drvdata(hdev, info);
 	SET_HCIDEV_DEV(hdev, &info->p_dev->dev);
 	SET_HCIDEV_DEV(hdev, &info->p_dev->dev);
 
 
 	hdev->open     = bt3c_hci_open;
 	hdev->open     = bt3c_hci_open;
 	hdev->close    = bt3c_hci_close;
 	hdev->close    = bt3c_hci_close;
 	hdev->flush    = bt3c_hci_flush;
 	hdev->flush    = bt3c_hci_flush;
 	hdev->send     = bt3c_hci_send_frame;
 	hdev->send     = bt3c_hci_send_frame;
-	hdev->destruct = bt3c_hci_destruct;
 	hdev->ioctl    = bt3c_hci_ioctl;
 	hdev->ioctl    = bt3c_hci_ioctl;
 
 
-	hdev->owner = THIS_MODULE;
-
 	/* Load firmware */
 	/* Load firmware */
 	err = request_firmware(&firmware, "BT3CPCC.bin", &info->p_dev->dev);
 	err = request_firmware(&firmware, "BT3CPCC.bin", &info->p_dev->dev);
 	if (err < 0) {
 	if (err < 0) {

+ 14 - 16
drivers/bluetooth/btmrvl_debugfs.c

@@ -384,7 +384,7 @@ static const struct file_operations btmrvl_txdnldready_fops = {
 
 
 void btmrvl_debugfs_init(struct hci_dev *hdev)
 void btmrvl_debugfs_init(struct hci_dev *hdev)
 {
 {
-	struct btmrvl_private *priv = hdev->driver_data;
+	struct btmrvl_private *priv = hci_get_drvdata(hdev);
 	struct btmrvl_debugfs_data *dbg;
 	struct btmrvl_debugfs_data *dbg;
 
 
 	if (!hdev->debugfs)
 	if (!hdev->debugfs)
@@ -401,36 +401,34 @@ void btmrvl_debugfs_init(struct hci_dev *hdev)
 	dbg->config_dir = debugfs_create_dir("config", hdev->debugfs);
 	dbg->config_dir = debugfs_create_dir("config", hdev->debugfs);
 
 
 	dbg->psmode = debugfs_create_file("psmode", 0644, dbg->config_dir,
 	dbg->psmode = debugfs_create_file("psmode", 0644, dbg->config_dir,
-				hdev->driver_data, &btmrvl_psmode_fops);
+					  priv, &btmrvl_psmode_fops);
 	dbg->pscmd = debugfs_create_file("pscmd", 0644, dbg->config_dir,
 	dbg->pscmd = debugfs_create_file("pscmd", 0644, dbg->config_dir,
-				hdev->driver_data, &btmrvl_pscmd_fops);
+					 priv, &btmrvl_pscmd_fops);
 	dbg->gpiogap = debugfs_create_file("gpiogap", 0644, dbg->config_dir,
 	dbg->gpiogap = debugfs_create_file("gpiogap", 0644, dbg->config_dir,
-				hdev->driver_data, &btmrvl_gpiogap_fops);
+					   priv, &btmrvl_gpiogap_fops);
 	dbg->hsmode =  debugfs_create_file("hsmode", 0644, dbg->config_dir,
 	dbg->hsmode =  debugfs_create_file("hsmode", 0644, dbg->config_dir,
-				hdev->driver_data, &btmrvl_hsmode_fops);
+					   priv, &btmrvl_hsmode_fops);
 	dbg->hscmd = debugfs_create_file("hscmd", 0644, dbg->config_dir,
 	dbg->hscmd = debugfs_create_file("hscmd", 0644, dbg->config_dir,
-				hdev->driver_data, &btmrvl_hscmd_fops);
+					 priv, &btmrvl_hscmd_fops);
 	dbg->hscfgcmd = debugfs_create_file("hscfgcmd", 0644, dbg->config_dir,
 	dbg->hscfgcmd = debugfs_create_file("hscfgcmd", 0644, dbg->config_dir,
-				hdev->driver_data, &btmrvl_hscfgcmd_fops);
+					    priv, &btmrvl_hscfgcmd_fops);
 
 
 	dbg->status_dir = debugfs_create_dir("status", hdev->debugfs);
 	dbg->status_dir = debugfs_create_dir("status", hdev->debugfs);
 	dbg->curpsmode = debugfs_create_file("curpsmode", 0444,
 	dbg->curpsmode = debugfs_create_file("curpsmode", 0444,
-						dbg->status_dir,
-						hdev->driver_data,
-						&btmrvl_curpsmode_fops);
+					     dbg->status_dir, priv,
+					     &btmrvl_curpsmode_fops);
 	dbg->psstate = debugfs_create_file("psstate", 0444, dbg->status_dir,
 	dbg->psstate = debugfs_create_file("psstate", 0444, dbg->status_dir,
-				hdev->driver_data, &btmrvl_psstate_fops);
+					   priv, &btmrvl_psstate_fops);
 	dbg->hsstate = debugfs_create_file("hsstate", 0444, dbg->status_dir,
 	dbg->hsstate = debugfs_create_file("hsstate", 0444, dbg->status_dir,
-				hdev->driver_data, &btmrvl_hsstate_fops);
+					   priv, &btmrvl_hsstate_fops);
 	dbg->txdnldready = debugfs_create_file("txdnldready", 0444,
 	dbg->txdnldready = debugfs_create_file("txdnldready", 0444,
-						dbg->status_dir,
-						hdev->driver_data,
-						&btmrvl_txdnldready_fops);
+					       dbg->status_dir, priv,
+					       &btmrvl_txdnldready_fops);
 }
 }
 
 
 void btmrvl_debugfs_remove(struct hci_dev *hdev)
 void btmrvl_debugfs_remove(struct hci_dev *hdev)
 {
 {
-	struct btmrvl_private *priv = hdev->driver_data;
+	struct btmrvl_private *priv = hci_get_drvdata(hdev);
 	struct btmrvl_debugfs_data *dbg = priv->debugfs_data;
 	struct btmrvl_debugfs_data *dbg = priv->debugfs_data;
 
 
 	if (!dbg)
 	if (!dbg)

+ 6 - 11
drivers/bluetooth/btmrvl_main.c

@@ -387,10 +387,6 @@ static int btmrvl_ioctl(struct hci_dev *hdev,
 	return -ENOIOCTLCMD;
 	return -ENOIOCTLCMD;
 }
 }
 
 
-static void btmrvl_destruct(struct hci_dev *hdev)
-{
-}
-
 static int btmrvl_send_frame(struct sk_buff *skb)
 static int btmrvl_send_frame(struct sk_buff *skb)
 {
 {
 	struct hci_dev *hdev = (struct hci_dev *) skb->dev;
 	struct hci_dev *hdev = (struct hci_dev *) skb->dev;
@@ -398,12 +394,13 @@ static int btmrvl_send_frame(struct sk_buff *skb)
 
 
 	BT_DBG("type=%d, len=%d", skb->pkt_type, skb->len);
 	BT_DBG("type=%d, len=%d", skb->pkt_type, skb->len);
 
 
-	if (!hdev || !hdev->driver_data) {
+	if (!hdev) {
 		BT_ERR("Frame for unknown HCI device");
 		BT_ERR("Frame for unknown HCI device");
 		return -ENODEV;
 		return -ENODEV;
 	}
 	}
 
 
-	priv = (struct btmrvl_private *) hdev->driver_data;
+	priv = hci_get_drvdata(hdev);
+
 	if (!test_bit(HCI_RUNNING, &hdev->flags)) {
 	if (!test_bit(HCI_RUNNING, &hdev->flags)) {
 		BT_ERR("Failed testing HCI_RUNING, flags=%lx", hdev->flags);
 		BT_ERR("Failed testing HCI_RUNING, flags=%lx", hdev->flags);
 		print_hex_dump_bytes("data: ", DUMP_PREFIX_OFFSET,
 		print_hex_dump_bytes("data: ", DUMP_PREFIX_OFFSET,
@@ -434,7 +431,7 @@ static int btmrvl_send_frame(struct sk_buff *skb)
 
 
 static int btmrvl_flush(struct hci_dev *hdev)
 static int btmrvl_flush(struct hci_dev *hdev)
 {
 {
-	struct btmrvl_private *priv = hdev->driver_data;
+	struct btmrvl_private *priv = hci_get_drvdata(hdev);
 
 
 	skb_queue_purge(&priv->adapter->tx_queue);
 	skb_queue_purge(&priv->adapter->tx_queue);
 
 
@@ -443,7 +440,7 @@ static int btmrvl_flush(struct hci_dev *hdev)
 
 
 static int btmrvl_close(struct hci_dev *hdev)
 static int btmrvl_close(struct hci_dev *hdev)
 {
 {
-	struct btmrvl_private *priv = hdev->driver_data;
+	struct btmrvl_private *priv = hci_get_drvdata(hdev);
 
 
 	if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
 	if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
 		return 0;
 		return 0;
@@ -546,16 +543,14 @@ int btmrvl_register_hdev(struct btmrvl_private *priv)
 	}
 	}
 
 
 	priv->btmrvl_dev.hcidev = hdev;
 	priv->btmrvl_dev.hcidev = hdev;
-	hdev->driver_data = priv;
+	hci_set_drvdata(hdev, priv);
 
 
 	hdev->bus = HCI_SDIO;
 	hdev->bus = HCI_SDIO;
 	hdev->open = btmrvl_open;
 	hdev->open = btmrvl_open;
 	hdev->close = btmrvl_close;
 	hdev->close = btmrvl_close;
 	hdev->flush = btmrvl_flush;
 	hdev->flush = btmrvl_flush;
 	hdev->send = btmrvl_send_frame;
 	hdev->send = btmrvl_send_frame;
-	hdev->destruct = btmrvl_destruct;
 	hdev->ioctl = btmrvl_ioctl;
 	hdev->ioctl = btmrvl_ioctl;
-	hdev->owner = THIS_MODULE;
 
 
 	btmrvl_send_module_cfg_cmd(priv, MODULE_BRINGUP_REQ);
 	btmrvl_send_module_cfg_cmd(priv, MODULE_BRINGUP_REQ);
 
 

+ 6 - 17
drivers/bluetooth/btsdio.c

@@ -189,7 +189,7 @@ static void btsdio_interrupt(struct sdio_func *func)
 
 
 static int btsdio_open(struct hci_dev *hdev)
 static int btsdio_open(struct hci_dev *hdev)
 {
 {
-	struct btsdio_data *data = hdev->driver_data;
+	struct btsdio_data *data = hci_get_drvdata(hdev);
 	int err;
 	int err;
 
 
 	BT_DBG("%s", hdev->name);
 	BT_DBG("%s", hdev->name);
@@ -225,7 +225,7 @@ release:
 
 
 static int btsdio_close(struct hci_dev *hdev)
 static int btsdio_close(struct hci_dev *hdev)
 {
 {
-	struct btsdio_data *data = hdev->driver_data;
+	struct btsdio_data *data = hci_get_drvdata(hdev);
 
 
 	BT_DBG("%s", hdev->name);
 	BT_DBG("%s", hdev->name);
 
 
@@ -246,7 +246,7 @@ static int btsdio_close(struct hci_dev *hdev)
 
 
 static int btsdio_flush(struct hci_dev *hdev)
 static int btsdio_flush(struct hci_dev *hdev)
 {
 {
-	struct btsdio_data *data = hdev->driver_data;
+	struct btsdio_data *data = hci_get_drvdata(hdev);
 
 
 	BT_DBG("%s", hdev->name);
 	BT_DBG("%s", hdev->name);
 
 
@@ -258,7 +258,7 @@ static int btsdio_flush(struct hci_dev *hdev)
 static int btsdio_send_frame(struct sk_buff *skb)
 static int btsdio_send_frame(struct sk_buff *skb)
 {
 {
 	struct hci_dev *hdev = (struct hci_dev *) skb->dev;
 	struct hci_dev *hdev = (struct hci_dev *) skb->dev;
-	struct btsdio_data *data = hdev->driver_data;
+	struct btsdio_data *data = hci_get_drvdata(hdev);
 
 
 	BT_DBG("%s", hdev->name);
 	BT_DBG("%s", hdev->name);
 
 
@@ -289,15 +289,6 @@ static int btsdio_send_frame(struct sk_buff *skb)
 	return 0;
 	return 0;
 }
 }
 
 
-static void btsdio_destruct(struct hci_dev *hdev)
-{
-	struct btsdio_data *data = hdev->driver_data;
-
-	BT_DBG("%s", hdev->name);
-
-	kfree(data);
-}
-
 static int btsdio_probe(struct sdio_func *func,
 static int btsdio_probe(struct sdio_func *func,
 				const struct sdio_device_id *id)
 				const struct sdio_device_id *id)
 {
 {
@@ -330,7 +321,7 @@ static int btsdio_probe(struct sdio_func *func,
 	}
 	}
 
 
 	hdev->bus = HCI_SDIO;
 	hdev->bus = HCI_SDIO;
-	hdev->driver_data = data;
+	hci_set_drvdata(hdev, data);
 
 
 	if (id->class == SDIO_CLASS_BT_AMP)
 	if (id->class == SDIO_CLASS_BT_AMP)
 		hdev->dev_type = HCI_AMP;
 		hdev->dev_type = HCI_AMP;
@@ -345,9 +336,6 @@ static int btsdio_probe(struct sdio_func *func,
 	hdev->close    = btsdio_close;
 	hdev->close    = btsdio_close;
 	hdev->flush    = btsdio_flush;
 	hdev->flush    = btsdio_flush;
 	hdev->send     = btsdio_send_frame;
 	hdev->send     = btsdio_send_frame;
-	hdev->destruct = btsdio_destruct;
-
-	hdev->owner = THIS_MODULE;
 
 
 	err = hci_register_dev(hdev);
 	err = hci_register_dev(hdev);
 	if (err < 0) {
 	if (err < 0) {
@@ -378,6 +366,7 @@ static void btsdio_remove(struct sdio_func *func)
 	hci_unregister_dev(hdev);
 	hci_unregister_dev(hdev);
 
 
 	hci_free_dev(hdev);
 	hci_free_dev(hdev);
+	kfree(data);
 }
 }
 
 
 static struct sdio_driver btsdio_driver = {
 static struct sdio_driver btsdio_driver = {

+ 3 - 11
drivers/bluetooth/btuart_cs.c

@@ -397,7 +397,7 @@ static void btuart_change_speed(btuart_info_t *info, unsigned int speed)
 
 
 static int btuart_hci_flush(struct hci_dev *hdev)
 static int btuart_hci_flush(struct hci_dev *hdev)
 {
 {
-	btuart_info_t *info = (btuart_info_t *)(hdev->driver_data);
+	btuart_info_t *info = hci_get_drvdata(hdev);
 
 
 	/* Drop TX queue */
 	/* Drop TX queue */
 	skb_queue_purge(&(info->txq));
 	skb_queue_purge(&(info->txq));
@@ -435,7 +435,7 @@ static int btuart_hci_send_frame(struct sk_buff *skb)
 		return -ENODEV;
 		return -ENODEV;
 	}
 	}
 
 
-	info = (btuart_info_t *)(hdev->driver_data);
+	info = hci_get_drvdata(hdev);
 
 
 	switch (bt_cb(skb)->pkt_type) {
 	switch (bt_cb(skb)->pkt_type) {
 	case HCI_COMMAND_PKT:
 	case HCI_COMMAND_PKT:
@@ -459,11 +459,6 @@ static int btuart_hci_send_frame(struct sk_buff *skb)
 }
 }
 
 
 
 
-static void btuart_hci_destruct(struct hci_dev *hdev)
-{
-}
-
-
 static int btuart_hci_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned long arg)
 static int btuart_hci_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned long arg)
 {
 {
 	return -ENOIOCTLCMD;
 	return -ENOIOCTLCMD;
@@ -498,18 +493,15 @@ static int btuart_open(btuart_info_t *info)
 	info->hdev = hdev;
 	info->hdev = hdev;
 
 
 	hdev->bus = HCI_PCCARD;
 	hdev->bus = HCI_PCCARD;
-	hdev->driver_data = info;
+	hci_set_drvdata(hdev, info);
 	SET_HCIDEV_DEV(hdev, &info->p_dev->dev);
 	SET_HCIDEV_DEV(hdev, &info->p_dev->dev);
 
 
 	hdev->open     = btuart_hci_open;
 	hdev->open     = btuart_hci_open;
 	hdev->close    = btuart_hci_close;
 	hdev->close    = btuart_hci_close;
 	hdev->flush    = btuart_hci_flush;
 	hdev->flush    = btuart_hci_flush;
 	hdev->send     = btuart_hci_send_frame;
 	hdev->send     = btuart_hci_send_frame;
-	hdev->destruct = btuart_hci_destruct;
 	hdev->ioctl    = btuart_hci_ioctl;
 	hdev->ioctl    = btuart_hci_ioctl;
 
 
-	hdev->owner = THIS_MODULE;
-
 	spin_lock_irqsave(&(info->lock), flags);
 	spin_lock_irqsave(&(info->lock), flags);
 
 
 	/* Reset UART */
 	/* Reset UART */

+ 18 - 31
drivers/bluetooth/btusb.c

@@ -102,6 +102,7 @@ static struct usb_device_id btusb_table[] = {
 
 
 	/* Broadcom BCM20702A0 */
 	/* Broadcom BCM20702A0 */
 	{ USB_DEVICE(0x0a5c, 0x21e3) },
 	{ USB_DEVICE(0x0a5c, 0x21e3) },
+	{ USB_DEVICE(0x0a5c, 0x21e6) },
 	{ USB_DEVICE(0x0a5c, 0x21f3) },
 	{ USB_DEVICE(0x0a5c, 0x21f3) },
 	{ USB_DEVICE(0x413c, 0x8197) },
 	{ USB_DEVICE(0x413c, 0x8197) },
 
 
@@ -121,12 +122,14 @@ static struct usb_device_id blacklist_table[] = {
 	{ USB_DEVICE(0x0cf3, 0x3002), .driver_info = BTUSB_IGNORE },
 	{ USB_DEVICE(0x0cf3, 0x3002), .driver_info = BTUSB_IGNORE },
 	{ USB_DEVICE(0x13d3, 0x3304), .driver_info = BTUSB_IGNORE },
 	{ USB_DEVICE(0x13d3, 0x3304), .driver_info = BTUSB_IGNORE },
 	{ USB_DEVICE(0x0930, 0x0215), .driver_info = BTUSB_IGNORE },
 	{ USB_DEVICE(0x0930, 0x0215), .driver_info = BTUSB_IGNORE },
+	{ USB_DEVICE(0x0489, 0xe03d), .driver_info = BTUSB_IGNORE },
 
 
 	/* 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 */
 	/* Atheros 3012 with sflash firmware */
 	{ USB_DEVICE(0x0cf3, 0x3004), .driver_info = BTUSB_ATH3012 },
 	{ USB_DEVICE(0x0cf3, 0x3004), .driver_info = BTUSB_ATH3012 },
+	{ USB_DEVICE(0x13d3, 0x3375), .driver_info = BTUSB_ATH3012 },
 
 
 	/* Atheros AR5BBU12 with sflash firmware */
 	/* Atheros AR5BBU12 with sflash firmware */
 	{ USB_DEVICE(0x0489, 0xe02c), .driver_info = BTUSB_IGNORE },
 	{ USB_DEVICE(0x0489, 0xe02c), .driver_info = BTUSB_IGNORE },
@@ -243,7 +246,7 @@ static int inc_tx(struct btusb_data *data)
 static void btusb_intr_complete(struct urb *urb)
 static void btusb_intr_complete(struct urb *urb)
 {
 {
 	struct hci_dev *hdev = urb->context;
 	struct hci_dev *hdev = urb->context;
-	struct btusb_data *data = hdev->driver_data;
+	struct btusb_data *data = hci_get_drvdata(hdev);
 	int err;
 	int err;
 
 
 	BT_DBG("%s urb %p status %d count %d", hdev->name,
 	BT_DBG("%s urb %p status %d count %d", hdev->name,
@@ -282,7 +285,7 @@ static void btusb_intr_complete(struct urb *urb)
 
 
 static int btusb_submit_intr_urb(struct hci_dev *hdev, gfp_t mem_flags)
 static int btusb_submit_intr_urb(struct hci_dev *hdev, gfp_t mem_flags)
 {
 {
-	struct btusb_data *data = hdev->driver_data;
+	struct btusb_data *data = hci_get_drvdata(hdev);
 	struct urb *urb;
 	struct urb *urb;
 	unsigned char *buf;
 	unsigned char *buf;
 	unsigned int pipe;
 	unsigned int pipe;
@@ -331,7 +334,7 @@ static int btusb_submit_intr_urb(struct hci_dev *hdev, gfp_t mem_flags)
 static void btusb_bulk_complete(struct urb *urb)
 static void btusb_bulk_complete(struct urb *urb)
 {
 {
 	struct hci_dev *hdev = urb->context;
 	struct hci_dev *hdev = urb->context;
-	struct btusb_data *data = hdev->driver_data;
+	struct btusb_data *data = hci_get_drvdata(hdev);
 	int err;
 	int err;
 
 
 	BT_DBG("%s urb %p status %d count %d", hdev->name,
 	BT_DBG("%s urb %p status %d count %d", hdev->name,
@@ -370,7 +373,7 @@ static void btusb_bulk_complete(struct urb *urb)
 
 
 static int btusb_submit_bulk_urb(struct hci_dev *hdev, gfp_t mem_flags)
 static int btusb_submit_bulk_urb(struct hci_dev *hdev, gfp_t mem_flags)
 {
 {
-	struct btusb_data *data = hdev->driver_data;
+	struct btusb_data *data = hci_get_drvdata(hdev);
 	struct urb *urb;
 	struct urb *urb;
 	unsigned char *buf;
 	unsigned char *buf;
 	unsigned int pipe;
 	unsigned int pipe;
@@ -417,7 +420,7 @@ static int btusb_submit_bulk_urb(struct hci_dev *hdev, gfp_t mem_flags)
 static void btusb_isoc_complete(struct urb *urb)
 static void btusb_isoc_complete(struct urb *urb)
 {
 {
 	struct hci_dev *hdev = urb->context;
 	struct hci_dev *hdev = urb->context;
-	struct btusb_data *data = hdev->driver_data;
+	struct btusb_data *data = hci_get_drvdata(hdev);
 	int i, err;
 	int i, err;
 
 
 	BT_DBG("%s urb %p status %d count %d", hdev->name,
 	BT_DBG("%s urb %p status %d count %d", hdev->name,
@@ -484,7 +487,7 @@ static inline void __fill_isoc_descriptor(struct urb *urb, int len, int mtu)
 
 
 static int btusb_submit_isoc_urb(struct hci_dev *hdev, gfp_t mem_flags)
 static int btusb_submit_isoc_urb(struct hci_dev *hdev, gfp_t mem_flags)
 {
 {
-	struct btusb_data *data = hdev->driver_data;
+	struct btusb_data *data = hci_get_drvdata(hdev);
 	struct urb *urb;
 	struct urb *urb;
 	unsigned char *buf;
 	unsigned char *buf;
 	unsigned int pipe;
 	unsigned int pipe;
@@ -537,7 +540,7 @@ static void btusb_tx_complete(struct urb *urb)
 {
 {
 	struct sk_buff *skb = urb->context;
 	struct sk_buff *skb = urb->context;
 	struct hci_dev *hdev = (struct hci_dev *) skb->dev;
 	struct hci_dev *hdev = (struct hci_dev *) skb->dev;
-	struct btusb_data *data = hdev->driver_data;
+	struct btusb_data *data = hci_get_drvdata(hdev);
 
 
 	BT_DBG("%s urb %p status %d count %d", hdev->name,
 	BT_DBG("%s urb %p status %d count %d", hdev->name,
 					urb, urb->status, urb->actual_length);
 					urb, urb->status, urb->actual_length);
@@ -584,7 +587,7 @@ done:
 
 
 static int btusb_open(struct hci_dev *hdev)
 static int btusb_open(struct hci_dev *hdev)
 {
 {
-	struct btusb_data *data = hdev->driver_data;
+	struct btusb_data *data = hci_get_drvdata(hdev);
 	int err;
 	int err;
 
 
 	BT_DBG("%s", hdev->name);
 	BT_DBG("%s", hdev->name);
@@ -634,7 +637,7 @@ static void btusb_stop_traffic(struct btusb_data *data)
 
 
 static int btusb_close(struct hci_dev *hdev)
 static int btusb_close(struct hci_dev *hdev)
 {
 {
-	struct btusb_data *data = hdev->driver_data;
+	struct btusb_data *data = hci_get_drvdata(hdev);
 	int err;
 	int err;
 
 
 	BT_DBG("%s", hdev->name);
 	BT_DBG("%s", hdev->name);
@@ -664,7 +667,7 @@ failed:
 
 
 static int btusb_flush(struct hci_dev *hdev)
 static int btusb_flush(struct hci_dev *hdev)
 {
 {
-	struct btusb_data *data = hdev->driver_data;
+	struct btusb_data *data = hci_get_drvdata(hdev);
 
 
 	BT_DBG("%s", hdev->name);
 	BT_DBG("%s", hdev->name);
 
 
@@ -676,7 +679,7 @@ static int btusb_flush(struct hci_dev *hdev)
 static int btusb_send_frame(struct sk_buff *skb)
 static int btusb_send_frame(struct sk_buff *skb)
 {
 {
 	struct hci_dev *hdev = (struct hci_dev *) skb->dev;
 	struct hci_dev *hdev = (struct hci_dev *) skb->dev;
-	struct btusb_data *data = hdev->driver_data;
+	struct btusb_data *data = hci_get_drvdata(hdev);
 	struct usb_ctrlrequest *dr;
 	struct usb_ctrlrequest *dr;
 	struct urb *urb;
 	struct urb *urb;
 	unsigned int pipe;
 	unsigned int pipe;
@@ -784,18 +787,9 @@ done:
 	return err;
 	return err;
 }
 }
 
 
-static void btusb_destruct(struct hci_dev *hdev)
-{
-	struct btusb_data *data = hdev->driver_data;
-
-	BT_DBG("%s", hdev->name);
-
-	kfree(data);
-}
-
 static void btusb_notify(struct hci_dev *hdev, unsigned int evt)
 static void btusb_notify(struct hci_dev *hdev, unsigned int evt)
 {
 {
-	struct btusb_data *data = hdev->driver_data;
+	struct btusb_data *data = hci_get_drvdata(hdev);
 
 
 	BT_DBG("%s evt %d", hdev->name, evt);
 	BT_DBG("%s evt %d", hdev->name, evt);
 
 
@@ -807,7 +801,7 @@ static void btusb_notify(struct hci_dev *hdev, unsigned int evt)
 
 
 static inline int __set_isoc_interface(struct hci_dev *hdev, int altsetting)
 static inline int __set_isoc_interface(struct hci_dev *hdev, int altsetting)
 {
 {
-	struct btusb_data *data = hdev->driver_data;
+	struct btusb_data *data = hci_get_drvdata(hdev);
 	struct usb_interface *intf = data->isoc;
 	struct usb_interface *intf = data->isoc;
 	struct usb_endpoint_descriptor *ep_desc;
 	struct usb_endpoint_descriptor *ep_desc;
 	int i, err;
 	int i, err;
@@ -995,7 +989,7 @@ static int btusb_probe(struct usb_interface *intf,
 	}
 	}
 
 
 	hdev->bus = HCI_USB;
 	hdev->bus = HCI_USB;
-	hdev->driver_data = data;
+	hci_set_drvdata(hdev, data);
 
 
 	data->hdev = hdev;
 	data->hdev = hdev;
 
 
@@ -1005,11 +999,8 @@ static int btusb_probe(struct usb_interface *intf,
 	hdev->close    = btusb_close;
 	hdev->close    = btusb_close;
 	hdev->flush    = btusb_flush;
 	hdev->flush    = btusb_flush;
 	hdev->send     = btusb_send_frame;
 	hdev->send     = btusb_send_frame;
-	hdev->destruct = btusb_destruct;
 	hdev->notify   = btusb_notify;
 	hdev->notify   = btusb_notify;
 
 
-	hdev->owner = THIS_MODULE;
-
 	/* Interface numbers are hardcoded in the specification */
 	/* Interface numbers are hardcoded in the specification */
 	data->isoc = usb_ifnum_to_if(data->udev, 1);
 	data->isoc = usb_ifnum_to_if(data->udev, 1);
 
 
@@ -1091,9 +1082,6 @@ static void btusb_disconnect(struct usb_interface *intf)
 		return;
 		return;
 
 
 	hdev = data->hdev;
 	hdev = data->hdev;
-
-	__hci_dev_hold(hdev);
-
 	usb_set_intfdata(data->intf, NULL);
 	usb_set_intfdata(data->intf, NULL);
 
 
 	if (data->isoc)
 	if (data->isoc)
@@ -1106,9 +1094,8 @@ static void btusb_disconnect(struct usb_interface *intf)
 	else if (data->isoc)
 	else if (data->isoc)
 		usb_driver_release_interface(&btusb_driver, data->isoc);
 		usb_driver_release_interface(&btusb_driver, data->isoc);
 
 
-	__hci_dev_put(hdev);
-
 	hci_free_dev(hdev);
 	hci_free_dev(hdev);
+	kfree(data);
 }
 }
 
 
 #ifdef CONFIG_PM
 #ifdef CONFIG_PM

+ 4 - 14
drivers/bluetooth/btwilink.c

@@ -161,7 +161,7 @@ static int ti_st_open(struct hci_dev *hdev)
 		return -EBUSY;
 		return -EBUSY;
 
 
 	/* provide contexts for callbacks from ST */
 	/* provide contexts for callbacks from ST */
-	hst = hdev->driver_data;
+	hst = hci_get_drvdata(hdev);
 
 
 	for (i = 0; i < MAX_BT_CHNL_IDS; i++) {
 	for (i = 0; i < MAX_BT_CHNL_IDS; i++) {
 		ti_st_proto[i].priv_data = hst;
 		ti_st_proto[i].priv_data = hst;
@@ -236,7 +236,7 @@ done:
 static int ti_st_close(struct hci_dev *hdev)
 static int ti_st_close(struct hci_dev *hdev)
 {
 {
 	int err, i;
 	int err, i;
-	struct ti_st *hst = hdev->driver_data;
+	struct ti_st *hst = hci_get_drvdata(hdev);
 
 
 	if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
 	if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
 		return 0;
 		return 0;
@@ -264,7 +264,7 @@ static int ti_st_send_frame(struct sk_buff *skb)
 	if (!test_bit(HCI_RUNNING, &hdev->flags))
 	if (!test_bit(HCI_RUNNING, &hdev->flags))
 		return -EBUSY;
 		return -EBUSY;
 
 
-	hst = hdev->driver_data;
+	hst = hci_get_drvdata(hdev);
 
 
 	/* Prepend skb with frame type */
 	/* Prepend skb with frame type */
 	memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1);
 	memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1);
@@ -291,14 +291,6 @@ static int ti_st_send_frame(struct sk_buff *skb)
 	return 0;
 	return 0;
 }
 }
 
 
-static void ti_st_destruct(struct hci_dev *hdev)
-{
-	BT_DBG("%s", hdev->name);
-	/* do nothing here, since platform remove
-	 * would free the hdev->driver_data
-	 */
-}
-
 static int bt_ti_probe(struct platform_device *pdev)
 static int bt_ti_probe(struct platform_device *pdev)
 {
 {
 	static struct ti_st *hst;
 	static struct ti_st *hst;
@@ -320,13 +312,11 @@ static int bt_ti_probe(struct platform_device *pdev)
 
 
 	hst->hdev = hdev;
 	hst->hdev = hdev;
 	hdev->bus = HCI_UART;
 	hdev->bus = HCI_UART;
-	hdev->driver_data = hst;
+	hci_set_drvdata(hdev, hst);
 	hdev->open = ti_st_open;
 	hdev->open = ti_st_open;
 	hdev->close = ti_st_close;
 	hdev->close = ti_st_close;
 	hdev->flush = NULL;
 	hdev->flush = NULL;
 	hdev->send = ti_st_send_frame;
 	hdev->send = ti_st_send_frame;
-	hdev->destruct = ti_st_destruct;
-	hdev->owner = THIS_MODULE;
 
 
 	err = hci_register_dev(hdev);
 	err = hci_register_dev(hdev);
 	if (err < 0) {
 	if (err < 0) {

+ 6 - 28
drivers/bluetooth/dtl1_cs.c

@@ -83,9 +83,6 @@ typedef struct dtl1_info_t {
 
 
 
 
 static int dtl1_config(struct pcmcia_device *link);
 static int dtl1_config(struct pcmcia_device *link);
-static void dtl1_release(struct pcmcia_device *link);
-
-static void dtl1_detach(struct pcmcia_device *p_dev);
 
 
 
 
 /* Transmit states  */
 /* Transmit states  */
@@ -367,7 +364,7 @@ static int dtl1_hci_open(struct hci_dev *hdev)
 
 
 static int dtl1_hci_flush(struct hci_dev *hdev)
 static int dtl1_hci_flush(struct hci_dev *hdev)
 {
 {
-	dtl1_info_t *info = (dtl1_info_t *)(hdev->driver_data);
+	dtl1_info_t *info = hci_get_drvdata(hdev);
 
 
 	/* Drop TX queue */
 	/* Drop TX queue */
 	skb_queue_purge(&(info->txq));
 	skb_queue_purge(&(info->txq));
@@ -399,7 +396,7 @@ static int dtl1_hci_send_frame(struct sk_buff *skb)
 		return -ENODEV;
 		return -ENODEV;
 	}
 	}
 
 
-	info = (dtl1_info_t *)(hdev->driver_data);
+	info = hci_get_drvdata(hdev);
 
 
 	switch (bt_cb(skb)->pkt_type) {
 	switch (bt_cb(skb)->pkt_type) {
 	case HCI_COMMAND_PKT:
 	case HCI_COMMAND_PKT:
@@ -442,11 +439,6 @@ static int dtl1_hci_send_frame(struct sk_buff *skb)
 }
 }
 
 
 
 
-static void dtl1_hci_destruct(struct hci_dev *hdev)
-{
-}
-
-
 static int dtl1_hci_ioctl(struct hci_dev *hdev, unsigned int cmd,  unsigned long arg)
 static int dtl1_hci_ioctl(struct hci_dev *hdev, unsigned int cmd,  unsigned long arg)
 {
 {
 	return -ENOIOCTLCMD;
 	return -ENOIOCTLCMD;
@@ -483,18 +475,15 @@ static int dtl1_open(dtl1_info_t *info)
 	info->hdev = hdev;
 	info->hdev = hdev;
 
 
 	hdev->bus = HCI_PCCARD;
 	hdev->bus = HCI_PCCARD;
-	hdev->driver_data = info;
+	hci_set_drvdata(hdev, info);
 	SET_HCIDEV_DEV(hdev, &info->p_dev->dev);
 	SET_HCIDEV_DEV(hdev, &info->p_dev->dev);
 
 
 	hdev->open     = dtl1_hci_open;
 	hdev->open     = dtl1_hci_open;
 	hdev->close    = dtl1_hci_close;
 	hdev->close    = dtl1_hci_close;
 	hdev->flush    = dtl1_hci_flush;
 	hdev->flush    = dtl1_hci_flush;
 	hdev->send     = dtl1_hci_send_frame;
 	hdev->send     = dtl1_hci_send_frame;
-	hdev->destruct = dtl1_hci_destruct;
 	hdev->ioctl    = dtl1_hci_ioctl;
 	hdev->ioctl    = dtl1_hci_ioctl;
 
 
-	hdev->owner = THIS_MODULE;
-
 	spin_lock_irqsave(&(info->lock), flags);
 	spin_lock_irqsave(&(info->lock), flags);
 
 
 	/* Reset UART */
 	/* Reset UART */
@@ -579,8 +568,8 @@ static void dtl1_detach(struct pcmcia_device *link)
 {
 {
 	dtl1_info_t *info = link->priv;
 	dtl1_info_t *info = link->priv;
 
 
-	dtl1_release(link);
-
+	dtl1_close(info);
+	pcmcia_disable_device(link);
 	kfree(info);
 	kfree(info);
 }
 }
 
 
@@ -619,21 +608,10 @@ static int dtl1_config(struct pcmcia_device *link)
 	return 0;
 	return 0;
 
 
 failed:
 failed:
-	dtl1_release(link);
+	dtl1_detach(link);
 	return -ENODEV;
 	return -ENODEV;
 }
 }
 
 
-
-static void dtl1_release(struct pcmcia_device *link)
-{
-	dtl1_info_t *info = link->priv;
-
-	dtl1_close(info);
-
-	pcmcia_disable_device(link);
-}
-
-
 static const struct pcmcia_device_id dtl1_ids[] = {
 static const struct pcmcia_device_id dtl1_ids[] = {
 	PCMCIA_DEVICE_PROD_ID12("Nokia Mobile Phones", "DTL-1", 0xe1bfdd64, 0xe168480d),
 	PCMCIA_DEVICE_PROD_ID12("Nokia Mobile Phones", "DTL-1", 0xe1bfdd64, 0xe168480d),
 	PCMCIA_DEVICE_PROD_ID12("Nokia Mobile Phones", "DTL-4", 0xe1bfdd64, 0x9102bc82),
 	PCMCIA_DEVICE_PROD_ID12("Nokia Mobile Phones", "DTL-4", 0xe1bfdd64, 0x9102bc82),

+ 1 - 1
drivers/bluetooth/hci_ath.c

@@ -112,7 +112,7 @@ static int ath_open(struct hci_uart *hu)
 
 
 	BT_DBG("hu %p", hu);
 	BT_DBG("hu %p", hu);
 
 
-	ath = kzalloc(sizeof(*ath), GFP_ATOMIC);
+	ath = kzalloc(sizeof(*ath), GFP_KERNEL);
 	if (!ath)
 	if (!ath)
 		return -ENOMEM;
 		return -ENOMEM;
 
 

+ 1 - 1
drivers/bluetooth/hci_bcsp.c

@@ -692,7 +692,7 @@ static int bcsp_open(struct hci_uart *hu)
 
 
 	BT_DBG("hu %p", hu);
 	BT_DBG("hu %p", hu);
 
 
-	bcsp = kzalloc(sizeof(*bcsp), GFP_ATOMIC);
+	bcsp = kzalloc(sizeof(*bcsp), GFP_KERNEL);
 	if (!bcsp)
 	if (!bcsp)
 		return -ENOMEM;
 		return -ENOMEM;
 
 

+ 1 - 1
drivers/bluetooth/hci_h4.c

@@ -69,7 +69,7 @@ static int h4_open(struct hci_uart *hu)
 
 
 	BT_DBG("hu %p", hu);
 	BT_DBG("hu %p", hu);
 
 
-	h4 = kzalloc(sizeof(*h4), GFP_ATOMIC);
+	h4 = kzalloc(sizeof(*h4), GFP_KERNEL);
 	if (!h4)
 	if (!h4)
 		return -ENOMEM;
 		return -ENOMEM;
 
 

+ 12 - 22
drivers/bluetooth/hci_ldisc.c

@@ -48,8 +48,6 @@
 
 
 #define VERSION "2.2"
 #define VERSION "2.2"
 
 
-static bool reset = 0;
-
 static struct hci_uart_proto *hup[HCI_UART_MAX_PROTO];
 static struct hci_uart_proto *hup[HCI_UART_MAX_PROTO];
 
 
 int hci_uart_register_proto(struct hci_uart_proto *p)
 int hci_uart_register_proto(struct hci_uart_proto *p)
@@ -174,7 +172,7 @@ static int hci_uart_open(struct hci_dev *hdev)
 /* Reset device */
 /* Reset device */
 static int hci_uart_flush(struct hci_dev *hdev)
 static int hci_uart_flush(struct hci_dev *hdev)
 {
 {
-	struct hci_uart *hu  = (struct hci_uart *) hdev->driver_data;
+	struct hci_uart *hu  = hci_get_drvdata(hdev);
 	struct tty_struct *tty = hu->tty;
 	struct tty_struct *tty = hu->tty;
 
 
 	BT_DBG("hdev %p tty %p", hdev, tty);
 	BT_DBG("hdev %p tty %p", hdev, tty);
@@ -220,7 +218,7 @@ static int hci_uart_send_frame(struct sk_buff *skb)
 	if (!test_bit(HCI_RUNNING, &hdev->flags))
 	if (!test_bit(HCI_RUNNING, &hdev->flags))
 		return -EBUSY;
 		return -EBUSY;
 
 
-	hu = (struct hci_uart *) hdev->driver_data;
+	hu = hci_get_drvdata(hdev);
 
 
 	BT_DBG("%s: type %d len %d", hdev->name, bt_cb(skb)->pkt_type, skb->len);
 	BT_DBG("%s: type %d len %d", hdev->name, bt_cb(skb)->pkt_type, skb->len);
 
 
@@ -231,15 +229,6 @@ static int hci_uart_send_frame(struct sk_buff *skb)
 	return 0;
 	return 0;
 }
 }
 
 
-static void hci_uart_destruct(struct hci_dev *hdev)
-{
-	if (!hdev)
-		return;
-
-	BT_DBG("%s", hdev->name);
-	kfree(hdev->driver_data);
-}
-
 /* ------ LDISC part ------ */
 /* ------ LDISC part ------ */
 /* hci_uart_tty_open
 /* hci_uart_tty_open
  * 
  * 
@@ -316,6 +305,8 @@ static void hci_uart_tty_close(struct tty_struct *tty)
 				hci_free_dev(hdev);
 				hci_free_dev(hdev);
 			}
 			}
 		}
 		}
+
+		kfree(hu);
 	}
 	}
 }
 }
 
 
@@ -391,22 +382,24 @@ static int hci_uart_register_dev(struct hci_uart *hu)
 	hu->hdev = hdev;
 	hu->hdev = hdev;
 
 
 	hdev->bus = HCI_UART;
 	hdev->bus = HCI_UART;
-	hdev->driver_data = hu;
+	hci_set_drvdata(hdev, hu);
 
 
 	hdev->open  = hci_uart_open;
 	hdev->open  = hci_uart_open;
 	hdev->close = hci_uart_close;
 	hdev->close = hci_uart_close;
 	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->parent = hu->tty->dev;
 	hdev->parent = hu->tty->dev;
 
 
-	hdev->owner = THIS_MODULE;
+	if (test_bit(HCI_UART_RAW_DEVICE, &hu->hdev_flags))
+		set_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks);
 
 
-	if (!reset)
+	if (!test_bit(HCI_UART_RESET_ON_INIT, &hu->hdev_flags))
 		set_bit(HCI_QUIRK_NO_RESET, &hdev->quirks);
 		set_bit(HCI_QUIRK_NO_RESET, &hdev->quirks);
 
 
-	if (test_bit(HCI_UART_RAW_DEVICE, &hu->hdev_flags))
-		set_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks);
+	if (test_bit(HCI_UART_CREATE_AMP, &hu->hdev_flags))
+		hdev->dev_type = HCI_AMP;
+	else
+		hdev->dev_type = HCI_BREDR;
 
 
 	if (hci_register_dev(hdev) < 0) {
 	if (hci_register_dev(hdev) < 0) {
 		BT_ERR("Can't register HCI device");
 		BT_ERR("Can't register HCI device");
@@ -594,9 +587,6 @@ static void __exit hci_uart_exit(void)
 module_init(hci_uart_init);
 module_init(hci_uart_init);
 module_exit(hci_uart_exit);
 module_exit(hci_uart_exit);
 
 
-module_param(reset, bool, 0644);
-MODULE_PARM_DESC(reset, "Send HCI reset command on initialization");
-
 MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
 MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
 MODULE_DESCRIPTION("Bluetooth HCI UART driver ver " VERSION);
 MODULE_DESCRIPTION("Bluetooth HCI UART driver ver " VERSION);
 MODULE_VERSION(VERSION);
 MODULE_VERSION(VERSION);

+ 1 - 1
drivers/bluetooth/hci_ll.c

@@ -125,7 +125,7 @@ static int ll_open(struct hci_uart *hu)
 
 
 	BT_DBG("hu %p", hu);
 	BT_DBG("hu %p", hu);
 
 
-	ll = kzalloc(sizeof(*ll), GFP_ATOMIC);
+	ll = kzalloc(sizeof(*ll), GFP_KERNEL);
 	if (!ll)
 	if (!ll)
 		return -ENOMEM;
 		return -ENOMEM;
 
 

+ 2 - 0
drivers/bluetooth/hci_uart.h

@@ -45,6 +45,8 @@
 #define HCI_UART_ATH3K	5
 #define HCI_UART_ATH3K	5
 
 
 #define HCI_UART_RAW_DEVICE	0
 #define HCI_UART_RAW_DEVICE	0
+#define HCI_UART_RESET_ON_INIT	1
+#define HCI_UART_CREATE_AMP	2
 
 
 struct hci_uart;
 struct hci_uart;
 
 

+ 5 - 12
drivers/bluetooth/hci_vhci.c

@@ -61,7 +61,7 @@ static int vhci_open_dev(struct hci_dev *hdev)
 
 
 static int vhci_close_dev(struct hci_dev *hdev)
 static int vhci_close_dev(struct hci_dev *hdev)
 {
 {
-	struct vhci_data *data = hdev->driver_data;
+	struct vhci_data *data = hci_get_drvdata(hdev);
 
 
 	if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
 	if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
 		return 0;
 		return 0;
@@ -73,7 +73,7 @@ static int vhci_close_dev(struct hci_dev *hdev)
 
 
 static int vhci_flush(struct hci_dev *hdev)
 static int vhci_flush(struct hci_dev *hdev)
 {
 {
-	struct vhci_data *data = hdev->driver_data;
+	struct vhci_data *data = hci_get_drvdata(hdev);
 
 
 	skb_queue_purge(&data->readq);
 	skb_queue_purge(&data->readq);
 
 
@@ -93,7 +93,7 @@ static int vhci_send_frame(struct sk_buff *skb)
 	if (!test_bit(HCI_RUNNING, &hdev->flags))
 	if (!test_bit(HCI_RUNNING, &hdev->flags))
 		return -EBUSY;
 		return -EBUSY;
 
 
-	data = hdev->driver_data;
+	data = hci_get_drvdata(hdev);
 
 
 	memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1);
 	memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1);
 	skb_queue_tail(&data->readq, skb);
 	skb_queue_tail(&data->readq, skb);
@@ -103,11 +103,6 @@ static int vhci_send_frame(struct sk_buff *skb)
 	return 0;
 	return 0;
 }
 }
 
 
-static void vhci_destruct(struct hci_dev *hdev)
-{
-	kfree(hdev->driver_data);
-}
-
 static inline ssize_t vhci_get_user(struct vhci_data *data,
 static inline ssize_t vhci_get_user(struct vhci_data *data,
 					const char __user *buf, size_t count)
 					const char __user *buf, size_t count)
 {
 {
@@ -239,7 +234,7 @@ static int vhci_open(struct inode *inode, struct file *file)
 	data->hdev = hdev;
 	data->hdev = hdev;
 
 
 	hdev->bus = HCI_VIRTUAL;
 	hdev->bus = HCI_VIRTUAL;
-	hdev->driver_data = data;
+	hci_set_drvdata(hdev, data);
 
 
 	if (amp)
 	if (amp)
 		hdev->dev_type = HCI_AMP;
 		hdev->dev_type = HCI_AMP;
@@ -248,9 +243,6 @@ static int vhci_open(struct inode *inode, struct file *file)
 	hdev->close    = vhci_close_dev;
 	hdev->close    = vhci_close_dev;
 	hdev->flush    = vhci_flush;
 	hdev->flush    = vhci_flush;
 	hdev->send     = vhci_send_frame;
 	hdev->send     = vhci_send_frame;
-	hdev->destruct = vhci_destruct;
-
-	hdev->owner = THIS_MODULE;
 
 
 	if (hci_register_dev(hdev) < 0) {
 	if (hci_register_dev(hdev) < 0) {
 		BT_ERR("Can't register HCI device");
 		BT_ERR("Can't register HCI device");
@@ -273,6 +265,7 @@ static int vhci_release(struct inode *inode, struct file *file)
 	hci_free_dev(hdev);
 	hci_free_dev(hdev);
 
 
 	file->private_data = NULL;
 	file->private_data = NULL;
+	kfree(data);
 
 
 	return 0;
 	return 0;
 }
 }

+ 34 - 6
include/net/bluetooth/bluetooth.h

@@ -109,12 +109,14 @@ struct bt_power {
  */
  */
 #define BT_CHANNEL_POLICY_AMP_PREFERRED		2
 #define BT_CHANNEL_POLICY_AMP_PREFERRED		2
 
 
-__printf(2, 3)
-int bt_printk(const char *level, const char *fmt, ...);
+__printf(1, 2)
+int bt_info(const char *fmt, ...);
+__printf(1, 2)
+int bt_err(const char *fmt, ...);
 
 
-#define BT_INFO(fmt, arg...)   bt_printk(KERN_INFO, pr_fmt(fmt), ##arg)
-#define BT_ERR(fmt, arg...)    bt_printk(KERN_ERR, pr_fmt(fmt), ##arg)
-#define BT_DBG(fmt, arg...)    pr_debug(fmt "\n", ##arg)
+#define BT_INFO(fmt, ...)	bt_info(fmt "\n", ##__VA_ARGS__)
+#define BT_ERR(fmt, ...)	bt_err(fmt "\n", ##__VA_ARGS__)
+#define BT_DBG(fmt, ...)	pr_debug(fmt "\n", ##__VA_ARGS__)
 
 
 /* Connection and socket states */
 /* Connection and socket states */
 enum {
 enum {
@@ -129,6 +131,33 @@ enum {
 	BT_CLOSED
 	BT_CLOSED
 };
 };
 
 
+/* If unused will be removed by compiler */
+static inline const 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";
+}
+
 /* BD Address */
 /* BD Address */
 typedef struct {
 typedef struct {
 	__u8 b[6];
 	__u8 b[6];
@@ -193,7 +222,6 @@ struct bt_skb_cb {
 	__u16 tx_seq;
 	__u16 tx_seq;
 	__u8 retries;
 	__u8 retries;
 	__u8 sar;
 	__u8 sar;
-	unsigned short channel;
 	__u8 force_active;
 	__u8 force_active;
 };
 };
 #define bt_cb(skb) ((struct bt_skb_cb *)((skb)->cb))
 #define bt_cb(skb) ((struct bt_skb_cb *)((skb)->cb))

+ 59 - 17
include/net/bluetooth/hci.h

@@ -77,14 +77,6 @@ enum {
 
 
 	HCI_RAW,
 	HCI_RAW,
 
 
-	HCI_SETUP,
-	HCI_AUTO_OFF,
-	HCI_MGMT,
-	HCI_PAIRABLE,
-	HCI_SERVICE_CACHE,
-	HCI_LINK_KEYS,
-	HCI_DEBUG_KEYS,
-
 	HCI_RESET,
 	HCI_RESET,
 };
 };
 
 
@@ -93,7 +85,22 @@ enum {
  * states from the controller.
  * states from the controller.
  */
  */
 enum {
 enum {
+	HCI_SETUP,
+	HCI_AUTO_OFF,
+	HCI_MGMT,
+	HCI_PAIRABLE,
+	HCI_SERVICE_CACHE,
+	HCI_LINK_KEYS,
+	HCI_DEBUG_KEYS,
+
 	HCI_LE_SCAN,
 	HCI_LE_SCAN,
+	HCI_SSP_ENABLED,
+	HCI_HS_ENABLED,
+	HCI_LE_ENABLED,
+	HCI_CONNECTABLE,
+	HCI_DISCOVERABLE,
+	HCI_LINK_SECURITY,
+	HCI_PENDING_CLASS,
 };
 };
 
 
 /* HCI ioctl defines */
 /* HCI ioctl defines */
@@ -130,6 +137,7 @@ enum {
 #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 */
 #define HCI_CMD_TIMEOUT		(1000)	/* 1 seconds */
+#define HCI_ACL_TX_TIMEOUT	(45000)	/* 45 seconds */
 
 
 /* HCI data types */
 /* HCI data types */
 #define HCI_COMMAND_PKT		0x01
 #define HCI_COMMAND_PKT		0x01
@@ -229,7 +237,9 @@ enum {
 #define LMP_EXTFEATURES	0x80
 #define LMP_EXTFEATURES	0x80
 
 
 /* Extended LMP features */
 /* Extended LMP features */
-#define LMP_HOST_LE	0x02
+#define LMP_HOST_SSP		0x01
+#define LMP_HOST_LE		0x02
+#define LMP_HOST_LE_BREDR	0x04
 
 
 /* Connection modes */
 /* Connection modes */
 #define HCI_CM_ACTIVE	0x0000
 #define HCI_CM_ACTIVE	0x0000
@@ -268,10 +278,11 @@ enum {
 #define HCI_LK_UNAUTH_COMBINATION	0x04
 #define HCI_LK_UNAUTH_COMBINATION	0x04
 #define HCI_LK_AUTH_COMBINATION		0x05
 #define HCI_LK_AUTH_COMBINATION		0x05
 #define HCI_LK_CHANGED_COMBINATION	0x06
 #define HCI_LK_CHANGED_COMBINATION	0x06
-/* The spec doesn't define types for SMP keys */
-#define HCI_LK_SMP_LTK			0x81
-#define HCI_LK_SMP_IRK			0x82
-#define HCI_LK_SMP_CSRK			0x83
+/* The spec doesn't define types for SMP keys, the _MASTER suffix is implied */
+#define HCI_SMP_STK			0x80
+#define HCI_SMP_STK_SLAVE		0x81
+#define HCI_SMP_LTK			0x82
+#define HCI_SMP_LTK_SLAVE		0x83
 
 
 /* ---- HCI Error Codes ---- */
 /* ---- HCI Error Codes ---- */
 #define HCI_ERROR_AUTH_FAILURE		0x05
 #define HCI_ERROR_AUTH_FAILURE		0x05
@@ -284,6 +295,22 @@ enum {
 #define HCI_FLOW_CTL_MODE_PACKET_BASED	0x00
 #define HCI_FLOW_CTL_MODE_PACKET_BASED	0x00
 #define HCI_FLOW_CTL_MODE_BLOCK_BASED	0x01
 #define HCI_FLOW_CTL_MODE_BLOCK_BASED	0x01
 
 
+/* Extended Inquiry Response field types */
+#define EIR_FLAGS		0x01 /* flags */
+#define EIR_UUID16_SOME		0x02 /* 16-bit UUID, more available */
+#define EIR_UUID16_ALL		0x03 /* 16-bit UUID, all listed */
+#define EIR_UUID32_SOME		0x04 /* 32-bit UUID, more available */
+#define EIR_UUID32_ALL		0x05 /* 32-bit UUID, all listed */
+#define EIR_UUID128_SOME	0x06 /* 128-bit UUID, more available */
+#define EIR_UUID128_ALL		0x07 /* 128-bit UUID, all listed */
+#define EIR_NAME_SHORT		0x08 /* shortened local name */
+#define EIR_NAME_COMPLETE	0x09 /* complete local name */
+#define EIR_TX_POWER		0x0A /* transmit power level */
+#define EIR_CLASS_OF_DEV	0x0D /* Class of Device */
+#define EIR_SSP_HASH_C		0x0E /* Simple Pairing Hash C */
+#define EIR_SSP_RAND_R		0x0F /* Simple Pairing Randomizer R */
+#define EIR_DEVICE_ID		0x10 /* device ID */
+
 /* -----  HCI Commands ---- */
 /* -----  HCI Commands ---- */
 #define HCI_OP_NOP			0x0000
 #define HCI_OP_NOP			0x0000
 
 
@@ -666,8 +693,8 @@ struct hci_cp_host_buffer_size {
 
 
 #define HCI_OP_WRITE_EIR		0x0c52
 #define HCI_OP_WRITE_EIR		0x0c52
 struct hci_cp_write_eir {
 struct hci_cp_write_eir {
-	uint8_t		fec;
-	uint8_t		data[HCI_MAX_EIR_LENGTH];
+	__u8	fec;
+	__u8	data[HCI_MAX_EIR_LENGTH];
 } __packed;
 } __packed;
 
 
 #define HCI_OP_READ_SSP_MODE		0x0c55
 #define HCI_OP_READ_SSP_MODE		0x0c55
@@ -698,8 +725,8 @@ struct hci_rp_read_flow_control_mode {
 
 
 #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 simul;
+	__u8	le;
+	__u8	simul;
 } __packed;
 } __packed;
 
 
 #define HCI_OP_READ_LOCAL_VERSION	0x1001
 #define HCI_OP_READ_LOCAL_VERSION	0x1001
@@ -1155,6 +1182,19 @@ struct hci_ev_le_meta {
 	__u8     subevent;
 	__u8     subevent;
 } __packed;
 } __packed;
 
 
+#define HCI_EV_NUM_COMP_BLOCKS		0x48
+struct hci_comp_blocks_info {
+	__le16   handle;
+	__le16   pkts;
+	__le16   blocks;
+} __packed;
+
+struct hci_ev_num_comp_blocks {
+	__le16   num_blocks;
+	__u8     num_hndl;
+	struct hci_comp_blocks_info handles[0];
+} __packed;
+
 /* Low energy meta events */
 /* Low energy meta events */
 #define HCI_EV_LE_CONN_COMPLETE		0x01
 #define HCI_EV_LE_CONN_COMPLETE		0x01
 struct hci_ev_le_conn_complete {
 struct hci_ev_le_conn_complete {
@@ -1288,6 +1328,7 @@ struct sockaddr_hci {
 
 
 #define HCI_CHANNEL_RAW		0
 #define HCI_CHANNEL_RAW		0
 #define HCI_CHANNEL_CONTROL	1
 #define HCI_CHANNEL_CONTROL	1
+#define HCI_CHANNEL_MONITOR	2
 
 
 struct hci_filter {
 struct hci_filter {
 	unsigned long type_mask;
 	unsigned long type_mask;
@@ -1389,5 +1430,6 @@ struct hci_inquiry_req {
 #define IREQ_CACHE_FLUSH 0x0001
 #define IREQ_CACHE_FLUSH 0x0001
 
 
 extern bool enable_hs;
 extern bool enable_hs;
+extern bool enable_le;
 
 
 #endif /* __HCI_H */
 #endif /* __HCI_H */

+ 203 - 98
include/net/bluetooth/hci_core.h

@@ -44,14 +44,31 @@ struct inquiry_data {
 };
 };
 
 
 struct inquiry_entry {
 struct inquiry_entry {
-	struct inquiry_entry	*next;
+	struct list_head	all;		/* inq_cache.all */
+	struct list_head	list;		/* unknown or resolve */
+	enum {
+		NAME_NOT_KNOWN,
+		NAME_NEEDED,
+		NAME_PENDING,
+		NAME_KNOWN,
+	} name_state;
 	__u32			timestamp;
 	__u32			timestamp;
 	struct inquiry_data	data;
 	struct inquiry_data	data;
 };
 };
 
 
-struct inquiry_cache {
+struct discovery_state {
+	int			type;
+	enum {
+		DISCOVERY_STOPPED,
+		DISCOVERY_STARTING,
+		DISCOVERY_FINDING,
+		DISCOVERY_RESOLVING,
+		DISCOVERY_STOPPING,
+	} state;
+	struct list_head	all;		/* All devices found during inquiry */
+	struct list_head	unknown;	/* Name state not known */
+	struct list_head	resolve;	/* Name needs to be resolved */
 	__u32			timestamp;
 	__u32			timestamp;
-	struct inquiry_entry	*list;
 };
 };
 
 
 struct hci_conn_hash {
 struct hci_conn_hash {
@@ -72,18 +89,16 @@ struct bt_uuid {
 	u8 svc_hint;
 	u8 svc_hint;
 };
 };
 
 
-struct key_master_id {
-	__le16 ediv;
-	u8 rand[8];
-} __packed;
-
-struct link_key_data {
+struct smp_ltk {
+	struct list_head list;
 	bdaddr_t bdaddr;
 	bdaddr_t bdaddr;
+	u8 bdaddr_type;
+	u8 authenticated;
 	u8 type;
 	u8 type;
+	u8 enc_size;
+	__le16 ediv;
+	u8 rand[8];
 	u8 val[16];
 	u8 val[16];
-	u8 pin_len;
-	u8 dlen;
-	u8 data[0];
 } __packed;
 } __packed;
 
 
 struct link_key {
 struct link_key {
@@ -92,8 +107,6 @@ struct link_key {
 	u8 type;
 	u8 type;
 	u8 val[16];
 	u8 val[16];
 	u8 pin_len;
 	u8 pin_len;
-	u8 dlen;
-	u8 data[0];
 };
 };
 
 
 struct oob_data {
 struct oob_data {
@@ -109,11 +122,19 @@ struct adv_entry {
 	u8 bdaddr_type;
 	u8 bdaddr_type;
 };
 };
 
 
+struct le_scan_params {
+	u8 type;
+	u16 interval;
+	u16 window;
+	int timeout;
+};
+
+#define HCI_MAX_SHORT_NAME_LENGTH	10
+
 #define NUM_REASSEMBLY 4
 #define NUM_REASSEMBLY 4
 struct hci_dev {
 struct hci_dev {
 	struct list_head list;
 	struct list_head list;
 	struct mutex	lock;
 	struct mutex	lock;
-	atomic_t	refcnt;
 
 
 	char		name[8];
 	char		name[8];
 	unsigned long	flags;
 	unsigned long	flags;
@@ -122,6 +143,7 @@ struct hci_dev {
 	__u8		dev_type;
 	__u8		dev_type;
 	bdaddr_t	bdaddr;
 	bdaddr_t	bdaddr;
 	__u8		dev_name[HCI_MAX_NAME_LENGTH];
 	__u8		dev_name[HCI_MAX_NAME_LENGTH];
+	__u8		short_name[HCI_MAX_SHORT_NAME_LENGTH];
 	__u8		eir[HCI_MAX_EIR_LENGTH];
 	__u8		eir[HCI_MAX_EIR_LENGTH];
 	__u8		dev_class[3];
 	__u8		dev_class[3];
 	__u8		major_class;
 	__u8		major_class;
@@ -129,7 +151,6 @@ struct hci_dev {
 	__u8		features[8];
 	__u8		features[8];
 	__u8		host_features[8];
 	__u8		host_features[8];
 	__u8		commands[64];
 	__u8		commands[64];
-	__u8		ssp_mode;
 	__u8		hci_ver;
 	__u8		hci_ver;
 	__u16		hci_rev;
 	__u16		hci_rev;
 	__u8		lmp_ver;
 	__u8		lmp_ver;
@@ -217,7 +238,7 @@ struct hci_dev {
 
 
 	struct list_head	mgmt_pending;
 	struct list_head	mgmt_pending;
 
 
-	struct inquiry_cache	inq_cache;
+	struct discovery_state	discovery;
 	struct hci_conn_hash	conn_hash;
 	struct hci_conn_hash	conn_hash;
 	struct list_head	blacklist;
 	struct list_head	blacklist;
 
 
@@ -225,6 +246,8 @@ struct hci_dev {
 
 
 	struct list_head	link_keys;
 	struct list_head	link_keys;
 
 
+	struct list_head	long_term_keys;
+
 	struct list_head	remote_oob_data;
 	struct list_head	remote_oob_data;
 
 
 	struct list_head	adv_entries;
 	struct list_head	adv_entries;
@@ -234,7 +257,6 @@ struct hci_dev {
 
 
 	struct sk_buff_head	driver_init;
 	struct sk_buff_head	driver_init;
 
 
-	void			*driver_data;
 	void			*core_data;
 	void			*core_data;
 
 
 	atomic_t		promisc;
 	atomic_t		promisc;
@@ -246,15 +268,17 @@ struct hci_dev {
 
 
 	struct rfkill		*rfkill;
 	struct rfkill		*rfkill;
 
 
-	struct module		*owner;
-
 	unsigned long		dev_flags;
 	unsigned long		dev_flags;
 
 
+	struct delayed_work	le_scan_disable;
+
+	struct work_struct	le_scan;
+	struct le_scan_params	le_scan_params;
+
 	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);
 	int (*send)(struct sk_buff *skb);
 	int (*send)(struct sk_buff *skb);
-	void (*destruct)(struct hci_dev *hdev);
 	void (*notify)(struct hci_dev *hdev, unsigned int evt);
 	void (*notify)(struct hci_dev *hdev, unsigned int evt);
 	int (*ioctl)(struct hci_dev *hdev, unsigned int cmd, unsigned long arg);
 	int (*ioctl)(struct hci_dev *hdev, unsigned int cmd, unsigned long arg);
 };
 };
@@ -270,11 +294,10 @@ struct hci_conn {
 	__u16		state;
 	__u16		state;
 	__u8		mode;
 	__u8		mode;
 	__u8		type;
 	__u8		type;
-	__u8		out;
+	bool		out;
 	__u8		attempt;
 	__u8		attempt;
 	__u8		dev_class[3];
 	__u8		dev_class[3];
 	__u8		features[8];
 	__u8		features[8];
-	__u8		ssp_mode;
 	__u16		interval;
 	__u16		interval;
 	__u16		pkt_type;
 	__u16		pkt_type;
 	__u16		link_policy;
 	__u16		link_policy;
@@ -286,12 +309,10 @@ struct hci_conn {
 	__u8		pin_length;
 	__u8		pin_length;
 	__u8		enc_key_size;
 	__u8		enc_key_size;
 	__u8		io_capability;
 	__u8		io_capability;
-	__u8		power_save;
 	__u16		disc_timeout;
 	__u16		disc_timeout;
-	unsigned long	pend;
+	unsigned long	flags;
 
 
 	__u8		remote_cap;
 	__u8		remote_cap;
-	__u8		remote_oob;
 	__u8		remote_auth;
 	__u8		remote_auth;
 
 
 	unsigned int	sent;
 	unsigned int	sent;
@@ -348,21 +369,26 @@ extern int sco_recv_scodata(struct hci_conn *hcon, struct sk_buff *skb);
 #define INQUIRY_CACHE_AGE_MAX   (HZ*30)   /* 30 seconds */
 #define INQUIRY_CACHE_AGE_MAX   (HZ*30)   /* 30 seconds */
 #define INQUIRY_ENTRY_AGE_MAX   (HZ*60)   /* 60 seconds */
 #define INQUIRY_ENTRY_AGE_MAX   (HZ*60)   /* 60 seconds */
 
 
-static inline void inquiry_cache_init(struct hci_dev *hdev)
+static inline void discovery_init(struct hci_dev *hdev)
 {
 {
-	struct inquiry_cache *c = &hdev->inq_cache;
-	c->list = NULL;
+	hdev->discovery.state = DISCOVERY_STOPPED;
+	INIT_LIST_HEAD(&hdev->discovery.all);
+	INIT_LIST_HEAD(&hdev->discovery.unknown);
+	INIT_LIST_HEAD(&hdev->discovery.resolve);
 }
 }
 
 
+bool hci_discovery_active(struct hci_dev *hdev);
+
+void hci_discovery_set_state(struct hci_dev *hdev, int state);
+
 static inline int inquiry_cache_empty(struct hci_dev *hdev)
 static inline int inquiry_cache_empty(struct hci_dev *hdev)
 {
 {
-	struct inquiry_cache *c = &hdev->inq_cache;
-	return c->list == NULL;
+	return list_empty(&hdev->discovery.all);
 }
 }
 
 
 static inline long inquiry_cache_age(struct hci_dev *hdev)
 static inline long inquiry_cache_age(struct hci_dev *hdev)
 {
 {
-	struct inquiry_cache *c = &hdev->inq_cache;
+	struct discovery_state *c = &hdev->discovery;
 	return jiffies - c->timestamp;
 	return jiffies - c->timestamp;
 }
 }
 
 
@@ -372,8 +398,16 @@ static inline long inquiry_entry_age(struct inquiry_entry *e)
 }
 }
 
 
 struct inquiry_entry *hci_inquiry_cache_lookup(struct hci_dev *hdev,
 struct inquiry_entry *hci_inquiry_cache_lookup(struct hci_dev *hdev,
-							bdaddr_t *bdaddr);
-void hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_data *data);
+					       bdaddr_t *bdaddr);
+struct inquiry_entry *hci_inquiry_cache_lookup_unknown(struct hci_dev *hdev,
+						       bdaddr_t *bdaddr);
+struct inquiry_entry *hci_inquiry_cache_lookup_resolve(struct hci_dev *hdev,
+						       bdaddr_t *bdaddr,
+						       int state);
+void hci_inquiry_cache_update_resolve(struct hci_dev *hdev,
+				      struct inquiry_entry *ie);
+bool hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_data *data,
+			      bool name_known, bool *ssp);
 
 
 /* ----- HCI Connections ----- */
 /* ----- HCI Connections ----- */
 enum {
 enum {
@@ -384,8 +418,19 @@ enum {
 	HCI_CONN_MODE_CHANGE_PEND,
 	HCI_CONN_MODE_CHANGE_PEND,
 	HCI_CONN_SCO_SETUP_PEND,
 	HCI_CONN_SCO_SETUP_PEND,
 	HCI_CONN_LE_SMP_PEND,
 	HCI_CONN_LE_SMP_PEND,
+	HCI_CONN_MGMT_CONNECTED,
+	HCI_CONN_SSP_ENABLED,
+	HCI_CONN_POWER_SAVE,
+	HCI_CONN_REMOTE_OOB,
 };
 };
 
 
+static inline bool hci_conn_ssp_enabled(struct hci_conn *conn)
+{
+	struct hci_dev *hdev = conn->hdev;
+	return (test_bit(HCI_SSP_ENABLED, &hdev->flags) &&
+				test_bit(HCI_CONN_SSP_ENABLED, &conn->flags));
+}
+
 static inline void hci_conn_hash_init(struct hci_dev *hdev)
 static inline void hci_conn_hash_init(struct hci_dev *hdev)
 {
 {
 	struct hci_conn_hash *h = &hdev->conn_hash;
 	struct hci_conn_hash *h = &hdev->conn_hash;
@@ -566,36 +611,33 @@ static inline void hci_conn_put(struct hci_conn *conn)
 }
 }
 
 
 /* ----- HCI Devices ----- */
 /* ----- HCI Devices ----- */
-static inline void __hci_dev_put(struct hci_dev *d)
+static inline void hci_dev_put(struct hci_dev *d)
 {
 {
-	if (atomic_dec_and_test(&d->refcnt))
-		d->destruct(d);
+	put_device(&d->dev);
 }
 }
 
 
-/*
- * hci_dev_put and hci_dev_hold are macros to avoid dragging all the
- * overhead of all the modular infrastructure into this header.
- */
-#define hci_dev_put(d)		\
-do {				\
-	__hci_dev_put(d);	\
-	module_put(d->owner);	\
-} while (0)
-
-static inline struct hci_dev *__hci_dev_hold(struct hci_dev *d)
+static inline struct hci_dev *hci_dev_hold(struct hci_dev *d)
 {
 {
-	atomic_inc(&d->refcnt);
+	get_device(&d->dev);
 	return d;
 	return d;
 }
 }
 
 
-#define hci_dev_hold(d)						\
-({								\
-	try_module_get(d->owner) ? __hci_dev_hold(d) : NULL;	\
-})
-
 #define hci_dev_lock(d)		mutex_lock(&d->lock)
 #define hci_dev_lock(d)		mutex_lock(&d->lock)
 #define hci_dev_unlock(d)	mutex_unlock(&d->lock)
 #define hci_dev_unlock(d)	mutex_unlock(&d->lock)
 
 
+#define to_hci_dev(d) container_of(d, struct hci_dev, dev)
+#define to_hci_conn(c) container_of(c, struct hci_conn, dev)
+
+static inline void *hci_get_drvdata(struct hci_dev *hdev)
+{
+	return dev_get_drvdata(&hdev->dev);
+}
+
+static inline void hci_set_drvdata(struct hci_dev *hdev, void *data)
+{
+	dev_set_drvdata(&hdev->dev, data);
+}
+
 struct hci_dev *hci_dev_get(int index);
 struct hci_dev *hci_dev_get(int index);
 struct hci_dev *hci_get_route(bdaddr_t *src, bdaddr_t *dst);
 struct hci_dev *hci_get_route(bdaddr_t *src, bdaddr_t *dst);
 
 
@@ -619,20 +661,23 @@ int hci_inquiry(void __user *arg);
 
 
 struct bdaddr_list *hci_blacklist_lookup(struct hci_dev *hdev, bdaddr_t *bdaddr);
 struct bdaddr_list *hci_blacklist_lookup(struct hci_dev *hdev, bdaddr_t *bdaddr);
 int hci_blacklist_clear(struct hci_dev *hdev);
 int hci_blacklist_clear(struct hci_dev *hdev);
-int hci_blacklist_add(struct hci_dev *hdev, bdaddr_t *bdaddr);
-int hci_blacklist_del(struct hci_dev *hdev, bdaddr_t *bdaddr);
+int hci_blacklist_add(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type);
+int hci_blacklist_del(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type);
 
 
 int hci_uuids_clear(struct hci_dev *hdev);
 int hci_uuids_clear(struct hci_dev *hdev);
 
 
 int hci_link_keys_clear(struct hci_dev *hdev);
 int hci_link_keys_clear(struct hci_dev *hdev);
 struct link_key *hci_find_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr);
 struct link_key *hci_find_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr);
 int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key,
 int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key,
-			bdaddr_t *bdaddr, u8 *val, u8 type, u8 pin_len);
-struct link_key *hci_find_ltk(struct hci_dev *hdev, __le16 ediv, u8 rand[8]);
-struct link_key *hci_find_link_key_type(struct hci_dev *hdev,
-					bdaddr_t *bdaddr, u8 type);
-int hci_add_ltk(struct hci_dev *hdev, int new_key, bdaddr_t *bdaddr,
-			u8 key_size, __le16 ediv, u8 rand[8], u8 ltk[16]);
+		     bdaddr_t *bdaddr, u8 *val, u8 type, u8 pin_len);
+struct smp_ltk *hci_find_ltk(struct hci_dev *hdev, __le16 ediv, u8 rand[8]);
+int hci_add_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type, u8 type,
+		int new_key, u8 authenticated, u8 tk[16], u8 enc_size, u16 ediv,
+		u8 rand[8]);
+struct smp_ltk *hci_find_ltk_by_addr(struct hci_dev *hdev, bdaddr_t *bdaddr,
+				     u8 addr_type);
+int hci_remove_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr);
+int hci_smp_ltks_clear(struct hci_dev *hdev);
 int hci_remove_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr);
 int hci_remove_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr);
 
 
 int hci_remote_oob_data_clear(struct hci_dev *hdev);
 int hci_remote_oob_data_clear(struct hci_dev *hdev);
@@ -674,6 +719,7 @@ void hci_conn_del_sysfs(struct hci_conn *conn);
 #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)
 #define lmp_le_capable(dev)        ((dev)->features[4] & LMP_LE)
+#define lmp_bredr_capable(dev)     (!((dev)->features[4] & LMP_NO_BREDR))
 
 
 /* ----- Extended LMP capabilities ----- */
 /* ----- Extended LMP capabilities ----- */
 #define lmp_host_le_capable(dev)   ((dev)->host_features[0] & LMP_HOST_LE)
 #define lmp_host_le_capable(dev)   ((dev)->host_features[0] & LMP_HOST_LE)
@@ -755,7 +801,7 @@ static inline void hci_proto_auth_cfm(struct hci_conn *conn, __u8 status)
 	if (conn->type != ACL_LINK && conn->type != LE_LINK)
 	if (conn->type != ACL_LINK && conn->type != LE_LINK)
 		return;
 		return;
 
 
-	if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend))
+	if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags))
 		return;
 		return;
 
 
 	encrypt = (conn->link_mode & HCI_LM_ENCRYPT) ? 0x01 : 0x00;
 	encrypt = (conn->link_mode & HCI_LM_ENCRYPT) ? 0x01 : 0x00;
@@ -796,7 +842,7 @@ static inline void hci_auth_cfm(struct hci_conn *conn, __u8 status)
 
 
 	hci_proto_auth_cfm(conn, status);
 	hci_proto_auth_cfm(conn, status);
 
 
-	if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend))
+	if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags))
 		return;
 		return;
 
 
 	encrypt = (conn->link_mode & HCI_LM_ENCRYPT) ? 0x01 : 0x00;
 	encrypt = (conn->link_mode & HCI_LM_ENCRYPT) ? 0x01 : 0x00;
@@ -859,25 +905,71 @@ static inline void hci_role_switch_cfm(struct hci_conn *conn, __u8 status,
 	read_unlock(&hci_cb_list_lock);
 	read_unlock(&hci_cb_list_lock);
 }
 }
 
 
+static inline bool eir_has_data_type(u8 *data, size_t data_len, u8 type)
+{
+	u8 field_len;
+	size_t parsed;
+
+	for (parsed = 0; parsed < data_len - 1; parsed += field_len) {
+		field_len = data[0];
+
+		if (field_len == 0)
+			break;
+
+		parsed += field_len + 1;
+
+		if (parsed > data_len)
+			break;
+
+		if (data[1] == type)
+			return true;
+
+		data += field_len + 1;
+	}
+
+	return false;
+}
+
+static inline u16 eir_append_data(u8 *eir, u16 eir_len, u8 type, u8 *data,
+				  u8 data_len)
+{
+	eir[eir_len++] = sizeof(type) + data_len;
+	eir[eir_len++] = type;
+	memcpy(&eir[eir_len], data, data_len);
+	eir_len += data_len;
+
+	return eir_len;
+}
+
 int hci_register_cb(struct hci_cb *hcb);
 int hci_register_cb(struct hci_cb *hcb);
 int hci_unregister_cb(struct hci_cb *hcb);
 int hci_unregister_cb(struct hci_cb *hcb);
 
 
-int hci_register_notifier(struct notifier_block *nb);
-int hci_unregister_notifier(struct notifier_block *nb);
-
 int hci_send_cmd(struct hci_dev *hdev, __u16 opcode, __u32 plen, void *param);
 int hci_send_cmd(struct hci_dev *hdev, __u16 opcode, __u32 plen, void *param);
 void hci_send_acl(struct hci_chan *chan, struct sk_buff *skb, __u16 flags);
 void hci_send_acl(struct hci_chan *chan, struct sk_buff *skb, __u16 flags);
 void hci_send_sco(struct hci_conn *conn, struct sk_buff *skb);
 void hci_send_sco(struct hci_conn *conn, struct sk_buff *skb);
 
 
 void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 opcode);
 void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 opcode);
 
 
-void hci_si_event(struct hci_dev *hdev, int type, int dlen, void *data);
-
 /* ----- HCI Sockets ----- */
 /* ----- HCI Sockets ----- */
-void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb,
-							struct sock *skip_sk);
+void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb);
+void hci_send_to_control(struct sk_buff *skb, struct sock *skip_sk);
+void hci_send_to_monitor(struct hci_dev *hdev, struct sk_buff *skb);
+
+void hci_sock_dev_event(struct hci_dev *hdev, int event);
 
 
 /* Management interface */
 /* Management interface */
+#define MGMT_ADDR_BREDR			0x00
+#define MGMT_ADDR_LE_PUBLIC		0x01
+#define MGMT_ADDR_LE_RANDOM		0x02
+#define MGMT_ADDR_INVALID		0xff
+
+#define DISCOV_TYPE_BREDR		(BIT(MGMT_ADDR_BREDR))
+#define DISCOV_TYPE_LE			(BIT(MGMT_ADDR_LE_PUBLIC) | \
+						BIT(MGMT_ADDR_LE_RANDOM))
+#define DISCOV_TYPE_INTERLEAVED		(BIT(MGMT_ADDR_BREDR) | \
+						BIT(MGMT_ADDR_LE_PUBLIC) | \
+						BIT(MGMT_ADDR_LE_RANDOM))
+
 int mgmt_control(struct sock *sk, struct msghdr *msg, size_t len);
 int mgmt_control(struct sock *sk, struct msghdr *msg, size_t len);
 int mgmt_index_added(struct hci_dev *hdev);
 int mgmt_index_added(struct hci_dev *hdev);
 int mgmt_index_removed(struct hci_dev *hdev);
 int mgmt_index_removed(struct hci_dev *hdev);
@@ -886,56 +978,67 @@ int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable);
 int mgmt_connectable(struct hci_dev *hdev, u8 connectable);
 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);
-int mgmt_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
-								u8 addr_type);
-int mgmt_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
-								u8 addr_type);
-int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 status);
+		      u8 persistent);
+int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
+			  u8 addr_type, u32 flags, u8 *name, u8 name_len,
+			  u8 *dev_class);
+int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
+			     u8 link_type, u8 addr_type);
+int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
+			   u8 link_type, u8 addr_type, u8 status);
 int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
 int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
-						u8 addr_type, u8 status);
+			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);
 int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
 int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
-								u8 status);
+				     u8 status);
 int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
 int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
-						__le32 value, u8 confirm_hint);
+			      u8 link_type, u8 addr_type, __le32 value,
+			      u8 confirm_hint);
 int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
 int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
-								u8 status);
-int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev,
-						bdaddr_t *bdaddr, u8 status);
-int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr);
+				     u8 link_type, u8 addr_type, u8 status);
+int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
+					 u8 link_type, u8 addr_type, u8 status);
+int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
+			      u8 link_type, u8 addr_type);
 int mgmt_user_passkey_reply_complete(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);
+				     u8 link_type, u8 addr_type, u8 status);
+int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
+					 u8 link_type, u8 addr_type, u8 status);
+int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
+		     u8 addr_type, u8 status);
+int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status);
+int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status);
+int mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
+				   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_le_enable_complete(struct hci_dev *hdev, u8 enable, u8 status);
 int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
 int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
-				u8 addr_type, u8 *dev_class, s8 rssi, u8 *eir);
-int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *name);
+		      u8 addr_type, u8 *dev_class, s8 rssi, u8 cfm_name,
+		      u8 ssp, u8 *eir, u16 eir_len);
+int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
+		     u8 addr_type, s8 rssi, u8 *name, u8 name_len);
 int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status);
 int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status);
 int mgmt_stop_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_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr);
+int mgmt_interleaved_discovery(struct hci_dev *hdev);
+int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type);
+int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type);
+
+int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent);
 
 
 /* HCI info for socket */
 /* HCI info for socket */
 #define hci_pi(sk) ((struct hci_pinfo *) sk)
 #define hci_pi(sk) ((struct hci_pinfo *) sk)
 
 
-/* HCI socket flags */
-#define HCI_PI_MGMT_INIT	0
-
 struct hci_pinfo {
 struct hci_pinfo {
 	struct bt_sock    bt;
 	struct bt_sock    bt;
 	struct hci_dev    *hdev;
 	struct hci_dev    *hdev;
 	struct hci_filter filter;
 	struct hci_filter filter;
 	__u32             cmsg_mask;
 	__u32             cmsg_mask;
 	unsigned short   channel;
 	unsigned short   channel;
-	unsigned long     flags;
 };
 };
 
 
 /* HCI security filter */
 /* HCI security filter */
@@ -966,5 +1069,7 @@ void hci_le_ltk_neg_reply(struct hci_conn *conn);
 
 
 int hci_do_inquiry(struct hci_dev *hdev, u8 length);
 int hci_do_inquiry(struct hci_dev *hdev, u8 length);
 int hci_cancel_inquiry(struct hci_dev *hdev);
 int hci_cancel_inquiry(struct hci_dev *hdev);
+int hci_le_scan(struct hci_dev *hdev, u8 type, u16 interval, u16 window,
+		int timeout);
 
 
 #endif /* __HCI_CORE_H */
 #endif /* __HCI_CORE_H */

+ 51 - 0
include/net/bluetooth/hci_mon.h

@@ -0,0 +1,51 @@
+/*
+   BlueZ - Bluetooth protocol stack for Linux
+
+   Copyright (C) 2011-2012  Intel Corporation
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License version 2 as
+   published by the Free Software Foundation;
+
+   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
+   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
+   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
+   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
+   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
+   SOFTWARE IS DISCLAIMED.
+*/
+
+#ifndef __HCI_MON_H
+#define __HCI_MON_H
+
+struct hci_mon_hdr {
+	__le16	opcode;
+	__le16	index;
+	__le16	len;
+} __packed;
+#define HCI_MON_HDR_SIZE 6
+
+#define HCI_MON_NEW_INDEX	0
+#define HCI_MON_DEL_INDEX	1
+#define HCI_MON_COMMAND_PKT	2
+#define HCI_MON_EVENT_PKT	3
+#define HCI_MON_ACL_TX_PKT	4
+#define HCI_MON_ACL_RX_PKT	5
+#define HCI_MON_SCO_TX_PKT	6
+#define HCI_MON_SCO_RX_PKT	7
+
+struct hci_mon_new_index {
+	__u8		type;
+	__u8		bus;
+	bdaddr_t	bdaddr;
+	char		name[8];
+} __packed;
+#define HCI_MON_NEW_INDEX_SIZE 16
+
+#endif /* __HCI_MON_H */

+ 54 - 33
include/net/bluetooth/l2cap.h

@@ -45,11 +45,11 @@
 #define L2CAP_DEFAULT_SDU_ITIME		0xFFFFFFFF
 #define L2CAP_DEFAULT_SDU_ITIME		0xFFFFFFFF
 #define L2CAP_DEFAULT_ACC_LAT		0xFFFFFFFF
 #define L2CAP_DEFAULT_ACC_LAT		0xFFFFFFFF
 
 
-#define L2CAP_DISC_TIMEOUT             (100)
-#define L2CAP_DISC_REJ_TIMEOUT         (5000)  /*  5 seconds */
-#define L2CAP_ENC_TIMEOUT              (5000)  /*  5 seconds */
-#define L2CAP_CONN_TIMEOUT             (40000) /* 40 seconds */
-#define L2CAP_INFO_TIMEOUT             (4000)  /*  4 seconds */
+#define L2CAP_DISC_TIMEOUT		msecs_to_jiffies(100)
+#define L2CAP_DISC_REJ_TIMEOUT		msecs_to_jiffies(5000)
+#define L2CAP_ENC_TIMEOUT		msecs_to_jiffies(5000)
+#define L2CAP_CONN_TIMEOUT		msecs_to_jiffies(40000)
+#define L2CAP_INFO_TIMEOUT		msecs_to_jiffies(4000)
 
 
 /* L2CAP socket address */
 /* L2CAP socket address */
 struct sockaddr_l2 {
 struct sockaddr_l2 {
@@ -492,51 +492,56 @@ struct l2cap_chan {
 	struct sk_buff_head	srej_q;
 	struct sk_buff_head	srej_q;
 	struct list_head	srej_l;
 	struct list_head	srej_l;
 
 
-	struct list_head list;
-	struct list_head global_l;
+	struct list_head	list;
+	struct list_head	global_l;
 
 
-	void		*data;
-	struct l2cap_ops *ops;
+	void			*data;
+	struct l2cap_ops	*ops;
+	struct mutex		lock;
 };
 };
 
 
 struct l2cap_ops {
 struct l2cap_ops {
-	char		*name;
+	char			*name;
 
 
 	struct l2cap_chan	*(*new_connection) (void *data);
 	struct l2cap_chan	*(*new_connection) (void *data);
 	int			(*recv) (void *data, struct sk_buff *skb);
 	int			(*recv) (void *data, struct sk_buff *skb);
 	void			(*close) (void *data);
 	void			(*close) (void *data);
 	void			(*state_change) (void *data, int state);
 	void			(*state_change) (void *data, int state);
+	struct sk_buff		*(*alloc_skb) (struct l2cap_chan *chan,
+					unsigned long len, int nb, int *err);
+
 };
 };
 
 
 struct l2cap_conn {
 struct l2cap_conn {
-	struct hci_conn	*hcon;
-	struct hci_chan	*hchan;
+	struct hci_conn		*hcon;
+	struct hci_chan		*hchan;
 
 
-	bdaddr_t	*dst;
-	bdaddr_t	*src;
+	bdaddr_t		*dst;
+	bdaddr_t		*src;
 
 
-	unsigned int	mtu;
+	unsigned int		mtu;
 
 
-	__u32		feat_mask;
+	__u32			feat_mask;
+	__u8			fixed_chan_mask;
 
 
-	__u8		info_state;
-	__u8		info_ident;
+	__u8			info_state;
+	__u8			info_ident;
 
 
-	struct delayed_work info_timer;
+	struct delayed_work	info_timer;
 
 
-	spinlock_t	lock;
+	spinlock_t		lock;
 
 
-	struct sk_buff *rx_skb;
-	__u32		rx_len;
-	__u8		tx_ident;
+	struct sk_buff		*rx_skb;
+	__u32			rx_len;
+	__u8			tx_ident;
 
 
-	__u8		disc_reason;
+	__u8			disc_reason;
 
 
-	struct delayed_work  security_timer;
-	struct smp_chan *smp_chan;
+	struct delayed_work	security_timer;
+	struct smp_chan		*smp_chan;
 
 
-	struct list_head chan_l;
-	struct mutex	chan_lock;
+	struct list_head	chan_l;
+	struct mutex		chan_lock;
 };
 };
 
 
 #define L2CAP_INFO_CL_MTU_REQ_SENT	0x01
 #define L2CAP_INFO_CL_MTU_REQ_SENT	0x01
@@ -551,9 +556,9 @@ struct l2cap_conn {
 #define l2cap_pi(sk) ((struct l2cap_pinfo *) sk)
 #define l2cap_pi(sk) ((struct l2cap_pinfo *) sk)
 
 
 struct l2cap_pinfo {
 struct l2cap_pinfo {
-	struct bt_sock	bt;
+	struct bt_sock		bt;
 	struct l2cap_chan	*chan;
 	struct l2cap_chan	*chan;
-	struct sk_buff	*rx_busy_skb;
+	struct sk_buff		*rx_busy_skb;
 };
 };
 
 
 enum {
 enum {
@@ -606,21 +611,37 @@ static inline void l2cap_chan_put(struct l2cap_chan *c)
 		kfree(c);
 		kfree(c);
 }
 }
 
 
+static inline void l2cap_chan_lock(struct l2cap_chan *chan)
+{
+	mutex_lock(&chan->lock);
+}
+
+static inline void l2cap_chan_unlock(struct l2cap_chan *chan)
+{
+	mutex_unlock(&chan->lock);
+}
+
 static inline void l2cap_set_timer(struct l2cap_chan *chan,
 static inline void l2cap_set_timer(struct l2cap_chan *chan,
 					struct delayed_work *work, long timeout)
 					struct delayed_work *work, long timeout)
 {
 {
-	BT_DBG("chan %p state %d timeout %ld", chan, chan->state, timeout);
+	BT_DBG("chan %p state %s timeout %ld", chan,
+					state_to_string(chan->state), timeout);
 
 
 	if (!cancel_delayed_work(work))
 	if (!cancel_delayed_work(work))
 		l2cap_chan_hold(chan);
 		l2cap_chan_hold(chan);
 	schedule_delayed_work(work, timeout);
 	schedule_delayed_work(work, timeout);
 }
 }
 
 
-static inline void l2cap_clear_timer(struct l2cap_chan *chan,
+static inline bool l2cap_clear_timer(struct l2cap_chan *chan,
 					struct delayed_work *work)
 					struct delayed_work *work)
 {
 {
-	if (cancel_delayed_work(work))
+	bool ret;
+
+	ret = cancel_delayed_work(work);
+	if (ret)
 		l2cap_chan_put(chan);
 		l2cap_chan_put(chan);
+
+	return ret;
 }
 }
 
 
 #define __set_chan_timer(c, t) l2cap_set_timer(c, &c->chan_timer, (t))
 #define __set_chan_timer(c, t) l2cap_set_timer(c, &c->chan_timer, (t))

+ 205 - 133
include/net/bluetooth/mgmt.h

@@ -2,6 +2,7 @@
    BlueZ - Bluetooth protocol stack for Linux
    BlueZ - Bluetooth protocol stack for Linux
 
 
    Copyright (C) 2010  Nokia Corporation
    Copyright (C) 2010  Nokia Corporation
+   Copyright (C) 2011-2012  Intel Corporation
 
 
    This program is free software; you can redistribute it and/or modify
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License version 2 as
    it under the terms of the GNU General Public License version 2 as
@@ -39,29 +40,47 @@
 #define MGMT_STATUS_INVALID_PARAMS	0x0d
 #define MGMT_STATUS_INVALID_PARAMS	0x0d
 #define MGMT_STATUS_DISCONNECTED	0x0e
 #define MGMT_STATUS_DISCONNECTED	0x0e
 #define MGMT_STATUS_NOT_POWERED		0x0f
 #define MGMT_STATUS_NOT_POWERED		0x0f
+#define MGMT_STATUS_CANCELLED		0x10
+#define MGMT_STATUS_INVALID_INDEX	0x11
 
 
 struct mgmt_hdr {
 struct mgmt_hdr {
-	__le16 opcode;
-	__le16 index;
-	__le16 len;
+	__le16	opcode;
+	__le16	index;
+	__le16	len;
 } __packed;
 } __packed;
 
 
+struct mgmt_addr_info {
+	bdaddr_t	bdaddr;
+	__u8		type;
+} __packed;
+#define MGMT_ADDR_INFO_SIZE		7
+
 #define MGMT_OP_READ_VERSION		0x0001
 #define MGMT_OP_READ_VERSION		0x0001
+#define MGMT_READ_VERSION_SIZE		0
 struct mgmt_rp_read_version {
 struct mgmt_rp_read_version {
-	__u8 version;
-	__le16 revision;
+	__u8	version;
+	__le16	revision;
+} __packed;
+
+#define MGMT_OP_READ_COMMANDS		0x0002
+#define MGMT_READ_COMMANDS_SIZE		0
+struct mgmt_rp_read_commands {
+	__le16	num_commands;
+	__le16	num_events;
+	__le16	opcodes[0];
 } __packed;
 } __packed;
 
 
 #define MGMT_OP_READ_INDEX_LIST		0x0003
 #define MGMT_OP_READ_INDEX_LIST		0x0003
+#define MGMT_READ_INDEX_LIST_SIZE	0
 struct mgmt_rp_read_index_list {
 struct mgmt_rp_read_index_list {
-	__le16 num_controllers;
-	__le16 index[0];
+	__le16	num_controllers;
+	__le16	index[0];
 } __packed;
 } __packed;
 
 
 /* Reserve one extra byte for names in management messages so that they
 /* Reserve one extra byte for names in management messages so that they
  * are always guaranteed to be nul-terminated */
  * are always guaranteed to be nul-terminated */
 #define MGMT_MAX_NAME_LENGTH		(HCI_MAX_NAME_LENGTH + 1)
 #define MGMT_MAX_NAME_LENGTH		(HCI_MAX_NAME_LENGTH + 1)
-#define MGMT_MAX_SHORT_NAME_LENGTH	(10 + 1)
+#define MGMT_MAX_SHORT_NAME_LENGTH	(HCI_MAX_SHORT_NAME_LENGTH + 1)
 
 
 #define MGMT_SETTING_POWERED		0x00000001
 #define MGMT_SETTING_POWERED		0x00000001
 #define MGMT_SETTING_CONNECTABLE	0x00000002
 #define MGMT_SETTING_CONNECTABLE	0x00000002
@@ -75,28 +94,32 @@ struct mgmt_rp_read_index_list {
 #define MGMT_SETTING_LE			0x00000200
 #define MGMT_SETTING_LE			0x00000200
 
 
 #define MGMT_OP_READ_INFO		0x0004
 #define MGMT_OP_READ_INFO		0x0004
+#define MGMT_READ_INFO_SIZE		0
 struct mgmt_rp_read_info {
 struct mgmt_rp_read_info {
-	bdaddr_t bdaddr;
-	__u8 version;
-	__le16 manufacturer;
-	__le32 supported_settings;
-	__le32 current_settings;
-	__u8 dev_class[3];
-	__u8 name[MGMT_MAX_NAME_LENGTH];
-	__u8 short_name[MGMT_MAX_SHORT_NAME_LENGTH];
+	bdaddr_t	bdaddr;
+	__u8		version;
+	__le16		manufacturer;
+	__le32		supported_settings;
+	__le32		current_settings;
+	__u8		dev_class[3];
+	__u8		name[MGMT_MAX_NAME_LENGTH];
+	__u8		short_name[MGMT_MAX_SHORT_NAME_LENGTH];
 } __packed;
 } __packed;
 
 
 struct mgmt_mode {
 struct mgmt_mode {
 	__u8 val;
 	__u8 val;
 } __packed;
 } __packed;
 
 
+#define MGMT_SETTING_SIZE		1
+
 #define MGMT_OP_SET_POWERED		0x0005
 #define MGMT_OP_SET_POWERED		0x0005
 
 
 #define MGMT_OP_SET_DISCOVERABLE	0x0006
 #define MGMT_OP_SET_DISCOVERABLE	0x0006
 struct mgmt_cp_set_discoverable {
 struct mgmt_cp_set_discoverable {
-	__u8 val;
-	__u16 timeout;
+	__u8	val;
+	__u16	timeout;
 } __packed;
 } __packed;
+#define MGMT_SET_DISCOVERABLE_SIZE	3
 
 
 #define MGMT_OP_SET_CONNECTABLE		0x0007
 #define MGMT_OP_SET_CONNECTABLE		0x0007
 
 
@@ -111,73 +134,76 @@ struct mgmt_cp_set_discoverable {
 #define MGMT_OP_SET_HS			0x000C
 #define MGMT_OP_SET_HS			0x000C
 
 
 #define MGMT_OP_SET_LE			0x000D
 #define MGMT_OP_SET_LE			0x000D
-
 #define MGMT_OP_SET_DEV_CLASS		0x000E
 #define MGMT_OP_SET_DEV_CLASS		0x000E
 struct mgmt_cp_set_dev_class {
 struct mgmt_cp_set_dev_class {
-	__u8 major;
-	__u8 minor;
+	__u8	major;
+	__u8	minor;
 } __packed;
 } __packed;
+#define MGMT_SET_DEV_CLASS_SIZE		2
 
 
 #define MGMT_OP_SET_LOCAL_NAME		0x000F
 #define MGMT_OP_SET_LOCAL_NAME		0x000F
 struct mgmt_cp_set_local_name {
 struct mgmt_cp_set_local_name {
-	__u8 name[MGMT_MAX_NAME_LENGTH];
+	__u8	name[MGMT_MAX_NAME_LENGTH];
+	__u8	short_name[MGMT_MAX_SHORT_NAME_LENGTH];
 } __packed;
 } __packed;
+#define MGMT_SET_LOCAL_NAME_SIZE	260
 
 
 #define MGMT_OP_ADD_UUID		0x0010
 #define MGMT_OP_ADD_UUID		0x0010
 struct mgmt_cp_add_uuid {
 struct mgmt_cp_add_uuid {
-	__u8 uuid[16];
-	__u8 svc_hint;
+	__u8	uuid[16];
+	__u8	svc_hint;
 } __packed;
 } __packed;
+#define MGMT_ADD_UUID_SIZE		17
 
 
 #define MGMT_OP_REMOVE_UUID		0x0011
 #define MGMT_OP_REMOVE_UUID		0x0011
 struct mgmt_cp_remove_uuid {
 struct mgmt_cp_remove_uuid {
-	__u8 uuid[16];
+	__u8	uuid[16];
 } __packed;
 } __packed;
+#define MGMT_REMOVE_UUID_SIZE		16
 
 
 struct mgmt_link_key_info {
 struct mgmt_link_key_info {
-	bdaddr_t bdaddr;
-	u8 type;
-	u8 val[16];
-	u8 pin_len;
+	struct mgmt_addr_info addr;
+	__u8	type;
+	__u8	val[16];
+	__u8	pin_len;
 } __packed;
 } __packed;
 
 
 #define MGMT_OP_LOAD_LINK_KEYS		0x0012
 #define MGMT_OP_LOAD_LINK_KEYS		0x0012
 struct mgmt_cp_load_link_keys {
 struct mgmt_cp_load_link_keys {
-	__u8 debug_keys;
-	__le16 key_count;
-	struct mgmt_link_key_info keys[0];
+	__u8	debug_keys;
+	__le16	key_count;
+	struct	mgmt_link_key_info keys[0];
 } __packed;
 } __packed;
+#define MGMT_LOAD_LINK_KEYS_SIZE	3
 
 
-#define MGMT_OP_REMOVE_KEYS		0x0013
-struct mgmt_cp_remove_keys {
-	bdaddr_t bdaddr;
-	__u8 disconnect;
+struct mgmt_ltk_info {
+	struct mgmt_addr_info addr;
+	__u8	authenticated;
+	__u8	master;
+	__u8	enc_size;
+	__le16	ediv;
+	__u8	rand[8];
+	__u8	val[16];
 } __packed;
 } __packed;
-struct mgmt_rp_remove_keys {
-	bdaddr_t bdaddr;
-	__u8 status;
-};
+
+#define MGMT_OP_LOAD_LONG_TERM_KEYS	0x0013
+struct mgmt_cp_load_long_term_keys {
+	__le16	key_count;
+	struct	mgmt_ltk_info keys[0];
+} __packed;
+#define MGMT_LOAD_LONG_TERM_KEYS_SIZE	2
 
 
 #define MGMT_OP_DISCONNECT		0x0014
 #define MGMT_OP_DISCONNECT		0x0014
 struct mgmt_cp_disconnect {
 struct mgmt_cp_disconnect {
-	bdaddr_t bdaddr;
+	struct mgmt_addr_info addr;
 } __packed;
 } __packed;
+#define MGMT_DISCONNECT_SIZE		MGMT_ADDR_INFO_SIZE
 struct mgmt_rp_disconnect {
 struct mgmt_rp_disconnect {
-	bdaddr_t bdaddr;
-	__u8 status;
-} __packed;
-
-#define MGMT_ADDR_BREDR			0x00
-#define MGMT_ADDR_LE_PUBLIC		0x01
-#define MGMT_ADDR_LE_RANDOM		0x02
-#define MGMT_ADDR_INVALID		0xff
-
-struct mgmt_addr_info {
-	bdaddr_t bdaddr;
-	__u8 type;
+	struct mgmt_addr_info addr;
 } __packed;
 } __packed;
 
 
 #define MGMT_OP_GET_CONNECTIONS		0x0015
 #define MGMT_OP_GET_CONNECTIONS		0x0015
+#define MGMT_GET_CONNECTIONS_SIZE	0
 struct mgmt_rp_get_connections {
 struct mgmt_rp_get_connections {
 	__le16 conn_count;
 	__le16 conn_count;
 	struct mgmt_addr_info addr[0];
 	struct mgmt_addr_info addr[0];
@@ -185,124 +211,152 @@ struct mgmt_rp_get_connections {
 
 
 #define MGMT_OP_PIN_CODE_REPLY		0x0016
 #define MGMT_OP_PIN_CODE_REPLY		0x0016
 struct mgmt_cp_pin_code_reply {
 struct mgmt_cp_pin_code_reply {
-	bdaddr_t bdaddr;
-	__u8 pin_len;
-	__u8 pin_code[16];
+	struct mgmt_addr_info addr;
+	__u8	pin_len;
+	__u8	pin_code[16];
 } __packed;
 } __packed;
+#define MGMT_PIN_CODE_REPLY_SIZE	(MGMT_ADDR_INFO_SIZE + 17)
 struct mgmt_rp_pin_code_reply {
 struct mgmt_rp_pin_code_reply {
-	bdaddr_t bdaddr;
-	uint8_t status;
+	struct mgmt_addr_info addr;
 } __packed;
 } __packed;
 
 
 #define MGMT_OP_PIN_CODE_NEG_REPLY	0x0017
 #define MGMT_OP_PIN_CODE_NEG_REPLY	0x0017
 struct mgmt_cp_pin_code_neg_reply {
 struct mgmt_cp_pin_code_neg_reply {
-	bdaddr_t bdaddr;
+	struct mgmt_addr_info addr;
 } __packed;
 } __packed;
+#define MGMT_PIN_CODE_NEG_REPLY_SIZE	MGMT_ADDR_INFO_SIZE
 
 
 #define MGMT_OP_SET_IO_CAPABILITY	0x0018
 #define MGMT_OP_SET_IO_CAPABILITY	0x0018
 struct mgmt_cp_set_io_capability {
 struct mgmt_cp_set_io_capability {
-	__u8 io_capability;
+	__u8	io_capability;
 } __packed;
 } __packed;
+#define MGMT_SET_IO_CAPABILITY_SIZE	1
 
 
 #define MGMT_OP_PAIR_DEVICE		0x0019
 #define MGMT_OP_PAIR_DEVICE		0x0019
 struct mgmt_cp_pair_device {
 struct mgmt_cp_pair_device {
 	struct mgmt_addr_info addr;
 	struct mgmt_addr_info addr;
-	__u8 io_cap;
+	__u8	io_cap;
 } __packed;
 } __packed;
+#define MGMT_PAIR_DEVICE_SIZE		(MGMT_ADDR_INFO_SIZE + 1)
 struct mgmt_rp_pair_device {
 struct mgmt_rp_pair_device {
 	struct mgmt_addr_info addr;
 	struct mgmt_addr_info addr;
-	__u8 status;
 } __packed;
 } __packed;
 
 
-#define MGMT_OP_USER_CONFIRM_REPLY	0x001A
+#define MGMT_OP_CANCEL_PAIR_DEVICE	0x001A
+#define MGMT_CANCEL_PAIR_DEVICE_SIZE	MGMT_ADDR_INFO_SIZE
+
+#define MGMT_OP_UNPAIR_DEVICE		0x001B
+struct mgmt_cp_unpair_device {
+	struct mgmt_addr_info addr;
+	__u8 disconnect;
+} __packed;
+#define MGMT_UNPAIR_DEVICE_SIZE		(MGMT_ADDR_INFO_SIZE + 1)
+struct mgmt_rp_unpair_device {
+	struct mgmt_addr_info addr;
+};
+
+#define MGMT_OP_USER_CONFIRM_REPLY	0x001C
 struct mgmt_cp_user_confirm_reply {
 struct mgmt_cp_user_confirm_reply {
-	bdaddr_t bdaddr;
+	struct mgmt_addr_info addr;
 } __packed;
 } __packed;
+#define MGMT_USER_CONFIRM_REPLY_SIZE	MGMT_ADDR_INFO_SIZE
 struct mgmt_rp_user_confirm_reply {
 struct mgmt_rp_user_confirm_reply {
-	bdaddr_t bdaddr;
-	__u8 status;
+	struct mgmt_addr_info addr;
 } __packed;
 } __packed;
 
 
-#define MGMT_OP_USER_CONFIRM_NEG_REPLY	0x001B
+#define MGMT_OP_USER_CONFIRM_NEG_REPLY	0x001D
 struct mgmt_cp_user_confirm_neg_reply {
 struct mgmt_cp_user_confirm_neg_reply {
-	bdaddr_t bdaddr;
+	struct mgmt_addr_info addr;
 } __packed;
 } __packed;
+#define MGMT_USER_CONFIRM_NEG_REPLY_SIZE MGMT_ADDR_INFO_SIZE
 
 
-#define MGMT_OP_USER_PASSKEY_REPLY	0x001C
+#define MGMT_OP_USER_PASSKEY_REPLY	0x001E
 struct mgmt_cp_user_passkey_reply {
 struct mgmt_cp_user_passkey_reply {
-	bdaddr_t bdaddr;
-	__le32 passkey;
+	struct mgmt_addr_info addr;
+	__le32	passkey;
 } __packed;
 } __packed;
+#define MGMT_USER_PASSKEY_REPLY_SIZE	(MGMT_ADDR_INFO_SIZE + 4)
 struct mgmt_rp_user_passkey_reply {
 struct mgmt_rp_user_passkey_reply {
-	bdaddr_t bdaddr;
-	__u8 status;
+	struct mgmt_addr_info addr;
 } __packed;
 } __packed;
 
 
-#define MGMT_OP_USER_PASSKEY_NEG_REPLY	0x001D
+#define MGMT_OP_USER_PASSKEY_NEG_REPLY	0x001F
 struct mgmt_cp_user_passkey_neg_reply {
 struct mgmt_cp_user_passkey_neg_reply {
-	bdaddr_t bdaddr;
+	struct mgmt_addr_info addr;
 } __packed;
 } __packed;
+#define MGMT_USER_PASSKEY_NEG_REPLY_SIZE MGMT_ADDR_INFO_SIZE
 
 
-#define MGMT_OP_READ_LOCAL_OOB_DATA	0x001E
+#define MGMT_OP_READ_LOCAL_OOB_DATA	0x0020
+#define MGMT_READ_LOCAL_OOB_DATA_SIZE	0
 struct mgmt_rp_read_local_oob_data {
 struct mgmt_rp_read_local_oob_data {
-	__u8 hash[16];
-	__u8 randomizer[16];
+	__u8	hash[16];
+	__u8	randomizer[16];
 } __packed;
 } __packed;
 
 
-#define MGMT_OP_ADD_REMOTE_OOB_DATA	0x001F
+#define MGMT_OP_ADD_REMOTE_OOB_DATA	0x0021
 struct mgmt_cp_add_remote_oob_data {
 struct mgmt_cp_add_remote_oob_data {
-	bdaddr_t bdaddr;
-	__u8 hash[16];
-	__u8 randomizer[16];
+	struct mgmt_addr_info addr;
+	__u8	hash[16];
+	__u8	randomizer[16];
 } __packed;
 } __packed;
+#define MGMT_ADD_REMOTE_OOB_DATA_SIZE	(MGMT_ADDR_INFO_SIZE + 32)
 
 
-#define MGMT_OP_REMOVE_REMOTE_OOB_DATA	0x0020
+#define MGMT_OP_REMOVE_REMOTE_OOB_DATA	0x0022
 struct mgmt_cp_remove_remote_oob_data {
 struct mgmt_cp_remove_remote_oob_data {
-	bdaddr_t bdaddr;
+	struct mgmt_addr_info addr;
 } __packed;
 } __packed;
+#define MGMT_REMOVE_REMOTE_OOB_DATA_SIZE MGMT_ADDR_INFO_SIZE
 
 
-#define MGMT_OP_START_DISCOVERY		0x0021
+#define MGMT_OP_START_DISCOVERY		0x0023
 struct mgmt_cp_start_discovery {
 struct mgmt_cp_start_discovery {
 	__u8 type;
 	__u8 type;
 } __packed;
 } __packed;
+#define MGMT_START_DISCOVERY_SIZE	1
 
 
-#define MGMT_OP_STOP_DISCOVERY		0x0022
+#define MGMT_OP_STOP_DISCOVERY		0x0024
+struct mgmt_cp_stop_discovery {
+	__u8 type;
+} __packed;
+#define MGMT_STOP_DISCOVERY_SIZE	1
 
 
-#define MGMT_OP_CONFIRM_NAME		0x0023
+#define MGMT_OP_CONFIRM_NAME		0x0025
 struct mgmt_cp_confirm_name {
 struct mgmt_cp_confirm_name {
-	bdaddr_t bdaddr;
-	__u8 name_known;
+	struct mgmt_addr_info addr;
+	__u8	name_known;
 } __packed;
 } __packed;
+#define MGMT_CONFIRM_NAME_SIZE		(MGMT_ADDR_INFO_SIZE + 1)
 struct mgmt_rp_confirm_name {
 struct mgmt_rp_confirm_name {
-	bdaddr_t bdaddr;
-	__u8 status;
+	struct mgmt_addr_info addr;
 } __packed;
 } __packed;
 
 
-#define MGMT_OP_BLOCK_DEVICE		0x0024
+#define MGMT_OP_BLOCK_DEVICE		0x0026
 struct mgmt_cp_block_device {
 struct mgmt_cp_block_device {
-	bdaddr_t bdaddr;
+	struct mgmt_addr_info addr;
 } __packed;
 } __packed;
+#define MGMT_BLOCK_DEVICE_SIZE		MGMT_ADDR_INFO_SIZE
 
 
-#define MGMT_OP_UNBLOCK_DEVICE		0x0025
+#define MGMT_OP_UNBLOCK_DEVICE		0x0027
 struct mgmt_cp_unblock_device {
 struct mgmt_cp_unblock_device {
-	bdaddr_t bdaddr;
+	struct mgmt_addr_info addr;
 } __packed;
 } __packed;
+#define MGMT_UNBLOCK_DEVICE_SIZE	MGMT_ADDR_INFO_SIZE
 
 
 #define MGMT_EV_CMD_COMPLETE		0x0001
 #define MGMT_EV_CMD_COMPLETE		0x0001
 struct mgmt_ev_cmd_complete {
 struct mgmt_ev_cmd_complete {
-	__le16 opcode;
-	__u8 data[0];
+	__le16	opcode;
+	__u8	status;
+	__u8	data[0];
 } __packed;
 } __packed;
 
 
 #define MGMT_EV_CMD_STATUS		0x0002
 #define MGMT_EV_CMD_STATUS		0x0002
 struct mgmt_ev_cmd_status {
 struct mgmt_ev_cmd_status {
-	__u8 status;
-	__le16 opcode;
+	__le16	opcode;
+	__u8	status;
 } __packed;
 } __packed;
 
 
 #define MGMT_EV_CONTROLLER_ERROR	0x0003
 #define MGMT_EV_CONTROLLER_ERROR	0x0003
 struct mgmt_ev_controller_error {
 struct mgmt_ev_controller_error {
-	__u8 error_code;
+	__u8	error_code;
 } __packed;
 } __packed;
 
 
 #define MGMT_EV_INDEX_ADDED		0x0004
 #define MGMT_EV_INDEX_ADDED		0x0004
@@ -313,78 +367,96 @@ struct mgmt_ev_controller_error {
 
 
 #define MGMT_EV_CLASS_OF_DEV_CHANGED	0x0007
 #define MGMT_EV_CLASS_OF_DEV_CHANGED	0x0007
 struct mgmt_ev_class_of_dev_changed {
 struct mgmt_ev_class_of_dev_changed {
-	__u8 dev_class[3];
+	__u8	dev_class[3];
 };
 };
 
 
 #define MGMT_EV_LOCAL_NAME_CHANGED	0x0008
 #define MGMT_EV_LOCAL_NAME_CHANGED	0x0008
 struct mgmt_ev_local_name_changed {
 struct mgmt_ev_local_name_changed {
-	__u8 name[MGMT_MAX_NAME_LENGTH];
-	__u8 short_name[MGMT_MAX_SHORT_NAME_LENGTH];
+	__u8	name[MGMT_MAX_NAME_LENGTH];
+	__u8	short_name[MGMT_MAX_SHORT_NAME_LENGTH];
 } __packed;
 } __packed;
 
 
 #define MGMT_EV_NEW_LINK_KEY		0x0009
 #define MGMT_EV_NEW_LINK_KEY		0x0009
 struct mgmt_ev_new_link_key {
 struct mgmt_ev_new_link_key {
-	__u8 store_hint;
+	__u8	store_hint;
 	struct mgmt_link_key_info key;
 	struct mgmt_link_key_info key;
 } __packed;
 } __packed;
 
 
-#define MGMT_EV_CONNECTED		0x000A
+#define MGMT_EV_NEW_LONG_TERM_KEY	0x000A
+struct mgmt_ev_new_long_term_key {
+	__u8	store_hint;
+	struct mgmt_ltk_info key;
+} __packed;
 
 
-#define MGMT_EV_DISCONNECTED		0x000B
+#define MGMT_EV_DEVICE_CONNECTED	0x000B
+struct mgmt_ev_device_connected {
+	struct mgmt_addr_info addr;
+	__le32	flags;
+	__le16	eir_len;
+	__u8	eir[0];
+} __packed;
+
+#define MGMT_EV_DEVICE_DISCONNECTED	0x000C
 
 
-#define MGMT_EV_CONNECT_FAILED		0x000C
+#define MGMT_EV_CONNECT_FAILED		0x000D
 struct mgmt_ev_connect_failed {
 struct mgmt_ev_connect_failed {
 	struct mgmt_addr_info addr;
 	struct mgmt_addr_info addr;
-	__u8 status;
+	__u8	status;
 } __packed;
 } __packed;
 
 
-#define MGMT_EV_PIN_CODE_REQUEST	0x000D
+#define MGMT_EV_PIN_CODE_REQUEST	0x000E
 struct mgmt_ev_pin_code_request {
 struct mgmt_ev_pin_code_request {
-	bdaddr_t bdaddr;
-	__u8 secure;
+	struct mgmt_addr_info addr;
+	__u8	secure;
 } __packed;
 } __packed;
 
 
-#define MGMT_EV_USER_CONFIRM_REQUEST	0x000E
+#define MGMT_EV_USER_CONFIRM_REQUEST	0x000F
 struct mgmt_ev_user_confirm_request {
 struct mgmt_ev_user_confirm_request {
-	bdaddr_t bdaddr;
-	__u8 confirm_hint;
-	__le32 value;
+	struct mgmt_addr_info addr;
+	__u8	confirm_hint;
+	__le32	value;
 } __packed;
 } __packed;
 
 
-#define MGMT_EV_USER_PASSKEY_REQUEST	0x000F
+#define MGMT_EV_USER_PASSKEY_REQUEST	0x0010
 struct mgmt_ev_user_passkey_request {
 struct mgmt_ev_user_passkey_request {
-	bdaddr_t bdaddr;
+	struct mgmt_addr_info addr;
 } __packed;
 } __packed;
 
 
-#define MGMT_EV_AUTH_FAILED		0x0010
+#define MGMT_EV_AUTH_FAILED		0x0011
 struct mgmt_ev_auth_failed {
 struct mgmt_ev_auth_failed {
-	bdaddr_t bdaddr;
-	__u8 status;
+	struct mgmt_addr_info addr;
+	__u8	status;
 } __packed;
 } __packed;
 
 
-#define MGMT_EV_DEVICE_FOUND		0x0011
+#define MGMT_DEV_FOUND_CONFIRM_NAME    0x01
+#define MGMT_DEV_FOUND_LEGACY_PAIRING  0x02
+
+#define MGMT_EV_DEVICE_FOUND		0x0012
 struct mgmt_ev_device_found {
 struct mgmt_ev_device_found {
 	struct mgmt_addr_info addr;
 	struct mgmt_addr_info addr;
-	__u8 dev_class[3];
-	__s8 rssi;
-	__u8 confirm_name;
-	__u8 eir[HCI_MAX_EIR_LENGTH];
-} __packed;
-
-#define MGMT_EV_REMOTE_NAME		0x0012
-struct mgmt_ev_remote_name {
-	bdaddr_t bdaddr;
-	__u8 name[MGMT_MAX_NAME_LENGTH];
+	__s8	rssi;
+	__u8	flags[4];
+	__le16	eir_len;
+	__u8	eir[0];
 } __packed;
 } __packed;
 
 
 #define MGMT_EV_DISCOVERING		0x0013
 #define MGMT_EV_DISCOVERING		0x0013
+struct mgmt_ev_discovering {
+	__u8	type;
+	__u8	discovering;
+} __packed;
 
 
 #define MGMT_EV_DEVICE_BLOCKED		0x0014
 #define MGMT_EV_DEVICE_BLOCKED		0x0014
 struct mgmt_ev_device_blocked {
 struct mgmt_ev_device_blocked {
-	bdaddr_t bdaddr;
+	struct mgmt_addr_info addr;
 } __packed;
 } __packed;
 
 
 #define MGMT_EV_DEVICE_UNBLOCKED	0x0015
 #define MGMT_EV_DEVICE_UNBLOCKED	0x0015
 struct mgmt_ev_device_unblocked {
 struct mgmt_ev_device_unblocked {
-	bdaddr_t bdaddr;
+	struct mgmt_addr_info addr;
+} __packed;
+
+#define MGMT_EV_DEVICE_UNPAIRED		0x0016
+struct mgmt_ev_device_unpaired {
+	struct mgmt_addr_info addr;
 } __packed;
 } __packed;

+ 1 - 1
include/net/bluetooth/smp.h

@@ -127,7 +127,7 @@ struct smp_chan {
 	u8              rrnd[16]; /* SMP Pairing Random (remote) */
 	u8              rrnd[16]; /* SMP Pairing Random (remote) */
 	u8		pcnf[16]; /* SMP Pairing Confirm */
 	u8		pcnf[16]; /* SMP Pairing Confirm */
 	u8		tk[16]; /* SMP Temporary Key */
 	u8		tk[16]; /* SMP Temporary Key */
-	u8		smp_key_size;
+	u8		enc_key_size;
 	unsigned long	smp_flags;
 	unsigned long	smp_flags;
 	struct crypto_blkcipher	*tfm;
 	struct crypto_blkcipher	*tfm;
 	struct work_struct confirm;
 	struct work_struct confirm;

+ 0 - 1
net/bluetooth/Kconfig

@@ -29,7 +29,6 @@ menuconfig BT
 	     BNEP Module (Bluetooth Network Encapsulation Protocol)
 	     BNEP Module (Bluetooth Network Encapsulation Protocol)
 	     CMTP Module (CAPI Message Transport Protocol)
 	     CMTP Module (CAPI Message Transport Protocol)
 	     HIDP Module (Human Interface Device Protocol)
 	     HIDP Module (Human Interface Device Protocol)
-	     SMP Module (Security Manager Protocol)
 
 
 	  Say Y here to compile Bluetooth support into the kernel or say M to
 	  Say Y here to compile Bluetooth support into the kernel or say M to
 	  compile it as module (bluetooth).
 	  compile it as module (bluetooth).

+ 3 - 3
net/bluetooth/bnep/sock.c

@@ -143,10 +143,10 @@ static int bnep_sock_compat_ioctl(struct socket *sock, unsigned int cmd, unsigne
 {
 {
 	if (cmd == BNEPGETCONNLIST) {
 	if (cmd == BNEPGETCONNLIST) {
 		struct bnep_connlist_req cl;
 		struct bnep_connlist_req cl;
-		uint32_t uci;
+		u32 uci;
 		int err;
 		int err;
 
 
-		if (get_user(cl.cnum, (uint32_t __user *) arg) ||
+		if (get_user(cl.cnum, (u32 __user *) arg) ||
 				get_user(uci, (u32 __user *) (arg + 4)))
 				get_user(uci, (u32 __user *) (arg + 4)))
 			return -EFAULT;
 			return -EFAULT;
 
 
@@ -157,7 +157,7 @@ static int bnep_sock_compat_ioctl(struct socket *sock, unsigned int cmd, unsigne
 
 
 		err = bnep_get_connlist(&cl);
 		err = bnep_get_connlist(&cl);
 
 
-		if (!err && put_user(cl.cnum, (uint32_t __user *) arg))
+		if (!err && put_user(cl.cnum, (u32 __user *) arg))
 			err = -EFAULT;
 			err = -EFAULT;
 
 
 		return err;
 		return err;

+ 3 - 3
net/bluetooth/cmtp/sock.c

@@ -137,10 +137,10 @@ static int cmtp_sock_compat_ioctl(struct socket *sock, unsigned int cmd, unsigne
 {
 {
 	if (cmd == CMTPGETCONNLIST) {
 	if (cmd == CMTPGETCONNLIST) {
 		struct cmtp_connlist_req cl;
 		struct cmtp_connlist_req cl;
-		uint32_t uci;
+		u32 uci;
 		int err;
 		int err;
 
 
-		if (get_user(cl.cnum, (uint32_t __user *) arg) ||
+		if (get_user(cl.cnum, (u32 __user *) arg) ||
 				get_user(uci, (u32 __user *) (arg + 4)))
 				get_user(uci, (u32 __user *) (arg + 4)))
 			return -EFAULT;
 			return -EFAULT;
 
 
@@ -151,7 +151,7 @@ static int cmtp_sock_compat_ioctl(struct socket *sock, unsigned int cmd, unsigne
 
 
 		err = cmtp_get_connlist(&cl);
 		err = cmtp_get_connlist(&cl);
 
 
-		if (!err && put_user(cl.cnum, (uint32_t __user *) arg))
+		if (!err && put_user(cl.cnum, (u32 __user *) arg))
 			err = -EFAULT;
 			err = -EFAULT;
 
 
 		return err;
 		return err;

+ 33 - 40
net/bluetooth/hci_conn.c

@@ -35,7 +35,6 @@
 #include <linux/init.h>
 #include <linux/init.h>
 #include <linux/skbuff.h>
 #include <linux/skbuff.h>
 #include <linux/interrupt.h>
 #include <linux/interrupt.h>
-#include <linux/notifier.h>
 #include <net/sock.h>
 #include <net/sock.h>
 
 
 #include <asm/system.h>
 #include <asm/system.h>
@@ -51,7 +50,7 @@ static void hci_le_connect(struct hci_conn *conn)
 	struct hci_cp_le_create_conn cp;
 	struct hci_cp_le_create_conn cp;
 
 
 	conn->state = BT_CONNECT;
 	conn->state = BT_CONNECT;
-	conn->out = 1;
+	conn->out = true;
 	conn->link_mode |= HCI_LM_MASTER;
 	conn->link_mode |= HCI_LM_MASTER;
 	conn->sec_level = BT_SECURITY_LOW;
 	conn->sec_level = BT_SECURITY_LOW;
 
 
@@ -80,10 +79,10 @@ void hci_acl_connect(struct hci_conn *conn)
 	struct inquiry_entry *ie;
 	struct inquiry_entry *ie;
 	struct hci_cp_create_conn cp;
 	struct hci_cp_create_conn cp;
 
 
-	BT_DBG("%p", conn);
+	BT_DBG("hcon %p", conn);
 
 
 	conn->state = BT_CONNECT;
 	conn->state = BT_CONNECT;
-	conn->out = 1;
+	conn->out = true;
 
 
 	conn->link_mode = HCI_LM_MASTER;
 	conn->link_mode = HCI_LM_MASTER;
 
 
@@ -105,7 +104,8 @@ void hci_acl_connect(struct hci_conn *conn)
 		}
 		}
 
 
 		memcpy(conn->dev_class, ie->data.dev_class, 3);
 		memcpy(conn->dev_class, ie->data.dev_class, 3);
-		conn->ssp_mode = ie->data.ssp_mode;
+		if (ie->data.ssp_mode > 0)
+			set_bit(HCI_CONN_SSP_ENABLED, &conn->flags);
 	}
 	}
 
 
 	cp.pkt_type = cpu_to_le16(conn->pkt_type);
 	cp.pkt_type = cpu_to_le16(conn->pkt_type);
@@ -151,7 +151,7 @@ void hci_add_sco(struct hci_conn *conn, __u16 handle)
 	BT_DBG("%p", conn);
 	BT_DBG("%p", conn);
 
 
 	conn->state = BT_CONNECT;
 	conn->state = BT_CONNECT;
-	conn->out = 1;
+	conn->out = true;
 
 
 	conn->attempt++;
 	conn->attempt++;
 
 
@@ -169,7 +169,7 @@ void hci_setup_sync(struct hci_conn *conn, __u16 handle)
 	BT_DBG("%p", conn);
 	BT_DBG("%p", conn);
 
 
 	conn->state = BT_CONNECT;
 	conn->state = BT_CONNECT;
-	conn->out = 1;
+	conn->out = true;
 
 
 	conn->attempt++;
 	conn->attempt++;
 
 
@@ -279,16 +279,13 @@ static void hci_conn_timeout(struct work_struct *work)
 {
 {
 	struct hci_conn *conn = container_of(work, struct hci_conn,
 	struct hci_conn *conn = container_of(work, struct hci_conn,
 							disc_work.work);
 							disc_work.work);
-	struct hci_dev *hdev = conn->hdev;
 	__u8 reason;
 	__u8 reason;
 
 
-	BT_DBG("conn %p state %d", conn, conn->state);
+	BT_DBG("conn %p state %s", conn, state_to_string(conn->state));
 
 
 	if (atomic_read(&conn->refcnt))
 	if (atomic_read(&conn->refcnt))
 		return;
 		return;
 
 
-	hci_dev_lock(hdev);
-
 	switch (conn->state) {
 	switch (conn->state) {
 	case BT_CONNECT:
 	case BT_CONNECT:
 	case BT_CONNECT2:
 	case BT_CONNECT2:
@@ -308,8 +305,6 @@ static void hci_conn_timeout(struct work_struct *work)
 		conn->state = BT_CLOSED;
 		conn->state = BT_CLOSED;
 		break;
 		break;
 	}
 	}
-
-	hci_dev_unlock(hdev);
 }
 }
 
 
 /* Enter sniff mode */
 /* Enter sniff mode */
@@ -337,7 +332,7 @@ static void hci_conn_enter_sniff_mode(struct hci_conn *conn)
 		hci_send_cmd(hdev, HCI_OP_SNIFF_SUBRATE, sizeof(cp), &cp);
 		hci_send_cmd(hdev, HCI_OP_SNIFF_SUBRATE, sizeof(cp), &cp);
 	}
 	}
 
 
-	if (!test_and_set_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->pend)) {
+	if (!test_and_set_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->flags)) {
 		struct hci_cp_sniff_mode cp;
 		struct hci_cp_sniff_mode cp;
 		cp.handle       = cpu_to_le16(conn->handle);
 		cp.handle       = cpu_to_le16(conn->handle);
 		cp.max_interval = cpu_to_le16(hdev->sniff_max_interval);
 		cp.max_interval = cpu_to_le16(hdev->sniff_max_interval);
@@ -372,7 +367,7 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst)
 
 
 	BT_DBG("%s dst %s", hdev->name, batostr(dst));
 	BT_DBG("%s dst %s", hdev->name, batostr(dst));
 
 
-	conn = kzalloc(sizeof(struct hci_conn), GFP_ATOMIC);
+	conn = kzalloc(sizeof(struct hci_conn), GFP_KERNEL);
 	if (!conn)
 	if (!conn)
 		return NULL;
 		return NULL;
 
 
@@ -386,7 +381,7 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst)
 	conn->remote_auth = 0xff;
 	conn->remote_auth = 0xff;
 	conn->key_type = 0xff;
 	conn->key_type = 0xff;
 
 
-	conn->power_save = 1;
+	set_bit(HCI_CONN_POWER_SAVE, &conn->flags);
 	conn->disc_timeout = HCI_DISCONN_TIMEOUT;
 	conn->disc_timeout = HCI_DISCONN_TIMEOUT;
 
 
 	switch (type) {
 	switch (type) {
@@ -407,7 +402,7 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst)
 
 
 	skb_queue_head_init(&conn->data_q);
 	skb_queue_head_init(&conn->data_q);
 
 
-	INIT_LIST_HEAD(&conn->chan_list);;
+	INIT_LIST_HEAD(&conn->chan_list);
 
 
 	INIT_DELAYED_WORK(&conn->disc_work, hci_conn_timeout);
 	INIT_DELAYED_WORK(&conn->disc_work, hci_conn_timeout);
 	setup_timer(&conn->idle_timer, hci_conn_idle, (unsigned long)conn);
 	setup_timer(&conn->idle_timer, hci_conn_idle, (unsigned long)conn);
@@ -555,7 +550,7 @@ struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8
 	if (!acl) {
 	if (!acl) {
 		acl = hci_conn_add(hdev, ACL_LINK, dst);
 		acl = hci_conn_add(hdev, ACL_LINK, dst);
 		if (!acl)
 		if (!acl)
-			return NULL;
+			return ERR_PTR(-ENOMEM);
 	}
 	}
 
 
 	hci_conn_hold(acl);
 	hci_conn_hold(acl);
@@ -575,7 +570,7 @@ struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8
 		sco = hci_conn_add(hdev, type, dst);
 		sco = hci_conn_add(hdev, type, dst);
 		if (!sco) {
 		if (!sco) {
 			hci_conn_put(acl);
 			hci_conn_put(acl);
-			return NULL;
+			return ERR_PTR(-ENOMEM);
 		}
 		}
 	}
 	}
 
 
@@ -586,12 +581,12 @@ struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8
 
 
 	if (acl->state == BT_CONNECTED &&
 	if (acl->state == BT_CONNECTED &&
 			(sco->state == BT_OPEN || sco->state == BT_CLOSED)) {
 			(sco->state == BT_OPEN || sco->state == BT_CLOSED)) {
-		acl->power_save = 1;
+		set_bit(HCI_CONN_POWER_SAVE, &acl->flags);
 		hci_conn_enter_active_mode(acl, BT_POWER_FORCE_ACTIVE_ON);
 		hci_conn_enter_active_mode(acl, BT_POWER_FORCE_ACTIVE_ON);
 
 
-		if (test_bit(HCI_CONN_MODE_CHANGE_PEND, &acl->pend)) {
+		if (test_bit(HCI_CONN_MODE_CHANGE_PEND, &acl->flags)) {
 			/* defer SCO setup until mode change completed */
 			/* defer SCO setup until mode change completed */
-			set_bit(HCI_CONN_SCO_SETUP_PEND, &acl->pend);
+			set_bit(HCI_CONN_SCO_SETUP_PEND, &acl->flags);
 			return sco;
 			return sco;
 		}
 		}
 
 
@@ -607,8 +602,7 @@ int hci_conn_check_link_mode(struct hci_conn *conn)
 {
 {
 	BT_DBG("conn %p", conn);
 	BT_DBG("conn %p", conn);
 
 
-	if (conn->ssp_mode > 0 && conn->hdev->ssp_mode > 0 &&
-					!(conn->link_mode & HCI_LM_ENCRYPT))
+	if (hci_conn_ssp_enabled(conn) && !(conn->link_mode & HCI_LM_ENCRYPT))
 		return 0;
 		return 0;
 
 
 	return 1;
 	return 1;
@@ -633,17 +627,17 @@ static int hci_conn_auth(struct hci_conn *conn, __u8 sec_level, __u8 auth_type)
 
 
 	conn->auth_type = auth_type;
 	conn->auth_type = auth_type;
 
 
-	if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->pend)) {
+	if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->flags)) {
 		struct hci_cp_auth_requested cp;
 		struct hci_cp_auth_requested cp;
 
 
 		/* encrypt must be pending if auth is also pending */
 		/* encrypt must be pending if auth is also pending */
-		set_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend);
+		set_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags);
 
 
 		cp.handle = cpu_to_le16(conn->handle);
 		cp.handle = cpu_to_le16(conn->handle);
 		hci_send_cmd(conn->hdev, HCI_OP_AUTH_REQUESTED,
 		hci_send_cmd(conn->hdev, HCI_OP_AUTH_REQUESTED,
 							sizeof(cp), &cp);
 							sizeof(cp), &cp);
 		if (conn->key_type != 0xff)
 		if (conn->key_type != 0xff)
-			set_bit(HCI_CONN_REAUTH_PEND, &conn->pend);
+			set_bit(HCI_CONN_REAUTH_PEND, &conn->flags);
 	}
 	}
 
 
 	return 0;
 	return 0;
@@ -654,7 +648,7 @@ static void hci_conn_encrypt(struct hci_conn *conn)
 {
 {
 	BT_DBG("conn %p", conn);
 	BT_DBG("conn %p", conn);
 
 
-	if (!test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend)) {
+	if (!test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags)) {
 		struct hci_cp_set_conn_encrypt cp;
 		struct hci_cp_set_conn_encrypt cp;
 		cp.handle  = cpu_to_le16(conn->handle);
 		cp.handle  = cpu_to_le16(conn->handle);
 		cp.encrypt = 0x01;
 		cp.encrypt = 0x01;
@@ -674,8 +668,7 @@ int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type)
 
 
 	/* For non 2.1 devices and low security level we don't need the link
 	/* For non 2.1 devices and low security level we don't need the link
 	   key. */
 	   key. */
-	if (sec_level == BT_SECURITY_LOW &&
-				(!conn->ssp_mode || !conn->hdev->ssp_mode))
+	if (sec_level == BT_SECURITY_LOW && !hci_conn_ssp_enabled(conn))
 		return 1;
 		return 1;
 
 
 	/* For other security levels we need the link key. */
 	/* For other security levels we need the link key. */
@@ -704,7 +697,7 @@ int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type)
 		goto encrypt;
 		goto encrypt;
 
 
 auth:
 auth:
-	if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend))
+	if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags))
 		return 0;
 		return 0;
 
 
 	if (!hci_conn_auth(conn, sec_level, auth_type))
 	if (!hci_conn_auth(conn, sec_level, auth_type))
@@ -739,7 +732,7 @@ int hci_conn_change_link_key(struct hci_conn *conn)
 {
 {
 	BT_DBG("conn %p", conn);
 	BT_DBG("conn %p", conn);
 
 
-	if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->pend)) {
+	if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->flags)) {
 		struct hci_cp_change_conn_link_key cp;
 		struct hci_cp_change_conn_link_key cp;
 		cp.handle = cpu_to_le16(conn->handle);
 		cp.handle = cpu_to_le16(conn->handle);
 		hci_send_cmd(conn->hdev, HCI_OP_CHANGE_CONN_LINK_KEY,
 		hci_send_cmd(conn->hdev, HCI_OP_CHANGE_CONN_LINK_KEY,
@@ -758,7 +751,7 @@ int hci_conn_switch_role(struct hci_conn *conn, __u8 role)
 	if (!role && conn->link_mode & HCI_LM_MASTER)
 	if (!role && conn->link_mode & HCI_LM_MASTER)
 		return 1;
 		return 1;
 
 
-	if (!test_and_set_bit(HCI_CONN_RSWITCH_PEND, &conn->pend)) {
+	if (!test_and_set_bit(HCI_CONN_RSWITCH_PEND, &conn->flags)) {
 		struct hci_cp_switch_role cp;
 		struct hci_cp_switch_role cp;
 		bacpy(&cp.bdaddr, &conn->dst);
 		bacpy(&cp.bdaddr, &conn->dst);
 		cp.role = role;
 		cp.role = role;
@@ -782,10 +775,10 @@ void hci_conn_enter_active_mode(struct hci_conn *conn, __u8 force_active)
 	if (conn->mode != HCI_CM_SNIFF)
 	if (conn->mode != HCI_CM_SNIFF)
 		goto timer;
 		goto timer;
 
 
-	if (!conn->power_save && !force_active)
+	if (!test_bit(HCI_CONN_POWER_SAVE, &conn->flags) && !force_active)
 		goto timer;
 		goto timer;
 
 
-	if (!test_and_set_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->pend)) {
+	if (!test_and_set_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->flags)) {
 		struct hci_cp_exit_sniff_mode cp;
 		struct hci_cp_exit_sniff_mode cp;
 		cp.handle = cpu_to_le16(conn->handle);
 		cp.handle = cpu_to_le16(conn->handle);
 		hci_send_cmd(hdev, HCI_OP_EXIT_SNIFF_MODE, sizeof(cp), &cp);
 		hci_send_cmd(hdev, HCI_OP_EXIT_SNIFF_MODE, sizeof(cp), &cp);
@@ -801,11 +794,11 @@ timer:
 void hci_conn_hash_flush(struct hci_dev *hdev)
 void hci_conn_hash_flush(struct hci_dev *hdev)
 {
 {
 	struct hci_conn_hash *h = &hdev->conn_hash;
 	struct hci_conn_hash *h = &hdev->conn_hash;
-	struct hci_conn *c;
+	struct hci_conn *c, *n;
 
 
 	BT_DBG("hdev %s", hdev->name);
 	BT_DBG("hdev %s", hdev->name);
 
 
-	list_for_each_entry_rcu(c, &h->list, list) {
+	list_for_each_entry_safe(c, n, &h->list, list) {
 		c->state = BT_CLOSED;
 		c->state = BT_CLOSED;
 
 
 		hci_proto_disconn_cfm(c, HCI_ERROR_LOCAL_HOST_TERM);
 		hci_proto_disconn_cfm(c, HCI_ERROR_LOCAL_HOST_TERM);
@@ -950,7 +943,7 @@ struct hci_chan *hci_chan_create(struct hci_conn *conn)
 
 
 	BT_DBG("%s conn %p", hdev->name, conn);
 	BT_DBG("%s conn %p", hdev->name, conn);
 
 
-	chan = kzalloc(sizeof(struct hci_chan), GFP_ATOMIC);
+	chan = kzalloc(sizeof(struct hci_chan), GFP_KERNEL);
 	if (!chan)
 	if (!chan)
 		return NULL;
 		return NULL;
 
 
@@ -981,10 +974,10 @@ int hci_chan_del(struct hci_chan *chan)
 
 
 void hci_chan_list_flush(struct hci_conn *conn)
 void hci_chan_list_flush(struct hci_conn *conn)
 {
 {
-	struct hci_chan *chan;
+	struct hci_chan *chan, *n;
 
 
 	BT_DBG("conn %p", conn);
 	BT_DBG("conn %p", conn);
 
 
-	list_for_each_entry_rcu(chan, &conn->chan_list, list)
+	list_for_each_entry_safe(chan, n, &conn->chan_list, list)
 		hci_chan_del(chan);
 		hci_chan_del(chan);
 }
 }

+ 497 - 148
net/bluetooth/hci_core.c

@@ -40,7 +40,6 @@
 #include <linux/skbuff.h>
 #include <linux/skbuff.h>
 #include <linux/workqueue.h>
 #include <linux/workqueue.h>
 #include <linux/interrupt.h>
 #include <linux/interrupt.h>
-#include <linux/notifier.h>
 #include <linux/rfkill.h>
 #include <linux/rfkill.h>
 #include <linux/timer.h>
 #include <linux/timer.h>
 #include <linux/crypto.h>
 #include <linux/crypto.h>
@@ -55,8 +54,6 @@
 
 
 #define AUTO_OFF_TIMEOUT 2000
 #define AUTO_OFF_TIMEOUT 2000
 
 
-bool enable_hs;
-
 static void hci_rx_work(struct work_struct *work);
 static void hci_rx_work(struct work_struct *work);
 static void hci_cmd_work(struct work_struct *work);
 static void hci_cmd_work(struct work_struct *work);
 static void hci_tx_work(struct work_struct *work);
 static void hci_tx_work(struct work_struct *work);
@@ -69,24 +66,11 @@ DEFINE_RWLOCK(hci_dev_list_lock);
 LIST_HEAD(hci_cb_list);
 LIST_HEAD(hci_cb_list);
 DEFINE_RWLOCK(hci_cb_list_lock);
 DEFINE_RWLOCK(hci_cb_list_lock);
 
 
-/* HCI notifiers list */
-static ATOMIC_NOTIFIER_HEAD(hci_notifier);
-
 /* ---- HCI notifications ---- */
 /* ---- HCI notifications ---- */
 
 
-int hci_register_notifier(struct notifier_block *nb)
-{
-	return atomic_notifier_chain_register(&hci_notifier, nb);
-}
-
-int hci_unregister_notifier(struct notifier_block *nb)
-{
-	return atomic_notifier_chain_unregister(&hci_notifier, nb);
-}
-
 static void hci_notify(struct hci_dev *hdev, int event)
 static void hci_notify(struct hci_dev *hdev, int event)
 {
 {
-	atomic_notifier_call_chain(&hci_notifier, event, hdev);
+	hci_sock_dev_event(hdev, event);
 }
 }
 
 
 /* ---- HCI requests ---- */
 /* ---- HCI requests ---- */
@@ -98,8 +82,28 @@ void hci_req_complete(struct hci_dev *hdev, __u16 cmd, int result)
 	/* If this is the init phase check if the completed command matches
 	/* If this is the init phase check if the completed command matches
 	 * the last init command, and if not just return.
 	 * the last init command, and if not just return.
 	 */
 	 */
-	if (test_bit(HCI_INIT, &hdev->flags) && hdev->init_last_cmd != cmd)
+	if (test_bit(HCI_INIT, &hdev->flags) && hdev->init_last_cmd != cmd) {
+		struct hci_command_hdr *sent = (void *) hdev->sent_cmd->data;
+		struct sk_buff *skb;
+
+		/* Some CSR based controllers generate a spontaneous
+		 * reset complete event during init and any pending
+		 * command will never be completed. In such a case we
+		 * need to resend whatever was the last sent
+		 * command.
+		 */
+
+		if (cmd != HCI_OP_RESET || sent->opcode == HCI_OP_RESET)
+			return;
+
+		skb = skb_clone(hdev->sent_cmd, GFP_ATOMIC);
+		if (skb) {
+			skb_queue_head(&hdev->cmd_q, skb);
+			queue_work(hdev->workqueue, &hdev->cmd_work);
+		}
+
 		return;
 		return;
+	}
 
 
 	if (hdev->req_status == HCI_REQ_PEND) {
 	if (hdev->req_status == HCI_REQ_PEND) {
 		hdev->req_result = result;
 		hdev->req_result = result;
@@ -355,72 +359,209 @@ struct hci_dev *hci_dev_get(int index)
 }
 }
 
 
 /* ---- Inquiry support ---- */
 /* ---- Inquiry support ---- */
-static void inquiry_cache_flush(struct hci_dev *hdev)
+
+bool hci_discovery_active(struct hci_dev *hdev)
 {
 {
-	struct inquiry_cache *cache = &hdev->inq_cache;
-	struct inquiry_entry *next  = cache->list, *e;
+	struct discovery_state *discov = &hdev->discovery;
+
+	switch (discov->state) {
+	case DISCOVERY_FINDING:
+	case DISCOVERY_RESOLVING:
+		return true;
+
+	default:
+		return false;
+	}
+}
+
+void hci_discovery_set_state(struct hci_dev *hdev, int state)
+{
+	BT_DBG("%s state %u -> %u", hdev->name, hdev->discovery.state, state);
+
+	if (hdev->discovery.state == state)
+		return;
+
+	switch (state) {
+	case DISCOVERY_STOPPED:
+		if (hdev->discovery.state != DISCOVERY_STARTING)
+			mgmt_discovering(hdev, 0);
+		hdev->discovery.type = 0;
+		break;
+	case DISCOVERY_STARTING:
+		break;
+	case DISCOVERY_FINDING:
+		mgmt_discovering(hdev, 1);
+		break;
+	case DISCOVERY_RESOLVING:
+		break;
+	case DISCOVERY_STOPPING:
+		break;
+	}
+
+	hdev->discovery.state = state;
+}
 
 
-	BT_DBG("cache %p", cache);
+static void inquiry_cache_flush(struct hci_dev *hdev)
+{
+	struct discovery_state *cache = &hdev->discovery;
+	struct inquiry_entry *p, *n;
 
 
-	cache->list = NULL;
-	while ((e = next)) {
-		next = e->next;
-		kfree(e);
+	list_for_each_entry_safe(p, n, &cache->all, all) {
+		list_del(&p->all);
+		kfree(p);
 	}
 	}
+
+	INIT_LIST_HEAD(&cache->unknown);
+	INIT_LIST_HEAD(&cache->resolve);
 }
 }
 
 
 struct inquiry_entry *hci_inquiry_cache_lookup(struct hci_dev *hdev, bdaddr_t *bdaddr)
 struct inquiry_entry *hci_inquiry_cache_lookup(struct hci_dev *hdev, bdaddr_t *bdaddr)
 {
 {
-	struct inquiry_cache *cache = &hdev->inq_cache;
+	struct discovery_state *cache = &hdev->discovery;
 	struct inquiry_entry *e;
 	struct inquiry_entry *e;
 
 
 	BT_DBG("cache %p, %s", cache, batostr(bdaddr));
 	BT_DBG("cache %p, %s", cache, batostr(bdaddr));
 
 
-	for (e = cache->list; e; e = e->next)
+	list_for_each_entry(e, &cache->all, all) {
+		if (!bacmp(&e->data.bdaddr, bdaddr))
+			return e;
+	}
+
+	return NULL;
+}
+
+struct inquiry_entry *hci_inquiry_cache_lookup_unknown(struct hci_dev *hdev,
+						       bdaddr_t *bdaddr)
+{
+	struct discovery_state *cache = &hdev->discovery;
+	struct inquiry_entry *e;
+
+	BT_DBG("cache %p, %s", cache, batostr(bdaddr));
+
+	list_for_each_entry(e, &cache->unknown, list) {
+		if (!bacmp(&e->data.bdaddr, bdaddr))
+			return e;
+	}
+
+	return NULL;
+}
+
+struct inquiry_entry *hci_inquiry_cache_lookup_resolve(struct hci_dev *hdev,
+						       bdaddr_t *bdaddr,
+						       int state)
+{
+	struct discovery_state *cache = &hdev->discovery;
+	struct inquiry_entry *e;
+
+	BT_DBG("cache %p bdaddr %s state %d", cache, batostr(bdaddr), state);
+
+	list_for_each_entry(e, &cache->resolve, list) {
+		if (!bacmp(bdaddr, BDADDR_ANY) && e->name_state == state)
+			return e;
 		if (!bacmp(&e->data.bdaddr, bdaddr))
 		if (!bacmp(&e->data.bdaddr, bdaddr))
+			return e;
+	}
+
+	return NULL;
+}
+
+void hci_inquiry_cache_update_resolve(struct hci_dev *hdev,
+				      struct inquiry_entry *ie)
+{
+	struct discovery_state *cache = &hdev->discovery;
+	struct list_head *pos = &cache->resolve;
+	struct inquiry_entry *p;
+
+	list_del(&ie->list);
+
+	list_for_each_entry(p, &cache->resolve, list) {
+		if (p->name_state != NAME_PENDING &&
+				abs(p->data.rssi) >= abs(ie->data.rssi))
 			break;
 			break;
-	return e;
+		pos = &p->list;
+	}
+
+	list_add(&ie->list, pos);
 }
 }
 
 
-void hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_data *data)
+bool hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_data *data,
+			      bool name_known, bool *ssp)
 {
 {
-	struct inquiry_cache *cache = &hdev->inq_cache;
+	struct discovery_state *cache = &hdev->discovery;
 	struct inquiry_entry *ie;
 	struct inquiry_entry *ie;
 
 
 	BT_DBG("cache %p, %s", cache, batostr(&data->bdaddr));
 	BT_DBG("cache %p, %s", cache, batostr(&data->bdaddr));
 
 
+	if (ssp)
+		*ssp = data->ssp_mode;
+
 	ie = hci_inquiry_cache_lookup(hdev, &data->bdaddr);
 	ie = hci_inquiry_cache_lookup(hdev, &data->bdaddr);
-	if (!ie) {
-		/* Entry not in the cache. Add new one. */
-		ie = kzalloc(sizeof(struct inquiry_entry), GFP_ATOMIC);
-		if (!ie)
-			return;
+	if (ie) {
+		if (ie->data.ssp_mode && ssp)
+			*ssp = true;
+
+		if (ie->name_state == NAME_NEEDED &&
+						data->rssi != ie->data.rssi) {
+			ie->data.rssi = data->rssi;
+			hci_inquiry_cache_update_resolve(hdev, ie);
+		}
 
 
-		ie->next = cache->list;
-		cache->list = ie;
+		goto update;
+	}
+
+	/* Entry not in the cache. Add new one. */
+	ie = kzalloc(sizeof(struct inquiry_entry), GFP_ATOMIC);
+	if (!ie)
+		return false;
+
+	list_add(&ie->all, &cache->all);
+
+	if (name_known) {
+		ie->name_state = NAME_KNOWN;
+	} else {
+		ie->name_state = NAME_NOT_KNOWN;
+		list_add(&ie->list, &cache->unknown);
+	}
+
+update:
+	if (name_known && ie->name_state != NAME_KNOWN &&
+					ie->name_state != NAME_PENDING) {
+		ie->name_state = NAME_KNOWN;
+		list_del(&ie->list);
 	}
 	}
 
 
 	memcpy(&ie->data, data, sizeof(*data));
 	memcpy(&ie->data, data, sizeof(*data));
 	ie->timestamp = jiffies;
 	ie->timestamp = jiffies;
 	cache->timestamp = jiffies;
 	cache->timestamp = jiffies;
+
+	if (ie->name_state == NAME_NOT_KNOWN)
+		return false;
+
+	return true;
 }
 }
 
 
 static int inquiry_cache_dump(struct hci_dev *hdev, int num, __u8 *buf)
 static int inquiry_cache_dump(struct hci_dev *hdev, int num, __u8 *buf)
 {
 {
-	struct inquiry_cache *cache = &hdev->inq_cache;
+	struct discovery_state *cache = &hdev->discovery;
 	struct inquiry_info *info = (struct inquiry_info *) buf;
 	struct inquiry_info *info = (struct inquiry_info *) buf;
 	struct inquiry_entry *e;
 	struct inquiry_entry *e;
 	int copied = 0;
 	int copied = 0;
 
 
-	for (e = cache->list; e && copied < num; e = e->next, copied++) {
+	list_for_each_entry(e, &cache->all, all) {
 		struct inquiry_data *data = &e->data;
 		struct inquiry_data *data = &e->data;
+
+		if (copied >= num)
+			break;
+
 		bacpy(&info->bdaddr, &data->bdaddr);
 		bacpy(&info->bdaddr, &data->bdaddr);
 		info->pscan_rep_mode	= data->pscan_rep_mode;
 		info->pscan_rep_mode	= data->pscan_rep_mode;
 		info->pscan_period_mode	= data->pscan_period_mode;
 		info->pscan_period_mode	= data->pscan_period_mode;
 		info->pscan_mode	= data->pscan_mode;
 		info->pscan_mode	= data->pscan_mode;
 		memcpy(info->dev_class, data->dev_class, 3);
 		memcpy(info->dev_class, data->dev_class, 3);
 		info->clock_offset	= data->clock_offset;
 		info->clock_offset	= data->clock_offset;
+
 		info++;
 		info++;
+		copied++;
 	}
 	}
 
 
 	BT_DBG("cache %p, copied %d", cache, copied);
 	BT_DBG("cache %p, copied %d", cache, copied);
@@ -567,7 +708,7 @@ int hci_dev_open(__u16 dev)
 		hci_dev_hold(hdev);
 		hci_dev_hold(hdev);
 		set_bit(HCI_UP, &hdev->flags);
 		set_bit(HCI_UP, &hdev->flags);
 		hci_notify(hdev, HCI_DEV_UP);
 		hci_notify(hdev, HCI_DEV_UP);
-		if (!test_bit(HCI_SETUP, &hdev->flags)) {
+		if (!test_bit(HCI_SETUP, &hdev->dev_flags)) {
 			hci_dev_lock(hdev);
 			hci_dev_lock(hdev);
 			mgmt_powered(hdev, 1);
 			mgmt_powered(hdev, 1);
 			hci_dev_unlock(hdev);
 			hci_dev_unlock(hdev);
@@ -603,6 +744,8 @@ static int hci_dev_do_close(struct hci_dev *hdev)
 {
 {
 	BT_DBG("%s %p", hdev->name, hdev);
 	BT_DBG("%s %p", hdev->name, hdev);
 
 
+	cancel_work_sync(&hdev->le_scan);
+
 	hci_req_cancel(hdev, ENODEV);
 	hci_req_cancel(hdev, ENODEV);
 	hci_req_lock(hdev);
 	hci_req_lock(hdev);
 
 
@@ -619,14 +762,14 @@ static int hci_dev_do_close(struct hci_dev *hdev)
 	if (hdev->discov_timeout > 0) {
 	if (hdev->discov_timeout > 0) {
 		cancel_delayed_work(&hdev->discov_off);
 		cancel_delayed_work(&hdev->discov_off);
 		hdev->discov_timeout = 0;
 		hdev->discov_timeout = 0;
+		clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
 	}
 	}
 
 
-	if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->flags))
-		cancel_delayed_work(&hdev->power_off);
-
-	if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->flags))
+	if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
 		cancel_delayed_work(&hdev->service_cache);
 		cancel_delayed_work(&hdev->service_cache);
 
 
+	cancel_delayed_work_sync(&hdev->le_scan_disable);
+
 	hci_dev_lock(hdev);
 	hci_dev_lock(hdev);
 	inquiry_cache_flush(hdev);
 	inquiry_cache_flush(hdev);
 	hci_conn_hash_flush(hdev);
 	hci_conn_hash_flush(hdev);
@@ -667,13 +810,18 @@ static int hci_dev_do_close(struct hci_dev *hdev)
 	 * and no tasks are scheduled. */
 	 * and no tasks are scheduled. */
 	hdev->close(hdev);
 	hdev->close(hdev);
 
 
-	hci_dev_lock(hdev);
-	mgmt_powered(hdev, 0);
-	hci_dev_unlock(hdev);
+	if (!test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) {
+		hci_dev_lock(hdev);
+		mgmt_powered(hdev, 0);
+		hci_dev_unlock(hdev);
+	}
 
 
 	/* Clear flags */
 	/* Clear flags */
 	hdev->flags = 0;
 	hdev->flags = 0;
 
 
+	memset(hdev->eir, 0, sizeof(hdev->eir));
+	memset(hdev->dev_class, 0, sizeof(hdev->dev_class));
+
 	hci_req_unlock(hdev);
 	hci_req_unlock(hdev);
 
 
 	hci_dev_put(hdev);
 	hci_dev_put(hdev);
@@ -688,7 +836,12 @@ int hci_dev_close(__u16 dev)
 	hdev = hci_dev_get(dev);
 	hdev = hci_dev_get(dev);
 	if (!hdev)
 	if (!hdev)
 		return -ENODEV;
 		return -ENODEV;
+
+	if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags))
+		cancel_delayed_work(&hdev->power_off);
+
 	err = hci_dev_do_close(hdev);
 	err = hci_dev_do_close(hdev);
+
 	hci_dev_put(hdev);
 	hci_dev_put(hdev);
 	return err;
 	return err;
 }
 }
@@ -847,11 +1000,11 @@ int hci_get_dev_list(void __user *arg)
 
 
 	read_lock(&hci_dev_list_lock);
 	read_lock(&hci_dev_list_lock);
 	list_for_each_entry(hdev, &hci_dev_list, list) {
 	list_for_each_entry(hdev, &hci_dev_list, list) {
-		if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->flags))
+		if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags))
 			cancel_delayed_work(&hdev->power_off);
 			cancel_delayed_work(&hdev->power_off);
 
 
-		if (!test_bit(HCI_MGMT, &hdev->flags))
-			set_bit(HCI_PAIRABLE, &hdev->flags);
+		if (!test_bit(HCI_MGMT, &hdev->dev_flags))
+			set_bit(HCI_PAIRABLE, &hdev->dev_flags);
 
 
 		(dr + n)->dev_id  = hdev->id;
 		(dr + n)->dev_id  = hdev->id;
 		(dr + n)->dev_opt = hdev->flags;
 		(dr + n)->dev_opt = hdev->flags;
@@ -883,11 +1036,11 @@ int hci_get_dev_info(void __user *arg)
 	if (!hdev)
 	if (!hdev)
 		return -ENODEV;
 		return -ENODEV;
 
 
-	if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->flags))
+	if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags))
 		cancel_delayed_work_sync(&hdev->power_off);
 		cancel_delayed_work_sync(&hdev->power_off);
 
 
-	if (!test_bit(HCI_MGMT, &hdev->flags))
-		set_bit(HCI_PAIRABLE, &hdev->flags);
+	if (!test_bit(HCI_MGMT, &hdev->dev_flags))
+		set_bit(HCI_PAIRABLE, &hdev->dev_flags);
 
 
 	strcpy(di.name, hdev->name);
 	strcpy(di.name, hdev->name);
 	di.bdaddr   = hdev->bdaddr;
 	di.bdaddr   = hdev->bdaddr;
@@ -967,11 +1120,11 @@ static void hci_power_on(struct work_struct *work)
 	if (hci_dev_open(hdev->id) < 0)
 	if (hci_dev_open(hdev->id) < 0)
 		return;
 		return;
 
 
-	if (test_bit(HCI_AUTO_OFF, &hdev->flags))
+	if (test_bit(HCI_AUTO_OFF, &hdev->dev_flags))
 		schedule_delayed_work(&hdev->power_off,
 		schedule_delayed_work(&hdev->power_off,
 					msecs_to_jiffies(AUTO_OFF_TIMEOUT));
 					msecs_to_jiffies(AUTO_OFF_TIMEOUT));
 
 
-	if (test_and_clear_bit(HCI_SETUP, &hdev->flags))
+	if (test_and_clear_bit(HCI_SETUP, &hdev->dev_flags))
 		mgmt_index_added(hdev);
 		mgmt_index_added(hdev);
 }
 }
 
 
@@ -982,9 +1135,7 @@ static void hci_power_off(struct work_struct *work)
 
 
 	BT_DBG("%s", hdev->name);
 	BT_DBG("%s", hdev->name);
 
 
-	clear_bit(HCI_AUTO_OFF, &hdev->flags);
-
-	hci_dev_close(hdev->id);
+	hci_dev_do_close(hdev);
 }
 }
 
 
 static void hci_discov_off(struct work_struct *work)
 static void hci_discov_off(struct work_struct *work)
@@ -1037,6 +1188,18 @@ int hci_link_keys_clear(struct hci_dev *hdev)
 	return 0;
 	return 0;
 }
 }
 
 
+int hci_smp_ltks_clear(struct hci_dev *hdev)
+{
+	struct smp_ltk *k, *tmp;
+
+	list_for_each_entry_safe(k, tmp, &hdev->long_term_keys, list) {
+		list_del(&k->list);
+		kfree(k);
+	}
+
+	return 0;
+}
+
 struct link_key *hci_find_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr)
 struct link_key *hci_find_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr)
 {
 {
 	struct link_key *k;
 	struct link_key *k;
@@ -1084,44 +1247,38 @@ static int hci_persistent_key(struct hci_dev *hdev, struct hci_conn *conn,
 	return 0;
 	return 0;
 }
 }
 
 
-struct link_key *hci_find_ltk(struct hci_dev *hdev, __le16 ediv, u8 rand[8])
+struct smp_ltk *hci_find_ltk(struct hci_dev *hdev, __le16 ediv, u8 rand[8])
 {
 {
-	struct link_key *k;
+	struct smp_ltk *k;
 
 
-	list_for_each_entry(k, &hdev->link_keys, list) {
-		struct key_master_id *id;
-
-		if (k->type != HCI_LK_SMP_LTK)
+	list_for_each_entry(k, &hdev->long_term_keys, list) {
+		if (k->ediv != ediv ||
+				memcmp(rand, k->rand, sizeof(k->rand)))
 			continue;
 			continue;
 
 
-		if (k->dlen != sizeof(*id))
-			continue;
-
-		id = (void *) &k->data;
-		if (id->ediv == ediv &&
-				(memcmp(rand, id->rand, sizeof(id->rand)) == 0))
-			return k;
+		return k;
 	}
 	}
 
 
 	return NULL;
 	return NULL;
 }
 }
 EXPORT_SYMBOL(hci_find_ltk);
 EXPORT_SYMBOL(hci_find_ltk);
 
 
-struct link_key *hci_find_link_key_type(struct hci_dev *hdev,
-					bdaddr_t *bdaddr, u8 type)
+struct smp_ltk *hci_find_ltk_by_addr(struct hci_dev *hdev, bdaddr_t *bdaddr,
+				     u8 addr_type)
 {
 {
-	struct link_key *k;
+	struct smp_ltk *k;
 
 
-	list_for_each_entry(k, &hdev->link_keys, list)
-		if (k->type == type && bacmp(bdaddr, &k->bdaddr) == 0)
+	list_for_each_entry(k, &hdev->long_term_keys, list)
+		if (addr_type == k->bdaddr_type &&
+					bacmp(bdaddr, &k->bdaddr) == 0)
 			return k;
 			return k;
 
 
 	return NULL;
 	return NULL;
 }
 }
-EXPORT_SYMBOL(hci_find_link_key_type);
+EXPORT_SYMBOL(hci_find_ltk_by_addr);
 
 
 int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key,
 int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key,
-				bdaddr_t *bdaddr, u8 *val, u8 type, u8 pin_len)
+		     bdaddr_t *bdaddr, u8 *val, u8 type, u8 pin_len)
 {
 {
 	struct link_key *key, *old_key;
 	struct link_key *key, *old_key;
 	u8 old_key_type, persistent;
 	u8 old_key_type, persistent;
@@ -1175,40 +1332,39 @@ int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key,
 	return 0;
 	return 0;
 }
 }
 
 
-int hci_add_ltk(struct hci_dev *hdev, int new_key, bdaddr_t *bdaddr,
-			u8 key_size, __le16 ediv, u8 rand[8], u8 ltk[16])
+int hci_add_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type, u8 type,
+		int new_key, u8 authenticated, u8 tk[16], u8 enc_size, u16
+		ediv, u8 rand[8])
 {
 {
-	struct link_key *key, *old_key;
-	struct key_master_id *id;
-	u8 old_key_type;
+	struct smp_ltk *key, *old_key;
 
 
-	BT_DBG("%s addr %s", hdev->name, batostr(bdaddr));
+	if (!(type & HCI_SMP_STK) && !(type & HCI_SMP_LTK))
+		return 0;
 
 
-	old_key = hci_find_link_key_type(hdev, bdaddr, HCI_LK_SMP_LTK);
-	if (old_key) {
+	old_key = hci_find_ltk_by_addr(hdev, bdaddr, addr_type);
+	if (old_key)
 		key = old_key;
 		key = old_key;
-		old_key_type = old_key->type;
-	} else {
-		key = kzalloc(sizeof(*key) + sizeof(*id), GFP_ATOMIC);
+	else {
+		key = kzalloc(sizeof(*key), GFP_ATOMIC);
 		if (!key)
 		if (!key)
 			return -ENOMEM;
 			return -ENOMEM;
-		list_add(&key->list, &hdev->link_keys);
-		old_key_type = 0xff;
+		list_add(&key->list, &hdev->long_term_keys);
 	}
 	}
 
 
-	key->dlen = sizeof(*id);
-
 	bacpy(&key->bdaddr, bdaddr);
 	bacpy(&key->bdaddr, bdaddr);
-	memcpy(key->val, ltk, sizeof(key->val));
-	key->type = HCI_LK_SMP_LTK;
-	key->pin_len = key_size;
+	key->bdaddr_type = addr_type;
+	memcpy(key->val, tk, sizeof(key->val));
+	key->authenticated = authenticated;
+	key->ediv = ediv;
+	key->enc_size = enc_size;
+	key->type = type;
+	memcpy(key->rand, rand, sizeof(key->rand));
 
 
-	id = (void *) &key->data;
-	id->ediv = ediv;
-	memcpy(id->rand, rand, sizeof(id->rand));
+	if (!new_key)
+		return 0;
 
 
-	if (new_key)
-		mgmt_new_link_key(hdev, key, old_key_type);
+	if (type & HCI_SMP_LTK)
+		mgmt_new_ltk(hdev, key, 1);
 
 
 	return 0;
 	return 0;
 }
 }
@@ -1229,6 +1385,23 @@ int hci_remove_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr)
 	return 0;
 	return 0;
 }
 }
 
 
+int hci_remove_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr)
+{
+	struct smp_ltk *k, *tmp;
+
+	list_for_each_entry_safe(k, tmp, &hdev->long_term_keys, list) {
+		if (bacmp(bdaddr, &k->bdaddr))
+			continue;
+
+		BT_DBG("%s removing %s", hdev->name, batostr(bdaddr));
+
+		list_del(&k->list);
+		kfree(k);
+	}
+
+	return 0;
+}
+
 /* HCI command timer function */
 /* HCI command timer function */
 static void hci_cmd_timer(unsigned long arg)
 static void hci_cmd_timer(unsigned long arg)
 {
 {
@@ -1240,7 +1413,7 @@ static void hci_cmd_timer(unsigned long arg)
 }
 }
 
 
 struct oob_data *hci_find_remote_oob_data(struct hci_dev *hdev,
 struct oob_data *hci_find_remote_oob_data(struct hci_dev *hdev,
-							bdaddr_t *bdaddr)
+					  bdaddr_t *bdaddr)
 {
 {
 	struct oob_data *data;
 	struct oob_data *data;
 
 
@@ -1280,7 +1453,7 @@ int hci_remote_oob_data_clear(struct hci_dev *hdev)
 }
 }
 
 
 int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *hash,
 int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *hash,
-								u8 *randomizer)
+			    u8 *randomizer)
 {
 {
 	struct oob_data *data;
 	struct oob_data *data;
 
 
@@ -1303,8 +1476,7 @@ int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *hash,
 	return 0;
 	return 0;
 }
 }
 
 
-struct bdaddr_list *hci_blacklist_lookup(struct hci_dev *hdev,
-						bdaddr_t *bdaddr)
+struct bdaddr_list *hci_blacklist_lookup(struct hci_dev *hdev, bdaddr_t *bdaddr)
 {
 {
 	struct bdaddr_list *b;
 	struct bdaddr_list *b;
 
 
@@ -1331,7 +1503,7 @@ int hci_blacklist_clear(struct hci_dev *hdev)
 	return 0;
 	return 0;
 }
 }
 
 
-int hci_blacklist_add(struct hci_dev *hdev, bdaddr_t *bdaddr)
+int hci_blacklist_add(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
 {
 {
 	struct bdaddr_list *entry;
 	struct bdaddr_list *entry;
 
 
@@ -1349,10 +1521,10 @@ int hci_blacklist_add(struct hci_dev *hdev, bdaddr_t *bdaddr)
 
 
 	list_add(&entry->list, &hdev->blacklist);
 	list_add(&entry->list, &hdev->blacklist);
 
 
-	return mgmt_device_blocked(hdev, bdaddr);
+	return mgmt_device_blocked(hdev, bdaddr, type);
 }
 }
 
 
-int hci_blacklist_del(struct hci_dev *hdev, bdaddr_t *bdaddr)
+int hci_blacklist_del(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
 {
 {
 	struct bdaddr_list *entry;
 	struct bdaddr_list *entry;
 
 
@@ -1366,13 +1538,13 @@ int hci_blacklist_del(struct hci_dev *hdev, bdaddr_t *bdaddr)
 	list_del(&entry->list);
 	list_del(&entry->list);
 	kfree(entry);
 	kfree(entry);
 
 
-	return mgmt_device_unblocked(hdev, bdaddr);
+	return mgmt_device_unblocked(hdev, bdaddr, type);
 }
 }
 
 
 static void hci_clear_adv_cache(struct work_struct *work)
 static void hci_clear_adv_cache(struct work_struct *work)
 {
 {
 	struct hci_dev *hdev = container_of(work, struct hci_dev,
 	struct hci_dev *hdev = container_of(work, struct hci_dev,
-							adv_work.work);
+					    adv_work.work);
 
 
 	hci_dev_lock(hdev);
 	hci_dev_lock(hdev);
 
 
@@ -1415,11 +1587,7 @@ static inline int is_connectable_adv(u8 evt_type)
 }
 }
 
 
 int hci_add_adv_entry(struct hci_dev *hdev,
 int hci_add_adv_entry(struct hci_dev *hdev,
-					struct hci_ev_le_advertising_info *ev)
-{
-	struct adv_entry *entry;
-
-	if (!is_connectable_adv(ev->evt_type))
+					struct hci_ev_le_advertising_info *ev) { struct adv_entry *entry; if (!is_connectable_adv(ev->evt_type))
 		return -EINVAL;
 		return -EINVAL;
 
 
 	/* Only new entries should be added to adv_entries. So, if
 	/* Only new entries should be added to adv_entries. So, if
@@ -1427,7 +1595,7 @@ int hci_add_adv_entry(struct hci_dev *hdev,
 	if (hci_find_adv_entry(hdev, &ev->bdaddr))
 	if (hci_find_adv_entry(hdev, &ev->bdaddr))
 		return 0;
 		return 0;
 
 
-	entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
+	entry = kzalloc(sizeof(*entry), GFP_KERNEL);
 	if (!entry)
 	if (!entry)
 		return -ENOMEM;
 		return -ENOMEM;
 
 
@@ -1442,16 +1610,116 @@ int hci_add_adv_entry(struct hci_dev *hdev,
 	return 0;
 	return 0;
 }
 }
 
 
+static void le_scan_param_req(struct hci_dev *hdev, unsigned long opt)
+{
+	struct le_scan_params *param =  (struct le_scan_params *) opt;
+	struct hci_cp_le_set_scan_param cp;
+
+	memset(&cp, 0, sizeof(cp));
+	cp.type = param->type;
+	cp.interval = cpu_to_le16(param->interval);
+	cp.window = cpu_to_le16(param->window);
+
+	hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_PARAM, sizeof(cp), &cp);
+}
+
+static void le_scan_enable_req(struct hci_dev *hdev, unsigned long opt)
+{
+	struct hci_cp_le_set_scan_enable cp;
+
+	memset(&cp, 0, sizeof(cp));
+	cp.enable = 1;
+
+	hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(cp), &cp);
+}
+
+static int hci_do_le_scan(struct hci_dev *hdev, u8 type, u16 interval,
+			  u16 window, int timeout)
+{
+	long timeo = msecs_to_jiffies(3000);
+	struct le_scan_params param;
+	int err;
+
+	BT_DBG("%s", hdev->name);
+
+	if (test_bit(HCI_LE_SCAN, &hdev->dev_flags))
+		return -EINPROGRESS;
+
+	param.type = type;
+	param.interval = interval;
+	param.window = window;
+
+	hci_req_lock(hdev);
+
+	err = __hci_request(hdev, le_scan_param_req, (unsigned long) &param,
+			    timeo);
+	if (!err)
+		err = __hci_request(hdev, le_scan_enable_req, 0, timeo);
+
+	hci_req_unlock(hdev);
+
+	if (err < 0)
+		return err;
+
+	schedule_delayed_work(&hdev->le_scan_disable,
+			      msecs_to_jiffies(timeout));
+
+	return 0;
+}
+
+static void le_scan_disable_work(struct work_struct *work)
+{
+	struct hci_dev *hdev = container_of(work, struct hci_dev,
+					    le_scan_disable.work);
+	struct hci_cp_le_set_scan_enable cp;
+
+	BT_DBG("%s", hdev->name);
+
+	memset(&cp, 0, sizeof(cp));
+
+	hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(cp), &cp);
+}
+
+static void le_scan_work(struct work_struct *work)
+{
+	struct hci_dev *hdev = container_of(work, struct hci_dev, le_scan);
+	struct le_scan_params *param = &hdev->le_scan_params;
+
+	BT_DBG("%s", hdev->name);
+
+	hci_do_le_scan(hdev, param->type, param->interval, param->window,
+		       param->timeout);
+}
+
+int hci_le_scan(struct hci_dev *hdev, u8 type, u16 interval, u16 window,
+		int timeout)
+{
+	struct le_scan_params *param = &hdev->le_scan_params;
+
+	BT_DBG("%s", hdev->name);
+
+	if (work_busy(&hdev->le_scan))
+		return -EINPROGRESS;
+
+	param->type = type;
+	param->interval = interval;
+	param->window = window;
+	param->timeout = timeout;
+
+	queue_work(system_long_wq, &hdev->le_scan);
+
+	return 0;
+}
+
 /* Register HCI device */
 /* Register HCI device */
 int hci_register_dev(struct hci_dev *hdev)
 int hci_register_dev(struct hci_dev *hdev)
 {
 {
 	struct list_head *head = &hci_dev_list, *p;
 	struct list_head *head = &hci_dev_list, *p;
 	int i, id, error;
 	int i, id, error;
 
 
-	BT_DBG("%p name %s bus %d owner %p", hdev, hdev->name,
-						hdev->bus, hdev->owner);
+	BT_DBG("%p name %s bus %d", hdev, hdev->name, hdev->bus);
 
 
-	if (!hdev->open || !hdev->close || !hdev->destruct)
+	if (!hdev->open || !hdev->close)
 		return -EINVAL;
 		return -EINVAL;
 
 
 	/* Do not allow HCI_AMP devices to register at index 0,
 	/* Do not allow HCI_AMP devices to register at index 0,
@@ -1472,7 +1740,6 @@ int hci_register_dev(struct hci_dev *hdev)
 	hdev->id = id;
 	hdev->id = id;
 	list_add_tail(&hdev->list, head);
 	list_add_tail(&hdev->list, head);
 
 
-	atomic_set(&hdev->refcnt, 1);
 	mutex_init(&hdev->lock);
 	mutex_init(&hdev->lock);
 
 
 	hdev->flags = 0;
 	hdev->flags = 0;
@@ -1503,7 +1770,7 @@ int hci_register_dev(struct hci_dev *hdev)
 	init_waitqueue_head(&hdev->req_wait_q);
 	init_waitqueue_head(&hdev->req_wait_q);
 	mutex_init(&hdev->req_lock);
 	mutex_init(&hdev->req_lock);
 
 
-	inquiry_cache_init(hdev);
+	discovery_init(hdev);
 
 
 	hci_conn_hash_init(hdev);
 	hci_conn_hash_init(hdev);
 
 
@@ -1514,6 +1781,7 @@ int hci_register_dev(struct hci_dev *hdev)
 	INIT_LIST_HEAD(&hdev->uuids);
 	INIT_LIST_HEAD(&hdev->uuids);
 
 
 	INIT_LIST_HEAD(&hdev->link_keys);
 	INIT_LIST_HEAD(&hdev->link_keys);
+	INIT_LIST_HEAD(&hdev->long_term_keys);
 
 
 	INIT_LIST_HEAD(&hdev->remote_oob_data);
 	INIT_LIST_HEAD(&hdev->remote_oob_data);
 
 
@@ -1529,6 +1797,10 @@ int hci_register_dev(struct hci_dev *hdev)
 
 
 	atomic_set(&hdev->promisc, 0);
 	atomic_set(&hdev->promisc, 0);
 
 
+	INIT_WORK(&hdev->le_scan, le_scan_work);
+
+	INIT_DELAYED_WORK(&hdev->le_scan_disable, le_scan_disable_work);
+
 	write_unlock(&hci_dev_list_lock);
 	write_unlock(&hci_dev_list_lock);
 
 
 	hdev->workqueue = alloc_workqueue(hdev->name, WQ_HIGHPRI | WQ_UNBOUND |
 	hdev->workqueue = alloc_workqueue(hdev->name, WQ_HIGHPRI | WQ_UNBOUND |
@@ -1551,11 +1823,12 @@ int hci_register_dev(struct hci_dev *hdev)
 		}
 		}
 	}
 	}
 
 
-	set_bit(HCI_AUTO_OFF, &hdev->flags);
-	set_bit(HCI_SETUP, &hdev->flags);
+	set_bit(HCI_AUTO_OFF, &hdev->dev_flags);
+	set_bit(HCI_SETUP, &hdev->dev_flags);
 	schedule_work(&hdev->power_on);
 	schedule_work(&hdev->power_on);
 
 
 	hci_notify(hdev, HCI_DEV_REG);
 	hci_notify(hdev, HCI_DEV_REG);
+	hci_dev_hold(hdev);
 
 
 	return id;
 	return id;
 
 
@@ -1587,7 +1860,7 @@ void hci_unregister_dev(struct hci_dev *hdev)
 		kfree_skb(hdev->reassembly[i]);
 		kfree_skb(hdev->reassembly[i]);
 
 
 	if (!test_bit(HCI_INIT, &hdev->flags) &&
 	if (!test_bit(HCI_INIT, &hdev->flags) &&
-					!test_bit(HCI_SETUP, &hdev->flags)) {
+				!test_bit(HCI_SETUP, &hdev->dev_flags)) {
 		hci_dev_lock(hdev);
 		hci_dev_lock(hdev);
 		mgmt_index_removed(hdev);
 		mgmt_index_removed(hdev);
 		hci_dev_unlock(hdev);
 		hci_dev_unlock(hdev);
@@ -1614,11 +1887,12 @@ void hci_unregister_dev(struct hci_dev *hdev)
 	hci_blacklist_clear(hdev);
 	hci_blacklist_clear(hdev);
 	hci_uuids_clear(hdev);
 	hci_uuids_clear(hdev);
 	hci_link_keys_clear(hdev);
 	hci_link_keys_clear(hdev);
+	hci_smp_ltks_clear(hdev);
 	hci_remote_oob_data_clear(hdev);
 	hci_remote_oob_data_clear(hdev);
 	hci_adv_entries_clear(hdev);
 	hci_adv_entries_clear(hdev);
 	hci_dev_unlock(hdev);
 	hci_dev_unlock(hdev);
 
 
-	__hci_dev_put(hdev);
+	hci_dev_put(hdev);
 }
 }
 EXPORT_SYMBOL(hci_unregister_dev);
 EXPORT_SYMBOL(hci_unregister_dev);
 
 
@@ -1706,7 +1980,7 @@ static int hci_reassembly(struct hci_dev *hdev, int type, void *data,
 
 
 	while (count) {
 	while (count) {
 		scb = (void *) skb->cb;
 		scb = (void *) skb->cb;
-		len = min(scb->expect, (__u16)count);
+		len = min_t(uint, scb->expect, count);
 
 
 		memcpy(skb_put(skb, len), data, len);
 		memcpy(skb_put(skb, len), data, len);
 
 
@@ -1862,11 +2136,15 @@ static int hci_send_frame(struct sk_buff *skb)
 
 
 	BT_DBG("%s type %d len %d", hdev->name, bt_cb(skb)->pkt_type, skb->len);
 	BT_DBG("%s type %d len %d", hdev->name, bt_cb(skb)->pkt_type, skb->len);
 
 
-	if (atomic_read(&hdev->promisc)) {
-		/* Time stamp */
-		__net_timestamp(skb);
+	/* Time stamp */
+	__net_timestamp(skb);
+
+	/* Send copy to monitor */
+	hci_send_to_monitor(hdev, skb);
 
 
-		hci_send_to_sock(hdev, skb, NULL);
+	if (atomic_read(&hdev->promisc)) {
+		/* Send copy to the sockets */
+		hci_send_to_sock(hdev, skb);
 	}
 	}
 
 
 	/* Get rid of skb owner, prior to sending to the driver. */
 	/* Get rid of skb owner, prior to sending to the driver. */
@@ -2235,26 +2513,31 @@ static void hci_prio_recalculate(struct hci_dev *hdev, __u8 type)
 
 
 }
 }
 
 
-static inline void hci_sched_acl(struct hci_dev *hdev)
+static inline int __get_blocks(struct hci_dev *hdev, struct sk_buff *skb)
 {
 {
-	struct hci_chan *chan;
-	struct sk_buff *skb;
-	int quote;
-	unsigned int cnt;
-
-	BT_DBG("%s", hdev->name);
-
-	if (!hci_conn_num(hdev, ACL_LINK))
-		return;
+	/* Calculate count of blocks used by this packet */
+	return DIV_ROUND_UP(skb->len - HCI_ACL_HDR_SIZE, hdev->block_len);
+}
 
 
+static inline void __check_timeout(struct hci_dev *hdev, unsigned int cnt)
+{
 	if (!test_bit(HCI_RAW, &hdev->flags)) {
 	if (!test_bit(HCI_RAW, &hdev->flags)) {
 		/* 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 (!cnt && time_after(jiffies, hdev->acl_last_tx +
+					msecs_to_jiffies(HCI_ACL_TX_TIMEOUT)))
 			hci_link_tx_to(hdev, ACL_LINK);
 			hci_link_tx_to(hdev, ACL_LINK);
 	}
 	}
+}
+
+static inline void hci_sched_acl_pkt(struct hci_dev *hdev)
+{
+	unsigned int cnt = hdev->acl_cnt;
+	struct hci_chan *chan;
+	struct sk_buff *skb;
+	int quote;
 
 
-	cnt = hdev->acl_cnt;
+	__check_timeout(hdev, cnt);
 
 
 	while (hdev->acl_cnt &&
 	while (hdev->acl_cnt &&
 			(chan = hci_chan_sent(hdev, ACL_LINK, &quote))) {
 			(chan = hci_chan_sent(hdev, ACL_LINK, &quote))) {
@@ -2270,7 +2553,7 @@ static inline void hci_sched_acl(struct hci_dev *hdev)
 			skb = skb_dequeue(&chan->data_q);
 			skb = skb_dequeue(&chan->data_q);
 
 
 			hci_conn_enter_active_mode(chan->conn,
 			hci_conn_enter_active_mode(chan->conn,
-						bt_cb(skb)->force_active);
+						   bt_cb(skb)->force_active);
 
 
 			hci_send_frame(skb);
 			hci_send_frame(skb);
 			hdev->acl_last_tx = jiffies;
 			hdev->acl_last_tx = jiffies;
@@ -2285,6 +2568,70 @@ static inline void hci_sched_acl(struct hci_dev *hdev)
 		hci_prio_recalculate(hdev, ACL_LINK);
 		hci_prio_recalculate(hdev, ACL_LINK);
 }
 }
 
 
+static inline void hci_sched_acl_blk(struct hci_dev *hdev)
+{
+	unsigned int cnt = hdev->block_cnt;
+	struct hci_chan *chan;
+	struct sk_buff *skb;
+	int quote;
+
+	__check_timeout(hdev, cnt);
+
+	while (hdev->block_cnt > 0 &&
+			(chan = hci_chan_sent(hdev, ACL_LINK, &quote))) {
+		u32 priority = (skb_peek(&chan->data_q))->priority;
+		while (quote > 0 && (skb = skb_peek(&chan->data_q))) {
+			int blocks;
+
+			BT_DBG("chan %p skb %p len %d priority %u", chan, skb,
+						skb->len, skb->priority);
+
+			/* Stop if priority has changed */
+			if (skb->priority < priority)
+				break;
+
+			skb = skb_dequeue(&chan->data_q);
+
+			blocks = __get_blocks(hdev, skb);
+			if (blocks > hdev->block_cnt)
+				return;
+
+			hci_conn_enter_active_mode(chan->conn,
+						bt_cb(skb)->force_active);
+
+			hci_send_frame(skb);
+			hdev->acl_last_tx = jiffies;
+
+			hdev->block_cnt -= blocks;
+			quote -= blocks;
+
+			chan->sent += blocks;
+			chan->conn->sent += blocks;
+		}
+	}
+
+	if (cnt != hdev->block_cnt)
+		hci_prio_recalculate(hdev, ACL_LINK);
+}
+
+static inline void hci_sched_acl(struct hci_dev *hdev)
+{
+	BT_DBG("%s", hdev->name);
+
+	if (!hci_conn_num(hdev, ACL_LINK))
+		return;
+
+	switch (hdev->flow_ctl_mode) {
+	case HCI_FLOW_CTL_MODE_PACKET_BASED:
+		hci_sched_acl_pkt(hdev);
+		break;
+
+	case HCI_FLOW_CTL_MODE_BLOCK_BASED:
+		hci_sched_acl_blk(hdev);
+		break;
+	}
+}
+
 /* Schedule SCO */
 /* Schedule SCO */
 static inline void hci_sched_sco(struct hci_dev *hdev)
 static inline void hci_sched_sco(struct hci_dev *hdev)
 {
 {
@@ -2482,9 +2829,12 @@ static void hci_rx_work(struct work_struct *work)
 	BT_DBG("%s", hdev->name);
 	BT_DBG("%s", hdev->name);
 
 
 	while ((skb = skb_dequeue(&hdev->rx_q))) {
 	while ((skb = skb_dequeue(&hdev->rx_q))) {
+		/* Send copy to monitor */
+		hci_send_to_monitor(hdev, skb);
+
 		if (atomic_read(&hdev->promisc)) {
 		if (atomic_read(&hdev->promisc)) {
 			/* Send copy to the sockets */
 			/* Send copy to the sockets */
-			hci_send_to_sock(hdev, skb, NULL);
+			hci_send_to_sock(hdev, skb);
 		}
 		}
 
 
 		if (test_bit(HCI_RAW, &hdev->flags)) {
 		if (test_bit(HCI_RAW, &hdev->flags)) {
@@ -2568,6 +2918,8 @@ int hci_do_inquiry(struct hci_dev *hdev, u8 length)
 	if (test_bit(HCI_INQUIRY, &hdev->flags))
 	if (test_bit(HCI_INQUIRY, &hdev->flags))
 		return -EINPROGRESS;
 		return -EINPROGRESS;
 
 
+	inquiry_cache_flush(hdev);
+
 	memset(&cp, 0, sizeof(cp));
 	memset(&cp, 0, sizeof(cp));
 	memcpy(&cp.lap, lap, sizeof(cp.lap));
 	memcpy(&cp.lap, lap, sizeof(cp.lap));
 	cp.length  = length;
 	cp.length  = length;
@@ -2584,6 +2936,3 @@ 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");

+ 441 - 190
net/bluetooth/hci_event.c

@@ -35,7 +35,6 @@
 #include <linux/init.h>
 #include <linux/init.h>
 #include <linux/skbuff.h>
 #include <linux/skbuff.h>
 #include <linux/interrupt.h>
 #include <linux/interrupt.h>
-#include <linux/notifier.h>
 #include <net/sock.h>
 #include <net/sock.h>
 
 
 #include <asm/system.h>
 #include <asm/system.h>
@@ -45,8 +44,6 @@
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci_core.h>
 #include <net/bluetooth/hci_core.h>
 
 
-static bool enable_le;
-
 /* Handle HCI Event packets */
 /* Handle HCI Event packets */
 
 
 static void hci_cc_inquiry_cancel(struct hci_dev *hdev, struct sk_buff *skb)
 static void hci_cc_inquiry_cancel(struct hci_dev *hdev, struct sk_buff *skb)
@@ -65,7 +62,7 @@ static void hci_cc_inquiry_cancel(struct hci_dev *hdev, struct sk_buff *skb)
 	clear_bit(HCI_INQUIRY, &hdev->flags);
 	clear_bit(HCI_INQUIRY, &hdev->flags);
 
 
 	hci_dev_lock(hdev);
 	hci_dev_lock(hdev);
-	mgmt_discovering(hdev, 0);
+	hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
 	hci_dev_unlock(hdev);
 	hci_dev_unlock(hdev);
 
 
 	hci_req_complete(hdev, HCI_OP_INQUIRY_CANCEL, status);
 	hci_req_complete(hdev, HCI_OP_INQUIRY_CANCEL, status);
@@ -195,7 +192,10 @@ static void hci_cc_reset(struct hci_dev *hdev, struct sk_buff *skb)
 
 
 	hci_req_complete(hdev, HCI_OP_RESET, status);
 	hci_req_complete(hdev, HCI_OP_RESET, status);
 
 
-	hdev->dev_flags = 0;
+	/* Reset all non-persistent flags */
+	hdev->dev_flags &= ~(BIT(HCI_LE_SCAN) | BIT(HCI_PENDING_CLASS));
+
+	hdev->discovery.state = DISCOVERY_STOPPED;
 }
 }
 
 
 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)
@@ -211,13 +211,14 @@ static void hci_cc_write_local_name(struct hci_dev *hdev, struct sk_buff *skb)
 
 
 	hci_dev_lock(hdev);
 	hci_dev_lock(hdev);
 
 
-	if (test_bit(HCI_MGMT, &hdev->flags))
+	if (test_bit(HCI_MGMT, &hdev->dev_flags))
 		mgmt_set_local_name_complete(hdev, sent, status);
 		mgmt_set_local_name_complete(hdev, sent, status);
-
-	if (status == 0)
+	else if (!status)
 		memcpy(hdev->dev_name, sent, HCI_MAX_NAME_LENGTH);
 		memcpy(hdev->dev_name, sent, HCI_MAX_NAME_LENGTH);
 
 
 	hci_dev_unlock(hdev);
 	hci_dev_unlock(hdev);
+
+	hci_req_complete(hdev, HCI_OP_WRITE_LOCAL_NAME, status);
 }
 }
 
 
 static void hci_cc_read_local_name(struct hci_dev *hdev, struct sk_buff *skb)
 static void hci_cc_read_local_name(struct hci_dev *hdev, struct sk_buff *skb)
@@ -229,7 +230,8 @@ static void hci_cc_read_local_name(struct hci_dev *hdev, struct sk_buff *skb)
 	if (rp->status)
 	if (rp->status)
 		return;
 		return;
 
 
-	memcpy(hdev->dev_name, rp->name, HCI_MAX_NAME_LENGTH);
+	if (test_bit(HCI_SETUP, &hdev->dev_flags))
+		memcpy(hdev->dev_name, rp->name, HCI_MAX_NAME_LENGTH);
 }
 }
 
 
 static void hci_cc_write_auth_enable(struct hci_dev *hdev, struct sk_buff *skb)
 static void hci_cc_write_auth_enable(struct hci_dev *hdev, struct sk_buff *skb)
@@ -252,6 +254,9 @@ static void hci_cc_write_auth_enable(struct hci_dev *hdev, struct sk_buff *skb)
 			clear_bit(HCI_AUTH, &hdev->flags);
 			clear_bit(HCI_AUTH, &hdev->flags);
 	}
 	}
 
 
+	if (test_bit(HCI_MGMT, &hdev->dev_flags))
+		mgmt_auth_enable_complete(hdev, status);
+
 	hci_req_complete(hdev, HCI_OP_WRITE_AUTH_ENABLE, status);
 	hci_req_complete(hdev, HCI_OP_WRITE_AUTH_ENABLE, status);
 }
 }
 
 
@@ -349,14 +354,19 @@ static void hci_cc_write_class_of_dev(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)
-		return;
-
 	sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_CLASS_OF_DEV);
 	sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_CLASS_OF_DEV);
 	if (!sent)
 	if (!sent)
 		return;
 		return;
 
 
-	memcpy(hdev->dev_class, sent, 3);
+	hci_dev_lock(hdev);
+
+	if (status == 0)
+		memcpy(hdev->dev_class, sent, 3);
+
+	if (test_bit(HCI_MGMT, &hdev->dev_flags))
+		mgmt_set_class_of_dev_complete(hdev, sent, status);
+
+	hci_dev_unlock(hdev);
 }
 }
 
 
 static void hci_cc_read_voice_setting(struct hci_dev *hdev, struct sk_buff *skb)
 static void hci_cc_read_voice_setting(struct hci_dev *hdev, struct sk_buff *skb)
@@ -419,18 +429,6 @@ static void hci_cc_host_buffer_size(struct hci_dev *hdev, struct sk_buff *skb)
 	hci_req_complete(hdev, HCI_OP_HOST_BUFFER_SIZE, status);
 	hci_req_complete(hdev, HCI_OP_HOST_BUFFER_SIZE, status);
 }
 }
 
 
-static void hci_cc_read_ssp_mode(struct hci_dev *hdev, struct sk_buff *skb)
-{
-	struct hci_rp_read_ssp_mode *rp = (void *) skb->data;
-
-	BT_DBG("%s status 0x%x", hdev->name, rp->status);
-
-	if (rp->status)
-		return;
-
-	hdev->ssp_mode = rp->mode;
-}
-
 static void hci_cc_write_ssp_mode(struct hci_dev *hdev, struct sk_buff *skb)
 static void hci_cc_write_ssp_mode(struct hci_dev *hdev, struct sk_buff *skb)
 {
 {
 	__u8 status = *((__u8 *) skb->data);
 	__u8 status = *((__u8 *) skb->data);
@@ -438,14 +436,18 @@ static void hci_cc_write_ssp_mode(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)
-		return;
-
 	sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_SSP_MODE);
 	sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_SSP_MODE);
 	if (!sent)
 	if (!sent)
 		return;
 		return;
 
 
-	hdev->ssp_mode = *((__u8 *) sent);
+	if (test_bit(HCI_MGMT, &hdev->dev_flags))
+		mgmt_ssp_enable_complete(hdev, *((u8 *) sent), status);
+	else if (!status) {
+		if (*((u8 *) sent))
+			set_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
+		else
+			clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
+	}
 }
 }
 
 
 static u8 hci_get_inquiry_mode(struct hci_dev *hdev)
 static u8 hci_get_inquiry_mode(struct hci_dev *hdev)
@@ -540,20 +542,6 @@ static void hci_setup_event_mask(struct hci_dev *hdev)
 	hci_send_cmd(hdev, HCI_OP_SET_EVENT_MASK, sizeof(events), events);
 	hci_send_cmd(hdev, HCI_OP_SET_EVENT_MASK, sizeof(events), events);
 }
 }
 
 
-static void hci_set_le_support(struct hci_dev *hdev)
-{
-	struct hci_cp_write_le_host_supported cp;
-
-	memset(&cp, 0, sizeof(cp));
-
-	if (enable_le) {
-		cp.le = 1;
-		cp.simul = !!(hdev->features[6] & LMP_SIMUL_LE_BR);
-	}
-
-	hci_send_cmd(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(cp), &cp);
-}
-
 static void hci_setup(struct hci_dev *hdev)
 static void hci_setup(struct hci_dev *hdev)
 {
 {
 	if (hdev->dev_type != HCI_BREDR)
 	if (hdev->dev_type != HCI_BREDR)
@@ -565,8 +553,18 @@ static void hci_setup(struct hci_dev *hdev)
 		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) {
-		u8 mode = 0x01;
-		hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, sizeof(mode), &mode);
+		if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
+			u8 mode = 0x01;
+			hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE,
+				     sizeof(mode), &mode);
+		} else {
+			struct hci_cp_write_eir cp;
+
+			memset(hdev->eir, 0, sizeof(hdev->eir));
+			memset(&cp, 0, sizeof(cp));
+
+			hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
+		}
 	}
 	}
 
 
 	if (hdev->features[3] & LMP_RSSI_INQ)
 	if (hdev->features[3] & LMP_RSSI_INQ)
@@ -579,12 +577,15 @@ static void hci_setup(struct hci_dev *hdev)
 		struct hci_cp_read_local_ext_features cp;
 		struct hci_cp_read_local_ext_features cp;
 
 
 		cp.page = 0x01;
 		cp.page = 0x01;
-		hci_send_cmd(hdev, HCI_OP_READ_LOCAL_EXT_FEATURES,
-							sizeof(cp), &cp);
+		hci_send_cmd(hdev, HCI_OP_READ_LOCAL_EXT_FEATURES, sizeof(cp),
+			     &cp);
 	}
 	}
 
 
-	if (hdev->features[4] & LMP_LE)
-		hci_set_le_support(hdev);
+	if (test_bit(HCI_LINK_SECURITY, &hdev->dev_flags)) {
+		u8 enable = 1;
+		hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(enable),
+			     &enable);
+	}
 }
 }
 
 
 static void hci_cc_read_local_version(struct hci_dev *hdev, struct sk_buff *skb)
 static void hci_cc_read_local_version(struct hci_dev *hdev, struct sk_buff *skb)
@@ -594,7 +595,7 @@ static void hci_cc_read_local_version(struct hci_dev *hdev, struct sk_buff *skb)
 	BT_DBG("%s status 0x%x", hdev->name, rp->status);
 	BT_DBG("%s status 0x%x", hdev->name, rp->status);
 
 
 	if (rp->status)
 	if (rp->status)
-		return;
+		goto done;
 
 
 	hdev->hci_ver = rp->hci_ver;
 	hdev->hci_ver = rp->hci_ver;
 	hdev->hci_rev = __le16_to_cpu(rp->hci_rev);
 	hdev->hci_rev = __le16_to_cpu(rp->hci_rev);
@@ -608,6 +609,9 @@ static void hci_cc_read_local_version(struct hci_dev *hdev, struct sk_buff *skb)
 
 
 	if (test_bit(HCI_INIT, &hdev->flags))
 	if (test_bit(HCI_INIT, &hdev->flags))
 		hci_setup(hdev);
 		hci_setup(hdev);
+
+done:
+	hci_req_complete(hdev, HCI_OP_READ_LOCAL_VERSION, rp->status);
 }
 }
 
 
 static void hci_setup_link_policy(struct hci_dev *hdev)
 static void hci_setup_link_policy(struct hci_dev *hdev)
@@ -624,8 +628,8 @@ static void hci_setup_link_policy(struct hci_dev *hdev)
 		link_policy |= HCI_LP_PARK;
 		link_policy |= HCI_LP_PARK;
 
 
 	link_policy = cpu_to_le16(link_policy);
 	link_policy = cpu_to_le16(link_policy);
-	hci_send_cmd(hdev, HCI_OP_WRITE_DEF_LINK_POLICY,
-					sizeof(link_policy), &link_policy);
+	hci_send_cmd(hdev, HCI_OP_WRITE_DEF_LINK_POLICY, sizeof(link_policy),
+		     &link_policy);
 }
 }
 
 
 static void hci_cc_read_local_commands(struct hci_dev *hdev, struct sk_buff *skb)
 static void hci_cc_read_local_commands(struct hci_dev *hdev, struct sk_buff *skb)
@@ -701,6 +705,22 @@ static void hci_cc_read_local_features(struct hci_dev *hdev, struct sk_buff *skb
 					hdev->features[6], hdev->features[7]);
 					hdev->features[6], hdev->features[7]);
 }
 }
 
 
+static void hci_set_le_support(struct hci_dev *hdev)
+{
+	struct hci_cp_write_le_host_supported cp;
+
+	memset(&cp, 0, sizeof(cp));
+
+	if (enable_le && test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
+		cp.le = 1;
+		cp.simul = !!(hdev->features[6] & LMP_SIMUL_LE_BR);
+	}
+
+	if (cp.le != !!(hdev->host_features[0] & LMP_HOST_LE))
+		hci_send_cmd(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(cp),
+			     &cp);
+}
+
 static void hci_cc_read_local_ext_features(struct hci_dev *hdev,
 static void hci_cc_read_local_ext_features(struct hci_dev *hdev,
 							struct sk_buff *skb)
 							struct sk_buff *skb)
 {
 {
@@ -709,7 +729,7 @@ static void hci_cc_read_local_ext_features(struct hci_dev *hdev,
 	BT_DBG("%s status 0x%x", hdev->name, rp->status);
 	BT_DBG("%s status 0x%x", hdev->name, rp->status);
 
 
 	if (rp->status)
 	if (rp->status)
-		return;
+		goto done;
 
 
 	switch (rp->page) {
 	switch (rp->page) {
 	case 0:
 	case 0:
@@ -720,6 +740,10 @@ static void hci_cc_read_local_ext_features(struct hci_dev *hdev,
 		break;
 		break;
 	}
 	}
 
 
+	if (test_bit(HCI_INIT, &hdev->flags) && hdev->features[4] & LMP_LE)
+		hci_set_le_support(hdev);
+
+done:
 	hci_req_complete(hdev, HCI_OP_READ_LOCAL_EXT_FEATURES, rp->status);
 	hci_req_complete(hdev, HCI_OP_READ_LOCAL_EXT_FEATURES, rp->status);
 }
 }
 
 
@@ -890,7 +914,7 @@ static void hci_cc_pin_code_reply(struct hci_dev *hdev, struct sk_buff *skb)
 
 
 	hci_dev_lock(hdev);
 	hci_dev_lock(hdev);
 
 
-	if (test_bit(HCI_MGMT, &hdev->flags))
+	if (test_bit(HCI_MGMT, &hdev->dev_flags))
 		mgmt_pin_code_reply_complete(hdev, &rp->bdaddr, rp->status);
 		mgmt_pin_code_reply_complete(hdev, &rp->bdaddr, rp->status);
 
 
 	if (rp->status != 0)
 	if (rp->status != 0)
@@ -916,7 +940,7 @@ static void hci_cc_pin_code_neg_reply(struct hci_dev *hdev, struct sk_buff *skb)
 
 
 	hci_dev_lock(hdev);
 	hci_dev_lock(hdev);
 
 
-	if (test_bit(HCI_MGMT, &hdev->flags))
+	if (test_bit(HCI_MGMT, &hdev->dev_flags))
 		mgmt_pin_code_neg_reply_complete(hdev, &rp->bdaddr,
 		mgmt_pin_code_neg_reply_complete(hdev, &rp->bdaddr,
 								rp->status);
 								rp->status);
 
 
@@ -951,9 +975,9 @@ static void hci_cc_user_confirm_reply(struct hci_dev *hdev, struct sk_buff *skb)
 
 
 	hci_dev_lock(hdev);
 	hci_dev_lock(hdev);
 
 
-	if (test_bit(HCI_MGMT, &hdev->flags))
-		mgmt_user_confirm_reply_complete(hdev, &rp->bdaddr,
-								rp->status);
+	if (test_bit(HCI_MGMT, &hdev->dev_flags))
+		mgmt_user_confirm_reply_complete(hdev, &rp->bdaddr, ACL_LINK, 0,
+						 rp->status);
 
 
 	hci_dev_unlock(hdev);
 	hci_dev_unlock(hdev);
 }
 }
@@ -967,9 +991,9 @@ static void hci_cc_user_confirm_neg_reply(struct hci_dev *hdev,
 
 
 	hci_dev_lock(hdev);
 	hci_dev_lock(hdev);
 
 
-	if (test_bit(HCI_MGMT, &hdev->flags))
+	if (test_bit(HCI_MGMT, &hdev->dev_flags))
 		mgmt_user_confirm_neg_reply_complete(hdev, &rp->bdaddr,
 		mgmt_user_confirm_neg_reply_complete(hdev, &rp->bdaddr,
-								rp->status);
+						     ACL_LINK, 0, rp->status);
 
 
 	hci_dev_unlock(hdev);
 	hci_dev_unlock(hdev);
 }
 }
@@ -982,9 +1006,9 @@ static void hci_cc_user_passkey_reply(struct hci_dev *hdev, struct sk_buff *skb)
 
 
 	hci_dev_lock(hdev);
 	hci_dev_lock(hdev);
 
 
-	if (test_bit(HCI_MGMT, &hdev->flags))
-		mgmt_user_passkey_reply_complete(hdev, &rp->bdaddr,
-								rp->status);
+	if (test_bit(HCI_MGMT, &hdev->dev_flags))
+		mgmt_user_passkey_reply_complete(hdev, &rp->bdaddr, ACL_LINK,
+						 0, rp->status);
 
 
 	hci_dev_unlock(hdev);
 	hci_dev_unlock(hdev);
 }
 }
@@ -998,9 +1022,9 @@ static void hci_cc_user_passkey_neg_reply(struct hci_dev *hdev,
 
 
 	hci_dev_lock(hdev);
 	hci_dev_lock(hdev);
 
 
-	if (test_bit(HCI_MGMT, &hdev->flags))
+	if (test_bit(HCI_MGMT, &hdev->dev_flags))
 		mgmt_user_passkey_neg_reply_complete(hdev, &rp->bdaddr,
 		mgmt_user_passkey_neg_reply_complete(hdev, &rp->bdaddr,
-								rp->status);
+						     ACL_LINK, 0, rp->status);
 
 
 	hci_dev_unlock(hdev);
 	hci_dev_unlock(hdev);
 }
 }
@@ -1023,6 +1047,15 @@ static void hci_cc_le_set_scan_param(struct hci_dev *hdev, struct sk_buff *skb)
 	__u8 status = *((__u8 *) skb->data);
 	__u8 status = *((__u8 *) skb->data);
 
 
 	BT_DBG("%s status 0x%x", hdev->name, status);
 	BT_DBG("%s status 0x%x", hdev->name, status);
+
+	hci_req_complete(hdev, HCI_OP_LE_SET_SCAN_PARAM, status);
+
+	if (status) {
+		hci_dev_lock(hdev);
+		mgmt_start_discovery_failed(hdev, status);
+		hci_dev_unlock(hdev);
+		return;
+	}
 }
 }
 
 
 static void hci_cc_le_set_scan_enable(struct hci_dev *hdev,
 static void hci_cc_le_set_scan_enable(struct hci_dev *hdev,
@@ -1033,28 +1066,47 @@ static void hci_cc_le_set_scan_enable(struct hci_dev *hdev,
 
 
 	BT_DBG("%s status 0x%x", hdev->name, status);
 	BT_DBG("%s status 0x%x", hdev->name, status);
 
 
-	if (status)
-		return;
-
 	cp = hci_sent_cmd_data(hdev, HCI_OP_LE_SET_SCAN_ENABLE);
 	cp = hci_sent_cmd_data(hdev, HCI_OP_LE_SET_SCAN_ENABLE);
 	if (!cp)
 	if (!cp)
 		return;
 		return;
 
 
 	switch (cp->enable) {
 	switch (cp->enable) {
 	case LE_SCANNING_ENABLED:
 	case LE_SCANNING_ENABLED:
+		hci_req_complete(hdev, HCI_OP_LE_SET_SCAN_ENABLE, status);
+
+		if (status) {
+			hci_dev_lock(hdev);
+			mgmt_start_discovery_failed(hdev, status);
+			hci_dev_unlock(hdev);
+			return;
+		}
+
 		set_bit(HCI_LE_SCAN, &hdev->dev_flags);
 		set_bit(HCI_LE_SCAN, &hdev->dev_flags);
 
 
 		cancel_delayed_work_sync(&hdev->adv_work);
 		cancel_delayed_work_sync(&hdev->adv_work);
 
 
 		hci_dev_lock(hdev);
 		hci_dev_lock(hdev);
 		hci_adv_entries_clear(hdev);
 		hci_adv_entries_clear(hdev);
+		hci_discovery_set_state(hdev, DISCOVERY_FINDING);
 		hci_dev_unlock(hdev);
 		hci_dev_unlock(hdev);
 		break;
 		break;
 
 
 	case LE_SCANNING_DISABLED:
 	case LE_SCANNING_DISABLED:
+		if (status)
+			return;
+
 		clear_bit(HCI_LE_SCAN, &hdev->dev_flags);
 		clear_bit(HCI_LE_SCAN, &hdev->dev_flags);
 
 
 		schedule_delayed_work(&hdev->adv_work, ADV_CLEAR_TIMEOUT);
 		schedule_delayed_work(&hdev->adv_work, ADV_CLEAR_TIMEOUT);
+
+		if (hdev->discovery.type == DISCOV_TYPE_INTERLEAVED) {
+			mgmt_interleaved_discovery(hdev);
+		} else {
+			hci_dev_lock(hdev);
+			hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
+			hci_dev_unlock(hdev);
+		}
+
 		break;
 		break;
 
 
 	default:
 	default:
@@ -1090,16 +1142,27 @@ static void hci_cc_le_ltk_neg_reply(struct hci_dev *hdev, struct sk_buff *skb)
 static inline void hci_cc_write_le_host_supported(struct hci_dev *hdev,
 static inline void hci_cc_write_le_host_supported(struct hci_dev *hdev,
 							struct sk_buff *skb)
 							struct sk_buff *skb)
 {
 {
-	struct hci_cp_read_local_ext_features cp;
+	struct hci_cp_write_le_host_supported *sent;
 	__u8 status = *((__u8 *) skb->data);
 	__u8 status = *((__u8 *) skb->data);
 
 
 	BT_DBG("%s status 0x%x", hdev->name, status);
 	BT_DBG("%s status 0x%x", hdev->name, status);
 
 
-	if (status)
+	sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED);
+	if (!sent)
 		return;
 		return;
 
 
-	cp.page = 0x01;
-	hci_send_cmd(hdev, HCI_OP_READ_LOCAL_EXT_FEATURES, sizeof(cp), &cp);
+	if (!status) {
+		if (sent->le)
+			hdev->host_features[0] |= LMP_HOST_LE;
+		else
+			hdev->host_features[0] &= ~LMP_HOST_LE;
+	}
+
+	if (test_bit(HCI_MGMT, &hdev->dev_flags) &&
+					!test_bit(HCI_INIT, &hdev->flags))
+		mgmt_le_enable_complete(hdev, sent->le, status);
+
+	hci_req_complete(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED, 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)
@@ -1110,7 +1173,7 @@ static inline void hci_cs_inquiry(struct hci_dev *hdev, __u8 status)
 		hci_req_complete(hdev, HCI_OP_INQUIRY, status);
 		hci_req_complete(hdev, HCI_OP_INQUIRY, 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->dev_flags))
 			mgmt_start_discovery_failed(hdev, status);
 			mgmt_start_discovery_failed(hdev, status);
 		hci_dev_unlock(hdev);
 		hci_dev_unlock(hdev);
 		return;
 		return;
@@ -1119,7 +1182,7 @@ static inline void hci_cs_inquiry(struct hci_dev *hdev, __u8 status)
 	set_bit(HCI_INQUIRY, &hdev->flags);
 	set_bit(HCI_INQUIRY, &hdev->flags);
 
 
 	hci_dev_lock(hdev);
 	hci_dev_lock(hdev);
-	mgmt_discovering(hdev, 1);
+	hci_discovery_set_state(hdev, DISCOVERY_FINDING);
 	hci_dev_unlock(hdev);
 	hci_dev_unlock(hdev);
 }
 }
 
 
@@ -1153,7 +1216,7 @@ static inline void hci_cs_create_conn(struct hci_dev *hdev, __u8 status)
 		if (!conn) {
 		if (!conn) {
 			conn = hci_conn_add(hdev, ACL_LINK, &cp->bdaddr);
 			conn = hci_conn_add(hdev, ACL_LINK, &cp->bdaddr);
 			if (conn) {
 			if (conn) {
-				conn->out = 1;
+				conn->out = true;
 				conn->link_mode |= HCI_LM_MASTER;
 				conn->link_mode |= HCI_LM_MASTER;
 			} else
 			} else
 				BT_ERR("No memory for new connection");
 				BT_ERR("No memory for new connection");
@@ -1263,7 +1326,7 @@ static int hci_outgoing_auth_needed(struct hci_dev *hdev,
 
 
 	/* Only request authentication for SSP connections or non-SSP
 	/* Only request authentication for SSP connections or non-SSP
 	 * devices with sec_level HIGH or if MITM protection is requested */
 	 * devices with sec_level HIGH or if MITM protection is requested */
-	if (!(hdev->ssp_mode > 0 && conn->ssp_mode > 0) &&
+	if (!hci_conn_ssp_enabled(conn) &&
 				conn->pending_sec_level != BT_SECURITY_HIGH &&
 				conn->pending_sec_level != BT_SECURITY_HIGH &&
 				!(conn->auth_type & 0x01))
 				!(conn->auth_type & 0x01))
 		return 0;
 		return 0;
@@ -1271,6 +1334,73 @@ static int hci_outgoing_auth_needed(struct hci_dev *hdev,
 	return 1;
 	return 1;
 }
 }
 
 
+static inline int hci_resolve_name(struct hci_dev *hdev,
+				   struct inquiry_entry *e)
+{
+	struct hci_cp_remote_name_req cp;
+
+	memset(&cp, 0, sizeof(cp));
+
+	bacpy(&cp.bdaddr, &e->data.bdaddr);
+	cp.pscan_rep_mode = e->data.pscan_rep_mode;
+	cp.pscan_mode = e->data.pscan_mode;
+	cp.clock_offset = e->data.clock_offset;
+
+	return hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ, sizeof(cp), &cp);
+}
+
+static bool hci_resolve_next_name(struct hci_dev *hdev)
+{
+	struct discovery_state *discov = &hdev->discovery;
+	struct inquiry_entry *e;
+
+	if (list_empty(&discov->resolve))
+		return false;
+
+	e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY, NAME_NEEDED);
+	if (hci_resolve_name(hdev, e) == 0) {
+		e->name_state = NAME_PENDING;
+		return true;
+	}
+
+	return false;
+}
+
+static void hci_check_pending_name(struct hci_dev *hdev, struct hci_conn *conn,
+				   bdaddr_t *bdaddr, u8 *name, u8 name_len)
+{
+	struct discovery_state *discov = &hdev->discovery;
+	struct inquiry_entry *e;
+
+	if (conn && !test_and_set_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags))
+		mgmt_device_connected(hdev, bdaddr, ACL_LINK, 0x00, 0, name,
+				      name_len, conn->dev_class);
+
+	if (discov->state == DISCOVERY_STOPPED)
+		return;
+
+	if (discov->state == DISCOVERY_STOPPING)
+		goto discov_complete;
+
+	if (discov->state != DISCOVERY_RESOLVING)
+		return;
+
+	e = hci_inquiry_cache_lookup_resolve(hdev, bdaddr, NAME_PENDING);
+	if (e) {
+		e->name_state = NAME_KNOWN;
+		list_del(&e->list);
+		if (name)
+			mgmt_remote_name(hdev, bdaddr, ACL_LINK, 0x00,
+					 e->data.rssi, name, name_len);
+	}
+
+	if (hci_resolve_next_name(hdev))
+		return;
+
+discov_complete:
+	hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
+}
+
 static void hci_cs_remote_name_req(struct hci_dev *hdev, __u8 status)
 static void hci_cs_remote_name_req(struct hci_dev *hdev, __u8 status)
 {
 {
 	struct hci_cp_remote_name_req *cp;
 	struct hci_cp_remote_name_req *cp;
@@ -1290,13 +1420,17 @@ static void hci_cs_remote_name_req(struct hci_dev *hdev, __u8 status)
 	hci_dev_lock(hdev);
 	hci_dev_lock(hdev);
 
 
 	conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
 	conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
+
+	if (test_bit(HCI_MGMT, &hdev->dev_flags))
+		hci_check_pending_name(hdev, conn, &cp->bdaddr, NULL, 0);
+
 	if (!conn)
 	if (!conn)
 		goto unlock;
 		goto unlock;
 
 
 	if (!hci_outgoing_auth_needed(hdev, conn))
 	if (!hci_outgoing_auth_needed(hdev, conn))
 		goto unlock;
 		goto unlock;
 
 
-	if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->pend)) {
+	if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->flags)) {
 		struct hci_cp_auth_requested cp;
 		struct hci_cp_auth_requested cp;
 		cp.handle = __cpu_to_le16(conn->handle);
 		cp.handle = __cpu_to_le16(conn->handle);
 		hci_send_cmd(hdev, HCI_OP_AUTH_REQUESTED, sizeof(cp), &cp);
 		hci_send_cmd(hdev, HCI_OP_AUTH_REQUESTED, sizeof(cp), &cp);
@@ -1413,9 +1547,9 @@ static void hci_cs_sniff_mode(struct hci_dev *hdev, __u8 status)
 
 
 	conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(cp->handle));
 	conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(cp->handle));
 	if (conn) {
 	if (conn) {
-		clear_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->pend);
+		clear_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->flags);
 
 
-		if (test_and_clear_bit(HCI_CONN_SCO_SETUP_PEND, &conn->pend))
+		if (test_and_clear_bit(HCI_CONN_SCO_SETUP_PEND, &conn->flags))
 			hci_sco_setup(conn, status);
 			hci_sco_setup(conn, status);
 	}
 	}
 
 
@@ -1440,15 +1574,37 @@ static void hci_cs_exit_sniff_mode(struct hci_dev *hdev, __u8 status)
 
 
 	conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(cp->handle));
 	conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(cp->handle));
 	if (conn) {
 	if (conn) {
-		clear_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->pend);
+		clear_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->flags);
 
 
-		if (test_and_clear_bit(HCI_CONN_SCO_SETUP_PEND, &conn->pend))
+		if (test_and_clear_bit(HCI_CONN_SCO_SETUP_PEND, &conn->flags))
 			hci_sco_setup(conn, status);
 			hci_sco_setup(conn, status);
 	}
 	}
 
 
 	hci_dev_unlock(hdev);
 	hci_dev_unlock(hdev);
 }
 }
 
 
+static void hci_cs_disconnect(struct hci_dev *hdev, u8 status)
+{
+	struct hci_cp_disconnect *cp;
+	struct hci_conn *conn;
+
+	if (!status)
+		return;
+
+	cp = hci_sent_cmd_data(hdev, HCI_OP_DISCONNECT);
+	if (!cp)
+		return;
+
+	hci_dev_lock(hdev);
+
+	conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(cp->handle));
+	if (conn)
+		mgmt_disconnect_failed(hdev, &conn->dst, conn->type,
+				       conn->dst_type, status);
+
+	hci_dev_unlock(hdev);
+}
+
 static void hci_cs_le_create_conn(struct hci_dev *hdev, __u8 status)
 static void hci_cs_le_create_conn(struct hci_dev *hdev, __u8 status)
 {
 {
 	struct hci_cp_le_create_conn *cp;
 	struct hci_cp_le_create_conn *cp;
@@ -1478,7 +1634,7 @@ static void hci_cs_le_create_conn(struct hci_dev *hdev, __u8 status)
 			conn = hci_conn_add(hdev, LE_LINK, &cp->peer_addr);
 			conn = hci_conn_add(hdev, LE_LINK, &cp->peer_addr);
 			if (conn) {
 			if (conn) {
 				conn->dst_type = cp->peer_addr_type;
 				conn->dst_type = cp->peer_addr_type;
-				conn->out = 1;
+				conn->out = true;
 			} else {
 			} else {
 				BT_ERR("No memory for new connection");
 				BT_ERR("No memory for new connection");
 			}
 			}
@@ -1496,6 +1652,8 @@ static void hci_cs_le_start_enc(struct hci_dev *hdev, u8 status)
 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);
+	struct discovery_state *discov = &hdev->discovery;
+	struct inquiry_entry *e;
 
 
 	BT_DBG("%s status %d", hdev->name, status);
 	BT_DBG("%s status %d", hdev->name, status);
 
 
@@ -1506,8 +1664,28 @@ static inline void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff
 	if (!test_and_clear_bit(HCI_INQUIRY, &hdev->flags))
 	if (!test_and_clear_bit(HCI_INQUIRY, &hdev->flags))
 		return;
 		return;
 
 
+	if (!test_bit(HCI_MGMT, &hdev->dev_flags))
+		return;
+
 	hci_dev_lock(hdev);
 	hci_dev_lock(hdev);
-	mgmt_discovering(hdev, 0);
+
+	if (discov->state != DISCOVERY_FINDING)
+		goto unlock;
+
+	if (list_empty(&discov->resolve)) {
+		hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
+		goto unlock;
+	}
+
+	e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY, NAME_NEEDED);
+	if (e && hci_resolve_name(hdev, e) == 0) {
+		e->name_state = NAME_PENDING;
+		hci_discovery_set_state(hdev, DISCOVERY_RESOLVING);
+	} else {
+		hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
+	}
+
+unlock:
 	hci_dev_unlock(hdev);
 	hci_dev_unlock(hdev);
 }
 }
 
 
@@ -1525,6 +1703,8 @@ static inline void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *
 	hci_dev_lock(hdev);
 	hci_dev_lock(hdev);
 
 
 	for (; num_rsp; num_rsp--, info++) {
 	for (; num_rsp; num_rsp--, info++) {
+		bool name_known, ssp;
+
 		bacpy(&data.bdaddr, &info->bdaddr);
 		bacpy(&data.bdaddr, &info->bdaddr);
 		data.pscan_rep_mode	= info->pscan_rep_mode;
 		data.pscan_rep_mode	= info->pscan_rep_mode;
 		data.pscan_period_mode	= info->pscan_period_mode;
 		data.pscan_period_mode	= info->pscan_period_mode;
@@ -1533,9 +1713,11 @@ static inline void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *
 		data.clock_offset	= info->clock_offset;
 		data.clock_offset	= info->clock_offset;
 		data.rssi		= 0x00;
 		data.rssi		= 0x00;
 		data.ssp_mode		= 0x00;
 		data.ssp_mode		= 0x00;
-		hci_inquiry_cache_update(hdev, &data);
+
+		name_known = hci_inquiry_cache_update(hdev, &data, false, &ssp);
 		mgmt_device_found(hdev, &info->bdaddr, ACL_LINK, 0x00,
 		mgmt_device_found(hdev, &info->bdaddr, ACL_LINK, 0x00,
-						info->dev_class, 0, NULL);
+				  info->dev_class, 0, !name_known, ssp, NULL,
+				  0);
 	}
 	}
 
 
 	hci_dev_unlock(hdev);
 	hci_dev_unlock(hdev);
@@ -1569,8 +1751,6 @@ 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,
-							conn->dst_type);
 		} else
 		} else
 			conn->state = BT_CONNECTED;
 			conn->state = BT_CONNECTED;
 
 
@@ -1588,7 +1768,7 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s
 			struct hci_cp_read_remote_features cp;
 			struct hci_cp_read_remote_features cp;
 			cp.handle = ev->handle;
 			cp.handle = ev->handle;
 			hci_send_cmd(hdev, HCI_OP_READ_REMOTE_FEATURES,
 			hci_send_cmd(hdev, HCI_OP_READ_REMOTE_FEATURES,
-							sizeof(cp), &cp);
+				     sizeof(cp), &cp);
 		}
 		}
 
 
 		/* Set packet type for incoming connection */
 		/* Set packet type for incoming connection */
@@ -1596,14 +1776,14 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s
 			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);
-			hci_send_cmd(hdev, HCI_OP_CHANGE_CONN_PTYPE,
-							sizeof(cp), &cp);
+			hci_send_cmd(hdev, HCI_OP_CHANGE_CONN_PTYPE, sizeof(cp),
+				     &cp);
 		}
 		}
 	} else {
 	} else {
 		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,
-						conn->dst_type, ev->status);
+					    conn->dst_type, ev->status);
 	}
 	}
 
 
 	if (conn->type == ACL_LINK)
 	if (conn->type == ACL_LINK)
@@ -1668,8 +1848,8 @@ static inline void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *sk
 			else
 			else
 				cp.role = 0x01; /* Remain slave */
 				cp.role = 0x01; /* Remain slave */
 
 
-			hci_send_cmd(hdev, HCI_OP_ACCEPT_CONN_REQ,
-							sizeof(cp), &cp);
+			hci_send_cmd(hdev, HCI_OP_ACCEPT_CONN_REQ, sizeof(cp),
+				     &cp);
 		} else {
 		} else {
 			struct hci_cp_accept_sync_conn_req cp;
 			struct hci_cp_accept_sync_conn_req cp;
 
 
@@ -1683,7 +1863,7 @@ static inline void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *sk
 			cp.retrans_effort = 0xff;
 			cp.retrans_effort = 0xff;
 
 
 			hci_send_cmd(hdev, HCI_OP_ACCEPT_SYNC_CONN_REQ,
 			hci_send_cmd(hdev, HCI_OP_ACCEPT_SYNC_CONN_REQ,
-							sizeof(cp), &cp);
+				     sizeof(cp), &cp);
 		}
 		}
 	} else {
 	} else {
 		/* Connection rejected */
 		/* Connection rejected */
@@ -1711,12 +1891,14 @@ static inline void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff
 	if (ev->status == 0)
 	if (ev->status == 0)
 		conn->state = BT_CLOSED;
 		conn->state = BT_CLOSED;
 
 
-	if (conn->type == ACL_LINK || conn->type == LE_LINK) {
+	if (test_and_clear_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags) &&
+			(conn->type == ACL_LINK || conn->type == LE_LINK)) {
 		if (ev->status != 0)
 		if (ev->status != 0)
-			mgmt_disconnect_failed(hdev, &conn->dst, ev->status);
+			mgmt_disconnect_failed(hdev, &conn->dst, conn->type,
+						conn->dst_type, ev->status);
 		else
 		else
-			mgmt_disconnected(hdev, &conn->dst, conn->type,
-							conn->dst_type);
+			mgmt_device_disconnected(hdev, &conn->dst, conn->type,
+						 conn->dst_type);
 	}
 	}
 
 
 	if (ev->status == 0) {
 	if (ev->status == 0) {
@@ -1742,22 +1924,23 @@ static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *s
 		goto unlock;
 		goto unlock;
 
 
 	if (!ev->status) {
 	if (!ev->status) {
-		if (!(conn->ssp_mode > 0 && hdev->ssp_mode > 0) &&
-				test_bit(HCI_CONN_REAUTH_PEND,	&conn->pend)) {
+		if (!hci_conn_ssp_enabled(conn) &&
+				test_bit(HCI_CONN_REAUTH_PEND, &conn->flags)) {
 			BT_INFO("re-auth of legacy device is not possible.");
 			BT_INFO("re-auth of legacy device is not possible.");
 		} else {
 		} else {
 			conn->link_mode |= HCI_LM_AUTH;
 			conn->link_mode |= HCI_LM_AUTH;
 			conn->sec_level = conn->pending_sec_level;
 			conn->sec_level = conn->pending_sec_level;
 		}
 		}
 	} else {
 	} else {
-		mgmt_auth_failed(hdev, &conn->dst, ev->status);
+		mgmt_auth_failed(hdev, &conn->dst, conn->type, conn->dst_type,
+				 ev->status);
 	}
 	}
 
 
-	clear_bit(HCI_CONN_AUTH_PEND, &conn->pend);
-	clear_bit(HCI_CONN_REAUTH_PEND, &conn->pend);
+	clear_bit(HCI_CONN_AUTH_PEND, &conn->flags);
+	clear_bit(HCI_CONN_REAUTH_PEND, &conn->flags);
 
 
 	if (conn->state == BT_CONFIG) {
 	if (conn->state == BT_CONFIG) {
-		if (!ev->status && hdev->ssp_mode > 0 && conn->ssp_mode > 0) {
+		if (!ev->status && hci_conn_ssp_enabled(conn)) {
 			struct hci_cp_set_conn_encrypt cp;
 			struct hci_cp_set_conn_encrypt cp;
 			cp.handle  = ev->handle;
 			cp.handle  = ev->handle;
 			cp.encrypt = 0x01;
 			cp.encrypt = 0x01;
@@ -1776,7 +1959,7 @@ static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *s
 		hci_conn_put(conn);
 		hci_conn_put(conn);
 	}
 	}
 
 
-	if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend)) {
+	if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags)) {
 		if (!ev->status) {
 		if (!ev->status) {
 			struct hci_cp_set_conn_encrypt cp;
 			struct hci_cp_set_conn_encrypt cp;
 			cp.handle  = ev->handle;
 			cp.handle  = ev->handle;
@@ -1784,7 +1967,7 @@ static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *s
 			hci_send_cmd(hdev, HCI_OP_SET_CONN_ENCRYPT, sizeof(cp),
 			hci_send_cmd(hdev, HCI_OP_SET_CONN_ENCRYPT, sizeof(cp),
 									&cp);
 									&cp);
 		} else {
 		} else {
-			clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend);
+			clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags);
 			hci_encrypt_cfm(conn, ev->status, 0x00);
 			hci_encrypt_cfm(conn, ev->status, 0x00);
 		}
 		}
 	}
 	}
@@ -1804,17 +1987,25 @@ static inline void hci_remote_name_evt(struct hci_dev *hdev, struct sk_buff *skb
 
 
 	hci_dev_lock(hdev);
 	hci_dev_lock(hdev);
 
 
-	if (ev->status == 0 && test_bit(HCI_MGMT, &hdev->flags))
-		mgmt_remote_name(hdev, &ev->bdaddr, ev->name);
-
 	conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
 	conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
+
+	if (!test_bit(HCI_MGMT, &hdev->dev_flags))
+		goto check_auth;
+
+	if (ev->status == 0)
+		hci_check_pending_name(hdev, conn, &ev->bdaddr, ev->name,
+				       strnlen(ev->name, HCI_MAX_NAME_LENGTH));
+	else
+		hci_check_pending_name(hdev, conn, &ev->bdaddr, NULL, 0);
+
+check_auth:
 	if (!conn)
 	if (!conn)
 		goto unlock;
 		goto unlock;
 
 
 	if (!hci_outgoing_auth_needed(hdev, conn))
 	if (!hci_outgoing_auth_needed(hdev, conn))
 		goto unlock;
 		goto unlock;
 
 
-	if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->pend)) {
+	if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->flags)) {
 		struct hci_cp_auth_requested cp;
 		struct hci_cp_auth_requested cp;
 		cp.handle = __cpu_to_le16(conn->handle);
 		cp.handle = __cpu_to_le16(conn->handle);
 		hci_send_cmd(hdev, HCI_OP_AUTH_REQUESTED, sizeof(cp), &cp);
 		hci_send_cmd(hdev, HCI_OP_AUTH_REQUESTED, sizeof(cp), &cp);
@@ -1845,7 +2036,7 @@ static inline void hci_encrypt_change_evt(struct hci_dev *hdev, struct sk_buff *
 				conn->link_mode &= ~HCI_LM_ENCRYPT;
 				conn->link_mode &= ~HCI_LM_ENCRYPT;
 		}
 		}
 
 
-		clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend);
+		clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags);
 
 
 		if (conn->state == BT_CONFIG) {
 		if (conn->state == BT_CONFIG) {
 			if (!ev->status)
 			if (!ev->status)
@@ -1874,7 +2065,7 @@ static inline void hci_change_link_key_complete_evt(struct hci_dev *hdev, struct
 		if (!ev->status)
 		if (!ev->status)
 			conn->link_mode |= HCI_LM_SECURE;
 			conn->link_mode |= HCI_LM_SECURE;
 
 
-		clear_bit(HCI_CONN_AUTH_PEND, &conn->pend);
+		clear_bit(HCI_CONN_AUTH_PEND, &conn->flags);
 
 
 		hci_key_change_cfm(conn, ev->status);
 		hci_key_change_cfm(conn, ev->status);
 	}
 	}
@@ -1916,7 +2107,10 @@ static inline void hci_remote_features_evt(struct hci_dev *hdev, struct sk_buff
 		bacpy(&cp.bdaddr, &conn->dst);
 		bacpy(&cp.bdaddr, &conn->dst);
 		cp.pscan_rep_mode = 0x02;
 		cp.pscan_rep_mode = 0x02;
 		hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ, sizeof(cp), &cp);
 		hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ, sizeof(cp), &cp);
-	}
+	} else if (!test_and_set_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags))
+		mgmt_device_connected(hdev, &conn->dst, conn->type,
+				      conn->dst_type, 0, NULL, 0,
+				      conn->dev_class);
 
 
 	if (!hci_outgoing_auth_needed(hdev, conn)) {
 	if (!hci_outgoing_auth_needed(hdev, conn)) {
 		conn->state = BT_CONNECTED;
 		conn->state = BT_CONNECTED;
@@ -2024,10 +2218,6 @@ static inline void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *sk
 		hci_cc_host_buffer_size(hdev, skb);
 		hci_cc_host_buffer_size(hdev, skb);
 		break;
 		break;
 
 
-	case HCI_OP_READ_SSP_MODE:
-		hci_cc_read_ssp_mode(hdev, skb);
-		break;
-
 	case HCI_OP_WRITE_SSP_MODE:
 	case HCI_OP_WRITE_SSP_MODE:
 		hci_cc_write_ssp_mode(hdev, skb);
 		hci_cc_write_ssp_mode(hdev, skb);
 		break;
 		break;
@@ -2213,8 +2403,7 @@ static inline void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb)
 		break;
 		break;
 
 
 	case HCI_OP_DISCONNECT:
 	case HCI_OP_DISCONNECT:
-		if (ev->status != 0)
-			mgmt_disconnect_failed(hdev, NULL, ev->status);
+		hci_cs_disconnect(hdev, ev->status);
 		break;
 		break;
 
 
 	case HCI_OP_LE_CREATE_CONN:
 	case HCI_OP_LE_CREATE_CONN:
@@ -2258,7 +2447,7 @@ static inline void hci_role_change_evt(struct hci_dev *hdev, struct sk_buff *skb
 				conn->link_mode |= HCI_LM_MASTER;
 				conn->link_mode |= HCI_LM_MASTER;
 		}
 		}
 
 
-		clear_bit(HCI_CONN_RSWITCH_PEND, &conn->pend);
+		clear_bit(HCI_CONN_RSWITCH_PEND, &conn->flags);
 
 
 		hci_role_switch_cfm(conn, ev->status, ev->role);
 		hci_role_switch_cfm(conn, ev->status, ev->role);
 	}
 	}
@@ -2332,6 +2521,56 @@ static inline void hci_num_comp_pkts_evt(struct hci_dev *hdev, struct sk_buff *s
 	queue_work(hdev->workqueue, &hdev->tx_work);
 	queue_work(hdev->workqueue, &hdev->tx_work);
 }
 }
 
 
+static inline void hci_num_comp_blocks_evt(struct hci_dev *hdev,
+					   struct sk_buff *skb)
+{
+	struct hci_ev_num_comp_blocks *ev = (void *) skb->data;
+	int i;
+
+	if (hdev->flow_ctl_mode != HCI_FLOW_CTL_MODE_BLOCK_BASED) {
+		BT_ERR("Wrong event for mode %d", hdev->flow_ctl_mode);
+		return;
+	}
+
+	if (skb->len < sizeof(*ev) || skb->len < sizeof(*ev) +
+			ev->num_hndl * sizeof(struct hci_comp_blocks_info)) {
+		BT_DBG("%s bad parameters", hdev->name);
+		return;
+	}
+
+	BT_DBG("%s num_blocks %d num_hndl %d", hdev->name, ev->num_blocks,
+								ev->num_hndl);
+
+	for (i = 0; i < ev->num_hndl; i++) {
+		struct hci_comp_blocks_info *info = &ev->handles[i];
+		struct hci_conn *conn;
+		__u16  handle, block_count;
+
+		handle = __le16_to_cpu(info->handle);
+		block_count = __le16_to_cpu(info->blocks);
+
+		conn = hci_conn_hash_lookup_handle(hdev, handle);
+		if (!conn)
+			continue;
+
+		conn->sent -= block_count;
+
+		switch (conn->type) {
+		case ACL_LINK:
+			hdev->block_cnt += block_count;
+			if (hdev->block_cnt > hdev->num_blocks)
+				hdev->block_cnt = hdev->num_blocks;
+			break;
+
+		default:
+			BT_ERR("Unknown type %d conn %p", conn->type, conn);
+			break;
+		}
+	}
+
+	queue_work(hdev->workqueue, &hdev->tx_work);
+}
+
 static inline void hci_mode_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
 static inline void hci_mode_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
 {
 	struct hci_ev_mode_change *ev = (void *) skb->data;
 	struct hci_ev_mode_change *ev = (void *) skb->data;
@@ -2346,14 +2585,14 @@ static inline void hci_mode_change_evt(struct hci_dev *hdev, struct sk_buff *skb
 		conn->mode = ev->mode;
 		conn->mode = ev->mode;
 		conn->interval = __le16_to_cpu(ev->interval);
 		conn->interval = __le16_to_cpu(ev->interval);
 
 
-		if (!test_and_clear_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->pend)) {
+		if (!test_and_clear_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->flags)) {
 			if (conn->mode == HCI_CM_ACTIVE)
 			if (conn->mode == HCI_CM_ACTIVE)
-				conn->power_save = 1;
+				set_bit(HCI_CONN_POWER_SAVE, &conn->flags);
 			else
 			else
-				conn->power_save = 0;
+				clear_bit(HCI_CONN_POWER_SAVE, &conn->flags);
 		}
 		}
 
 
-		if (test_and_clear_bit(HCI_CONN_SCO_SETUP_PEND, &conn->pend))
+		if (test_and_clear_bit(HCI_CONN_SCO_SETUP_PEND, &conn->flags))
 			hci_sco_setup(conn, ev->status);
 			hci_sco_setup(conn, ev->status);
 	}
 	}
 
 
@@ -2379,10 +2618,10 @@ static inline void hci_pin_code_request_evt(struct hci_dev *hdev, struct sk_buff
 		hci_conn_put(conn);
 		hci_conn_put(conn);
 	}
 	}
 
 
-	if (!test_bit(HCI_PAIRABLE, &hdev->flags))
+	if (!test_bit(HCI_PAIRABLE, &hdev->dev_flags))
 		hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
 		hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
 					sizeof(ev->bdaddr), &ev->bdaddr);
 					sizeof(ev->bdaddr), &ev->bdaddr);
-	else if (test_bit(HCI_MGMT, &hdev->flags)) {
+	else if (test_bit(HCI_MGMT, &hdev->dev_flags)) {
 		u8 secure;
 		u8 secure;
 
 
 		if (conn->pending_sec_level == BT_SECURITY_HIGH)
 		if (conn->pending_sec_level == BT_SECURITY_HIGH)
@@ -2406,7 +2645,7 @@ static inline void hci_link_key_request_evt(struct hci_dev *hdev, struct sk_buff
 
 
 	BT_DBG("%s", hdev->name);
 	BT_DBG("%s", hdev->name);
 
 
-	if (!test_bit(HCI_LINK_KEYS, &hdev->flags))
+	if (!test_bit(HCI_LINK_KEYS, &hdev->dev_flags))
 		return;
 		return;
 
 
 	hci_dev_lock(hdev);
 	hci_dev_lock(hdev);
@@ -2421,7 +2660,7 @@ static inline void hci_link_key_request_evt(struct hci_dev *hdev, struct sk_buff
 	BT_DBG("%s found key type %u for %s", hdev->name, key->type,
 	BT_DBG("%s found key type %u for %s", hdev->name, key->type,
 							batostr(&ev->bdaddr));
 							batostr(&ev->bdaddr));
 
 
-	if (!test_bit(HCI_DEBUG_KEYS, &hdev->flags) &&
+	if (!test_bit(HCI_DEBUG_KEYS, &hdev->dev_flags) &&
 				key->type == HCI_LK_DEBUG_COMBINATION) {
 				key->type == HCI_LK_DEBUG_COMBINATION) {
 		BT_DBG("%s ignoring debug key", hdev->name);
 		BT_DBG("%s ignoring debug key", hdev->name);
 		goto not_found;
 		goto not_found;
@@ -2483,7 +2722,7 @@ static inline void hci_link_key_notify_evt(struct hci_dev *hdev, struct sk_buff
 		hci_conn_put(conn);
 		hci_conn_put(conn);
 	}
 	}
 
 
-	if (test_bit(HCI_LINK_KEYS, &hdev->flags))
+	if (test_bit(HCI_LINK_KEYS, &hdev->dev_flags))
 		hci_add_link_key(hdev, conn, 1, &ev->bdaddr, ev->link_key,
 		hci_add_link_key(hdev, conn, 1, &ev->bdaddr, ev->link_key,
 							ev->key_type, pin_len);
 							ev->key_type, pin_len);
 
 
@@ -2551,6 +2790,7 @@ static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct
 {
 {
 	struct inquiry_data data;
 	struct inquiry_data data;
 	int num_rsp = *((__u8 *) skb->data);
 	int num_rsp = *((__u8 *) skb->data);
+	bool name_known, ssp;
 
 
 	BT_DBG("%s num_rsp %d", hdev->name, num_rsp);
 	BT_DBG("%s num_rsp %d", hdev->name, num_rsp);
 
 
@@ -2572,10 +2812,12 @@ static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct
 			data.clock_offset	= info->clock_offset;
 			data.clock_offset	= info->clock_offset;
 			data.rssi		= info->rssi;
 			data.rssi		= info->rssi;
 			data.ssp_mode		= 0x00;
 			data.ssp_mode		= 0x00;
-			hci_inquiry_cache_update(hdev, &data);
+
+			name_known = hci_inquiry_cache_update(hdev, &data,
+							      false, &ssp);
 			mgmt_device_found(hdev, &info->bdaddr, ACL_LINK, 0x00,
 			mgmt_device_found(hdev, &info->bdaddr, ACL_LINK, 0x00,
-						info->dev_class, info->rssi,
-						NULL);
+					  info->dev_class, info->rssi,
+					  !name_known, ssp, NULL, 0);
 		}
 		}
 	} else {
 	} else {
 		struct inquiry_info_with_rssi *info = (void *) (skb->data + 1);
 		struct inquiry_info_with_rssi *info = (void *) (skb->data + 1);
@@ -2589,10 +2831,11 @@ static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct
 			data.clock_offset	= info->clock_offset;
 			data.clock_offset	= info->clock_offset;
 			data.rssi		= info->rssi;
 			data.rssi		= info->rssi;
 			data.ssp_mode		= 0x00;
 			data.ssp_mode		= 0x00;
-			hci_inquiry_cache_update(hdev, &data);
+			name_known = hci_inquiry_cache_update(hdev, &data,
+							      false, &ssp);
 			mgmt_device_found(hdev, &info->bdaddr, ACL_LINK, 0x00,
 			mgmt_device_found(hdev, &info->bdaddr, ACL_LINK, 0x00,
-						info->dev_class, info->rssi,
-						NULL);
+					  info->dev_class, info->rssi,
+					  !name_known, ssp, NULL, 0);
 		}
 		}
 	}
 	}
 
 
@@ -2617,9 +2860,10 @@ static inline void hci_remote_ext_features_evt(struct hci_dev *hdev, struct sk_b
 
 
 		ie = hci_inquiry_cache_lookup(hdev, &conn->dst);
 		ie = hci_inquiry_cache_lookup(hdev, &conn->dst);
 		if (ie)
 		if (ie)
-			ie->data.ssp_mode = (ev->features[0] & 0x01);
+			ie->data.ssp_mode = (ev->features[0] & LMP_HOST_SSP);
 
 
-		conn->ssp_mode = (ev->features[0] & 0x01);
+		if (ev->features[0] & LMP_HOST_SSP)
+			set_bit(HCI_CONN_SSP_ENABLED, &conn->flags);
 	}
 	}
 
 
 	if (conn->state != BT_CONFIG)
 	if (conn->state != BT_CONFIG)
@@ -2631,7 +2875,10 @@ static inline void hci_remote_ext_features_evt(struct hci_dev *hdev, struct sk_b
 		bacpy(&cp.bdaddr, &conn->dst);
 		bacpy(&cp.bdaddr, &conn->dst);
 		cp.pscan_rep_mode = 0x02;
 		cp.pscan_rep_mode = 0x02;
 		hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ, sizeof(cp), &cp);
 		hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ, sizeof(cp), &cp);
-	}
+	} else if (!test_and_set_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags))
+		mgmt_device_connected(hdev, &conn->dst, conn->type,
+				      conn->dst_type, 0, NULL, 0,
+				      conn->dev_class);
 
 
 	if (!hci_outgoing_auth_needed(hdev, conn)) {
 	if (!hci_outgoing_auth_needed(hdev, conn)) {
 		conn->state = BT_CONNECTED;
 		conn->state = BT_CONNECTED;
@@ -2724,6 +2971,8 @@ static inline void hci_extended_inquiry_result_evt(struct hci_dev *hdev, struct
 	hci_dev_lock(hdev);
 	hci_dev_lock(hdev);
 
 
 	for (; num_rsp; num_rsp--, info++) {
 	for (; num_rsp; num_rsp--, info++) {
+		bool name_known, ssp;
+
 		bacpy(&data.bdaddr, &info->bdaddr);
 		bacpy(&data.bdaddr, &info->bdaddr);
 		data.pscan_rep_mode	= info->pscan_rep_mode;
 		data.pscan_rep_mode	= info->pscan_rep_mode;
 		data.pscan_period_mode	= info->pscan_period_mode;
 		data.pscan_period_mode	= info->pscan_period_mode;
@@ -2732,9 +2981,19 @@ static inline void hci_extended_inquiry_result_evt(struct hci_dev *hdev, struct
 		data.clock_offset	= info->clock_offset;
 		data.clock_offset	= info->clock_offset;
 		data.rssi		= info->rssi;
 		data.rssi		= info->rssi;
 		data.ssp_mode		= 0x01;
 		data.ssp_mode		= 0x01;
-		hci_inquiry_cache_update(hdev, &data);
+
+		if (test_bit(HCI_MGMT, &hdev->dev_flags))
+			name_known = eir_has_data_type(info->data,
+						       sizeof(info->data),
+						       EIR_NAME_COMPLETE);
+		else
+			name_known = true;
+
+		name_known = hci_inquiry_cache_update(hdev, &data, name_known,
+						      &ssp);
 		mgmt_device_found(hdev, &info->bdaddr, ACL_LINK, 0x00,
 		mgmt_device_found(hdev, &info->bdaddr, ACL_LINK, 0x00,
-				info->dev_class, info->rssi, info->data);
+				  info->dev_class, info->rssi, !name_known,
+				  ssp, info->data, sizeof(info->data));
 	}
 	}
 
 
 	hci_dev_unlock(hdev);
 	hci_dev_unlock(hdev);
@@ -2774,19 +3033,22 @@ static inline void hci_io_capa_request_evt(struct hci_dev *hdev, struct sk_buff
 
 
 	hci_conn_hold(conn);
 	hci_conn_hold(conn);
 
 
-	if (!test_bit(HCI_MGMT, &hdev->flags))
+	if (!test_bit(HCI_MGMT, &hdev->dev_flags))
 		goto unlock;
 		goto unlock;
 
 
-	if (test_bit(HCI_PAIRABLE, &hdev->flags) ||
+	if (test_bit(HCI_PAIRABLE, &hdev->dev_flags) ||
 			(conn->remote_auth & ~0x01) == HCI_AT_NO_BONDING) {
 			(conn->remote_auth & ~0x01) == HCI_AT_NO_BONDING) {
 		struct hci_cp_io_capability_reply cp;
 		struct hci_cp_io_capability_reply cp;
 
 
 		bacpy(&cp.bdaddr, &ev->bdaddr);
 		bacpy(&cp.bdaddr, &ev->bdaddr);
-		cp.capability = conn->io_capability;
+		/* Change the IO capability from KeyboardDisplay
+		 * to DisplayYesNo as it is not supported by BT spec. */
+		cp.capability = (conn->io_capability == 0x04) ?
+						0x01 : conn->io_capability;
 		conn->auth_type = hci_get_auth_req(conn);
 		conn->auth_type = hci_get_auth_req(conn);
 		cp.authentication = conn->auth_type;
 		cp.authentication = conn->auth_type;
 
 
-		if ((conn->out == 0x01 || conn->remote_oob == 0x01) &&
+		if ((conn->out || test_bit(HCI_CONN_REMOTE_OOB, &conn->flags)) &&
 				hci_find_remote_oob_data(hdev, &conn->dst))
 				hci_find_remote_oob_data(hdev, &conn->dst))
 			cp.oob_data = 0x01;
 			cp.oob_data = 0x01;
 		else
 		else
@@ -2822,8 +3084,9 @@ static inline void hci_io_capa_reply_evt(struct hci_dev *hdev, struct sk_buff *s
 		goto unlock;
 		goto unlock;
 
 
 	conn->remote_cap = ev->capability;
 	conn->remote_cap = ev->capability;
-	conn->remote_oob = ev->oob_data;
 	conn->remote_auth = ev->authentication;
 	conn->remote_auth = ev->authentication;
+	if (ev->oob_data)
+		set_bit(HCI_CONN_REMOTE_OOB, &conn->flags);
 
 
 unlock:
 unlock:
 	hci_dev_unlock(hdev);
 	hci_dev_unlock(hdev);
@@ -2840,7 +3103,7 @@ static inline void hci_user_confirm_request_evt(struct hci_dev *hdev,
 
 
 	hci_dev_lock(hdev);
 	hci_dev_lock(hdev);
 
 
-	if (!test_bit(HCI_MGMT, &hdev->flags))
+	if (!test_bit(HCI_MGMT, &hdev->dev_flags))
 		goto unlock;
 		goto unlock;
 
 
 	conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
 	conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
@@ -2869,7 +3132,7 @@ static inline void hci_user_confirm_request_evt(struct hci_dev *hdev,
 		/* If we're not the initiators request authorization to
 		/* If we're not the initiators request authorization to
 		 * proceed from user space (mgmt_user_confirm with
 		 * proceed from user space (mgmt_user_confirm with
 		 * confirm_hint set to 1). */
 		 * confirm_hint set to 1). */
-		if (!test_bit(HCI_CONN_AUTH_PEND, &conn->pend)) {
+		if (!test_bit(HCI_CONN_AUTH_PEND, &conn->flags)) {
 			BT_DBG("Confirming auto-accept as acceptor");
 			BT_DBG("Confirming auto-accept as acceptor");
 			confirm_hint = 1;
 			confirm_hint = 1;
 			goto confirm;
 			goto confirm;
@@ -2890,8 +3153,8 @@ static inline void hci_user_confirm_request_evt(struct hci_dev *hdev,
 	}
 	}
 
 
 confirm:
 confirm:
-	mgmt_user_confirm_request(hdev, &ev->bdaddr, ev->passkey,
-								confirm_hint);
+	mgmt_user_confirm_request(hdev, &ev->bdaddr, ACL_LINK, 0, ev->passkey,
+				  confirm_hint);
 
 
 unlock:
 unlock:
 	hci_dev_unlock(hdev);
 	hci_dev_unlock(hdev);
@@ -2906,8 +3169,8 @@ static inline void hci_user_passkey_request_evt(struct hci_dev *hdev,
 
 
 	hci_dev_lock(hdev);
 	hci_dev_lock(hdev);
 
 
-	if (test_bit(HCI_MGMT, &hdev->flags))
-		mgmt_user_passkey_request(hdev, &ev->bdaddr);
+	if (test_bit(HCI_MGMT, &hdev->dev_flags))
+		mgmt_user_passkey_request(hdev, &ev->bdaddr, ACL_LINK, 0);
 
 
 	hci_dev_unlock(hdev);
 	hci_dev_unlock(hdev);
 }
 }
@@ -2930,8 +3193,9 @@ static inline void hci_simple_pair_complete_evt(struct hci_dev *hdev, struct sk_
 	 * initiated the authentication. A traditional auth_complete
 	 * initiated the authentication. A traditional auth_complete
 	 * event gets always produced as initiator and is also mapped to
 	 * event gets always produced as initiator and is also mapped to
 	 * the mgmt_auth_failed event */
 	 * the mgmt_auth_failed event */
-	if (!test_bit(HCI_CONN_AUTH_PEND, &conn->pend) && ev->status != 0)
-		mgmt_auth_failed(hdev, &conn->dst, ev->status);
+	if (!test_bit(HCI_CONN_AUTH_PEND, &conn->flags) && ev->status != 0)
+		mgmt_auth_failed(hdev, &conn->dst, conn->type, conn->dst_type,
+				 ev->status);
 
 
 	hci_conn_put(conn);
 	hci_conn_put(conn);
 
 
@@ -2950,13 +3214,13 @@ static inline void hci_remote_host_features_evt(struct hci_dev *hdev, struct sk_
 
 
 	ie = hci_inquiry_cache_lookup(hdev, &ev->bdaddr);
 	ie = hci_inquiry_cache_lookup(hdev, &ev->bdaddr);
 	if (ie)
 	if (ie)
-		ie->data.ssp_mode = (ev->features[0] & 0x01);
+		ie->data.ssp_mode = (ev->features[0] & LMP_HOST_SSP);
 
 
 	hci_dev_unlock(hdev);
 	hci_dev_unlock(hdev);
 }
 }
 
 
 static inline void hci_remote_oob_data_request_evt(struct hci_dev *hdev,
 static inline void hci_remote_oob_data_request_evt(struct hci_dev *hdev,
-							struct sk_buff *skb)
+						   struct sk_buff *skb)
 {
 {
 	struct hci_ev_remote_oob_data_request *ev = (void *) skb->data;
 	struct hci_ev_remote_oob_data_request *ev = (void *) skb->data;
 	struct oob_data *data;
 	struct oob_data *data;
@@ -2965,7 +3229,7 @@ static inline void hci_remote_oob_data_request_evt(struct hci_dev *hdev,
 
 
 	hci_dev_lock(hdev);
 	hci_dev_lock(hdev);
 
 
-	if (!test_bit(HCI_MGMT, &hdev->flags))
+	if (!test_bit(HCI_MGMT, &hdev->dev_flags))
 		goto unlock;
 		goto unlock;
 
 
 	data = hci_find_remote_oob_data(hdev, &ev->bdaddr);
 	data = hci_find_remote_oob_data(hdev, &ev->bdaddr);
@@ -3020,7 +3284,9 @@ static inline void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff
 		goto unlock;
 		goto unlock;
 	}
 	}
 
 
-	mgmt_connected(hdev, &ev->bdaddr, conn->type, conn->dst_type);
+	if (!test_and_set_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags))
+		mgmt_device_connected(hdev, &ev->bdaddr, conn->type,
+				      conn->dst_type, 0, NULL, 0, NULL);
 
 
 	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);
@@ -3040,6 +3306,7 @@ static inline void hci_le_adv_report_evt(struct hci_dev *hdev,
 {
 {
 	u8 num_reports = skb->data[0];
 	u8 num_reports = skb->data[0];
 	void *ptr = &skb->data[1];
 	void *ptr = &skb->data[1];
+	s8 rssi;
 
 
 	hci_dev_lock(hdev);
 	hci_dev_lock(hdev);
 
 
@@ -3048,6 +3315,10 @@ static inline void hci_le_adv_report_evt(struct hci_dev *hdev,
 
 
 		hci_add_adv_entry(hdev, ev);
 		hci_add_adv_entry(hdev, ev);
 
 
+		rssi = ev->data[ev->length];
+		mgmt_device_found(hdev, &ev->bdaddr, LE_LINK, ev->bdaddr_type,
+				  NULL, rssi, 0, 1, ev->data, ev->length);
+
 		ptr += sizeof(*ev) + ev->length + 1;
 		ptr += sizeof(*ev) + ev->length + 1;
 	}
 	}
 
 
@@ -3061,7 +3332,7 @@ static inline void hci_le_ltk_request_evt(struct hci_dev *hdev,
 	struct hci_cp_le_ltk_reply cp;
 	struct hci_cp_le_ltk_reply cp;
 	struct hci_cp_le_ltk_neg_reply neg;
 	struct hci_cp_le_ltk_neg_reply neg;
 	struct hci_conn *conn;
 	struct hci_conn *conn;
-	struct link_key *ltk;
+	struct smp_ltk *ltk;
 
 
 	BT_DBG("%s handle %d", hdev->name, cpu_to_le16(ev->handle));
 	BT_DBG("%s handle %d", hdev->name, cpu_to_le16(ev->handle));
 
 
@@ -3077,10 +3348,17 @@ static inline void hci_le_ltk_request_evt(struct hci_dev *hdev,
 
 
 	memcpy(cp.ltk, ltk->val, sizeof(ltk->val));
 	memcpy(cp.ltk, ltk->val, sizeof(ltk->val));
 	cp.handle = cpu_to_le16(conn->handle);
 	cp.handle = cpu_to_le16(conn->handle);
-	conn->pin_length = ltk->pin_len;
+
+	if (ltk->authenticated)
+		conn->sec_level = BT_SECURITY_HIGH;
 
 
 	hci_send_cmd(hdev, HCI_OP_LE_LTK_REPLY, sizeof(cp), &cp);
 	hci_send_cmd(hdev, HCI_OP_LE_LTK_REPLY, sizeof(cp), &cp);
 
 
+	if (ltk->type & HCI_SMP_STK) {
+		list_del(&ltk->list);
+		kfree(ltk);
+	}
+
 	hci_dev_unlock(hdev);
 	hci_dev_unlock(hdev);
 
 
 	return;
 	return;
@@ -3271,6 +3549,10 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
 		hci_remote_oob_data_request_evt(hdev, skb);
 		hci_remote_oob_data_request_evt(hdev, skb);
 		break;
 		break;
 
 
+	case HCI_EV_NUM_COMP_BLOCKS:
+		hci_num_comp_blocks_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;
@@ -3279,34 +3561,3 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
 	kfree_skb(skb);
 	kfree_skb(skb);
 	hdev->stat.evt_rx++;
 	hdev->stat.evt_rx++;
 }
 }
-
-/* Generate internal stack event */
-void hci_si_event(struct hci_dev *hdev, int type, int dlen, void *data)
-{
-	struct hci_event_hdr *hdr;
-	struct hci_ev_stack_internal *ev;
-	struct sk_buff *skb;
-
-	skb = bt_skb_alloc(HCI_EVENT_HDR_SIZE + sizeof(*ev) + dlen, GFP_ATOMIC);
-	if (!skb)
-		return;
-
-	hdr = (void *) skb_put(skb, HCI_EVENT_HDR_SIZE);
-	hdr->evt  = HCI_EV_STACK_INTERNAL;
-	hdr->plen = sizeof(*ev) + dlen;
-
-	ev  = (void *) skb_put(skb, sizeof(*ev) + dlen);
-	ev->type = type;
-	memcpy(ev->data, data, dlen);
-
-	bt_cb(skb)->incoming = 1;
-	__net_timestamp(skb);
-
-	bt_cb(skb)->pkt_type = HCI_EVENT_PKT;
-	skb->dev = (void *) hdev;
-	hci_send_to_sock(hdev, skb, NULL);
-	kfree_skb(skb);
-}
-
-module_param(enable_le, bool, 0644);
-MODULE_PARM_DESC(enable_le, "Enable LE support");

+ 383 - 86
net/bluetooth/hci_sock.c

@@ -48,8 +48,9 @@
 
 
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci_core.h>
 #include <net/bluetooth/hci_core.h>
+#include <net/bluetooth/hci_mon.h>
 
 
-static bool enable_mgmt;
+static atomic_t monitor_promisc = ATOMIC_INIT(0);
 
 
 /* ----- HCI socket interface ----- */
 /* ----- HCI socket interface ----- */
 
 
@@ -85,22 +86,20 @@ static struct bt_sock_list hci_sk_list = {
 };
 };
 
 
 /* Send frame to RAW socket */
 /* Send frame to RAW socket */
-void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb,
-							struct sock *skip_sk)
+void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb)
 {
 {
 	struct sock *sk;
 	struct sock *sk;
 	struct hlist_node *node;
 	struct hlist_node *node;
+	struct sk_buff *skb_copy = NULL;
 
 
 	BT_DBG("hdev %p len %d", hdev, skb->len);
 	BT_DBG("hdev %p len %d", hdev, skb->len);
 
 
 	read_lock(&hci_sk_list.lock);
 	read_lock(&hci_sk_list.lock);
+
 	sk_for_each(sk, node, &hci_sk_list.head) {
 	sk_for_each(sk, node, &hci_sk_list.head) {
 		struct hci_filter *flt;
 		struct hci_filter *flt;
 		struct sk_buff *nskb;
 		struct sk_buff *nskb;
 
 
-		if (sk == skip_sk)
-			continue;
-
 		if (sk->sk_state != BT_BOUND || hci_pi(sk)->hdev != hdev)
 		if (sk->sk_state != BT_BOUND || hci_pi(sk)->hdev != hdev)
 			continue;
 			continue;
 
 
@@ -108,12 +107,9 @@ void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb,
 		if (skb->sk == sk)
 		if (skb->sk == sk)
 			continue;
 			continue;
 
 
-		if (bt_cb(skb)->channel != hci_pi(sk)->channel)
+		if (hci_pi(sk)->channel != HCI_CHANNEL_RAW)
 			continue;
 			continue;
 
 
-		if (bt_cb(skb)->channel == HCI_CHANNEL_CONTROL)
-			goto clone;
-
 		/* Apply filter */
 		/* Apply filter */
 		flt = &hci_pi(sk)->filter;
 		flt = &hci_pi(sk)->filter;
 
 
@@ -137,21 +133,303 @@ void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb,
 				continue;
 				continue;
 		}
 		}
 
 
-clone:
+		if (!skb_copy) {
+			/* Create a private copy with headroom */
+			skb_copy = __pskb_copy(skb, 1, GFP_ATOMIC);
+			if (!skb_copy)
+				continue;
+
+			/* Put type byte before the data */
+			memcpy(skb_push(skb_copy, 1), &bt_cb(skb)->pkt_type, 1);
+		}
+
+		nskb = skb_clone(skb_copy, GFP_ATOMIC);
+		if (!nskb)
+			continue;
+
+		if (sock_queue_rcv_skb(sk, nskb))
+			kfree_skb(nskb);
+	}
+
+	read_unlock(&hci_sk_list.lock);
+
+	kfree_skb(skb_copy);
+}
+
+/* Send frame to control socket */
+void hci_send_to_control(struct sk_buff *skb, struct sock *skip_sk)
+{
+	struct sock *sk;
+	struct hlist_node *node;
+
+	BT_DBG("len %d", skb->len);
+
+	read_lock(&hci_sk_list.lock);
+
+	sk_for_each(sk, node, &hci_sk_list.head) {
+		struct sk_buff *nskb;
+
+		/* Skip the original socket */
+		if (sk == skip_sk)
+			continue;
+
+		if (sk->sk_state != BT_BOUND)
+			continue;
+
+		if (hci_pi(sk)->channel != HCI_CHANNEL_CONTROL)
+			continue;
+
 		nskb = skb_clone(skb, GFP_ATOMIC);
 		nskb = skb_clone(skb, GFP_ATOMIC);
 		if (!nskb)
 		if (!nskb)
 			continue;
 			continue;
 
 
-		/* Put type byte before the data */
-		if (bt_cb(skb)->channel == HCI_CHANNEL_RAW)
-			memcpy(skb_push(nskb, 1), &bt_cb(nskb)->pkt_type, 1);
+		if (sock_queue_rcv_skb(sk, nskb))
+			kfree_skb(nskb);
+	}
+
+	read_unlock(&hci_sk_list.lock);
+}
+
+/* Send frame to monitor socket */
+void hci_send_to_monitor(struct hci_dev *hdev, struct sk_buff *skb)
+{
+	struct sock *sk;
+	struct hlist_node *node;
+	struct sk_buff *skb_copy = NULL;
+	__le16 opcode;
+
+	if (!atomic_read(&monitor_promisc))
+		return;
+
+	BT_DBG("hdev %p len %d", hdev, skb->len);
+
+	switch (bt_cb(skb)->pkt_type) {
+	case HCI_COMMAND_PKT:
+		opcode = __constant_cpu_to_le16(HCI_MON_COMMAND_PKT);
+		break;
+	case HCI_EVENT_PKT:
+		opcode = __constant_cpu_to_le16(HCI_MON_EVENT_PKT);
+		break;
+	case HCI_ACLDATA_PKT:
+		if (bt_cb(skb)->incoming)
+			opcode = __constant_cpu_to_le16(HCI_MON_ACL_RX_PKT);
+		else
+			opcode = __constant_cpu_to_le16(HCI_MON_ACL_TX_PKT);
+		break;
+	case HCI_SCODATA_PKT:
+		if (bt_cb(skb)->incoming)
+			opcode = __constant_cpu_to_le16(HCI_MON_SCO_RX_PKT);
+		else
+			opcode = __constant_cpu_to_le16(HCI_MON_SCO_TX_PKT);
+		break;
+	default:
+		return;
+	}
+
+	read_lock(&hci_sk_list.lock);
+
+	sk_for_each(sk, node, &hci_sk_list.head) {
+		struct sk_buff *nskb;
+
+		if (sk->sk_state != BT_BOUND)
+			continue;
+
+		if (hci_pi(sk)->channel != HCI_CHANNEL_MONITOR)
+			continue;
+
+		if (!skb_copy) {
+			struct hci_mon_hdr *hdr;
+
+			/* Create a private copy with headroom */
+			skb_copy = __pskb_copy(skb, HCI_MON_HDR_SIZE, GFP_ATOMIC);
+			if (!skb_copy)
+				continue;
+
+			/* Put header before the data */
+			hdr = (void *) skb_push(skb_copy, HCI_MON_HDR_SIZE);
+			hdr->opcode = opcode;
+			hdr->index = cpu_to_le16(hdev->id);
+			hdr->len = cpu_to_le16(skb->len);
+		}
+
+		nskb = skb_clone(skb_copy, GFP_ATOMIC);
+		if (!nskb)
+			continue;
+
+		if (sock_queue_rcv_skb(sk, nskb))
+			kfree_skb(nskb);
+	}
+
+	read_unlock(&hci_sk_list.lock);
+
+	kfree_skb(skb_copy);
+}
+
+static void send_monitor_event(struct sk_buff *skb)
+{
+	struct sock *sk;
+	struct hlist_node *node;
+
+	BT_DBG("len %d", skb->len);
+
+	read_lock(&hci_sk_list.lock);
+
+	sk_for_each(sk, node, &hci_sk_list.head) {
+		struct sk_buff *nskb;
+
+		if (sk->sk_state != BT_BOUND)
+			continue;
+
+		if (hci_pi(sk)->channel != HCI_CHANNEL_MONITOR)
+			continue;
+
+		nskb = skb_clone(skb, GFP_ATOMIC);
+		if (!nskb)
+			continue;
 
 
 		if (sock_queue_rcv_skb(sk, nskb))
 		if (sock_queue_rcv_skb(sk, nskb))
 			kfree_skb(nskb);
 			kfree_skb(nskb);
 	}
 	}
+
 	read_unlock(&hci_sk_list.lock);
 	read_unlock(&hci_sk_list.lock);
 }
 }
 
 
+static struct sk_buff *create_monitor_event(struct hci_dev *hdev, int event)
+{
+	struct hci_mon_hdr *hdr;
+	struct hci_mon_new_index *ni;
+	struct sk_buff *skb;
+	__le16 opcode;
+
+	switch (event) {
+	case HCI_DEV_REG:
+		skb = bt_skb_alloc(HCI_MON_NEW_INDEX_SIZE, GFP_ATOMIC);
+		if (!skb)
+			return NULL;
+
+		ni = (void *) skb_put(skb, HCI_MON_NEW_INDEX_SIZE);
+		ni->type = hdev->dev_type;
+		ni->bus = hdev->bus;
+		bacpy(&ni->bdaddr, &hdev->bdaddr);
+		memcpy(ni->name, hdev->name, 8);
+
+		opcode = __constant_cpu_to_le16(HCI_MON_NEW_INDEX);
+		break;
+
+	case HCI_DEV_UNREG:
+		skb = bt_skb_alloc(0, GFP_ATOMIC);
+		if (!skb)
+			return NULL;
+
+		opcode = __constant_cpu_to_le16(HCI_MON_DEL_INDEX);
+		break;
+
+	default:
+		return NULL;
+	}
+
+	__net_timestamp(skb);
+
+	hdr = (void *) skb_push(skb, HCI_MON_HDR_SIZE);
+	hdr->opcode = opcode;
+	hdr->index = cpu_to_le16(hdev->id);
+	hdr->len = cpu_to_le16(skb->len - HCI_MON_HDR_SIZE);
+
+	return skb;
+}
+
+static void send_monitor_replay(struct sock *sk)
+{
+	struct hci_dev *hdev;
+
+	read_lock(&hci_dev_list_lock);
+
+	list_for_each_entry(hdev, &hci_dev_list, list) {
+		struct sk_buff *skb;
+
+		skb = create_monitor_event(hdev, HCI_DEV_REG);
+		if (!skb)
+			continue;
+
+		if (sock_queue_rcv_skb(sk, skb))
+			kfree_skb(skb);
+	}
+
+	read_unlock(&hci_dev_list_lock);
+}
+
+/* Generate internal stack event */
+static void hci_si_event(struct hci_dev *hdev, int type, int dlen, void *data)
+{
+	struct hci_event_hdr *hdr;
+	struct hci_ev_stack_internal *ev;
+	struct sk_buff *skb;
+
+	skb = bt_skb_alloc(HCI_EVENT_HDR_SIZE + sizeof(*ev) + dlen, GFP_ATOMIC);
+	if (!skb)
+		return;
+
+	hdr = (void *) skb_put(skb, HCI_EVENT_HDR_SIZE);
+	hdr->evt  = HCI_EV_STACK_INTERNAL;
+	hdr->plen = sizeof(*ev) + dlen;
+
+	ev  = (void *) skb_put(skb, sizeof(*ev) + dlen);
+	ev->type = type;
+	memcpy(ev->data, data, dlen);
+
+	bt_cb(skb)->incoming = 1;
+	__net_timestamp(skb);
+
+	bt_cb(skb)->pkt_type = HCI_EVENT_PKT;
+	skb->dev = (void *) hdev;
+	hci_send_to_sock(hdev, skb);
+	kfree_skb(skb);
+}
+
+void hci_sock_dev_event(struct hci_dev *hdev, int event)
+{
+	struct hci_ev_si_device ev;
+
+	BT_DBG("hdev %s event %d", hdev->name, event);
+
+	/* Send event to monitor */
+	if (atomic_read(&monitor_promisc)) {
+		struct sk_buff *skb;
+
+		skb = create_monitor_event(hdev, event);
+		if (skb) {
+			send_monitor_event(skb);
+			kfree_skb(skb);
+		}
+	}
+
+	/* Send event to sockets */
+	ev.event  = event;
+	ev.dev_id = hdev->id;
+	hci_si_event(NULL, HCI_EV_SI_DEVICE, sizeof(ev), &ev);
+
+	if (event == HCI_DEV_UNREG) {
+		struct sock *sk;
+		struct hlist_node *node;
+
+		/* Detach sockets from device */
+		read_lock(&hci_sk_list.lock);
+		sk_for_each(sk, node, &hci_sk_list.head) {
+			bh_lock_sock_nested(sk);
+			if (hci_pi(sk)->hdev == hdev) {
+				hci_pi(sk)->hdev = NULL;
+				sk->sk_err = EPIPE;
+				sk->sk_state = BT_OPEN;
+				sk->sk_state_change(sk);
+
+				hci_dev_put(hdev);
+			}
+			bh_unlock_sock(sk);
+		}
+		read_unlock(&hci_sk_list.lock);
+	}
+}
+
 static int hci_sock_release(struct socket *sock)
 static int hci_sock_release(struct socket *sock)
 {
 {
 	struct sock *sk = sock->sk;
 	struct sock *sk = sock->sk;
@@ -164,6 +442,9 @@ static int hci_sock_release(struct socket *sock)
 
 
 	hdev = hci_pi(sk)->hdev;
 	hdev = hci_pi(sk)->hdev;
 
 
+	if (hci_pi(sk)->channel == HCI_CHANNEL_MONITOR)
+		atomic_dec(&monitor_promisc);
+
 	bt_sock_unlink(&hci_sk_list, sk);
 	bt_sock_unlink(&hci_sk_list, sk);
 
 
 	if (hdev) {
 	if (hdev) {
@@ -190,7 +471,7 @@ static int hci_sock_blacklist_add(struct hci_dev *hdev, void __user *arg)
 
 
 	hci_dev_lock(hdev);
 	hci_dev_lock(hdev);
 
 
-	err = hci_blacklist_add(hdev, &bdaddr);
+	err = hci_blacklist_add(hdev, &bdaddr, 0);
 
 
 	hci_dev_unlock(hdev);
 	hci_dev_unlock(hdev);
 
 
@@ -207,7 +488,7 @@ static int hci_sock_blacklist_del(struct hci_dev *hdev, void __user *arg)
 
 
 	hci_dev_lock(hdev);
 	hci_dev_lock(hdev);
 
 
-	err = hci_blacklist_del(hdev, &bdaddr);
+	err = hci_blacklist_del(hdev, &bdaddr, 0);
 
 
 	hci_dev_unlock(hdev);
 	hci_dev_unlock(hdev);
 
 
@@ -340,34 +621,69 @@ static int hci_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_le
 	if (haddr.hci_family != AF_BLUETOOTH)
 	if (haddr.hci_family != AF_BLUETOOTH)
 		return -EINVAL;
 		return -EINVAL;
 
 
-	if (haddr.hci_channel > HCI_CHANNEL_CONTROL)
-		return -EINVAL;
-
-	if (haddr.hci_channel == HCI_CHANNEL_CONTROL) {
-		if (!enable_mgmt)
-			return -EINVAL;
-		set_bit(HCI_PI_MGMT_INIT, &hci_pi(sk)->flags);
-	}
-
 	lock_sock(sk);
 	lock_sock(sk);
 
 
-	if (sk->sk_state == BT_BOUND || hci_pi(sk)->hdev) {
+	if (sk->sk_state == BT_BOUND) {
 		err = -EALREADY;
 		err = -EALREADY;
 		goto done;
 		goto done;
 	}
 	}
 
 
-	if (haddr.hci_dev != HCI_DEV_NONE) {
-		hdev = hci_dev_get(haddr.hci_dev);
-		if (!hdev) {
-			err = -ENODEV;
+	switch (haddr.hci_channel) {
+	case HCI_CHANNEL_RAW:
+		if (hci_pi(sk)->hdev) {
+			err = -EALREADY;
 			goto done;
 			goto done;
 		}
 		}
 
 
-		atomic_inc(&hdev->promisc);
+		if (haddr.hci_dev != HCI_DEV_NONE) {
+			hdev = hci_dev_get(haddr.hci_dev);
+			if (!hdev) {
+				err = -ENODEV;
+				goto done;
+			}
+
+			atomic_inc(&hdev->promisc);
+		}
+
+		hci_pi(sk)->hdev = hdev;
+		break;
+
+	case HCI_CHANNEL_CONTROL:
+		if (haddr.hci_dev != HCI_DEV_NONE) {
+			err = -EINVAL;
+			goto done;
+		}
+
+		if (!capable(CAP_NET_ADMIN)) {
+			err = -EPERM;
+			goto done;
+		}
+
+		break;
+
+	case HCI_CHANNEL_MONITOR:
+		if (haddr.hci_dev != HCI_DEV_NONE) {
+			err = -EINVAL;
+			goto done;
+		}
+
+		if (!capable(CAP_NET_RAW)) {
+			err = -EPERM;
+			goto done;
+		}
+
+		send_monitor_replay(sk);
+
+		atomic_inc(&monitor_promisc);
+		break;
+
+	default:
+		err = -EINVAL;
+		goto done;
 	}
 	}
 
 
+
 	hci_pi(sk)->channel = haddr.hci_channel;
 	hci_pi(sk)->channel = haddr.hci_channel;
-	hci_pi(sk)->hdev = hdev;
 	sk->sk_state = BT_BOUND;
 	sk->sk_state = BT_BOUND;
 
 
 done:
 done:
@@ -461,7 +777,15 @@ static int hci_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
 	skb_reset_transport_header(skb);
 	skb_reset_transport_header(skb);
 	err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
 	err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
 
 
-	hci_sock_cmsg(sk, msg, skb);
+	switch (hci_pi(sk)->channel) {
+	case HCI_CHANNEL_RAW:
+		hci_sock_cmsg(sk, msg, skb);
+		break;
+	case HCI_CHANNEL_CONTROL:
+	case HCI_CHANNEL_MONITOR:
+		sock_recv_timestamp(msg, sk, skb);
+		break;
+	}
 
 
 	skb_free_datagram(sk, skb);
 	skb_free_datagram(sk, skb);
 
 
@@ -495,6 +819,9 @@ static int hci_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
 	case HCI_CHANNEL_CONTROL:
 	case HCI_CHANNEL_CONTROL:
 		err = mgmt_control(sk, msg, len);
 		err = mgmt_control(sk, msg, len);
 		goto done;
 		goto done;
+	case HCI_CHANNEL_MONITOR:
+		err = -EOPNOTSUPP;
+		goto done;
 	default:
 	default:
 		err = -EINVAL;
 		err = -EINVAL;
 		goto done;
 		goto done;
@@ -574,6 +901,11 @@ static int hci_sock_setsockopt(struct socket *sock, int level, int optname, char
 
 
 	lock_sock(sk);
 	lock_sock(sk);
 
 
+	if (hci_pi(sk)->channel != HCI_CHANNEL_RAW) {
+		err = -EINVAL;
+		goto done;
+	}
+
 	switch (optname) {
 	switch (optname) {
 	case HCI_DATA_DIR:
 	case HCI_DATA_DIR:
 		if (get_user(opt, (int __user *)optval)) {
 		if (get_user(opt, (int __user *)optval)) {
@@ -636,6 +968,7 @@ static int hci_sock_setsockopt(struct socket *sock, int level, int optname, char
 		break;
 		break;
 	}
 	}
 
 
+done:
 	release_sock(sk);
 	release_sock(sk);
 	return err;
 	return err;
 }
 }
@@ -644,11 +977,20 @@ static int hci_sock_getsockopt(struct socket *sock, int level, int optname, char
 {
 {
 	struct hci_ufilter uf;
 	struct hci_ufilter uf;
 	struct sock *sk = sock->sk;
 	struct sock *sk = sock->sk;
-	int len, opt;
+	int len, opt, err = 0;
+
+	BT_DBG("sk %p, opt %d", sk, optname);
 
 
 	if (get_user(len, optlen))
 	if (get_user(len, optlen))
 		return -EFAULT;
 		return -EFAULT;
 
 
+	lock_sock(sk);
+
+	if (hci_pi(sk)->channel != HCI_CHANNEL_RAW) {
+		err = -EINVAL;
+		goto done;
+	}
+
 	switch (optname) {
 	switch (optname) {
 	case HCI_DATA_DIR:
 	case HCI_DATA_DIR:
 		if (hci_pi(sk)->cmsg_mask & HCI_CMSG_DIR)
 		if (hci_pi(sk)->cmsg_mask & HCI_CMSG_DIR)
@@ -657,7 +999,7 @@ static int hci_sock_getsockopt(struct socket *sock, int level, int optname, char
 			opt = 0;
 			opt = 0;
 
 
 		if (put_user(opt, optval))
 		if (put_user(opt, optval))
-			return -EFAULT;
+			err = -EFAULT;
 		break;
 		break;
 
 
 	case HCI_TIME_STAMP:
 	case HCI_TIME_STAMP:
@@ -667,7 +1009,7 @@ static int hci_sock_getsockopt(struct socket *sock, int level, int optname, char
 			opt = 0;
 			opt = 0;
 
 
 		if (put_user(opt, optval))
 		if (put_user(opt, optval))
-			return -EFAULT;
+			err = -EFAULT;
 		break;
 		break;
 
 
 	case HCI_FILTER:
 	case HCI_FILTER:
@@ -682,15 +1024,17 @@ static int hci_sock_getsockopt(struct socket *sock, int level, int optname, char
 
 
 		len = min_t(unsigned int, len, sizeof(uf));
 		len = min_t(unsigned int, len, sizeof(uf));
 		if (copy_to_user(optval, &uf, len))
 		if (copy_to_user(optval, &uf, len))
-			return -EFAULT;
+			err = -EFAULT;
 		break;
 		break;
 
 
 	default:
 	default:
-		return -ENOPROTOOPT;
+		err = -ENOPROTOOPT;
 		break;
 		break;
 	}
 	}
 
 
-	return 0;
+done:
+	release_sock(sk);
+	return err;
 }
 }
 
 
 static const struct proto_ops hci_sock_ops = {
 static const struct proto_ops hci_sock_ops = {
@@ -748,52 +1092,12 @@ static int hci_sock_create(struct net *net, struct socket *sock, int protocol,
 	return 0;
 	return 0;
 }
 }
 
 
-static int hci_sock_dev_event(struct notifier_block *this, unsigned long event, void *ptr)
-{
-	struct hci_dev *hdev = (struct hci_dev *) ptr;
-	struct hci_ev_si_device ev;
-
-	BT_DBG("hdev %s event %ld", hdev->name, event);
-
-	/* Send event to sockets */
-	ev.event  = event;
-	ev.dev_id = hdev->id;
-	hci_si_event(NULL, HCI_EV_SI_DEVICE, sizeof(ev), &ev);
-
-	if (event == HCI_DEV_UNREG) {
-		struct sock *sk;
-		struct hlist_node *node;
-
-		/* Detach sockets from device */
-		read_lock(&hci_sk_list.lock);
-		sk_for_each(sk, node, &hci_sk_list.head) {
-			bh_lock_sock_nested(sk);
-			if (hci_pi(sk)->hdev == hdev) {
-				hci_pi(sk)->hdev = NULL;
-				sk->sk_err = EPIPE;
-				sk->sk_state = BT_OPEN;
-				sk->sk_state_change(sk);
-
-				hci_dev_put(hdev);
-			}
-			bh_unlock_sock(sk);
-		}
-		read_unlock(&hci_sk_list.lock);
-	}
-
-	return NOTIFY_DONE;
-}
-
 static const struct net_proto_family hci_sock_family_ops = {
 static const struct net_proto_family hci_sock_family_ops = {
 	.family	= PF_BLUETOOTH,
 	.family	= PF_BLUETOOTH,
 	.owner	= THIS_MODULE,
 	.owner	= THIS_MODULE,
 	.create	= hci_sock_create,
 	.create	= hci_sock_create,
 };
 };
 
 
-static struct notifier_block hci_sock_nblock = {
-	.notifier_call = hci_sock_dev_event
-};
-
 int __init hci_sock_init(void)
 int __init hci_sock_init(void)
 {
 {
 	int err;
 	int err;
@@ -806,8 +1110,6 @@ int __init hci_sock_init(void)
 	if (err < 0)
 	if (err < 0)
 		goto error;
 		goto error;
 
 
-	hci_register_notifier(&hci_sock_nblock);
-
 	BT_INFO("HCI socket layer initialized");
 	BT_INFO("HCI socket layer initialized");
 
 
 	return 0;
 	return 0;
@@ -823,10 +1125,5 @@ void hci_sock_cleanup(void)
 	if (bt_sock_unregister(BTPROTO_HCI) < 0)
 	if (bt_sock_unregister(BTPROTO_HCI) < 0)
 		BT_ERR("HCI socket unregistration failed");
 		BT_ERR("HCI socket unregistration failed");
 
 
-	hci_unregister_notifier(&hci_sock_nblock);
-
 	proto_unregister(&hci_sk_proto);
 	proto_unregister(&hci_sk_proto);
 }
 }
-
-module_param(enable_mgmt, bool, 0644);
-MODULE_PARM_DESC(enable_mgmt, "Enable Management interface");

+ 26 - 27
net/bluetooth/hci_sysfs.c

@@ -33,19 +33,19 @@ static inline char *link_typetostr(int type)
 
 
 static ssize_t show_link_type(struct device *dev, struct device_attribute *attr, char *buf)
 static ssize_t show_link_type(struct device *dev, struct device_attribute *attr, char *buf)
 {
 {
-	struct hci_conn *conn = dev_get_drvdata(dev);
+	struct hci_conn *conn = to_hci_conn(dev);
 	return sprintf(buf, "%s\n", link_typetostr(conn->type));
 	return sprintf(buf, "%s\n", link_typetostr(conn->type));
 }
 }
 
 
 static ssize_t show_link_address(struct device *dev, struct device_attribute *attr, char *buf)
 static ssize_t show_link_address(struct device *dev, struct device_attribute *attr, char *buf)
 {
 {
-	struct hci_conn *conn = dev_get_drvdata(dev);
+	struct hci_conn *conn = to_hci_conn(dev);
 	return sprintf(buf, "%s\n", batostr(&conn->dst));
 	return sprintf(buf, "%s\n", batostr(&conn->dst));
 }
 }
 
 
 static ssize_t show_link_features(struct device *dev, struct device_attribute *attr, char *buf)
 static ssize_t show_link_features(struct device *dev, struct device_attribute *attr, char *buf)
 {
 {
-	struct hci_conn *conn = dev_get_drvdata(dev);
+	struct hci_conn *conn = to_hci_conn(dev);
 
 
 	return sprintf(buf, "0x%02x%02x%02x%02x%02x%02x%02x%02x\n",
 	return sprintf(buf, "0x%02x%02x%02x%02x%02x%02x%02x%02x\n",
 				conn->features[0], conn->features[1],
 				conn->features[0], conn->features[1],
@@ -79,8 +79,8 @@ static const struct attribute_group *bt_link_groups[] = {
 
 
 static void bt_link_release(struct device *dev)
 static void bt_link_release(struct device *dev)
 {
 {
-	void *data = dev_get_drvdata(dev);
-	kfree(data);
+	struct hci_conn *conn = to_hci_conn(dev);
+	kfree(conn);
 }
 }
 
 
 static struct device_type bt_link = {
 static struct device_type bt_link = {
@@ -120,8 +120,6 @@ void hci_conn_add_sysfs(struct hci_conn *conn)
 
 
 	dev_set_name(&conn->dev, "%s:%d", hdev->name, conn->handle);
 	dev_set_name(&conn->dev, "%s:%d", hdev->name, conn->handle);
 
 
-	dev_set_drvdata(&conn->dev, conn);
-
 	if (device_add(&conn->dev) < 0) {
 	if (device_add(&conn->dev) < 0) {
 		BT_ERR("Failed to register connection device");
 		BT_ERR("Failed to register connection device");
 		return;
 		return;
@@ -189,19 +187,19 @@ static inline char *host_typetostr(int type)
 
 
 static ssize_t show_bus(struct device *dev, struct device_attribute *attr, char *buf)
 static ssize_t show_bus(struct device *dev, struct device_attribute *attr, char *buf)
 {
 {
-	struct hci_dev *hdev = dev_get_drvdata(dev);
+	struct hci_dev *hdev = to_hci_dev(dev);
 	return sprintf(buf, "%s\n", host_bustostr(hdev->bus));
 	return sprintf(buf, "%s\n", host_bustostr(hdev->bus));
 }
 }
 
 
 static ssize_t show_type(struct device *dev, struct device_attribute *attr, char *buf)
 static ssize_t show_type(struct device *dev, struct device_attribute *attr, char *buf)
 {
 {
-	struct hci_dev *hdev = dev_get_drvdata(dev);
+	struct hci_dev *hdev = to_hci_dev(dev);
 	return sprintf(buf, "%s\n", host_typetostr(hdev->dev_type));
 	return sprintf(buf, "%s\n", host_typetostr(hdev->dev_type));
 }
 }
 
 
 static ssize_t show_name(struct device *dev, struct device_attribute *attr, char *buf)
 static ssize_t show_name(struct device *dev, struct device_attribute *attr, char *buf)
 {
 {
-	struct hci_dev *hdev = dev_get_drvdata(dev);
+	struct hci_dev *hdev = to_hci_dev(dev);
 	char name[HCI_MAX_NAME_LENGTH + 1];
 	char name[HCI_MAX_NAME_LENGTH + 1];
 	int i;
 	int i;
 
 
@@ -214,20 +212,20 @@ static ssize_t show_name(struct device *dev, struct device_attribute *attr, char
 
 
 static ssize_t show_class(struct device *dev, struct device_attribute *attr, char *buf)
 static ssize_t show_class(struct device *dev, struct device_attribute *attr, char *buf)
 {
 {
-	struct hci_dev *hdev = dev_get_drvdata(dev);
+	struct hci_dev *hdev = to_hci_dev(dev);
 	return sprintf(buf, "0x%.2x%.2x%.2x\n",
 	return sprintf(buf, "0x%.2x%.2x%.2x\n",
 			hdev->dev_class[2], hdev->dev_class[1], hdev->dev_class[0]);
 			hdev->dev_class[2], hdev->dev_class[1], hdev->dev_class[0]);
 }
 }
 
 
 static ssize_t show_address(struct device *dev, struct device_attribute *attr, char *buf)
 static ssize_t show_address(struct device *dev, struct device_attribute *attr, char *buf)
 {
 {
-	struct hci_dev *hdev = dev_get_drvdata(dev);
+	struct hci_dev *hdev = to_hci_dev(dev);
 	return sprintf(buf, "%s\n", batostr(&hdev->bdaddr));
 	return sprintf(buf, "%s\n", batostr(&hdev->bdaddr));
 }
 }
 
 
 static ssize_t show_features(struct device *dev, struct device_attribute *attr, char *buf)
 static ssize_t show_features(struct device *dev, struct device_attribute *attr, char *buf)
 {
 {
-	struct hci_dev *hdev = dev_get_drvdata(dev);
+	struct hci_dev *hdev = to_hci_dev(dev);
 
 
 	return sprintf(buf, "0x%02x%02x%02x%02x%02x%02x%02x%02x\n",
 	return sprintf(buf, "0x%02x%02x%02x%02x%02x%02x%02x%02x\n",
 				hdev->features[0], hdev->features[1],
 				hdev->features[0], hdev->features[1],
@@ -238,31 +236,31 @@ static ssize_t show_features(struct device *dev, struct device_attribute *attr,
 
 
 static ssize_t show_manufacturer(struct device *dev, struct device_attribute *attr, char *buf)
 static ssize_t show_manufacturer(struct device *dev, struct device_attribute *attr, char *buf)
 {
 {
-	struct hci_dev *hdev = dev_get_drvdata(dev);
+	struct hci_dev *hdev = to_hci_dev(dev);
 	return sprintf(buf, "%d\n", hdev->manufacturer);
 	return sprintf(buf, "%d\n", hdev->manufacturer);
 }
 }
 
 
 static ssize_t show_hci_version(struct device *dev, struct device_attribute *attr, char *buf)
 static ssize_t show_hci_version(struct device *dev, struct device_attribute *attr, char *buf)
 {
 {
-	struct hci_dev *hdev = dev_get_drvdata(dev);
+	struct hci_dev *hdev = to_hci_dev(dev);
 	return sprintf(buf, "%d\n", hdev->hci_ver);
 	return sprintf(buf, "%d\n", hdev->hci_ver);
 }
 }
 
 
 static ssize_t show_hci_revision(struct device *dev, struct device_attribute *attr, char *buf)
 static ssize_t show_hci_revision(struct device *dev, struct device_attribute *attr, char *buf)
 {
 {
-	struct hci_dev *hdev = dev_get_drvdata(dev);
+	struct hci_dev *hdev = to_hci_dev(dev);
 	return sprintf(buf, "%d\n", hdev->hci_rev);
 	return sprintf(buf, "%d\n", hdev->hci_rev);
 }
 }
 
 
 static ssize_t show_idle_timeout(struct device *dev, struct device_attribute *attr, char *buf)
 static ssize_t show_idle_timeout(struct device *dev, struct device_attribute *attr, char *buf)
 {
 {
-	struct hci_dev *hdev = dev_get_drvdata(dev);
+	struct hci_dev *hdev = to_hci_dev(dev);
 	return sprintf(buf, "%d\n", hdev->idle_timeout);
 	return sprintf(buf, "%d\n", hdev->idle_timeout);
 }
 }
 
 
 static ssize_t store_idle_timeout(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
 static ssize_t store_idle_timeout(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
 {
 {
-	struct hci_dev *hdev = dev_get_drvdata(dev);
+	struct hci_dev *hdev = to_hci_dev(dev);
 	unsigned int val;
 	unsigned int val;
 	int rv;
 	int rv;
 
 
@@ -280,13 +278,13 @@ static ssize_t store_idle_timeout(struct device *dev, struct device_attribute *a
 
 
 static ssize_t show_sniff_max_interval(struct device *dev, struct device_attribute *attr, char *buf)
 static ssize_t show_sniff_max_interval(struct device *dev, struct device_attribute *attr, char *buf)
 {
 {
-	struct hci_dev *hdev = dev_get_drvdata(dev);
+	struct hci_dev *hdev = to_hci_dev(dev);
 	return sprintf(buf, "%d\n", hdev->sniff_max_interval);
 	return sprintf(buf, "%d\n", hdev->sniff_max_interval);
 }
 }
 
 
 static ssize_t store_sniff_max_interval(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
 static ssize_t store_sniff_max_interval(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
 {
 {
-	struct hci_dev *hdev = dev_get_drvdata(dev);
+	struct hci_dev *hdev = to_hci_dev(dev);
 	u16 val;
 	u16 val;
 	int rv;
 	int rv;
 
 
@@ -304,13 +302,13 @@ static ssize_t store_sniff_max_interval(struct device *dev, struct device_attrib
 
 
 static ssize_t show_sniff_min_interval(struct device *dev, struct device_attribute *attr, char *buf)
 static ssize_t show_sniff_min_interval(struct device *dev, struct device_attribute *attr, char *buf)
 {
 {
-	struct hci_dev *hdev = dev_get_drvdata(dev);
+	struct hci_dev *hdev = to_hci_dev(dev);
 	return sprintf(buf, "%d\n", hdev->sniff_min_interval);
 	return sprintf(buf, "%d\n", hdev->sniff_min_interval);
 }
 }
 
 
 static ssize_t store_sniff_min_interval(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
 static ssize_t store_sniff_min_interval(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
 {
 {
-	struct hci_dev *hdev = dev_get_drvdata(dev);
+	struct hci_dev *hdev = to_hci_dev(dev);
 	u16 val;
 	u16 val;
 	int rv;
 	int rv;
 
 
@@ -370,8 +368,9 @@ static const struct attribute_group *bt_host_groups[] = {
 
 
 static void bt_host_release(struct device *dev)
 static void bt_host_release(struct device *dev)
 {
 {
-	void *data = dev_get_drvdata(dev);
-	kfree(data);
+	struct hci_dev *hdev = to_hci_dev(dev);
+	kfree(hdev);
+	module_put(THIS_MODULE);
 }
 }
 
 
 static struct device_type bt_host = {
 static struct device_type bt_host = {
@@ -383,12 +382,12 @@ static struct device_type bt_host = {
 static int inquiry_cache_show(struct seq_file *f, void *p)
 static int inquiry_cache_show(struct seq_file *f, void *p)
 {
 {
 	struct hci_dev *hdev = f->private;
 	struct hci_dev *hdev = f->private;
-	struct inquiry_cache *cache = &hdev->inq_cache;
+	struct discovery_state *cache = &hdev->discovery;
 	struct inquiry_entry *e;
 	struct inquiry_entry *e;
 
 
 	hci_dev_lock(hdev);
 	hci_dev_lock(hdev);
 
 
-	for (e = cache->list; e; e = e->next) {
+	list_for_each_entry(e, &cache->all, all) {
 		struct inquiry_data *data = &e->data;
 		struct inquiry_data *data = &e->data;
 		seq_printf(f, "%s %d %d %d 0x%.2x%.2x%.2x 0x%.4x %d %d %u\n",
 		seq_printf(f, "%s %d %d %d 0x%.2x%.2x%.2x 0x%.4x %d %d %u\n",
 			   batostr(&data->bdaddr),
 			   batostr(&data->bdaddr),
@@ -523,7 +522,7 @@ void hci_init_sysfs(struct hci_dev *hdev)
 	dev->type = &bt_host;
 	dev->type = &bt_host;
 	dev->class = bt_class;
 	dev->class = bt_class;
 
 
-	dev_set_drvdata(dev, hdev);
+	__module_get(THIS_MODULE);
 	device_initialize(dev);
 	device_initialize(dev);
 }
 }
 
 

+ 3 - 3
net/bluetooth/hidp/sock.c

@@ -160,10 +160,10 @@ static int hidp_sock_compat_ioctl(struct socket *sock, unsigned int cmd, unsigne
 {
 {
 	if (cmd == HIDPGETCONNLIST) {
 	if (cmd == HIDPGETCONNLIST) {
 		struct hidp_connlist_req cl;
 		struct hidp_connlist_req cl;
-		uint32_t uci;
+		u32 uci;
 		int err;
 		int err;
 
 
-		if (get_user(cl.cnum, (uint32_t __user *) arg) ||
+		if (get_user(cl.cnum, (u32 __user *) arg) ||
 				get_user(uci, (u32 __user *) (arg + 4)))
 				get_user(uci, (u32 __user *) (arg + 4)))
 			return -EFAULT;
 			return -EFAULT;
 
 
@@ -174,7 +174,7 @@ static int hidp_sock_compat_ioctl(struct socket *sock, unsigned int cmd, unsigne
 
 
 		err = hidp_get_connlist(&cl);
 		err = hidp_get_connlist(&cl);
 
 
-		if (!err && put_user(cl.cnum, (uint32_t __user *) arg))
+		if (!err && put_user(cl.cnum, (u32 __user *) arg))
 			err = -EFAULT;
 			err = -EFAULT;
 
 
 		return err;
 		return err;

+ 347 - 294
net/bluetooth/l2cap_core.c

@@ -73,42 +73,28 @@ static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data);
 static void l2cap_send_disconn_req(struct l2cap_conn *conn,
 static void l2cap_send_disconn_req(struct l2cap_conn *conn,
 				struct l2cap_chan *chan, int err);
 				struct l2cap_chan *chan, int err);
 
 
-static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb);
-
 /* ---- L2CAP channels ---- */
 /* ---- L2CAP channels ---- */
 
 
 static struct l2cap_chan *__l2cap_get_chan_by_dcid(struct l2cap_conn *conn, u16 cid)
 static struct l2cap_chan *__l2cap_get_chan_by_dcid(struct l2cap_conn *conn, u16 cid)
 {
 {
-	struct l2cap_chan *c, *r = NULL;
-
-	rcu_read_lock();
+	struct l2cap_chan *c;
 
 
-	list_for_each_entry_rcu(c, &conn->chan_l, list) {
-		if (c->dcid == cid) {
-			r = c;
-			break;
-		}
+	list_for_each_entry(c, &conn->chan_l, list) {
+		if (c->dcid == cid)
+			return c;
 	}
 	}
-
-	rcu_read_unlock();
-	return r;
+	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)
 {
 {
-	struct l2cap_chan *c, *r = NULL;
-
-	rcu_read_lock();
+	struct l2cap_chan *c;
 
 
-	list_for_each_entry_rcu(c, &conn->chan_l, list) {
-		if (c->scid == cid) {
-			r = c;
-			break;
-		}
+	list_for_each_entry(c, &conn->chan_l, list) {
+		if (c->scid == cid)
+			return c;
 	}
 	}
-
-	rcu_read_unlock();
-	return r;
+	return NULL;
 }
 }
 
 
 /* Find channel with given SCID.
 /* Find channel with given SCID.
@@ -117,36 +103,32 @@ static struct l2cap_chan *l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16 ci
 {
 {
 	struct l2cap_chan *c;
 	struct l2cap_chan *c;
 
 
+	mutex_lock(&conn->chan_lock);
 	c = __l2cap_get_chan_by_scid(conn, cid);
 	c = __l2cap_get_chan_by_scid(conn, cid);
-	if (c)
-		lock_sock(c->sk);
+	mutex_unlock(&conn->chan_lock);
+
 	return c;
 	return c;
 }
 }
 
 
 static struct l2cap_chan *__l2cap_get_chan_by_ident(struct l2cap_conn *conn, u8 ident)
 static struct l2cap_chan *__l2cap_get_chan_by_ident(struct l2cap_conn *conn, u8 ident)
 {
 {
-	struct l2cap_chan *c, *r = NULL;
-
-	rcu_read_lock();
+	struct l2cap_chan *c;
 
 
-	list_for_each_entry_rcu(c, &conn->chan_l, list) {
-		if (c->ident == ident) {
-			r = c;
-			break;
-		}
+	list_for_each_entry(c, &conn->chan_l, list) {
+		if (c->ident == ident)
+			return c;
 	}
 	}
-
-	rcu_read_unlock();
-	return r;
+	return NULL;
 }
 }
 
 
 static inline struct l2cap_chan *l2cap_get_chan_by_ident(struct l2cap_conn *conn, u8 ident)
 static inline struct l2cap_chan *l2cap_get_chan_by_ident(struct l2cap_conn *conn, u8 ident)
 {
 {
 	struct l2cap_chan *c;
 	struct l2cap_chan *c;
 
 
+	mutex_lock(&conn->chan_lock);
 	c = __l2cap_get_chan_by_ident(conn, ident);
 	c = __l2cap_get_chan_by_ident(conn, ident);
-	if (c)
-		lock_sock(c->sk);
+	mutex_unlock(&conn->chan_lock);
+
 	return c;
 	return c;
 }
 }
 
 
@@ -217,51 +199,51 @@ static u16 l2cap_alloc_cid(struct l2cap_conn *conn)
 	return 0;
 	return 0;
 }
 }
 
 
-static char *state_to_string(int state)
+static void __l2cap_state_change(struct l2cap_chan *chan, 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";
-	}
+	BT_DBG("chan %p %s -> %s", chan, state_to_string(chan->state),
+						state_to_string(state));
 
 
-	return "invalid state";
+	chan->state = state;
+	chan->ops->state_change(chan->data, 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));
+	struct sock *sk = chan->sk;
 
 
-	chan->state = state;
-	chan->ops->state_change(chan->data, state);
+	lock_sock(sk);
+	__l2cap_state_change(chan, state);
+	release_sock(sk);
+}
+
+static inline void __l2cap_chan_set_err(struct l2cap_chan *chan, int err)
+{
+	struct sock *sk = chan->sk;
+
+	sk->sk_err = err;
+}
+
+static inline void l2cap_chan_set_err(struct l2cap_chan *chan, int err)
+{
+	struct sock *sk = chan->sk;
+
+	lock_sock(sk);
+	__l2cap_chan_set_err(chan, err);
+	release_sock(sk);
 }
 }
 
 
 static void l2cap_chan_timeout(struct work_struct *work)
 static void l2cap_chan_timeout(struct work_struct *work)
 {
 {
 	struct l2cap_chan *chan = container_of(work, struct l2cap_chan,
 	struct l2cap_chan *chan = container_of(work, struct l2cap_chan,
 							chan_timer.work);
 							chan_timer.work);
-	struct sock *sk = chan->sk;
+	struct l2cap_conn *conn = chan->conn;
 	int reason;
 	int reason;
 
 
-	BT_DBG("chan %p state %d", chan, chan->state);
+	BT_DBG("chan %p state %s", chan, state_to_string(chan->state));
 
 
-	lock_sock(sk);
+	mutex_lock(&conn->chan_lock);
+	l2cap_chan_lock(chan);
 
 
 	if (chan->state == BT_CONNECTED || chan->state == BT_CONFIG)
 	if (chan->state == BT_CONNECTED || chan->state == BT_CONFIG)
 		reason = ECONNREFUSED;
 		reason = ECONNREFUSED;
@@ -273,9 +255,11 @@ static void l2cap_chan_timeout(struct work_struct *work)
 
 
 	l2cap_chan_close(chan, reason);
 	l2cap_chan_close(chan, reason);
 
 
-	release_sock(sk);
+	l2cap_chan_unlock(chan);
 
 
 	chan->ops->close(chan->data);
 	chan->ops->close(chan->data);
+	mutex_unlock(&conn->chan_lock);
+
 	l2cap_chan_put(chan);
 	l2cap_chan_put(chan);
 }
 }
 
 
@@ -287,6 +271,8 @@ struct l2cap_chan *l2cap_chan_create(struct sock *sk)
 	if (!chan)
 	if (!chan)
 		return NULL;
 		return NULL;
 
 
+	mutex_init(&chan->lock);
+
 	chan->sk = sk;
 	chan->sk = sk;
 
 
 	write_lock(&chan_list_lock);
 	write_lock(&chan_list_lock);
@@ -313,7 +299,7 @@ void l2cap_chan_destroy(struct l2cap_chan *chan)
 	l2cap_chan_put(chan);
 	l2cap_chan_put(chan);
 }
 }
 
 
-static void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
+void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
 {
 {
 	BT_DBG("conn %p, psm 0x%2.2x, dcid 0x%4.4x", conn,
 	BT_DBG("conn %p, psm 0x%2.2x, dcid 0x%4.4x", conn,
 			chan->psm, chan->dcid);
 			chan->psm, chan->dcid);
@@ -322,7 +308,8 @@ static void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
 
 
 	chan->conn = conn;
 	chan->conn = conn;
 
 
-	if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED) {
+	switch (chan->chan_type) {
+	case L2CAP_CHAN_CONN_ORIENTED:
 		if (conn->hcon->type == LE_LINK) {
 		if (conn->hcon->type == LE_LINK) {
 			/* LE connection */
 			/* LE connection */
 			chan->omtu = L2CAP_LE_DEFAULT_MTU;
 			chan->omtu = L2CAP_LE_DEFAULT_MTU;
@@ -333,12 +320,16 @@ static void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
 			chan->scid = l2cap_alloc_cid(conn);
 			chan->scid = l2cap_alloc_cid(conn);
 			chan->omtu = L2CAP_DEFAULT_MTU;
 			chan->omtu = L2CAP_DEFAULT_MTU;
 		}
 		}
-	} else if (chan->chan_type == L2CAP_CHAN_CONN_LESS) {
+		break;
+
+	case L2CAP_CHAN_CONN_LESS:
 		/* Connectionless socket */
 		/* Connectionless socket */
 		chan->scid = L2CAP_CID_CONN_LESS;
 		chan->scid = L2CAP_CID_CONN_LESS;
 		chan->dcid = L2CAP_CID_CONN_LESS;
 		chan->dcid = L2CAP_CID_CONN_LESS;
 		chan->omtu = L2CAP_DEFAULT_MTU;
 		chan->omtu = L2CAP_DEFAULT_MTU;
-	} else {
+		break;
+
+	default:
 		/* Raw socket can send/recv signalling messages only */
 		/* Raw socket can send/recv signalling messages only */
 		chan->scid = L2CAP_CID_SIGNALING;
 		chan->scid = L2CAP_CID_SIGNALING;
 		chan->dcid = L2CAP_CID_SIGNALING;
 		chan->dcid = L2CAP_CID_SIGNALING;
@@ -354,11 +345,16 @@ static void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
 
 
 	l2cap_chan_hold(chan);
 	l2cap_chan_hold(chan);
 
 
-	list_add_rcu(&chan->list, &conn->chan_l);
+	list_add(&chan->list, &conn->chan_l);
+}
+
+void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
+{
+	mutex_lock(&conn->chan_lock);
+	__l2cap_chan_add(conn, chan);
+	mutex_unlock(&conn->chan_lock);
 }
 }
 
 
-/* Delete channel.
- * Must be called on the locked socket. */
 static void l2cap_chan_del(struct l2cap_chan *chan, int err)
 static void l2cap_chan_del(struct l2cap_chan *chan, int err)
 {
 {
 	struct sock *sk = chan->sk;
 	struct sock *sk = chan->sk;
@@ -371,8 +367,7 @@ static void l2cap_chan_del(struct l2cap_chan *chan, int err)
 
 
 	if (conn) {
 	if (conn) {
 		/* Delete from channel list */
 		/* Delete from channel list */
-		list_del_rcu(&chan->list);
-		synchronize_rcu();
+		list_del(&chan->list);
 
 
 		l2cap_chan_put(chan);
 		l2cap_chan_put(chan);
 
 
@@ -380,11 +375,13 @@ static void l2cap_chan_del(struct l2cap_chan *chan, int err)
 		hci_conn_put(conn->hcon);
 		hci_conn_put(conn->hcon);
 	}
 	}
 
 
-	l2cap_state_change(chan, BT_CLOSED);
+	lock_sock(sk);
+
+	__l2cap_state_change(chan, BT_CLOSED);
 	sock_set_flag(sk, SOCK_ZAPPED);
 	sock_set_flag(sk, SOCK_ZAPPED);
 
 
 	if (err)
 	if (err)
-		sk->sk_err = err;
+		__l2cap_chan_set_err(chan, err);
 
 
 	if (parent) {
 	if (parent) {
 		bt_accept_unlink(sk);
 		bt_accept_unlink(sk);
@@ -392,6 +389,8 @@ static void l2cap_chan_del(struct l2cap_chan *chan, int err)
 	} else
 	} else
 		sk->sk_state_change(sk);
 		sk->sk_state_change(sk);
 
 
+	release_sock(sk);
+
 	if (!(test_bit(CONF_OUTPUT_DONE, &chan->conf_state) &&
 	if (!(test_bit(CONF_OUTPUT_DONE, &chan->conf_state) &&
 			test_bit(CONF_INPUT_DONE, &chan->conf_state)))
 			test_bit(CONF_INPUT_DONE, &chan->conf_state)))
 		return;
 		return;
@@ -423,10 +422,12 @@ static void l2cap_chan_cleanup_listen(struct sock *parent)
 	/* Close not yet accepted channels */
 	/* Close not yet accepted channels */
 	while ((sk = bt_accept_dequeue(parent, NULL))) {
 	while ((sk = bt_accept_dequeue(parent, NULL))) {
 		struct l2cap_chan *chan = l2cap_pi(sk)->chan;
 		struct l2cap_chan *chan = l2cap_pi(sk)->chan;
+
+		l2cap_chan_lock(chan);
 		__clear_chan_timer(chan);
 		__clear_chan_timer(chan);
-		lock_sock(sk);
 		l2cap_chan_close(chan, ECONNRESET);
 		l2cap_chan_close(chan, ECONNRESET);
-		release_sock(sk);
+		l2cap_chan_unlock(chan);
+
 		chan->ops->close(chan->data);
 		chan->ops->close(chan->data);
 	}
 	}
 }
 }
@@ -436,14 +437,17 @@ void l2cap_chan_close(struct l2cap_chan *chan, int reason)
 	struct l2cap_conn *conn = chan->conn;
 	struct l2cap_conn *conn = chan->conn;
 	struct sock *sk = chan->sk;
 	struct sock *sk = chan->sk;
 
 
-	BT_DBG("chan %p state %d socket %p", chan, chan->state, sk->sk_socket);
+	BT_DBG("chan %p state %s sk %p", chan,
+					state_to_string(chan->state), sk);
 
 
 	switch (chan->state) {
 	switch (chan->state) {
 	case BT_LISTEN:
 	case BT_LISTEN:
+		lock_sock(sk);
 		l2cap_chan_cleanup_listen(sk);
 		l2cap_chan_cleanup_listen(sk);
 
 
-		l2cap_state_change(chan, BT_CLOSED);
+		__l2cap_state_change(chan, BT_CLOSED);
 		sock_set_flag(sk, SOCK_ZAPPED);
 		sock_set_flag(sk, SOCK_ZAPPED);
+		release_sock(sk);
 		break;
 		break;
 
 
 	case BT_CONNECTED:
 	case BT_CONNECTED:
@@ -486,7 +490,9 @@ void l2cap_chan_close(struct l2cap_chan *chan, int reason)
 		break;
 		break;
 
 
 	default:
 	default:
+		lock_sock(sk);
 		sock_set_flag(sk, SOCK_ZAPPED);
 		sock_set_flag(sk, SOCK_ZAPPED);
+		release_sock(sk);
 		break;
 		break;
 	}
 	}
 }
 }
@@ -661,6 +667,21 @@ static inline int __l2cap_no_conn_pending(struct l2cap_chan *chan)
 	return !test_bit(CONF_CONNECT_PEND, &chan->conf_state);
 	return !test_bit(CONF_CONNECT_PEND, &chan->conf_state);
 }
 }
 
 
+static void l2cap_send_conn_req(struct l2cap_chan *chan)
+{
+	struct l2cap_conn *conn = chan->conn;
+	struct l2cap_conn_req req;
+
+	req.scid = cpu_to_le16(chan->scid);
+	req.psm  = chan->psm;
+
+	chan->ident = l2cap_get_ident(conn);
+
+	set_bit(CONF_CONNECT_PEND, &chan->conf_state);
+
+	l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_REQ, sizeof(req), &req);
+}
+
 static void l2cap_do_start(struct l2cap_chan *chan)
 static void l2cap_do_start(struct l2cap_chan *chan)
 {
 {
 	struct l2cap_conn *conn = chan->conn;
 	struct l2cap_conn *conn = chan->conn;
@@ -670,17 +691,8 @@ static void l2cap_do_start(struct l2cap_chan *chan)
 			return;
 			return;
 
 
 		if (l2cap_chan_check_security(chan) &&
 		if (l2cap_chan_check_security(chan) &&
-				__l2cap_no_conn_pending(chan)) {
-			struct l2cap_conn_req req;
-			req.scid = cpu_to_le16(chan->scid);
-			req.psm  = chan->psm;
-
-			chan->ident = l2cap_get_ident(conn);
-			set_bit(CONF_CONNECT_PEND, &chan->conf_state);
-
-			l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_REQ,
-							sizeof(req), &req);
-		}
+				__l2cap_no_conn_pending(chan))
+			l2cap_send_conn_req(chan);
 	} else {
 	} else {
 		struct l2cap_info_req req;
 		struct l2cap_info_req req;
 		req.type = cpu_to_le16(L2CAP_IT_FEAT_MASK);
 		req.type = cpu_to_le16(L2CAP_IT_FEAT_MASK);
@@ -688,8 +700,7 @@ static void l2cap_do_start(struct l2cap_chan *chan)
 		conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_SENT;
 		conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_SENT;
 		conn->info_ident = l2cap_get_ident(conn);
 		conn->info_ident = l2cap_get_ident(conn);
 
 
-		schedule_delayed_work(&conn->info_timer,
-					msecs_to_jiffies(L2CAP_INFO_TIMEOUT));
+		schedule_delayed_work(&conn->info_timer, L2CAP_INFO_TIMEOUT);
 
 
 		l2cap_send_cmd(conn, conn->info_ident,
 		l2cap_send_cmd(conn, conn->info_ident,
 					L2CAP_INFO_REQ, sizeof(req), &req);
 					L2CAP_INFO_REQ, sizeof(req), &req);
@@ -714,14 +725,12 @@ static inline int l2cap_mode_supported(__u8 mode, __u32 feat_mask)
 
 
 static void l2cap_send_disconn_req(struct l2cap_conn *conn, struct l2cap_chan *chan, int err)
 static void l2cap_send_disconn_req(struct l2cap_conn *conn, struct l2cap_chan *chan, int err)
 {
 {
-	struct sock *sk;
+	struct sock *sk = chan->sk;
 	struct l2cap_disconn_req req;
 	struct l2cap_disconn_req req;
 
 
 	if (!conn)
 	if (!conn)
 		return;
 		return;
 
 
-	sk = chan->sk;
-
 	if (chan->mode == L2CAP_MODE_ERTM) {
 	if (chan->mode == L2CAP_MODE_ERTM) {
 		__clear_retrans_timer(chan);
 		__clear_retrans_timer(chan);
 		__clear_monitor_timer(chan);
 		__clear_monitor_timer(chan);
@@ -733,56 +742,47 @@ static void l2cap_send_disconn_req(struct l2cap_conn *conn, struct l2cap_chan *c
 	l2cap_send_cmd(conn, l2cap_get_ident(conn),
 	l2cap_send_cmd(conn, l2cap_get_ident(conn),
 			L2CAP_DISCONN_REQ, sizeof(req), &req);
 			L2CAP_DISCONN_REQ, sizeof(req), &req);
 
 
-	l2cap_state_change(chan, BT_DISCONN);
-	sk->sk_err = err;
+	lock_sock(sk);
+	__l2cap_state_change(chan, BT_DISCONN);
+	__l2cap_chan_set_err(chan, err);
+	release_sock(sk);
 }
 }
 
 
 /* ---- L2CAP connections ---- */
 /* ---- L2CAP connections ---- */
 static void l2cap_conn_start(struct l2cap_conn *conn)
 static void l2cap_conn_start(struct l2cap_conn *conn)
 {
 {
-	struct l2cap_chan *chan;
+	struct l2cap_chan *chan, *tmp;
 
 
 	BT_DBG("conn %p", conn);
 	BT_DBG("conn %p", conn);
 
 
-	rcu_read_lock();
+	mutex_lock(&conn->chan_lock);
 
 
-	list_for_each_entry_rcu(chan, &conn->chan_l, list) {
+	list_for_each_entry_safe(chan, tmp, &conn->chan_l, list) {
 		struct sock *sk = chan->sk;
 		struct sock *sk = chan->sk;
 
 
-		bh_lock_sock(sk);
+		l2cap_chan_lock(chan);
 
 
 		if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
 		if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
-			bh_unlock_sock(sk);
+			l2cap_chan_unlock(chan);
 			continue;
 			continue;
 		}
 		}
 
 
 		if (chan->state == BT_CONNECT) {
 		if (chan->state == BT_CONNECT) {
-			struct l2cap_conn_req req;
-
 			if (!l2cap_chan_check_security(chan) ||
 			if (!l2cap_chan_check_security(chan) ||
 					!__l2cap_no_conn_pending(chan)) {
 					!__l2cap_no_conn_pending(chan)) {
-				bh_unlock_sock(sk);
+				l2cap_chan_unlock(chan);
 				continue;
 				continue;
 			}
 			}
 
 
 			if (!l2cap_mode_supported(chan->mode, conn->feat_mask)
 			if (!l2cap_mode_supported(chan->mode, conn->feat_mask)
 					&& test_bit(CONF_STATE2_DEVICE,
 					&& test_bit(CONF_STATE2_DEVICE,
 					&chan->conf_state)) {
 					&chan->conf_state)) {
-				/* l2cap_chan_close() calls list_del(chan)
-				 * so release the lock */
 				l2cap_chan_close(chan, ECONNRESET);
 				l2cap_chan_close(chan, ECONNRESET);
-				bh_unlock_sock(sk);
+				l2cap_chan_unlock(chan);
 				continue;
 				continue;
 			}
 			}
 
 
-			req.scid = cpu_to_le16(chan->scid);
-			req.psm  = chan->psm;
-
-			chan->ident = l2cap_get_ident(conn);
-			set_bit(CONF_CONNECT_PEND, &chan->conf_state);
-
-			l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_REQ,
-							sizeof(req), &req);
+			l2cap_send_conn_req(chan);
 
 
 		} else if (chan->state == BT_CONNECT2) {
 		} else if (chan->state == BT_CONNECT2) {
 			struct l2cap_conn_rsp rsp;
 			struct l2cap_conn_rsp rsp;
@@ -791,6 +791,7 @@ static void l2cap_conn_start(struct l2cap_conn *conn)
 			rsp.dcid = cpu_to_le16(chan->scid);
 			rsp.dcid = cpu_to_le16(chan->scid);
 
 
 			if (l2cap_chan_check_security(chan)) {
 			if (l2cap_chan_check_security(chan)) {
+				lock_sock(sk);
 				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);
@@ -799,10 +800,11 @@ static void l2cap_conn_start(struct l2cap_conn *conn)
 						parent->sk_data_ready(parent, 0);
 						parent->sk_data_ready(parent, 0);
 
 
 				} else {
 				} else {
-					l2cap_state_change(chan, BT_CONFIG);
+					__l2cap_state_change(chan, BT_CONFIG);
 					rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS);
 					rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS);
 					rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
 					rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
 				}
 				}
+				release_sock(sk);
 			} else {
 			} else {
 				rsp.result = cpu_to_le16(L2CAP_CR_PEND);
 				rsp.result = cpu_to_le16(L2CAP_CR_PEND);
 				rsp.status = cpu_to_le16(L2CAP_CS_AUTHEN_PEND);
 				rsp.status = cpu_to_le16(L2CAP_CS_AUTHEN_PEND);
@@ -813,7 +815,7 @@ static void l2cap_conn_start(struct l2cap_conn *conn)
 
 
 			if (test_bit(CONF_REQ_SENT, &chan->conf_state) ||
 			if (test_bit(CONF_REQ_SENT, &chan->conf_state) ||
 					rsp.result != L2CAP_CR_SUCCESS) {
 					rsp.result != L2CAP_CR_SUCCESS) {
-				bh_unlock_sock(sk);
+				l2cap_chan_unlock(chan);
 				continue;
 				continue;
 			}
 			}
 
 
@@ -823,10 +825,10 @@ static void l2cap_conn_start(struct l2cap_conn *conn)
 			chan->num_conf_req++;
 			chan->num_conf_req++;
 		}
 		}
 
 
-		bh_unlock_sock(sk);
+		l2cap_chan_unlock(chan);
 	}
 	}
 
 
-	rcu_read_unlock();
+	mutex_unlock(&conn->chan_lock);
 }
 }
 
 
 /* Find socket with cid and source bdaddr.
 /* Find socket with cid and source bdaddr.
@@ -902,28 +904,34 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn)
 
 
 	__set_chan_timer(chan, sk->sk_sndtimeo);
 	__set_chan_timer(chan, sk->sk_sndtimeo);
 
 
-	l2cap_state_change(chan, BT_CONNECTED);
+	__l2cap_state_change(chan, BT_CONNECTED);
 	parent->sk_data_ready(parent, 0);
 	parent->sk_data_ready(parent, 0);
 
 
 clean:
 clean:
 	release_sock(parent);
 	release_sock(parent);
 }
 }
 
 
-static void l2cap_chan_ready(struct sock *sk)
+static void l2cap_chan_ready(struct l2cap_chan *chan)
 {
 {
-	struct l2cap_chan *chan = l2cap_pi(sk)->chan;
-	struct sock *parent = bt_sk(sk)->parent;
+	struct sock *sk = chan->sk;
+	struct sock *parent;
+
+	lock_sock(sk);
+
+	parent = bt_sk(sk)->parent;
 
 
 	BT_DBG("sk %p, parent %p", sk, parent);
 	BT_DBG("sk %p, parent %p", sk, parent);
 
 
 	chan->conf_state = 0;
 	chan->conf_state = 0;
 	__clear_chan_timer(chan);
 	__clear_chan_timer(chan);
 
 
-	l2cap_state_change(chan, BT_CONNECTED);
+	__l2cap_state_change(chan, BT_CONNECTED);
 	sk->sk_state_change(sk);
 	sk->sk_state_change(sk);
 
 
 	if (parent)
 	if (parent)
 		parent->sk_data_ready(parent, 0);
 		parent->sk_data_ready(parent, 0);
+
+	release_sock(sk);
 }
 }
 
 
 static void l2cap_conn_ready(struct l2cap_conn *conn)
 static void l2cap_conn_ready(struct l2cap_conn *conn)
@@ -938,29 +946,31 @@ static void l2cap_conn_ready(struct l2cap_conn *conn)
 	if (conn->hcon->out && conn->hcon->type == LE_LINK)
 	if (conn->hcon->out && conn->hcon->type == LE_LINK)
 		smp_conn_security(conn, conn->hcon->pending_sec_level);
 		smp_conn_security(conn, conn->hcon->pending_sec_level);
 
 
-	rcu_read_lock();
+	mutex_lock(&conn->chan_lock);
 
 
-	list_for_each_entry_rcu(chan, &conn->chan_l, list) {
-		struct sock *sk = chan->sk;
+	list_for_each_entry(chan, &conn->chan_l, list) {
 
 
-		bh_lock_sock(sk);
+		l2cap_chan_lock(chan);
 
 
 		if (conn->hcon->type == LE_LINK) {
 		if (conn->hcon->type == LE_LINK) {
 			if (smp_conn_security(conn, chan->sec_level))
 			if (smp_conn_security(conn, chan->sec_level))
-				l2cap_chan_ready(sk);
+				l2cap_chan_ready(chan);
 
 
 		} else if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
 		} else if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
+			struct sock *sk = chan->sk;
 			__clear_chan_timer(chan);
 			__clear_chan_timer(chan);
-			l2cap_state_change(chan, BT_CONNECTED);
+			lock_sock(sk);
+			__l2cap_state_change(chan, BT_CONNECTED);
 			sk->sk_state_change(sk);
 			sk->sk_state_change(sk);
+			release_sock(sk);
 
 
 		} else if (chan->state == BT_CONNECT)
 		} else if (chan->state == BT_CONNECT)
 			l2cap_do_start(chan);
 			l2cap_do_start(chan);
 
 
-		bh_unlock_sock(sk);
+		l2cap_chan_unlock(chan);
 	}
 	}
 
 
-	rcu_read_unlock();
+	mutex_unlock(&conn->chan_lock);
 }
 }
 
 
 /* Notify sockets that we cannot guaranty reliability anymore */
 /* Notify sockets that we cannot guaranty reliability anymore */
@@ -970,16 +980,14 @@ static void l2cap_conn_unreliable(struct l2cap_conn *conn, int err)
 
 
 	BT_DBG("conn %p", conn);
 	BT_DBG("conn %p", conn);
 
 
-	rcu_read_lock();
-
-	list_for_each_entry_rcu(chan, &conn->chan_l, list) {
-		struct sock *sk = chan->sk;
+	mutex_lock(&conn->chan_lock);
 
 
+	list_for_each_entry(chan, &conn->chan_l, list) {
 		if (test_bit(FLAG_FORCE_RELIABLE, &chan->flags))
 		if (test_bit(FLAG_FORCE_RELIABLE, &chan->flags))
-			sk->sk_err = err;
+			__l2cap_chan_set_err(chan, err);
 	}
 	}
 
 
-	rcu_read_unlock();
+	mutex_unlock(&conn->chan_lock);
 }
 }
 
 
 static void l2cap_info_timeout(struct work_struct *work)
 static void l2cap_info_timeout(struct work_struct *work)
@@ -997,7 +1005,6 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err)
 {
 {
 	struct l2cap_conn *conn = hcon->l2cap_data;
 	struct l2cap_conn *conn = hcon->l2cap_data;
 	struct l2cap_chan *chan, *l;
 	struct l2cap_chan *chan, *l;
-	struct sock *sk;
 
 
 	if (!conn)
 	if (!conn)
 		return;
 		return;
@@ -1006,21 +1013,27 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err)
 
 
 	kfree_skb(conn->rx_skb);
 	kfree_skb(conn->rx_skb);
 
 
+	mutex_lock(&conn->chan_lock);
+
 	/* Kill channels */
 	/* Kill channels */
 	list_for_each_entry_safe(chan, l, &conn->chan_l, list) {
 	list_for_each_entry_safe(chan, l, &conn->chan_l, list) {
-		sk = chan->sk;
-		lock_sock(sk);
+		l2cap_chan_lock(chan);
+
 		l2cap_chan_del(chan, err);
 		l2cap_chan_del(chan, err);
-		release_sock(sk);
+
+		l2cap_chan_unlock(chan);
+
 		chan->ops->close(chan->data);
 		chan->ops->close(chan->data);
 	}
 	}
 
 
+	mutex_unlock(&conn->chan_lock);
+
 	hci_chan_del(conn->hchan);
 	hci_chan_del(conn->hchan);
 
 
 	if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT)
 	if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT)
 		cancel_delayed_work_sync(&conn->info_timer);
 		cancel_delayed_work_sync(&conn->info_timer);
 
 
-	if (test_and_clear_bit(HCI_CONN_LE_SMP_PEND, &hcon->pend)) {
+	if (test_and_clear_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags)) {
 		cancel_delayed_work_sync(&conn->security_timer);
 		cancel_delayed_work_sync(&conn->security_timer);
 		smp_chan_destroy(conn);
 		smp_chan_destroy(conn);
 	}
 	}
@@ -1072,6 +1085,7 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status)
 	conn->feat_mask = 0;
 	conn->feat_mask = 0;
 
 
 	spin_lock_init(&conn->lock);
 	spin_lock_init(&conn->lock);
+	mutex_init(&conn->chan_lock);
 
 
 	INIT_LIST_HEAD(&conn->chan_l);
 	INIT_LIST_HEAD(&conn->chan_l);
 
 
@@ -1139,7 +1153,7 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, bdaddr_t *d
 
 
 	hci_dev_lock(hdev);
 	hci_dev_lock(hdev);
 
 
-	lock_sock(sk);
+	l2cap_chan_lock(chan);
 
 
 	/* 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(psm) & 0x0101) != 0x0001 && !cid &&
 	if ((__le16_to_cpu(psm) & 0x0101) != 0x0001 && !cid &&
@@ -1166,17 +1180,21 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, bdaddr_t *d
 		goto done;
 		goto done;
 	}
 	}
 
 
+	lock_sock(sk);
+
 	switch (sk->sk_state) {
 	switch (sk->sk_state) {
 	case BT_CONNECT:
 	case BT_CONNECT:
 	case BT_CONNECT2:
 	case BT_CONNECT2:
 	case BT_CONFIG:
 	case BT_CONFIG:
 		/* Already connecting */
 		/* Already connecting */
 		err = 0;
 		err = 0;
+		release_sock(sk);
 		goto done;
 		goto done;
 
 
 	case BT_CONNECTED:
 	case BT_CONNECTED:
 		/* Already connected */
 		/* Already connected */
 		err = -EISCONN;
 		err = -EISCONN;
+		release_sock(sk);
 		goto done;
 		goto done;
 
 
 	case BT_OPEN:
 	case BT_OPEN:
@@ -1186,11 +1204,15 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, bdaddr_t *d
 
 
 	default:
 	default:
 		err = -EBADFD;
 		err = -EBADFD;
+		release_sock(sk);
 		goto done;
 		goto done;
 	}
 	}
 
 
 	/* Set destination address and psm */
 	/* Set destination address and psm */
 	bacpy(&bt_sk(sk)->dst, dst);
 	bacpy(&bt_sk(sk)->dst, dst);
+
+	release_sock(sk);
+
 	chan->psm = psm;
 	chan->psm = psm;
 	chan->dcid = cid;
 	chan->dcid = cid;
 
 
@@ -1218,7 +1240,9 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, bdaddr_t *d
 	/* Update source addr of the socket */
 	/* Update source addr of the socket */
 	bacpy(src, conn->src);
 	bacpy(src, conn->src);
 
 
+	l2cap_chan_unlock(chan);
 	l2cap_chan_add(conn, chan);
 	l2cap_chan_add(conn, chan);
+	l2cap_chan_lock(chan);
 
 
 	l2cap_state_change(chan, BT_CONNECT);
 	l2cap_state_change(chan, BT_CONNECT);
 	__set_chan_timer(chan, sk->sk_sndtimeo);
 	__set_chan_timer(chan, sk->sk_sndtimeo);
@@ -1235,6 +1259,7 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, bdaddr_t *d
 	err = 0;
 	err = 0;
 
 
 done:
 done:
+	l2cap_chan_unlock(chan);
 	hci_dev_unlock(hdev);
 	hci_dev_unlock(hdev);
 	hci_dev_put(hdev);
 	hci_dev_put(hdev);
 	return err;
 	return err;
@@ -1276,14 +1301,14 @@ static void l2cap_monitor_timeout(struct work_struct *work)
 {
 {
 	struct l2cap_chan *chan = container_of(work, struct l2cap_chan,
 	struct l2cap_chan *chan = container_of(work, struct l2cap_chan,
 							monitor_timer.work);
 							monitor_timer.work);
-	struct sock *sk = chan->sk;
 
 
 	BT_DBG("chan %p", chan);
 	BT_DBG("chan %p", chan);
 
 
-	lock_sock(sk);
+	l2cap_chan_lock(chan);
+
 	if (chan->retry_count >= chan->remote_max_tx) {
 	if (chan->retry_count >= chan->remote_max_tx) {
 		l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED);
 		l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED);
-		release_sock(sk);
+		l2cap_chan_unlock(chan);
 		return;
 		return;
 	}
 	}
 
 
@@ -1291,25 +1316,26 @@ static void l2cap_monitor_timeout(struct work_struct *work)
 	__set_monitor_timer(chan);
 	__set_monitor_timer(chan);
 
 
 	l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_POLL);
 	l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_POLL);
-	release_sock(sk);
+	l2cap_chan_unlock(chan);
 }
 }
 
 
 static void l2cap_retrans_timeout(struct work_struct *work)
 static void l2cap_retrans_timeout(struct work_struct *work)
 {
 {
 	struct l2cap_chan *chan = container_of(work, struct l2cap_chan,
 	struct l2cap_chan *chan = container_of(work, struct l2cap_chan,
 							retrans_timer.work);
 							retrans_timer.work);
-	struct sock *sk = chan->sk;
 
 
 	BT_DBG("chan %p", chan);
 	BT_DBG("chan %p", chan);
 
 
-	lock_sock(sk);
+	l2cap_chan_lock(chan);
+
 	chan->retry_count = 1;
 	chan->retry_count = 1;
 	__set_monitor_timer(chan);
 	__set_monitor_timer(chan);
 
 
 	set_bit(CONN_WAIT_F, &chan->conn_state);
 	set_bit(CONN_WAIT_F, &chan->conn_state);
 
 
 	l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_POLL);
 	l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_POLL);
-	release_sock(sk);
+
+	l2cap_chan_unlock(chan);
 }
 }
 
 
 static void l2cap_drop_acked_frames(struct l2cap_chan *chan)
 static void l2cap_drop_acked_frames(struct l2cap_chan *chan)
@@ -1450,17 +1476,19 @@ static int l2cap_ertm_send(struct l2cap_chan *chan)
 
 
 		chan->next_tx_seq = __next_seq(chan, chan->next_tx_seq);
 		chan->next_tx_seq = __next_seq(chan, chan->next_tx_seq);
 
 
-		if (bt_cb(skb)->retries == 1)
+		if (bt_cb(skb)->retries == 1) {
 			chan->unacked_frames++;
 			chan->unacked_frames++;
 
 
+			if (!nsent++)
+				__clear_ack_timer(chan);
+		}
+
 		chan->frames_sent++;
 		chan->frames_sent++;
 
 
 		if (skb_queue_is_last(&chan->tx_q, skb))
 		if (skb_queue_is_last(&chan->tx_q, skb))
 			chan->tx_send_head = NULL;
 			chan->tx_send_head = NULL;
 		else
 		else
 			chan->tx_send_head = skb_queue_next(&chan->tx_q, skb);
 			chan->tx_send_head = skb_queue_next(&chan->tx_q, skb);
-
-		nsent++;
 	}
 	}
 
 
 	return nsent;
 	return nsent;
@@ -1478,7 +1506,7 @@ static int l2cap_retransmit_frames(struct l2cap_chan *chan)
 	return ret;
 	return ret;
 }
 }
 
 
-static void l2cap_send_ack(struct l2cap_chan *chan)
+static void __l2cap_send_ack(struct l2cap_chan *chan)
 {
 {
 	u32 control = 0;
 	u32 control = 0;
 
 
@@ -1498,6 +1526,12 @@ static void l2cap_send_ack(struct l2cap_chan *chan)
 	l2cap_send_sframe(chan, control);
 	l2cap_send_sframe(chan, control);
 }
 }
 
 
+static void l2cap_send_ack(struct l2cap_chan *chan)
+{
+	__clear_ack_timer(chan);
+	__l2cap_send_ack(chan);
+}
+
 static void l2cap_send_srejtail(struct l2cap_chan *chan)
 static void l2cap_send_srejtail(struct l2cap_chan *chan)
 {
 {
 	struct srej_list *tail;
 	struct srej_list *tail;
@@ -1512,9 +1546,11 @@ static void l2cap_send_srejtail(struct l2cap_chan *chan)
 	l2cap_send_sframe(chan, control);
 	l2cap_send_sframe(chan, control);
 }
 }
 
 
-static inline int l2cap_skbuff_fromiovec(struct sock *sk, struct msghdr *msg, int len, int count, struct sk_buff *skb)
+static inline int l2cap_skbuff_fromiovec(struct l2cap_chan *chan,
+					 struct msghdr *msg, int len,
+					 int count, struct sk_buff *skb)
 {
 {
-	struct l2cap_conn *conn = l2cap_pi(sk)->chan->conn;
+	struct l2cap_conn *conn = chan->conn;
 	struct sk_buff **frag;
 	struct sk_buff **frag;
 	int err, sent = 0;
 	int err, sent = 0;
 
 
@@ -1529,7 +1565,10 @@ static inline int l2cap_skbuff_fromiovec(struct sock *sk, struct msghdr *msg, in
 	while (len) {
 	while (len) {
 		count = min_t(unsigned int, conn->mtu, len);
 		count = min_t(unsigned int, conn->mtu, len);
 
 
-		*frag = bt_skb_send_alloc(sk, count, msg->msg_flags & MSG_DONTWAIT, &err);
+		*frag = chan->ops->alloc_skb(chan, count,
+					     msg->msg_flags & MSG_DONTWAIT,
+					     &err);
+
 		if (!*frag)
 		if (!*frag)
 			return err;
 			return err;
 		if (memcpy_fromiovec(skb_put(*frag, count), msg->msg_iov, count))
 		if (memcpy_fromiovec(skb_put(*frag, count), msg->msg_iov, count))
@@ -1550,17 +1589,18 @@ static struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan,
 						struct msghdr *msg, size_t len,
 						struct msghdr *msg, size_t len,
 						u32 priority)
 						u32 priority)
 {
 {
-	struct sock *sk = chan->sk;
 	struct l2cap_conn *conn = chan->conn;
 	struct l2cap_conn *conn = chan->conn;
 	struct sk_buff *skb;
 	struct sk_buff *skb;
 	int err, count, hlen = L2CAP_HDR_SIZE + L2CAP_PSMLEN_SIZE;
 	int err, count, hlen = L2CAP_HDR_SIZE + L2CAP_PSMLEN_SIZE;
 	struct l2cap_hdr *lh;
 	struct l2cap_hdr *lh;
 
 
-	BT_DBG("sk %p len %d priority %u", sk, (int)len, priority);
+	BT_DBG("chan %p len %d priority %u", chan, (int)len, priority);
 
 
 	count = min_t(unsigned int, (conn->mtu - hlen), len);
 	count = min_t(unsigned int, (conn->mtu - hlen), len);
-	skb = bt_skb_send_alloc(sk, count + hlen,
-			msg->msg_flags & MSG_DONTWAIT, &err);
+
+	skb = chan->ops->alloc_skb(chan, count + hlen,
+				   msg->msg_flags & MSG_DONTWAIT, &err);
+
 	if (!skb)
 	if (!skb)
 		return ERR_PTR(err);
 		return ERR_PTR(err);
 
 
@@ -1572,7 +1612,7 @@ static struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan,
 	lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
 	lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
 	put_unaligned_le16(chan->psm, skb_put(skb, 2));
 	put_unaligned_le16(chan->psm, skb_put(skb, 2));
 
 
-	err = l2cap_skbuff_fromiovec(sk, msg, len, count, skb);
+	err = l2cap_skbuff_fromiovec(chan, msg, len, count, skb);
 	if (unlikely(err < 0)) {
 	if (unlikely(err < 0)) {
 		kfree_skb(skb);
 		kfree_skb(skb);
 		return ERR_PTR(err);
 		return ERR_PTR(err);
@@ -1584,17 +1624,18 @@ static struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan,
 						struct msghdr *msg, size_t len,
 						struct msghdr *msg, size_t len,
 						u32 priority)
 						u32 priority)
 {
 {
-	struct sock *sk = chan->sk;
 	struct l2cap_conn *conn = chan->conn;
 	struct l2cap_conn *conn = chan->conn;
 	struct sk_buff *skb;
 	struct sk_buff *skb;
 	int err, count, hlen = L2CAP_HDR_SIZE;
 	int err, count, hlen = L2CAP_HDR_SIZE;
 	struct l2cap_hdr *lh;
 	struct l2cap_hdr *lh;
 
 
-	BT_DBG("sk %p len %d", sk, (int)len);
+	BT_DBG("chan %p len %d", chan, (int)len);
 
 
 	count = min_t(unsigned int, (conn->mtu - hlen), len);
 	count = min_t(unsigned int, (conn->mtu - hlen), len);
-	skb = bt_skb_send_alloc(sk, count + hlen,
-			msg->msg_flags & MSG_DONTWAIT, &err);
+
+	skb = chan->ops->alloc_skb(chan, count + hlen,
+				   msg->msg_flags & MSG_DONTWAIT, &err);
+
 	if (!skb)
 	if (!skb)
 		return ERR_PTR(err);
 		return ERR_PTR(err);
 
 
@@ -1605,7 +1646,7 @@ static struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan,
 	lh->cid = cpu_to_le16(chan->dcid);
 	lh->cid = cpu_to_le16(chan->dcid);
 	lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
 	lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
 
 
-	err = l2cap_skbuff_fromiovec(sk, msg, len, count, skb);
+	err = l2cap_skbuff_fromiovec(chan, msg, len, count, skb);
 	if (unlikely(err < 0)) {
 	if (unlikely(err < 0)) {
 		kfree_skb(skb);
 		kfree_skb(skb);
 		return ERR_PTR(err);
 		return ERR_PTR(err);
@@ -1617,13 +1658,12 @@ static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan,
 						struct msghdr *msg, size_t len,
 						struct msghdr *msg, size_t len,
 						u32 control, u16 sdulen)
 						u32 control, u16 sdulen)
 {
 {
-	struct sock *sk = chan->sk;
 	struct l2cap_conn *conn = chan->conn;
 	struct l2cap_conn *conn = chan->conn;
 	struct sk_buff *skb;
 	struct sk_buff *skb;
 	int err, count, hlen;
 	int err, count, hlen;
 	struct l2cap_hdr *lh;
 	struct l2cap_hdr *lh;
 
 
-	BT_DBG("sk %p len %d", sk, (int)len);
+	BT_DBG("chan %p len %d", chan, (int)len);
 
 
 	if (!conn)
 	if (!conn)
 		return ERR_PTR(-ENOTCONN);
 		return ERR_PTR(-ENOTCONN);
@@ -1640,8 +1680,10 @@ static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan,
 		hlen += L2CAP_FCS_SIZE;
 		hlen += L2CAP_FCS_SIZE;
 
 
 	count = min_t(unsigned int, (conn->mtu - hlen), len);
 	count = min_t(unsigned int, (conn->mtu - hlen), len);
-	skb = bt_skb_send_alloc(sk, count + hlen,
-			msg->msg_flags & MSG_DONTWAIT, &err);
+
+	skb = chan->ops->alloc_skb(chan, count + hlen,
+					msg->msg_flags & MSG_DONTWAIT, &err);
+
 	if (!skb)
 	if (!skb)
 		return ERR_PTR(err);
 		return ERR_PTR(err);
 
 
@@ -1655,7 +1697,7 @@ static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan,
 	if (sdulen)
 	if (sdulen)
 		put_unaligned_le16(sdulen, skb_put(skb, L2CAP_SDULEN_SIZE));
 		put_unaligned_le16(sdulen, skb_put(skb, L2CAP_SDULEN_SIZE));
 
 
-	err = l2cap_skbuff_fromiovec(sk, msg, len, count, skb);
+	err = l2cap_skbuff_fromiovec(chan, msg, len, count, skb);
 	if (unlikely(err < 0)) {
 	if (unlikely(err < 0)) {
 		kfree_skb(skb);
 		kfree_skb(skb);
 		return ERR_PTR(err);
 		return ERR_PTR(err);
@@ -1801,9 +1843,9 @@ static void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb)
 
 
 	BT_DBG("conn %p", conn);
 	BT_DBG("conn %p", conn);
 
 
-	rcu_read_lock();
+	mutex_lock(&conn->chan_lock);
 
 
-	list_for_each_entry_rcu(chan, &conn->chan_l, list) {
+	list_for_each_entry(chan, &conn->chan_l, list) {
 		struct sock *sk = chan->sk;
 		struct sock *sk = chan->sk;
 		if (chan->chan_type != L2CAP_CHAN_RAW)
 		if (chan->chan_type != L2CAP_CHAN_RAW)
 			continue;
 			continue;
@@ -1819,7 +1861,7 @@ static void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb)
 			kfree_skb(nskb);
 			kfree_skb(nskb);
 	}
 	}
 
 
-	rcu_read_unlock();
+	mutex_unlock(&conn->chan_lock);
 }
 }
 
 
 /* ---- L2CAP signalling commands ---- */
 /* ---- L2CAP signalling commands ---- */
@@ -1987,9 +2029,13 @@ static void l2cap_ack_timeout(struct work_struct *work)
 
 
 	BT_DBG("chan %p", chan);
 	BT_DBG("chan %p", chan);
 
 
-	lock_sock(chan->sk);
-	l2cap_send_ack(chan);
-	release_sock(chan->sk);
+	l2cap_chan_lock(chan);
+
+	__l2cap_send_ack(chan);
+
+	l2cap_chan_unlock(chan);
+
+	l2cap_chan_put(chan);
 }
 }
 
 
 static inline void l2cap_ertm_init(struct l2cap_chan *chan)
 static inline void l2cap_ertm_init(struct l2cap_chan *chan)
@@ -2607,6 +2653,7 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd
 
 
 	parent = pchan->sk;
 	parent = pchan->sk;
 
 
+	mutex_lock(&conn->chan_lock);
 	lock_sock(parent);
 	lock_sock(parent);
 
 
 	/* Check if the ACL is secure enough (if not SDP) */
 	/* Check if the ACL is secure enough (if not SDP) */
@@ -2647,7 +2694,7 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd
 
 
 	bt_accept_enqueue(parent, sk);
 	bt_accept_enqueue(parent, sk);
 
 
-	l2cap_chan_add(conn, chan);
+	__l2cap_chan_add(conn, chan);
 
 
 	dcid = chan->scid;
 	dcid = chan->scid;
 
 
@@ -2658,28 +2705,29 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd
 	if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE) {
 	if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE) {
 		if (l2cap_chan_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;
 				status = L2CAP_CS_AUTHOR_PEND;
 				status = L2CAP_CS_AUTHOR_PEND;
 				parent->sk_data_ready(parent, 0);
 				parent->sk_data_ready(parent, 0);
 			} else {
 			} else {
-				l2cap_state_change(chan, BT_CONFIG);
+				__l2cap_state_change(chan, BT_CONFIG);
 				result = L2CAP_CR_SUCCESS;
 				result = L2CAP_CR_SUCCESS;
 				status = L2CAP_CS_NO_INFO;
 				status = L2CAP_CS_NO_INFO;
 			}
 			}
 		} else {
 		} else {
-			l2cap_state_change(chan, BT_CONNECT2);
+			__l2cap_state_change(chan, BT_CONNECT2);
 			result = L2CAP_CR_PEND;
 			result = L2CAP_CR_PEND;
 			status = L2CAP_CS_AUTHEN_PEND;
 			status = L2CAP_CS_AUTHEN_PEND;
 		}
 		}
 	} else {
 	} else {
-		l2cap_state_change(chan, BT_CONNECT2);
+		__l2cap_state_change(chan, BT_CONNECT2);
 		result = L2CAP_CR_PEND;
 		result = L2CAP_CR_PEND;
 		status = L2CAP_CS_NO_INFO;
 		status = L2CAP_CS_NO_INFO;
 	}
 	}
 
 
 response:
 response:
 	release_sock(parent);
 	release_sock(parent);
+	mutex_unlock(&conn->chan_lock);
 
 
 sendresp:
 sendresp:
 	rsp.scid   = cpu_to_le16(scid);
 	rsp.scid   = cpu_to_le16(scid);
@@ -2695,8 +2743,7 @@ sendresp:
 		conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_SENT;
 		conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_SENT;
 		conn->info_ident = l2cap_get_ident(conn);
 		conn->info_ident = l2cap_get_ident(conn);
 
 
-		schedule_delayed_work(&conn->info_timer,
-					msecs_to_jiffies(L2CAP_INFO_TIMEOUT));
+		schedule_delayed_work(&conn->info_timer, L2CAP_INFO_TIMEOUT);
 
 
 		l2cap_send_cmd(conn, conn->info_ident,
 		l2cap_send_cmd(conn, conn->info_ident,
 					L2CAP_INFO_REQ, sizeof(info), &info);
 					L2CAP_INFO_REQ, sizeof(info), &info);
@@ -2719,27 +2766,36 @@ static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hd
 	struct l2cap_conn_rsp *rsp = (struct l2cap_conn_rsp *) data;
 	struct l2cap_conn_rsp *rsp = (struct l2cap_conn_rsp *) data;
 	u16 scid, dcid, result, status;
 	u16 scid, dcid, result, status;
 	struct l2cap_chan *chan;
 	struct l2cap_chan *chan;
-	struct sock *sk;
 	u8 req[128];
 	u8 req[128];
+	int err;
 
 
 	scid   = __le16_to_cpu(rsp->scid);
 	scid   = __le16_to_cpu(rsp->scid);
 	dcid   = __le16_to_cpu(rsp->dcid);
 	dcid   = __le16_to_cpu(rsp->dcid);
 	result = __le16_to_cpu(rsp->result);
 	result = __le16_to_cpu(rsp->result);
 	status = __le16_to_cpu(rsp->status);
 	status = __le16_to_cpu(rsp->status);
 
 
-	BT_DBG("dcid 0x%4.4x scid 0x%4.4x result 0x%2.2x status 0x%2.2x", dcid, scid, result, status);
+	BT_DBG("dcid 0x%4.4x scid 0x%4.4x result 0x%2.2x status 0x%2.2x",
+						dcid, scid, result, status);
+
+	mutex_lock(&conn->chan_lock);
 
 
 	if (scid) {
 	if (scid) {
-		chan = l2cap_get_chan_by_scid(conn, scid);
-		if (!chan)
-			return -EFAULT;
+		chan = __l2cap_get_chan_by_scid(conn, scid);
+		if (!chan) {
+			err = -EFAULT;
+			goto unlock;
+		}
 	} else {
 	} else {
-		chan = l2cap_get_chan_by_ident(conn, cmd->ident);
-		if (!chan)
-			return -EFAULT;
+		chan = __l2cap_get_chan_by_ident(conn, cmd->ident);
+		if (!chan) {
+			err = -EFAULT;
+			goto unlock;
+		}
 	}
 	}
 
 
-	sk = chan->sk;
+	err = 0;
+
+	l2cap_chan_lock(chan);
 
 
 	switch (result) {
 	switch (result) {
 	case L2CAP_CR_SUCCESS:
 	case L2CAP_CR_SUCCESS:
@@ -2765,8 +2821,12 @@ static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hd
 		break;
 		break;
 	}
 	}
 
 
-	release_sock(sk);
-	return 0;
+	l2cap_chan_unlock(chan);
+
+unlock:
+	mutex_unlock(&conn->chan_lock);
+
+	return err;
 }
 }
 
 
 static inline void set_default_fcs(struct l2cap_chan *chan)
 static inline void set_default_fcs(struct l2cap_chan *chan)
@@ -2786,7 +2846,6 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr
 	u16 dcid, flags;
 	u16 dcid, flags;
 	u8 rsp[64];
 	u8 rsp[64];
 	struct l2cap_chan *chan;
 	struct l2cap_chan *chan;
-	struct sock *sk;
 	int len;
 	int len;
 
 
 	dcid  = __le16_to_cpu(req->dcid);
 	dcid  = __le16_to_cpu(req->dcid);
@@ -2798,7 +2857,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr
 	if (!chan)
 	if (!chan)
 		return -ENOENT;
 		return -ENOENT;
 
 
-	sk = chan->sk;
+	l2cap_chan_lock(chan);
 
 
 	if (chan->state != BT_CONFIG && chan->state != BT_CONNECT2) {
 	if (chan->state != BT_CONFIG && chan->state != BT_CONNECT2) {
 		struct l2cap_cmd_rej_cid rej;
 		struct l2cap_cmd_rej_cid rej;
@@ -2860,7 +2919,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr
 		if (chan->mode == L2CAP_MODE_ERTM)
 		if (chan->mode == L2CAP_MODE_ERTM)
 			l2cap_ertm_init(chan);
 			l2cap_ertm_init(chan);
 
 
-		l2cap_chan_ready(sk);
+		l2cap_chan_ready(chan);
 		goto unlock;
 		goto unlock;
 	}
 	}
 
 
@@ -2887,7 +2946,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr
 	}
 	}
 
 
 unlock:
 unlock:
-	release_sock(sk);
+	l2cap_chan_unlock(chan);
 	return 0;
 	return 0;
 }
 }
 
 
@@ -2896,7 +2955,6 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr
 	struct l2cap_conf_rsp *rsp = (struct l2cap_conf_rsp *)data;
 	struct l2cap_conf_rsp *rsp = (struct l2cap_conf_rsp *)data;
 	u16 scid, flags, result;
 	u16 scid, flags, result;
 	struct l2cap_chan *chan;
 	struct l2cap_chan *chan;
-	struct sock *sk;
 	int len = cmd->len - sizeof(*rsp);
 	int len = cmd->len - sizeof(*rsp);
 
 
 	scid   = __le16_to_cpu(rsp->scid);
 	scid   = __le16_to_cpu(rsp->scid);
@@ -2910,7 +2968,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr
 	if (!chan)
 	if (!chan)
 		return 0;
 		return 0;
 
 
-	sk = chan->sk;
+	l2cap_chan_lock(chan);
 
 
 	switch (result) {
 	switch (result) {
 	case L2CAP_CONF_SUCCESS:
 	case L2CAP_CONF_SUCCESS:
@@ -2969,9 +3027,9 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr
 		}
 		}
 
 
 	default:
 	default:
-		sk->sk_err = ECONNRESET;
-		__set_chan_timer(chan,
-				msecs_to_jiffies(L2CAP_DISC_REJ_TIMEOUT));
+		l2cap_chan_set_err(chan, ECONNRESET);
+
+		__set_chan_timer(chan, L2CAP_DISC_REJ_TIMEOUT);
 		l2cap_send_disconn_req(conn, chan, ECONNRESET);
 		l2cap_send_disconn_req(conn, chan, ECONNRESET);
 		goto done;
 		goto done;
 	}
 	}
@@ -2991,11 +3049,11 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr
 		if (chan->mode ==  L2CAP_MODE_ERTM)
 		if (chan->mode ==  L2CAP_MODE_ERTM)
 			l2cap_ertm_init(chan);
 			l2cap_ertm_init(chan);
 
 
-		l2cap_chan_ready(sk);
+		l2cap_chan_ready(chan);
 	}
 	}
 
 
 done:
 done:
-	release_sock(sk);
+	l2cap_chan_unlock(chan);
 	return 0;
 	return 0;
 }
 }
 
 
@@ -3012,9 +3070,15 @@ static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd
 
 
 	BT_DBG("scid 0x%4.4x dcid 0x%4.4x", scid, dcid);
 	BT_DBG("scid 0x%4.4x dcid 0x%4.4x", scid, dcid);
 
 
-	chan = l2cap_get_chan_by_scid(conn, dcid);
-	if (!chan)
+	mutex_lock(&conn->chan_lock);
+
+	chan = __l2cap_get_chan_by_scid(conn, dcid);
+	if (!chan) {
+		mutex_unlock(&conn->chan_lock);
 		return 0;
 		return 0;
+	}
+
+	l2cap_chan_lock(chan);
 
 
 	sk = chan->sk;
 	sk = chan->sk;
 
 
@@ -3022,12 +3086,18 @@ static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd
 	rsp.scid = cpu_to_le16(chan->dcid);
 	rsp.scid = cpu_to_le16(chan->dcid);
 	l2cap_send_cmd(conn, cmd->ident, L2CAP_DISCONN_RSP, sizeof(rsp), &rsp);
 	l2cap_send_cmd(conn, cmd->ident, L2CAP_DISCONN_RSP, sizeof(rsp), &rsp);
 
 
+	lock_sock(sk);
 	sk->sk_shutdown = SHUTDOWN_MASK;
 	sk->sk_shutdown = SHUTDOWN_MASK;
+	release_sock(sk);
 
 
 	l2cap_chan_del(chan, ECONNRESET);
 	l2cap_chan_del(chan, ECONNRESET);
-	release_sock(sk);
+
+	l2cap_chan_unlock(chan);
 
 
 	chan->ops->close(chan->data);
 	chan->ops->close(chan->data);
+
+	mutex_unlock(&conn->chan_lock);
+
 	return 0;
 	return 0;
 }
 }
 
 
@@ -3036,23 +3106,30 @@ static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, struct l2cap_cmd
 	struct l2cap_disconn_rsp *rsp = (struct l2cap_disconn_rsp *) data;
 	struct l2cap_disconn_rsp *rsp = (struct l2cap_disconn_rsp *) data;
 	u16 dcid, scid;
 	u16 dcid, scid;
 	struct l2cap_chan *chan;
 	struct l2cap_chan *chan;
-	struct sock *sk;
 
 
 	scid = __le16_to_cpu(rsp->scid);
 	scid = __le16_to_cpu(rsp->scid);
 	dcid = __le16_to_cpu(rsp->dcid);
 	dcid = __le16_to_cpu(rsp->dcid);
 
 
 	BT_DBG("dcid 0x%4.4x scid 0x%4.4x", dcid, scid);
 	BT_DBG("dcid 0x%4.4x scid 0x%4.4x", dcid, scid);
 
 
-	chan = l2cap_get_chan_by_scid(conn, scid);
-	if (!chan)
+	mutex_lock(&conn->chan_lock);
+
+	chan = __l2cap_get_chan_by_scid(conn, scid);
+	if (!chan) {
+		mutex_unlock(&conn->chan_lock);
 		return 0;
 		return 0;
+	}
 
 
-	sk = chan->sk;
+	l2cap_chan_lock(chan);
 
 
 	l2cap_chan_del(chan, 0);
 	l2cap_chan_del(chan, 0);
-	release_sock(sk);
+
+	l2cap_chan_unlock(chan);
 
 
 	chan->ops->close(chan->data);
 	chan->ops->close(chan->data);
+
+	mutex_unlock(&conn->chan_lock);
+
 	return 0;
 	return 0;
 }
 }
 
 
@@ -3132,7 +3209,8 @@ static inline int l2cap_information_rsp(struct l2cap_conn *conn, struct l2cap_cm
 		return 0;
 		return 0;
 	}
 	}
 
 
-	if (type == L2CAP_IT_FEAT_MASK) {
+	switch (type) {
+	case L2CAP_IT_FEAT_MASK:
 		conn->feat_mask = get_unaligned_le32(rsp->data);
 		conn->feat_mask = get_unaligned_le32(rsp->data);
 
 
 		if (conn->feat_mask & L2CAP_FEAT_FIXED_CHAN) {
 		if (conn->feat_mask & L2CAP_FEAT_FIXED_CHAN) {
@@ -3149,11 +3227,15 @@ static inline int l2cap_information_rsp(struct l2cap_conn *conn, struct l2cap_cm
 
 
 			l2cap_conn_start(conn);
 			l2cap_conn_start(conn);
 		}
 		}
-	} else if (type == L2CAP_IT_FIXED_CHAN) {
+		break;
+
+	case L2CAP_IT_FIXED_CHAN:
+		conn->fixed_chan_mask = rsp->data[0];
 		conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
 		conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
 		conn->info_ident = 0;
 		conn->info_ident = 0;
 
 
 		l2cap_conn_start(conn);
 		l2cap_conn_start(conn);
+		break;
 	}
 	}
 
 
 	return 0;
 	return 0;
@@ -3713,19 +3795,11 @@ static int l2cap_reassemble_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u3
 
 
 static void l2cap_ertm_enter_local_busy(struct l2cap_chan *chan)
 static void l2cap_ertm_enter_local_busy(struct l2cap_chan *chan)
 {
 {
-	u32 control;
-
 	BT_DBG("chan %p, Enter local busy", chan);
 	BT_DBG("chan %p, Enter local busy", chan);
 
 
 	set_bit(CONN_LOCAL_BUSY, &chan->conn_state);
 	set_bit(CONN_LOCAL_BUSY, &chan->conn_state);
 
 
-	control = __set_reqseq(chan, chan->buffer_seq);
-	control |= __set_ctrl_super(chan, L2CAP_SUPER_RNR);
-	l2cap_send_sframe(chan, control);
-
-	set_bit(CONN_RNR_SENT, &chan->conn_state);
-
-	__clear_ack_timer(chan);
+	__set_ack_timer(chan);
 }
 }
 
 
 static void l2cap_ertm_exit_local_busy(struct l2cap_chan *chan)
 static void l2cap_ertm_exit_local_busy(struct l2cap_chan *chan)
@@ -3865,8 +3939,11 @@ static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u32 rx_cont
 		goto drop;
 		goto drop;
 	}
 	}
 
 
-	if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state))
+	if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
+		if (!test_bit(CONN_RNR_SENT, &chan->conn_state))
+			l2cap_send_ack(chan);
 		goto drop;
 		goto drop;
+	}
 
 
 	if (tx_seq == chan->expected_tx_seq)
 	if (tx_seq == chan->expected_tx_seq)
 		goto expected;
 		goto expected;
@@ -3927,15 +4004,15 @@ static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u32 rx_cont
 		__skb_queue_head_init(&chan->srej_q);
 		__skb_queue_head_init(&chan->srej_q);
 		l2cap_add_to_srej_queue(chan, skb, tx_seq, sar);
 		l2cap_add_to_srej_queue(chan, skb, tx_seq, sar);
 
 
-		set_bit(CONN_SEND_PBIT, &chan->conn_state);
+		/* Set P-bit only if there are some I-frames to ack. */
+		if (__clear_ack_timer(chan))
+			set_bit(CONN_SEND_PBIT, &chan->conn_state);
 
 
 		err = l2cap_send_srejframe(chan, tx_seq);
 		err = l2cap_send_srejframe(chan, tx_seq);
 		if (err < 0) {
 		if (err < 0) {
 			l2cap_send_disconn_req(chan->conn, chan, -err);
 			l2cap_send_disconn_req(chan->conn, chan, -err);
 			return err;
 			return err;
 		}
 		}
-
-		__clear_ack_timer(chan);
 	}
 	}
 	return 0;
 	return 0;
 
 
@@ -4135,9 +4212,8 @@ static inline int l2cap_data_channel_sframe(struct l2cap_chan *chan, u32 rx_cont
 	return 0;
 	return 0;
 }
 }
 
 
-static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb)
+static int l2cap_ertm_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb)
 {
 {
-	struct l2cap_chan *chan = l2cap_pi(sk)->chan;
 	u32 control;
 	u32 control;
 	u16 req_seq;
 	u16 req_seq;
 	int len, next_tx_seq_offset, req_seq_offset;
 	int len, next_tx_seq_offset, req_seq_offset;
@@ -4205,7 +4281,6 @@ drop:
 static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk_buff *skb)
 static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk_buff *skb)
 {
 {
 	struct l2cap_chan *chan;
 	struct l2cap_chan *chan;
-	struct sock *sk = NULL;
 	u32 control;
 	u32 control;
 	u16 tx_seq;
 	u16 tx_seq;
 	int len;
 	int len;
@@ -4213,10 +4288,12 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk
 	chan = l2cap_get_chan_by_scid(conn, cid);
 	chan = l2cap_get_chan_by_scid(conn, cid);
 	if (!chan) {
 	if (!chan) {
 		BT_DBG("unknown cid 0x%4.4x", cid);
 		BT_DBG("unknown cid 0x%4.4x", cid);
-		goto drop;
+		/* Drop packet and return */
+		kfree_skb(skb);
+		return 0;
 	}
 	}
 
 
-	sk = chan->sk;
+	l2cap_chan_lock(chan);
 
 
 	BT_DBG("chan %p, len %d", chan, skb->len);
 	BT_DBG("chan %p, len %d", chan, skb->len);
 
 
@@ -4238,7 +4315,7 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk
 		break;
 		break;
 
 
 	case L2CAP_MODE_ERTM:
 	case L2CAP_MODE_ERTM:
-		l2cap_ertm_data_rcv(sk, skb);
+		l2cap_ertm_data_rcv(chan, skb);
 
 
 		goto done;
 		goto done;
 
 
@@ -4287,26 +4364,20 @@ drop:
 	kfree_skb(skb);
 	kfree_skb(skb);
 
 
 done:
 done:
-	if (sk)
-		release_sock(sk);
+	l2cap_chan_unlock(chan);
 
 
 	return 0;
 	return 0;
 }
 }
 
 
 static inline int l2cap_conless_channel(struct l2cap_conn *conn, __le16 psm, struct sk_buff *skb)
 static inline int l2cap_conless_channel(struct l2cap_conn *conn, __le16 psm, struct sk_buff *skb)
 {
 {
-	struct sock *sk = NULL;
 	struct l2cap_chan *chan;
 	struct l2cap_chan *chan;
 
 
 	chan = l2cap_global_chan_by_psm(0, psm, conn->src);
 	chan = l2cap_global_chan_by_psm(0, psm, conn->src);
 	if (!chan)
 	if (!chan)
 		goto drop;
 		goto drop;
 
 
-	sk = chan->sk;
-
-	lock_sock(sk);
-
-	BT_DBG("sk %p, len %d", sk, skb->len);
+	BT_DBG("chan %p, len %d", chan, skb->len);
 
 
 	if (chan->state != BT_BOUND && chan->state != BT_CONNECTED)
 	if (chan->state != BT_BOUND && chan->state != BT_CONNECTED)
 		goto drop;
 		goto drop;
@@ -4315,31 +4386,23 @@ static inline int l2cap_conless_channel(struct l2cap_conn *conn, __le16 psm, str
 		goto drop;
 		goto drop;
 
 
 	if (!chan->ops->recv(chan->data, skb))
 	if (!chan->ops->recv(chan->data, skb))
-		goto done;
+		return 0;
 
 
 drop:
 drop:
 	kfree_skb(skb);
 	kfree_skb(skb);
 
 
-done:
-	if (sk)
-		release_sock(sk);
 	return 0;
 	return 0;
 }
 }
 
 
 static inline int l2cap_att_channel(struct l2cap_conn *conn, __le16 cid, struct sk_buff *skb)
 static inline int l2cap_att_channel(struct l2cap_conn *conn, __le16 cid, struct sk_buff *skb)
 {
 {
-	struct sock *sk = NULL;
 	struct l2cap_chan *chan;
 	struct l2cap_chan *chan;
 
 
 	chan = l2cap_global_chan_by_scid(0, cid, conn->src);
 	chan = l2cap_global_chan_by_scid(0, cid, conn->src);
 	if (!chan)
 	if (!chan)
 		goto drop;
 		goto drop;
 
 
-	sk = chan->sk;
-
-	lock_sock(sk);
-
-	BT_DBG("sk %p, len %d", sk, skb->len);
+	BT_DBG("chan %p, len %d", chan, skb->len);
 
 
 	if (chan->state != BT_BOUND && chan->state != BT_CONNECTED)
 	if (chan->state != BT_BOUND && chan->state != BT_CONNECTED)
 		goto drop;
 		goto drop;
@@ -4348,14 +4411,11 @@ static inline int l2cap_att_channel(struct l2cap_conn *conn, __le16 cid, struct
 		goto drop;
 		goto drop;
 
 
 	if (!chan->ops->recv(chan->data, skb))
 	if (!chan->ops->recv(chan->data, skb))
-		goto done;
+		return 0;
 
 
 drop:
 drop:
 	kfree_skb(skb);
 	kfree_skb(skb);
 
 
-done:
-	if (sk)
-		release_sock(sk);
 	return 0;
 	return 0;
 }
 }
 
 
@@ -4479,8 +4539,7 @@ static inline void l2cap_check_encryption(struct l2cap_chan *chan, u8 encrypt)
 	if (encrypt == 0x00) {
 	if (encrypt == 0x00) {
 		if (chan->sec_level == BT_SECURITY_MEDIUM) {
 		if (chan->sec_level == BT_SECURITY_MEDIUM) {
 			__clear_chan_timer(chan);
 			__clear_chan_timer(chan);
-			__set_chan_timer(chan,
-					msecs_to_jiffies(L2CAP_ENC_TIMEOUT));
+			__set_chan_timer(chan, L2CAP_ENC_TIMEOUT);
 		} else if (chan->sec_level == BT_SECURITY_HIGH)
 		} else if (chan->sec_level == BT_SECURITY_HIGH)
 			l2cap_chan_close(chan, ECONNREFUSED);
 			l2cap_chan_close(chan, ECONNREFUSED);
 	} else {
 	} else {
@@ -4504,57 +4563,49 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
 		cancel_delayed_work(&conn->security_timer);
 		cancel_delayed_work(&conn->security_timer);
 	}
 	}
 
 
-	rcu_read_lock();
-
-	list_for_each_entry_rcu(chan, &conn->chan_l, list) {
-		struct sock *sk = chan->sk;
+	mutex_lock(&conn->chan_lock);
 
 
-		bh_lock_sock(sk);
+	list_for_each_entry(chan, &conn->chan_l, list) {
+		l2cap_chan_lock(chan);
 
 
 		BT_DBG("chan->scid %d", chan->scid);
 		BT_DBG("chan->scid %d", chan->scid);
 
 
 		if (chan->scid == L2CAP_CID_LE_DATA) {
 		if (chan->scid == L2CAP_CID_LE_DATA) {
 			if (!status && encrypt) {
 			if (!status && encrypt) {
 				chan->sec_level = hcon->sec_level;
 				chan->sec_level = hcon->sec_level;
-				l2cap_chan_ready(sk);
+				l2cap_chan_ready(chan);
 			}
 			}
 
 
-			bh_unlock_sock(sk);
+			l2cap_chan_unlock(chan);
 			continue;
 			continue;
 		}
 		}
 
 
 		if (test_bit(CONF_CONNECT_PEND, &chan->conf_state)) {
 		if (test_bit(CONF_CONNECT_PEND, &chan->conf_state)) {
-			bh_unlock_sock(sk);
+			l2cap_chan_unlock(chan);
 			continue;
 			continue;
 		}
 		}
 
 
 		if (!status && (chan->state == BT_CONNECTED ||
 		if (!status && (chan->state == BT_CONNECTED ||
 						chan->state == BT_CONFIG)) {
 						chan->state == BT_CONFIG)) {
 			l2cap_check_encryption(chan, encrypt);
 			l2cap_check_encryption(chan, encrypt);
-			bh_unlock_sock(sk);
+			l2cap_chan_unlock(chan);
 			continue;
 			continue;
 		}
 		}
 
 
 		if (chan->state == BT_CONNECT) {
 		if (chan->state == BT_CONNECT) {
 			if (!status) {
 			if (!status) {
-				struct l2cap_conn_req req;
-				req.scid = cpu_to_le16(chan->scid);
-				req.psm  = chan->psm;
-
-				chan->ident = l2cap_get_ident(conn);
-				set_bit(CONF_CONNECT_PEND, &chan->conf_state);
-
-				l2cap_send_cmd(conn, chan->ident,
-					L2CAP_CONN_REQ, sizeof(req), &req);
+				l2cap_send_conn_req(chan);
 			} else {
 			} else {
 				__clear_chan_timer(chan);
 				__clear_chan_timer(chan);
-				__set_chan_timer(chan,
-					msecs_to_jiffies(L2CAP_DISC_TIMEOUT));
+				__set_chan_timer(chan, L2CAP_DISC_TIMEOUT);
 			}
 			}
 		} else if (chan->state == BT_CONNECT2) {
 		} else if (chan->state == BT_CONNECT2) {
+			struct sock *sk = chan->sk;
 			struct l2cap_conn_rsp rsp;
 			struct l2cap_conn_rsp rsp;
 			__u16 res, stat;
 			__u16 res, stat;
 
 
+			lock_sock(sk);
+
 			if (!status) {
 			if (!status) {
 				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;
@@ -4563,18 +4614,19 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
 					if (parent)
 					if (parent)
 						parent->sk_data_ready(parent, 0);
 						parent->sk_data_ready(parent, 0);
 				} else {
 				} else {
-					l2cap_state_change(chan, BT_CONFIG);
+					__l2cap_state_change(chan, BT_CONFIG);
 					res = L2CAP_CR_SUCCESS;
 					res = L2CAP_CR_SUCCESS;
 					stat = L2CAP_CS_NO_INFO;
 					stat = L2CAP_CS_NO_INFO;
 				}
 				}
 			} else {
 			} else {
-				l2cap_state_change(chan, BT_DISCONN);
-				__set_chan_timer(chan,
-					msecs_to_jiffies(L2CAP_DISC_TIMEOUT));
+				__l2cap_state_change(chan, BT_DISCONN);
+				__set_chan_timer(chan, L2CAP_DISC_TIMEOUT);
 				res = L2CAP_CR_SEC_BLOCK;
 				res = L2CAP_CR_SEC_BLOCK;
 				stat = L2CAP_CS_NO_INFO;
 				stat = L2CAP_CS_NO_INFO;
 			}
 			}
 
 
+			release_sock(sk);
+
 			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);
 			rsp.result = cpu_to_le16(res);
 			rsp.result = cpu_to_le16(res);
@@ -4583,10 +4635,10 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
 							sizeof(rsp), &rsp);
 							sizeof(rsp), &rsp);
 		}
 		}
 
 
-		bh_unlock_sock(sk);
+		l2cap_chan_unlock(chan);
 	}
 	}
 
 
-	rcu_read_unlock();
+	mutex_unlock(&conn->chan_lock);
 
 
 	return 0;
 	return 0;
 }
 }
@@ -4647,6 +4699,7 @@ int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 flags)
 
 
 		if (chan && chan->sk) {
 		if (chan && chan->sk) {
 			struct sock *sk = chan->sk;
 			struct sock *sk = chan->sk;
+			lock_sock(sk);
 
 
 			if (chan->imtu < len - L2CAP_HDR_SIZE) {
 			if (chan->imtu < len - L2CAP_HDR_SIZE) {
 				BT_ERR("Frame exceeding recv MTU (len %d, "
 				BT_ERR("Frame exceeding recv MTU (len %d, "
@@ -4717,7 +4770,7 @@ static int l2cap_debugfs_show(struct seq_file *f, void *p)
 					c->state, __le16_to_cpu(c->psm),
 					c->state, __le16_to_cpu(c->psm),
 					c->scid, c->dcid, c->imtu, c->omtu,
 					c->scid, c->dcid, c->imtu, c->omtu,
 					c->sec_level, c->mode);
 					c->sec_level, c->mode);
-}
+	}
 
 
 	read_unlock(&chan_list_lock);
 	read_unlock(&chan_list_lock);
 
 

+ 45 - 9
net/bluetooth/l2cap_sock.c

@@ -125,13 +125,15 @@ static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int al
 
 
 	err = l2cap_chan_connect(chan, la.l2_psm, la.l2_cid, &la.l2_bdaddr);
 	err = l2cap_chan_connect(chan, la.l2_psm, la.l2_cid, &la.l2_bdaddr);
 	if (err)
 	if (err)
-		goto done;
+		return err;
+
+	lock_sock(sk);
 
 
 	err = bt_sock_wait_state(sk, BT_CONNECTED,
 	err = bt_sock_wait_state(sk, BT_CONNECTED,
 			sock_sndtimeo(sk, flags & O_NONBLOCK));
 			sock_sndtimeo(sk, flags & O_NONBLOCK));
-done:
-	if (sock_owned_by_user(sk))
-		release_sock(sk);
+
+	release_sock(sk);
+
 	return err;
 	return err;
 }
 }
 
 
@@ -783,7 +785,7 @@ static void l2cap_sock_kill(struct sock *sk)
 	if (!sock_flag(sk, SOCK_ZAPPED) || sk->sk_socket)
 	if (!sock_flag(sk, SOCK_ZAPPED) || sk->sk_socket)
 		return;
 		return;
 
 
-	BT_DBG("sk %p state %d", sk, sk->sk_state);
+	BT_DBG("sk %p state %s", sk, state_to_string(sk->sk_state));
 
 
 	/* Kill poor orphan */
 	/* Kill poor orphan */
 
 
@@ -795,7 +797,8 @@ static void l2cap_sock_kill(struct sock *sk)
 static int l2cap_sock_shutdown(struct socket *sock, int how)
 static int l2cap_sock_shutdown(struct socket *sock, int how)
 {
 {
 	struct sock *sk = sock->sk;
 	struct sock *sk = sock->sk;
-	struct l2cap_chan *chan = l2cap_pi(sk)->chan;
+	struct l2cap_chan *chan;
+	struct l2cap_conn *conn;
 	int err = 0;
 	int err = 0;
 
 
 	BT_DBG("sock %p, sk %p", sock, sk);
 	BT_DBG("sock %p, sk %p", sock, sk);
@@ -803,13 +806,24 @@ static int l2cap_sock_shutdown(struct socket *sock, int how)
 	if (!sk)
 	if (!sk)
 		return 0;
 		return 0;
 
 
+	chan = l2cap_pi(sk)->chan;
+	conn = chan->conn;
+
+	if (conn)
+		mutex_lock(&conn->chan_lock);
+
+	l2cap_chan_lock(chan);
 	lock_sock(sk);
 	lock_sock(sk);
+
 	if (!sk->sk_shutdown) {
 	if (!sk->sk_shutdown) {
 		if (chan->mode == L2CAP_MODE_ERTM)
 		if (chan->mode == L2CAP_MODE_ERTM)
 			err = __l2cap_wait_ack(sk);
 			err = __l2cap_wait_ack(sk);
 
 
 		sk->sk_shutdown = SHUTDOWN_MASK;
 		sk->sk_shutdown = SHUTDOWN_MASK;
+
+		release_sock(sk);
 		l2cap_chan_close(chan, 0);
 		l2cap_chan_close(chan, 0);
+		lock_sock(sk);
 
 
 		if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime)
 		if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime)
 			err = bt_sock_wait_state(sk, BT_CLOSED,
 			err = bt_sock_wait_state(sk, BT_CLOSED,
@@ -820,6 +834,11 @@ static int l2cap_sock_shutdown(struct socket *sock, int how)
 		err = -sk->sk_err;
 		err = -sk->sk_err;
 
 
 	release_sock(sk);
 	release_sock(sk);
+	l2cap_chan_unlock(chan);
+
+	if (conn)
+		mutex_unlock(&conn->chan_lock);
+
 	return err;
 	return err;
 }
 }
 
 
@@ -862,8 +881,12 @@ static int l2cap_sock_recv_cb(void *data, struct sk_buff *skb)
 	struct sock *sk = data;
 	struct sock *sk = data;
 	struct l2cap_pinfo *pi = l2cap_pi(sk);
 	struct l2cap_pinfo *pi = l2cap_pi(sk);
 
 
-	if (pi->rx_busy_skb)
-		return -ENOMEM;
+	lock_sock(sk);
+
+	if (pi->rx_busy_skb) {
+		err = -ENOMEM;
+		goto done;
+	}
 
 
 	err = sock_queue_rcv_skb(sk, skb);
 	err = sock_queue_rcv_skb(sk, skb);
 
 
@@ -882,6 +905,9 @@ static int l2cap_sock_recv_cb(void *data, struct sk_buff *skb)
 		err = 0;
 		err = 0;
 	}
 	}
 
 
+done:
+	release_sock(sk);
+
 	return err;
 	return err;
 }
 }
 
 
@@ -899,12 +925,22 @@ static void l2cap_sock_state_change_cb(void *data, int state)
 	sk->sk_state = state;
 	sk->sk_state = state;
 }
 }
 
 
+static struct sk_buff *l2cap_sock_alloc_skb_cb(struct l2cap_chan *chan,
+					       unsigned long len, int nb,
+					       int *err)
+{
+	struct sock *sk = chan->sk;
+
+	return bt_skb_send_alloc(sk, len, nb, err);
+}
+
 static struct l2cap_ops l2cap_chan_ops = {
 static struct l2cap_ops l2cap_chan_ops = {
 	.name		= "L2CAP Socket Interface",
 	.name		= "L2CAP Socket Interface",
 	.new_connection	= l2cap_sock_new_connection_cb,
 	.new_connection	= l2cap_sock_new_connection_cb,
 	.recv		= l2cap_sock_recv_cb,
 	.recv		= l2cap_sock_recv_cb,
 	.close		= l2cap_sock_close_cb,
 	.close		= l2cap_sock_close_cb,
 	.state_change	= l2cap_sock_state_change_cb,
 	.state_change	= l2cap_sock_state_change_cb,
+	.alloc_skb	= l2cap_sock_alloc_skb_cb,
 };
 };
 
 
 static void l2cap_sock_destruct(struct sock *sk)
 static void l2cap_sock_destruct(struct sock *sk)
@@ -1004,7 +1040,7 @@ static struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock, int p
 	INIT_LIST_HEAD(&bt_sk(sk)->accept_q);
 	INIT_LIST_HEAD(&bt_sk(sk)->accept_q);
 
 
 	sk->sk_destruct = l2cap_sock_destruct;
 	sk->sk_destruct = l2cap_sock_destruct;
-	sk->sk_sndtimeo = msecs_to_jiffies(L2CAP_CONN_TIMEOUT);
+	sk->sk_sndtimeo = L2CAP_CONN_TIMEOUT;
 
 
 	sock_reset_flag(sk, SOCK_ZAPPED);
 	sock_reset_flag(sk, SOCK_ZAPPED);
 
 

+ 24 - 3
net/bluetooth/lib.c

@@ -24,6 +24,8 @@
 
 
 /* Bluetooth kernel library. */
 /* Bluetooth kernel library. */
 
 
+#define pr_fmt(fmt) "Bluetooth: " fmt
+
 #include <linux/module.h>
 #include <linux/module.h>
 
 
 #include <linux/kernel.h>
 #include <linux/kernel.h>
@@ -151,7 +153,26 @@ int bt_to_errno(__u16 code)
 }
 }
 EXPORT_SYMBOL(bt_to_errno);
 EXPORT_SYMBOL(bt_to_errno);
 
 
-int bt_printk(const char *level, const char *format, ...)
+int bt_info(const char *format, ...)
+{
+	struct va_format vaf;
+	va_list args;
+	int r;
+
+	va_start(args, format);
+
+	vaf.fmt = format;
+	vaf.va = &args;
+
+	r = pr_info("%pV", &vaf);
+
+	va_end(args);
+
+	return r;
+}
+EXPORT_SYMBOL(bt_info);
+
+int bt_err(const char *format, ...)
 {
 {
 	struct va_format vaf;
 	struct va_format vaf;
 	va_list args;
 	va_list args;
@@ -162,10 +183,10 @@ int bt_printk(const char *level, const char *format, ...)
 	vaf.fmt = format;
 	vaf.fmt = format;
 	vaf.va = &args;
 	vaf.va = &args;
 
 
-	r = printk("%sBluetooth: %pV\n", level, &vaf);
+	r = pr_err("%pV", &vaf);
 
 
 	va_end(args);
 	va_end(args);
 
 
 	return r;
 	return r;
 }
 }
-EXPORT_SYMBOL(bt_printk);
+EXPORT_SYMBOL(bt_err);

+ 1742 - 955
net/bluetooth/mgmt.c

@@ -1,6 +1,8 @@
 /*
 /*
    BlueZ - Bluetooth protocol stack for Linux
    BlueZ - Bluetooth protocol stack for Linux
+
    Copyright (C) 2010  Nokia Corporation
    Copyright (C) 2010  Nokia Corporation
+   Copyright (C) 2011-2012 Intel Corporation
 
 
    This program is free software; you can redistribute it and/or modify
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License version 2 as
    it under the terms of the GNU General Public License version 2 as
@@ -32,12 +34,92 @@
 #include <net/bluetooth/mgmt.h>
 #include <net/bluetooth/mgmt.h>
 #include <net/bluetooth/smp.h>
 #include <net/bluetooth/smp.h>
 
 
-#define MGMT_VERSION	0
-#define MGMT_REVISION	1
+bool enable_hs;
+bool enable_le;
+
+#define MGMT_VERSION	1
+#define MGMT_REVISION	0
+
+static const u16 mgmt_commands[] = {
+	MGMT_OP_READ_INDEX_LIST,
+	MGMT_OP_READ_INFO,
+	MGMT_OP_SET_POWERED,
+	MGMT_OP_SET_DISCOVERABLE,
+	MGMT_OP_SET_CONNECTABLE,
+	MGMT_OP_SET_FAST_CONNECTABLE,
+	MGMT_OP_SET_PAIRABLE,
+	MGMT_OP_SET_LINK_SECURITY,
+	MGMT_OP_SET_SSP,
+	MGMT_OP_SET_HS,
+	MGMT_OP_SET_LE,
+	MGMT_OP_SET_DEV_CLASS,
+	MGMT_OP_SET_LOCAL_NAME,
+	MGMT_OP_ADD_UUID,
+	MGMT_OP_REMOVE_UUID,
+	MGMT_OP_LOAD_LINK_KEYS,
+	MGMT_OP_LOAD_LONG_TERM_KEYS,
+	MGMT_OP_DISCONNECT,
+	MGMT_OP_GET_CONNECTIONS,
+	MGMT_OP_PIN_CODE_REPLY,
+	MGMT_OP_PIN_CODE_NEG_REPLY,
+	MGMT_OP_SET_IO_CAPABILITY,
+	MGMT_OP_PAIR_DEVICE,
+	MGMT_OP_CANCEL_PAIR_DEVICE,
+	MGMT_OP_UNPAIR_DEVICE,
+	MGMT_OP_USER_CONFIRM_REPLY,
+	MGMT_OP_USER_CONFIRM_NEG_REPLY,
+	MGMT_OP_USER_PASSKEY_REPLY,
+	MGMT_OP_USER_PASSKEY_NEG_REPLY,
+	MGMT_OP_READ_LOCAL_OOB_DATA,
+	MGMT_OP_ADD_REMOTE_OOB_DATA,
+	MGMT_OP_REMOVE_REMOTE_OOB_DATA,
+	MGMT_OP_START_DISCOVERY,
+	MGMT_OP_STOP_DISCOVERY,
+	MGMT_OP_CONFIRM_NAME,
+	MGMT_OP_BLOCK_DEVICE,
+	MGMT_OP_UNBLOCK_DEVICE,
+};
+
+static const u16 mgmt_events[] = {
+	MGMT_EV_CONTROLLER_ERROR,
+	MGMT_EV_INDEX_ADDED,
+	MGMT_EV_INDEX_REMOVED,
+	MGMT_EV_NEW_SETTINGS,
+	MGMT_EV_CLASS_OF_DEV_CHANGED,
+	MGMT_EV_LOCAL_NAME_CHANGED,
+	MGMT_EV_NEW_LINK_KEY,
+	MGMT_EV_NEW_LONG_TERM_KEY,
+	MGMT_EV_DEVICE_CONNECTED,
+	MGMT_EV_DEVICE_DISCONNECTED,
+	MGMT_EV_CONNECT_FAILED,
+	MGMT_EV_PIN_CODE_REQUEST,
+	MGMT_EV_USER_CONFIRM_REQUEST,
+	MGMT_EV_USER_PASSKEY_REQUEST,
+	MGMT_EV_AUTH_FAILED,
+	MGMT_EV_DEVICE_FOUND,
+	MGMT_EV_DISCOVERING,
+	MGMT_EV_DEVICE_BLOCKED,
+	MGMT_EV_DEVICE_UNBLOCKED,
+	MGMT_EV_DEVICE_UNPAIRED,
+};
+
+/*
+ * These LE scan and inquiry parameters were chosen according to LE General
+ * Discovery Procedure specification.
+ */
+#define LE_SCAN_TYPE			0x01
+#define LE_SCAN_WIN			0x12
+#define LE_SCAN_INT			0x12
+#define LE_SCAN_TIMEOUT_LE_ONLY		10240	/* TGAP(gen_disc_scan_min) */
+#define LE_SCAN_TIMEOUT_BREDR_LE	5120	/* TGAP(100)/2 */
+
+#define INQUIRY_LEN_BREDR		0x08	/* TGAP(100) */
+#define INQUIRY_LEN_BREDR_LE		0x04	/* TGAP(100)/2 */
 
 
-#define INQUIRY_LEN_BREDR 0x08 /* TGAP(100) */
+#define CACHE_TIMEOUT	msecs_to_jiffies(2 * 1000)
 
 
-#define SERVICE_CACHE_TIMEOUT (5 * 1000)
+#define hdev_is_powered(hdev) (test_bit(HCI_UP, &hdev->flags) && \
+				!test_bit(HCI_AUTO_OFF, &hdev->dev_flags))
 
 
 struct pending_cmd {
 struct pending_cmd {
 	struct list_head list;
 	struct list_head list;
@@ -151,8 +233,8 @@ static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
 	return err;
 	return err;
 }
 }
 
 
-static int cmd_complete(struct sock *sk, u16 index, u16 cmd, void *rp,
-								size_t rp_len)
+static int cmd_complete(struct sock *sk, u16 index, u16 cmd, u8 status,
+			void *rp, size_t rp_len)
 {
 {
 	struct sk_buff *skb;
 	struct sk_buff *skb;
 	struct mgmt_hdr *hdr;
 	struct mgmt_hdr *hdr;
@@ -173,6 +255,7 @@ static int cmd_complete(struct sock *sk, u16 index, u16 cmd, void *rp,
 
 
 	ev = (void *) skb_put(skb, sizeof(*ev) + rp_len);
 	ev = (void *) skb_put(skb, sizeof(*ev) + rp_len);
 	put_unaligned_le16(cmd, &ev->opcode);
 	put_unaligned_le16(cmd, &ev->opcode);
+	ev->status = status;
 
 
 	if (rp)
 	if (rp)
 		memcpy(ev->data, rp, rp_len);
 		memcpy(ev->data, rp, rp_len);
@@ -181,10 +264,11 @@ static int cmd_complete(struct sock *sk, u16 index, u16 cmd, void *rp,
 	if (err < 0)
 	if (err < 0)
 		kfree_skb(skb);
 		kfree_skb(skb);
 
 
-	return err;;
+	return err;
 }
 }
 
 
-static int read_version(struct sock *sk)
+static int read_version(struct sock *sk, struct hci_dev *hdev, void *data,
+			u16 data_len)
 {
 {
 	struct mgmt_rp_read_version rp;
 	struct mgmt_rp_read_version rp;
 
 
@@ -193,11 +277,46 @@ static int read_version(struct sock *sk)
 	rp.version = MGMT_VERSION;
 	rp.version = MGMT_VERSION;
 	put_unaligned_le16(MGMT_REVISION, &rp.revision);
 	put_unaligned_le16(MGMT_REVISION, &rp.revision);
 
 
-	return cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, &rp,
-								sizeof(rp));
+	return cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, 0, &rp,
+			    sizeof(rp));
+}
+
+static int read_commands(struct sock *sk, struct hci_dev *hdev, void *data,
+			 u16 data_len)
+{
+	struct mgmt_rp_read_commands *rp;
+	u16 num_commands = ARRAY_SIZE(mgmt_commands);
+	u16 num_events = ARRAY_SIZE(mgmt_events);
+	u16 *opcode;
+	size_t rp_size;
+	int i, err;
+
+	BT_DBG("sock %p", sk);
+
+	rp_size = sizeof(*rp) + ((num_commands + num_events) * sizeof(u16));
+
+	rp = kmalloc(rp_size, GFP_KERNEL);
+	if (!rp)
+		return -ENOMEM;
+
+	put_unaligned_le16(num_commands, &rp->num_commands);
+	put_unaligned_le16(num_events, &rp->num_events);
+
+	for (i = 0, opcode = rp->opcodes; i < num_commands; i++, opcode++)
+		put_unaligned_le16(mgmt_commands[i], opcode);
+
+	for (i = 0; i < num_events; i++, opcode++)
+		put_unaligned_le16(mgmt_events[i], opcode);
+
+	err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_COMMANDS, 0, rp,
+			   rp_size);
+	kfree(rp);
+
+	return err;
 }
 }
 
 
-static int read_index_list(struct sock *sk)
+static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data,
+			   u16 data_len)
 {
 {
 	struct mgmt_rp_read_index_list *rp;
 	struct mgmt_rp_read_index_list *rp;
 	struct list_head *p;
 	struct list_head *p;
@@ -226,10 +345,7 @@ static int read_index_list(struct sock *sk)
 
 
 	i = 0;
 	i = 0;
 	list_for_each_entry(d, &hci_dev_list, list) {
 	list_for_each_entry(d, &hci_dev_list, list) {
-		if (test_and_clear_bit(HCI_AUTO_OFF, &d->flags))
-			cancel_delayed_work(&d->power_off);
-
-		if (test_bit(HCI_SETUP, &d->flags))
+		if (test_bit(HCI_SETUP, &d->dev_flags))
 			continue;
 			continue;
 
 
 		put_unaligned_le16(d->id, &rp->index[i++]);
 		put_unaligned_le16(d->id, &rp->index[i++]);
@@ -238,8 +354,8 @@ static int read_index_list(struct sock *sk)
 
 
 	read_unlock(&hci_dev_list_lock);
 	read_unlock(&hci_dev_list_lock);
 
 
-	err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST, rp,
-									rp_len);
+	err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST, 0, rp,
+			   rp_len);
 
 
 	kfree(rp);
 	kfree(rp);
 
 
@@ -264,8 +380,13 @@ static u32 get_supported_settings(struct hci_dev *hdev)
 		settings |= MGMT_SETTING_LINK_SECURITY;
 		settings |= MGMT_SETTING_LINK_SECURITY;
 	}
 	}
 
 
-	if (hdev->features[4] & LMP_LE)
-		settings |= MGMT_SETTING_LE;
+	if (enable_hs)
+		settings |= MGMT_SETTING_HS;
+
+	if (enable_le) {
+		if (hdev->features[4] & LMP_LE)
+			settings |= MGMT_SETTING_LE;
+	}
 
 
 	return settings;
 	return settings;
 }
 }
@@ -274,47 +395,36 @@ static u32 get_current_settings(struct hci_dev *hdev)
 {
 {
 	u32 settings = 0;
 	u32 settings = 0;
 
 
-	if (test_bit(HCI_UP, &hdev->flags))
+	if (hdev_is_powered(hdev))
 		settings |= MGMT_SETTING_POWERED;
 		settings |= MGMT_SETTING_POWERED;
-	else
-		return settings;
 
 
-	if (test_bit(HCI_PSCAN, &hdev->flags))
+	if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
 		settings |= MGMT_SETTING_CONNECTABLE;
 		settings |= MGMT_SETTING_CONNECTABLE;
 
 
-	if (test_bit(HCI_ISCAN, &hdev->flags))
+	if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
 		settings |= MGMT_SETTING_DISCOVERABLE;
 		settings |= MGMT_SETTING_DISCOVERABLE;
 
 
-	if (test_bit(HCI_PAIRABLE, &hdev->flags))
+	if (test_bit(HCI_PAIRABLE, &hdev->dev_flags))
 		settings |= MGMT_SETTING_PAIRABLE;
 		settings |= MGMT_SETTING_PAIRABLE;
 
 
 	if (!(hdev->features[4] & LMP_NO_BREDR))
 	if (!(hdev->features[4] & LMP_NO_BREDR))
 		settings |= MGMT_SETTING_BREDR;
 		settings |= MGMT_SETTING_BREDR;
 
 
-	if (hdev->host_features[0] & LMP_HOST_LE)
+	if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
 		settings |= MGMT_SETTING_LE;
 		settings |= MGMT_SETTING_LE;
 
 
-	if (test_bit(HCI_AUTH, &hdev->flags))
+	if (test_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
 		settings |= MGMT_SETTING_LINK_SECURITY;
 		settings |= MGMT_SETTING_LINK_SECURITY;
 
 
-	if (hdev->ssp_mode > 0)
+	if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
 		settings |= MGMT_SETTING_SSP;
 		settings |= MGMT_SETTING_SSP;
 
 
+	if (test_bit(HCI_HS_ENABLED, &hdev->dev_flags))
+		settings |= MGMT_SETTING_HS;
+
 	return settings;
 	return settings;
 }
 }
 
 
-#define EIR_FLAGS		0x01 /* flags */
-#define EIR_UUID16_SOME		0x02 /* 16-bit UUID, more available */
-#define EIR_UUID16_ALL		0x03 /* 16-bit UUID, all listed */
-#define EIR_UUID32_SOME		0x04 /* 32-bit UUID, more available */
-#define EIR_UUID32_ALL		0x05 /* 32-bit UUID, all listed */
-#define EIR_UUID128_SOME	0x06 /* 128-bit UUID, more available */
-#define EIR_UUID128_ALL		0x07 /* 128-bit UUID, all listed */
-#define EIR_NAME_SHORT		0x08 /* shortened local name */
-#define EIR_NAME_COMPLETE	0x09 /* complete local name */
-#define EIR_TX_POWER		0x0A /* transmit power level */
-#define EIR_DEVICE_ID		0x10 /* device ID */
-
 #define PNP_INFO_SVCLASS_ID		0x1200
 #define PNP_INFO_SVCLASS_ID		0x1200
 
 
 static u8 bluetooth_base_uuid[] = {
 static u8 bluetooth_base_uuid[] = {
@@ -425,13 +535,16 @@ static int update_eir(struct hci_dev *hdev)
 {
 {
 	struct hci_cp_write_eir cp;
 	struct hci_cp_write_eir cp;
 
 
+	if (!hdev_is_powered(hdev))
+		return 0;
+
 	if (!(hdev->features[6] & LMP_EXT_INQ))
 	if (!(hdev->features[6] & LMP_EXT_INQ))
 		return 0;
 		return 0;
 
 
-	if (hdev->ssp_mode == 0)
+	if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
 		return 0;
 		return 0;
 
 
-	if (test_bit(HCI_SERVICE_CACHE, &hdev->flags))
+	if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
 		return 0;
 		return 0;
 
 
 	memset(&cp, 0, sizeof(cp));
 	memset(&cp, 0, sizeof(cp));
@@ -460,10 +573,14 @@ static u8 get_service_classes(struct hci_dev *hdev)
 static int update_class(struct hci_dev *hdev)
 static int update_class(struct hci_dev *hdev)
 {
 {
 	u8 cod[3];
 	u8 cod[3];
+	int err;
 
 
 	BT_DBG("%s", hdev->name);
 	BT_DBG("%s", hdev->name);
 
 
-	if (test_bit(HCI_SERVICE_CACHE, &hdev->flags))
+	if (!hdev_is_powered(hdev))
+		return 0;
+
+	if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
 		return 0;
 		return 0;
 
 
 	cod[0] = hdev->minor_class;
 	cod[0] = hdev->minor_class;
@@ -473,15 +590,19 @@ static int update_class(struct hci_dev *hdev)
 	if (memcmp(cod, hdev->dev_class, 3) == 0)
 	if (memcmp(cod, hdev->dev_class, 3) == 0)
 		return 0;
 		return 0;
 
 
-	return hci_send_cmd(hdev, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
+	err = hci_send_cmd(hdev, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
+	if (err == 0)
+		set_bit(HCI_PENDING_CLASS, &hdev->dev_flags);
+
+	return err;
 }
 }
 
 
 static void service_cache_off(struct work_struct *work)
 static void service_cache_off(struct work_struct *work)
 {
 {
 	struct hci_dev *hdev = container_of(work, struct hci_dev,
 	struct hci_dev *hdev = container_of(work, struct hci_dev,
-							service_cache.work);
+					    service_cache.work);
 
 
-	if (!test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->flags))
+	if (!test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
 		return;
 		return;
 
 
 	hci_dev_lock(hdev);
 	hci_dev_lock(hdev);
@@ -492,36 +613,30 @@ static void service_cache_off(struct work_struct *work)
 	hci_dev_unlock(hdev);
 	hci_dev_unlock(hdev);
 }
 }
 
 
-static void mgmt_init_hdev(struct hci_dev *hdev)
+static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev)
 {
 {
-	if (!test_and_set_bit(HCI_MGMT, &hdev->flags))
-		INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
+	if (test_and_set_bit(HCI_MGMT, &hdev->dev_flags))
+		return;
+
+	INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
 
 
-	if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->flags))
-		schedule_delayed_work(&hdev->service_cache,
-				msecs_to_jiffies(SERVICE_CACHE_TIMEOUT));
+	/* Non-mgmt controlled devices get this bit set
+	 * implicitly so that pairing works for them, however
+	 * for mgmt we require user-space to explicitly enable
+	 * it
+	 */
+	clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
 }
 }
 
 
-static int read_controller_info(struct sock *sk, u16 index)
+static int read_controller_info(struct sock *sk, struct hci_dev *hdev,
+				void *data, u16 data_len)
 {
 {
 	struct mgmt_rp_read_info rp;
 	struct mgmt_rp_read_info rp;
-	struct hci_dev *hdev;
 
 
-	BT_DBG("sock %p hci%u", sk, index);
-
-	hdev = hci_dev_get(index);
-	if (!hdev)
-		return cmd_status(sk, index, MGMT_OP_READ_INFO,
-						MGMT_STATUS_INVALID_PARAMS);
-
-	if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->flags))
-		cancel_delayed_work_sync(&hdev->power_off);
+	BT_DBG("sock %p %s", sk, hdev->name);
 
 
 	hci_dev_lock(hdev);
 	hci_dev_lock(hdev);
 
 
-	if (test_and_clear_bit(HCI_PI_MGMT_INIT, &hci_pi(sk)->flags))
-		mgmt_init_hdev(hdev);
-
 	memset(&rp, 0, sizeof(rp));
 	memset(&rp, 0, sizeof(rp));
 
 
 	bacpy(&rp.bdaddr, &hdev->bdaddr);
 	bacpy(&rp.bdaddr, &hdev->bdaddr);
@@ -536,11 +651,12 @@ static int read_controller_info(struct sock *sk, u16 index)
 	memcpy(rp.dev_class, hdev->dev_class, 3);
 	memcpy(rp.dev_class, hdev->dev_class, 3);
 
 
 	memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
 	memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
+	memcpy(rp.short_name, hdev->short_name, sizeof(hdev->short_name));
 
 
 	hci_dev_unlock(hdev);
 	hci_dev_unlock(hdev);
-	hci_dev_put(hdev);
 
 
-	return cmd_complete(sk, index, MGMT_OP_READ_INFO, &rp, sizeof(rp));
+	return cmd_complete(sk, hdev->id, MGMT_OP_READ_INFO, 0, &rp,
+			    sizeof(rp));
 }
 }
 
 
 static void mgmt_pending_free(struct pending_cmd *cmd)
 static void mgmt_pending_free(struct pending_cmd *cmd)
@@ -551,8 +667,8 @@ static void mgmt_pending_free(struct pending_cmd *cmd)
 }
 }
 
 
 static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
 static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
-							struct hci_dev *hdev,
-							void *data, u16 len)
+					    struct hci_dev *hdev, void *data,
+					    u16 len)
 {
 {
 	struct pending_cmd *cmd;
 	struct pending_cmd *cmd;
 
 
@@ -581,8 +697,8 @@ static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
 }
 }
 
 
 static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
 static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
-				void (*cb)(struct pending_cmd *cmd, void *data),
-				void *data)
+				 void (*cb)(struct pending_cmd *cmd, void *data),
+				 void *data)
 {
 {
 	struct list_head *p, *n;
 	struct list_head *p, *n;
 
 
@@ -620,40 +736,39 @@ static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
 {
 {
 	__le32 settings = cpu_to_le32(get_current_settings(hdev));
 	__le32 settings = cpu_to_le32(get_current_settings(hdev));
 
 
-	return cmd_complete(sk, hdev->id, opcode, &settings, sizeof(settings));
+	return cmd_complete(sk, hdev->id, opcode, 0, &settings,
+			    sizeof(settings));
 }
 }
 
 
-static int set_powered(struct sock *sk, u16 index, unsigned char *data, u16 len)
+static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,
+		       u16 len)
 {
 {
-	struct mgmt_mode *cp;
-	struct hci_dev *hdev;
+	struct mgmt_mode *cp = data;
 	struct pending_cmd *cmd;
 	struct pending_cmd *cmd;
-	int err, up;
-
-	cp = (void *) data;
+	int err;
 
 
-	BT_DBG("request for hci%u", index);
+	BT_DBG("request for %s", hdev->name);
 
 
-	if (len != sizeof(*cp))
-		return cmd_status(sk, index, MGMT_OP_SET_POWERED,
-						MGMT_STATUS_INVALID_PARAMS);
+	hci_dev_lock(hdev);
 
 
-	hdev = hci_dev_get(index);
-	if (!hdev)
-		return cmd_status(sk, index, MGMT_OP_SET_POWERED,
-						MGMT_STATUS_INVALID_PARAMS);
+	if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) {
+		cancel_delayed_work(&hdev->power_off);
 
 
-	hci_dev_lock(hdev);
+		if (cp->val) {
+			err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
+			mgmt_powered(hdev, 1);
+			goto failed;
+		}
+	}
 
 
-	up = test_bit(HCI_UP, &hdev->flags);
-	if ((cp->val && up) || (!cp->val && !up)) {
+	if (!!cp->val == hdev_is_powered(hdev)) {
 		err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
 		err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
 		goto failed;
 		goto failed;
 	}
 	}
 
 
 	if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) {
 	if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) {
-		err = cmd_status(sk, index, MGMT_OP_SET_POWERED,
-							MGMT_STATUS_BUSY);
+		err = cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
+				 MGMT_STATUS_BUSY);
 		goto failed;
 		goto failed;
 	}
 	}
 
 
@@ -672,49 +787,115 @@ static int set_powered(struct sock *sk, u16 index, unsigned char *data, u16 len)
 
 
 failed:
 failed:
 	hci_dev_unlock(hdev);
 	hci_dev_unlock(hdev);
-	hci_dev_put(hdev);
 	return err;
 	return err;
 }
 }
 
 
-static int set_discoverable(struct sock *sk, u16 index, unsigned char *data,
-									u16 len)
+static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, u16 data_len,
+		      struct sock *skip_sk)
 {
 {
-	struct mgmt_cp_set_discoverable *cp;
-	struct hci_dev *hdev;
+	struct sk_buff *skb;
+	struct mgmt_hdr *hdr;
+
+	skb = alloc_skb(sizeof(*hdr) + data_len, GFP_ATOMIC);
+	if (!skb)
+		return -ENOMEM;
+
+	hdr = (void *) skb_put(skb, sizeof(*hdr));
+	hdr->opcode = cpu_to_le16(event);
+	if (hdev)
+		hdr->index = cpu_to_le16(hdev->id);
+	else
+		hdr->index = cpu_to_le16(MGMT_INDEX_NONE);
+	hdr->len = cpu_to_le16(data_len);
+
+	if (data)
+		memcpy(skb_put(skb, data_len), data, data_len);
+
+	/* Time stamp */
+	__net_timestamp(skb);
+
+	hci_send_to_control(skb, skip_sk);
+	kfree_skb(skb);
+
+	return 0;
+}
+
+static int new_settings(struct hci_dev *hdev, struct sock *skip)
+{
+	__le32 ev;
+
+	ev = cpu_to_le32(get_current_settings(hdev));
+
+	return mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), skip);
+}
+
+static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
+			    u16 len)
+{
+	struct mgmt_cp_set_discoverable *cp = data;
 	struct pending_cmd *cmd;
 	struct pending_cmd *cmd;
+	u16 timeout;
 	u8 scan;
 	u8 scan;
 	int err;
 	int err;
 
 
-	cp = (void *) data;
+	BT_DBG("request for %s", hdev->name);
 
 
-	BT_DBG("request for hci%u", index);
-
-	if (len != sizeof(*cp))
-		return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
-						MGMT_STATUS_INVALID_PARAMS);
-
-	hdev = hci_dev_get(index);
-	if (!hdev)
-		return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
-						MGMT_STATUS_INVALID_PARAMS);
+	timeout = get_unaligned_le16(&cp->timeout);
+	if (!cp->val && timeout > 0)
+		return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
+				  MGMT_STATUS_INVALID_PARAMS);
 
 
 	hci_dev_lock(hdev);
 	hci_dev_lock(hdev);
 
 
-	if (!test_bit(HCI_UP, &hdev->flags)) {
-		err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
-						MGMT_STATUS_NOT_POWERED);
+	if (!hdev_is_powered(hdev) && timeout > 0) {
+		err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
+				 MGMT_STATUS_NOT_POWERED);
 		goto failed;
 		goto failed;
 	}
 	}
 
 
 	if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
 	if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
 			mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
 			mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
-		err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
-							MGMT_STATUS_BUSY);
+		err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
+				 MGMT_STATUS_BUSY);
+		goto failed;
+	}
+
+	if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) {
+		err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
+				 MGMT_STATUS_REJECTED);
+		goto failed;
+	}
+
+	if (!hdev_is_powered(hdev)) {
+		bool changed = false;
+
+		if (!!cp->val != test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
+			change_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
+			changed = true;
+		}
+
+		err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
+		if (err < 0)
+			goto failed;
+
+		if (changed)
+			err = new_settings(hdev, sk);
+
 		goto failed;
 		goto failed;
 	}
 	}
 
 
-	if (cp->val == test_bit(HCI_ISCAN, &hdev->flags) &&
-					test_bit(HCI_PSCAN, &hdev->flags)) {
+	if (!!cp->val == test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
+		if (hdev->discov_timeout > 0) {
+			cancel_delayed_work(&hdev->discov_off);
+			hdev->discov_timeout = 0;
+		}
+
+		if (cp->val && timeout > 0) {
+			hdev->discov_timeout = timeout;
+			queue_delayed_work(hdev->workqueue, &hdev->discov_off,
+				msecs_to_jiffies(hdev->discov_timeout * 1000));
+		}
+
 		err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
 		err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
 		goto failed;
 		goto failed;
 	}
 	}
@@ -737,53 +918,56 @@ static int set_discoverable(struct sock *sk, u16 index, unsigned char *data,
 		mgmt_pending_remove(cmd);
 		mgmt_pending_remove(cmd);
 
 
 	if (cp->val)
 	if (cp->val)
-		hdev->discov_timeout = get_unaligned_le16(&cp->timeout);
+		hdev->discov_timeout = timeout;
 
 
 failed:
 failed:
 	hci_dev_unlock(hdev);
 	hci_dev_unlock(hdev);
-	hci_dev_put(hdev);
-
 	return err;
 	return err;
 }
 }
 
 
-static int set_connectable(struct sock *sk, u16 index, unsigned char *data,
-									u16 len)
+static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
+			   u16 len)
 {
 {
-	struct mgmt_mode *cp;
-	struct hci_dev *hdev;
+	struct mgmt_mode *cp = data;
 	struct pending_cmd *cmd;
 	struct pending_cmd *cmd;
 	u8 scan;
 	u8 scan;
 	int err;
 	int err;
 
 
-	cp = (void *) data;
+	BT_DBG("request for %s", hdev->name);
 
 
-	BT_DBG("request for hci%u", index);
+	hci_dev_lock(hdev);
 
 
-	if (len != sizeof(*cp))
-		return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
-						MGMT_STATUS_INVALID_PARAMS);
+	if (!hdev_is_powered(hdev)) {
+		bool changed = false;
 
 
-	hdev = hci_dev_get(index);
-	if (!hdev)
-		return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
-						MGMT_STATUS_INVALID_PARAMS);
+		if (!!cp->val != test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
+			changed = true;
 
 
-	hci_dev_lock(hdev);
+		if (cp->val) {
+			set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
+		} else {
+			clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
+			clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
+		}
+
+		err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
+		if (err < 0)
+			goto failed;
+
+		if (changed)
+			err = new_settings(hdev, sk);
 
 
-	if (!test_bit(HCI_UP, &hdev->flags)) {
-		err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
-						MGMT_STATUS_NOT_POWERED);
 		goto failed;
 		goto failed;
 	}
 	}
 
 
 	if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
 	if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
 			mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
 			mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
-		err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
-							MGMT_STATUS_BUSY);
+		err = cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
+				 MGMT_STATUS_BUSY);
 		goto failed;
 		goto failed;
 	}
 	}
 
 
-	if (cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
+	if (!!cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
 		err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
 		err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
 		goto failed;
 		goto failed;
 	}
 	}
@@ -794,233 +978,433 @@ static int set_connectable(struct sock *sk, u16 index, unsigned char *data,
 		goto failed;
 		goto failed;
 	}
 	}
 
 
-	if (cp->val)
+	if (cp->val) {
 		scan = SCAN_PAGE;
 		scan = SCAN_PAGE;
-	else
+	} else {
 		scan = 0;
 		scan = 0;
 
 
+		if (test_bit(HCI_ISCAN, &hdev->flags) &&
+						hdev->discov_timeout > 0)
+			cancel_delayed_work(&hdev->discov_off);
+	}
+
 	err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
 	err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
 	if (err < 0)
 	if (err < 0)
 		mgmt_pending_remove(cmd);
 		mgmt_pending_remove(cmd);
 
 
 failed:
 failed:
 	hci_dev_unlock(hdev);
 	hci_dev_unlock(hdev);
-	hci_dev_put(hdev);
-
 	return err;
 	return err;
 }
 }
 
 
-static int mgmt_event(u16 event, struct hci_dev *hdev, void *data,
-					u16 data_len, struct sock *skip_sk)
+static int set_pairable(struct sock *sk, struct hci_dev *hdev, void *data,
+			u16 len)
 {
 {
-	struct sk_buff *skb;
-	struct mgmt_hdr *hdr;
+	struct mgmt_mode *cp = data;
+	int err;
 
 
-	skb = alloc_skb(sizeof(*hdr) + data_len, GFP_ATOMIC);
-	if (!skb)
-		return -ENOMEM;
+	BT_DBG("request for %s", hdev->name);
 
 
-	bt_cb(skb)->channel = HCI_CHANNEL_CONTROL;
+	hci_dev_lock(hdev);
 
 
-	hdr = (void *) skb_put(skb, sizeof(*hdr));
-	hdr->opcode = cpu_to_le16(event);
-	if (hdev)
-		hdr->index = cpu_to_le16(hdev->id);
+	if (cp->val)
+		set_bit(HCI_PAIRABLE, &hdev->dev_flags);
 	else
 	else
-		hdr->index = cpu_to_le16(MGMT_INDEX_NONE);
-	hdr->len = cpu_to_le16(data_len);
+		clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
 
 
-	if (data)
-		memcpy(skb_put(skb, data_len), data, data_len);
+	err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev);
+	if (err < 0)
+		goto failed;
 
 
-	hci_send_to_sock(NULL, skb, skip_sk);
-	kfree_skb(skb);
+	err = new_settings(hdev, sk);
 
 
-	return 0;
+failed:
+	hci_dev_unlock(hdev);
+	return err;
 }
 }
 
 
-static int set_pairable(struct sock *sk, u16 index, unsigned char *data,
-									u16 len)
+static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data,
+			     u16 len)
 {
 {
-	struct mgmt_mode *cp;
-	struct hci_dev *hdev;
-	__le32 ev;
+	struct mgmt_mode *cp = data;
+	struct pending_cmd *cmd;
+	u8 val;
 	int err;
 	int err;
 
 
-	cp = (void *) data;
+	BT_DBG("request for %s", hdev->name);
 
 
-	BT_DBG("request for hci%u", index);
+	hci_dev_lock(hdev);
 
 
-	if (len != sizeof(*cp))
-		return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE,
-						MGMT_STATUS_INVALID_PARAMS);
+	if (!hdev_is_powered(hdev)) {
+		bool changed = false;
 
 
-	hdev = hci_dev_get(index);
-	if (!hdev)
-		return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE,
-						MGMT_STATUS_INVALID_PARAMS);
+		if (!!cp->val != test_bit(HCI_LINK_SECURITY,
+							&hdev->dev_flags)) {
+			change_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
+			changed = true;
+		}
 
 
-	hci_dev_lock(hdev);
+		err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
+		if (err < 0)
+			goto failed;
 
 
-	if (cp->val)
-		set_bit(HCI_PAIRABLE, &hdev->flags);
-	else
-		clear_bit(HCI_PAIRABLE, &hdev->flags);
+		if (changed)
+			err = new_settings(hdev, sk);
 
 
-	err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev);
-	if (err < 0)
 		goto failed;
 		goto failed;
+	}
 
 
-	ev = cpu_to_le32(get_current_settings(hdev));
+	if (mgmt_pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
+		err = cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
+				 MGMT_STATUS_BUSY);
+		goto failed;
+	}
+
+	val = !!cp->val;
+
+	if (test_bit(HCI_AUTH, &hdev->flags) == val) {
+		err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
+		goto failed;
+	}
+
+	cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
+	if (!cmd) {
+		err = -ENOMEM;
+		goto failed;
+	}
 
 
-	err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), sk);
+	err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
+	if (err < 0) {
+		mgmt_pending_remove(cmd);
+		goto failed;
+	}
 
 
 failed:
 failed:
 	hci_dev_unlock(hdev);
 	hci_dev_unlock(hdev);
-	hci_dev_put(hdev);
-
 	return err;
 	return err;
 }
 }
 
 
-static int add_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len)
+static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
 {
 {
-	struct mgmt_cp_add_uuid *cp;
-	struct hci_dev *hdev;
-	struct bt_uuid *uuid;
+	struct mgmt_mode *cp = data;
+	struct pending_cmd *cmd;
+	u8 val;
 	int err;
 	int err;
 
 
-	cp = (void *) data;
+	BT_DBG("request for %s", hdev->name);
 
 
-	BT_DBG("request for hci%u", index);
+	hci_dev_lock(hdev);
 
 
-	if (len != sizeof(*cp))
-		return cmd_status(sk, index, MGMT_OP_ADD_UUID,
-						MGMT_STATUS_INVALID_PARAMS);
+	if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
+		err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
+				 MGMT_STATUS_NOT_SUPPORTED);
+		goto failed;
+	}
 
 
-	hdev = hci_dev_get(index);
-	if (!hdev)
-		return cmd_status(sk, index, MGMT_OP_ADD_UUID,
-						MGMT_STATUS_INVALID_PARAMS);
+	val = !!cp->val;
 
 
-	hci_dev_lock(hdev);
+	if (!hdev_is_powered(hdev)) {
+		bool changed = false;
+
+		if (val != test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
+			change_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
+			changed = true;
+		}
+
+		err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
+		if (err < 0)
+			goto failed;
+
+		if (changed)
+			err = new_settings(hdev, sk);
 
 
-	uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC);
-	if (!uuid) {
-		err = -ENOMEM;
 		goto failed;
 		goto failed;
 	}
 	}
 
 
-	memcpy(uuid->uuid, cp->uuid, 16);
-	uuid->svc_hint = cp->svc_hint;
-
-	list_add(&uuid->list, &hdev->uuids);
+	if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev)) {
+	     err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
+			      MGMT_STATUS_BUSY);
+		goto failed;
+	}
 
 
-	err = update_class(hdev);
-	if (err < 0)
+	if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) == val) {
+		err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
 		goto failed;
 		goto failed;
+	}
 
 
-	err = update_eir(hdev);
-	if (err < 0)
+	cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
+	if (!cmd) {
+		err = -ENOMEM;
 		goto failed;
 		goto failed;
+	}
 
 
-	err = cmd_complete(sk, index, MGMT_OP_ADD_UUID, NULL, 0);
+	err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, sizeof(val), &val);
+	if (err < 0) {
+		mgmt_pending_remove(cmd);
+		goto failed;
+	}
 
 
 failed:
 failed:
 	hci_dev_unlock(hdev);
 	hci_dev_unlock(hdev);
-	hci_dev_put(hdev);
-
 	return err;
 	return err;
 }
 }
 
 
-static int remove_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len)
+static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
 {
 {
-	struct list_head *p, *n;
-	struct mgmt_cp_remove_uuid *cp;
-	struct hci_dev *hdev;
-	u8 bt_uuid_any[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
-	int err, found;
+	struct mgmt_mode *cp = data;
 
 
-	cp = (void *) data;
+	BT_DBG("request for %s", hdev->name);
 
 
-	BT_DBG("request for hci%u", index);
+	if (!enable_hs)
+		return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
+				  MGMT_STATUS_NOT_SUPPORTED);
 
 
-	if (len != sizeof(*cp))
-		return cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
-						MGMT_STATUS_INVALID_PARAMS);
+	if (cp->val)
+		set_bit(HCI_HS_ENABLED, &hdev->dev_flags);
+	else
+		clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
+
+	return send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
+}
 
 
-	hdev = hci_dev_get(index);
-	if (!hdev)
-		return cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
-						MGMT_STATUS_INVALID_PARAMS);
+static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
+{
+	struct mgmt_mode *cp = data;
+	struct hci_cp_write_le_host_supported hci_cp;
+	struct pending_cmd *cmd;
+	int err;
+	u8 val, enabled;
+
+	BT_DBG("request for %s", hdev->name);
 
 
 	hci_dev_lock(hdev);
 	hci_dev_lock(hdev);
 
 
-	if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
-		err = hci_uuids_clear(hdev);
+	if (!enable_le || !(hdev->features[4] & LMP_LE)) {
+		err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
+				 MGMT_STATUS_NOT_SUPPORTED);
 		goto unlock;
 		goto unlock;
 	}
 	}
 
 
-	found = 0;
+	val = !!cp->val;
+	enabled = !!(hdev->host_features[0] & LMP_HOST_LE);
 
 
-	list_for_each_safe(p, n, &hdev->uuids) {
-		struct bt_uuid *match = list_entry(p, struct bt_uuid, list);
+	if (!hdev_is_powered(hdev) || val == enabled) {
+		bool changed = false;
 
 
-		if (memcmp(match->uuid, cp->uuid, 16) != 0)
-			continue;
+		if (val != test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
+			change_bit(HCI_LE_ENABLED, &hdev->dev_flags);
+			changed = true;
+		}
 
 
-		list_del(&match->list);
-		found++;
-	}
+		err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
+		if (err < 0)
+			goto unlock;
+
+		if (changed)
+			err = new_settings(hdev, sk);
 
 
-	if (found == 0) {
-		err = cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
-						MGMT_STATUS_INVALID_PARAMS);
 		goto unlock;
 		goto unlock;
 	}
 	}
 
 
-	err = update_class(hdev);
-	if (err < 0)
+	if (mgmt_pending_find(MGMT_OP_SET_LE, hdev)) {
+		err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
+				 MGMT_STATUS_BUSY);
 		goto unlock;
 		goto unlock;
+	}
 
 
-	err = update_eir(hdev);
-	if (err < 0)
+	cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
+	if (!cmd) {
+		err = -ENOMEM;
 		goto unlock;
 		goto unlock;
+	}
+
+	memset(&hci_cp, 0, sizeof(hci_cp));
+
+	if (val) {
+		hci_cp.le = val;
+		hci_cp.simul = !!(hdev->features[6] & LMP_SIMUL_LE_BR);
+	}
 
 
-	err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, NULL, 0);
+	err = hci_send_cmd(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp),
+			   &hci_cp);
+	if (err < 0) {
+		mgmt_pending_remove(cmd);
+		goto unlock;
+	}
 
 
 unlock:
 unlock:
 	hci_dev_unlock(hdev);
 	hci_dev_unlock(hdev);
-	hci_dev_put(hdev);
-
 	return err;
 	return err;
 }
 }
 
 
-static int set_dev_class(struct sock *sk, u16 index, unsigned char *data,
-									u16 len)
+static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
 {
 {
-	struct hci_dev *hdev;
-	struct mgmt_cp_set_dev_class *cp;
+	struct mgmt_cp_add_uuid *cp = data;
+	struct pending_cmd *cmd;
+	struct bt_uuid *uuid;
 	int err;
 	int err;
 
 
-	cp = (void *) data;
+	BT_DBG("request for %s", hdev->name);
 
 
-	BT_DBG("request for hci%u", index);
+	hci_dev_lock(hdev);
 
 
-	if (len != sizeof(*cp))
-		return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS,
-						MGMT_STATUS_INVALID_PARAMS);
+	if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
+		err = cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
+				 MGMT_STATUS_BUSY);
+		goto failed;
+	}
+
+	uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC);
+	if (!uuid) {
+		err = -ENOMEM;
+		goto failed;
+	}
+
+	memcpy(uuid->uuid, cp->uuid, 16);
+	uuid->svc_hint = cp->svc_hint;
+
+	list_add(&uuid->list, &hdev->uuids);
+
+	err = update_class(hdev);
+	if (err < 0)
+		goto failed;
+
+	err = update_eir(hdev);
+	if (err < 0)
+		goto failed;
+
+	if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
+		err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0,
+				   hdev->dev_class, 3);
+		goto failed;
+	}
+
+	cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
+	if (!cmd) {
+		err = -ENOMEM;
+		goto failed;
+	}
+
+failed:
+	hci_dev_unlock(hdev);
+	return err;
+}
+
+static bool enable_service_cache(struct hci_dev *hdev)
+{
+	if (!hdev_is_powered(hdev))
+		return false;
+
+	if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
+		schedule_delayed_work(&hdev->service_cache, CACHE_TIMEOUT);
+		return true;
+	}
+
+	return false;
+}
+
+static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
+								u16 len)
+{
+	struct mgmt_cp_remove_uuid *cp = data;
+	struct pending_cmd *cmd;
+	struct list_head *p, *n;
+	u8 bt_uuid_any[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+	int err, found;
+
+	BT_DBG("request for %s", hdev->name);
+
+	hci_dev_lock(hdev);
+
+	if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
+		err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
+				 MGMT_STATUS_BUSY);
+		goto unlock;
+	}
+
+	if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
+		err = hci_uuids_clear(hdev);
+
+		if (enable_service_cache(hdev)) {
+			err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID,
+					   0, hdev->dev_class, 3);
+			goto unlock;
+		}
 
 
-	hdev = hci_dev_get(index);
-	if (!hdev)
-		return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS,
-						MGMT_STATUS_INVALID_PARAMS);
+		goto update_class;
+	}
+
+	found = 0;
+
+	list_for_each_safe(p, n, &hdev->uuids) {
+		struct bt_uuid *match = list_entry(p, struct bt_uuid, list);
+
+		if (memcmp(match->uuid, cp->uuid, 16) != 0)
+			continue;
+
+		list_del(&match->list);
+		found++;
+	}
+
+	if (found == 0) {
+		err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
+				 MGMT_STATUS_INVALID_PARAMS);
+		goto unlock;
+	}
+
+update_class:
+	err = update_class(hdev);
+	if (err < 0)
+		goto unlock;
+
+	err = update_eir(hdev);
+	if (err < 0)
+		goto unlock;
+
+	if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
+		err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0,
+				   hdev->dev_class, 3);
+		goto unlock;
+	}
+
+	cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
+	if (!cmd) {
+		err = -ENOMEM;
+		goto unlock;
+	}
+
+unlock:
+	hci_dev_unlock(hdev);
+	return err;
+}
+
+static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
+			 u16 len)
+{
+	struct mgmt_cp_set_dev_class *cp = data;
+	struct pending_cmd *cmd;
+	int err;
+
+	BT_DBG("request for %s", hdev->name);
 
 
 	hci_dev_lock(hdev);
 	hci_dev_lock(hdev);
 
 
+	if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
+		err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
+				 MGMT_STATUS_BUSY);
+		goto unlock;
+	}
+
 	hdev->major_class = cp->major;
 	hdev->major_class = cp->major;
 	hdev->minor_class = cp->minor;
 	hdev->minor_class = cp->minor;
 
 
-	if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->flags)) {
+	if (!hdev_is_powered(hdev)) {
+		err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
+				   hdev->dev_class, 3);
+		goto unlock;
+	}
+
+	if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
 		hci_dev_unlock(hdev);
 		hci_dev_unlock(hdev);
 		cancel_delayed_work_sync(&hdev->service_cache);
 		cancel_delayed_work_sync(&hdev->service_cache);
 		hci_dev_lock(hdev);
 		hci_dev_lock(hdev);
@@ -1028,30 +1412,33 @@ static int set_dev_class(struct sock *sk, u16 index, unsigned char *data,
 	}
 	}
 
 
 	err = update_class(hdev);
 	err = update_class(hdev);
+	if (err < 0)
+		goto unlock;
 
 
-	if (err == 0)
-		err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, NULL, 0);
+	if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
+		err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
+				   hdev->dev_class, 3);
+		goto unlock;
+	}
 
 
-	hci_dev_unlock(hdev);
-	hci_dev_put(hdev);
+	cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
+	if (!cmd) {
+		err = -ENOMEM;
+		goto unlock;
+	}
 
 
+unlock:
+	hci_dev_unlock(hdev);
 	return err;
 	return err;
 }
 }
 
 
-static int load_link_keys(struct sock *sk, u16 index, unsigned char *data,
+static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
 								u16 len)
 								u16 len)
 {
 {
-	struct hci_dev *hdev;
-	struct mgmt_cp_load_link_keys *cp;
+	struct mgmt_cp_load_link_keys *cp = data;
 	u16 key_count, expected_len;
 	u16 key_count, expected_len;
 	int i;
 	int i;
 
 
-	cp = (void *) data;
-
-	if (len < sizeof(*cp))
-		return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
-						MGMT_STATUS_INVALID_PARAMS);
-
 	key_count = get_unaligned_le16(&cp->key_count);
 	key_count = get_unaligned_le16(&cp->key_count);
 
 
 	expected_len = sizeof(*cp) + key_count *
 	expected_len = sizeof(*cp) + key_count *
@@ -1059,92 +1446,103 @@ static int load_link_keys(struct sock *sk, u16 index, unsigned char *data,
 	if (expected_len != len) {
 	if (expected_len != len) {
 		BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
 		BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
 							len, expected_len);
 							len, expected_len);
-		return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
-						MGMT_STATUS_INVALID_PARAMS);
+		return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
+				  MGMT_STATUS_INVALID_PARAMS);
 	}
 	}
 
 
-	hdev = hci_dev_get(index);
-	if (!hdev)
-		return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
-						MGMT_STATUS_INVALID_PARAMS);
-
-	BT_DBG("hci%u debug_keys %u key_count %u", index, cp->debug_keys,
+	BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys,
 								key_count);
 								key_count);
 
 
 	hci_dev_lock(hdev);
 	hci_dev_lock(hdev);
 
 
 	hci_link_keys_clear(hdev);
 	hci_link_keys_clear(hdev);
 
 
-	set_bit(HCI_LINK_KEYS, &hdev->flags);
+	set_bit(HCI_LINK_KEYS, &hdev->dev_flags);
 
 
 	if (cp->debug_keys)
 	if (cp->debug_keys)
-		set_bit(HCI_DEBUG_KEYS, &hdev->flags);
+		set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
 	else
 	else
-		clear_bit(HCI_DEBUG_KEYS, &hdev->flags);
+		clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
 
 
 	for (i = 0; i < key_count; i++) {
 	for (i = 0; i < key_count; i++) {
 		struct mgmt_link_key_info *key = &cp->keys[i];
 		struct mgmt_link_key_info *key = &cp->keys[i];
 
 
-		hci_add_link_key(hdev, NULL, 0, &key->bdaddr, key->val, key->type,
-								key->pin_len);
+		hci_add_link_key(hdev, NULL, 0, &key->addr.bdaddr, key->val,
+				 key->type, key->pin_len);
 	}
 	}
 
 
-	cmd_complete(sk, index, MGMT_OP_LOAD_LINK_KEYS, NULL, 0);
+	cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
 
 
 	hci_dev_unlock(hdev);
 	hci_dev_unlock(hdev);
-	hci_dev_put(hdev);
 
 
 	return 0;
 	return 0;
 }
 }
 
 
-static int remove_keys(struct sock *sk, u16 index, unsigned char *data,
-								u16 len)
+static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
+			   u8 addr_type, struct sock *skip_sk)
 {
 {
-	struct hci_dev *hdev;
-	struct mgmt_cp_remove_keys *cp;
-	struct mgmt_rp_remove_keys rp;
+	struct mgmt_ev_device_unpaired ev;
+
+	bacpy(&ev.addr.bdaddr, bdaddr);
+	ev.addr.type = addr_type;
+
+	return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
+			  skip_sk);
+}
+
+static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
+			 u16 len)
+{
+	struct mgmt_cp_unpair_device *cp = data;
+	struct mgmt_rp_unpair_device rp;
 	struct hci_cp_disconnect dc;
 	struct hci_cp_disconnect dc;
 	struct pending_cmd *cmd;
 	struct pending_cmd *cmd;
 	struct hci_conn *conn;
 	struct hci_conn *conn;
 	int err;
 	int err;
 
 
-	cp = (void *) data;
-
-	if (len != sizeof(*cp))
-		return cmd_status(sk, index, MGMT_OP_REMOVE_KEYS,
-						MGMT_STATUS_INVALID_PARAMS);
-
-	hdev = hci_dev_get(index);
-	if (!hdev)
-		return cmd_status(sk, index, MGMT_OP_REMOVE_KEYS,
-						MGMT_STATUS_INVALID_PARAMS);
-
 	hci_dev_lock(hdev);
 	hci_dev_lock(hdev);
 
 
 	memset(&rp, 0, sizeof(rp));
 	memset(&rp, 0, sizeof(rp));
-	bacpy(&rp.bdaddr, &cp->bdaddr);
-	rp.status = MGMT_STATUS_FAILED;
+	bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
+	rp.addr.type = cp->addr.type;
 
 
-	err = hci_remove_link_key(hdev, &cp->bdaddr);
-	if (err < 0) {
-		rp.status = MGMT_STATUS_NOT_PAIRED;
+	if (!hdev_is_powered(hdev)) {
+		err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
+				   MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
 		goto unlock;
 		goto unlock;
 	}
 	}
 
 
-	if (!test_bit(HCI_UP, &hdev->flags) || !cp->disconnect) {
-		err = cmd_complete(sk, index, MGMT_OP_REMOVE_KEYS, &rp,
-								sizeof(rp));
+	if (cp->addr.type == MGMT_ADDR_BREDR)
+		err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
+	else
+		err = hci_remove_ltk(hdev, &cp->addr.bdaddr);
+
+	if (err < 0) {
+		err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
+				   MGMT_STATUS_NOT_PAIRED, &rp, sizeof(rp));
 		goto unlock;
 		goto unlock;
 	}
 	}
 
 
-	conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
+	if (cp->disconnect) {
+		if (cp->addr.type == MGMT_ADDR_BREDR)
+			conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
+							&cp->addr.bdaddr);
+		else
+			conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
+							&cp->addr.bdaddr);
+	} else {
+		conn = NULL;
+	}
+
 	if (!conn) {
 	if (!conn) {
-		err = cmd_complete(sk, index, MGMT_OP_REMOVE_KEYS, &rp,
-								sizeof(rp));
+		err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0,
+				   &rp, sizeof(rp));
+		device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
 		goto unlock;
 		goto unlock;
 	}
 	}
 
 
-	cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_KEYS, hdev, cp, sizeof(*cp));
+	cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
+			       sizeof(*cp));
 	if (!cmd) {
 	if (!cmd) {
 		err = -ENOMEM;
 		err = -ENOMEM;
 		goto unlock;
 		goto unlock;
@@ -1157,19 +1555,14 @@ static int remove_keys(struct sock *sk, u16 index, unsigned char *data,
 		mgmt_pending_remove(cmd);
 		mgmt_pending_remove(cmd);
 
 
 unlock:
 unlock:
-	if (err < 0)
-		err = cmd_complete(sk, index, MGMT_OP_REMOVE_KEYS, &rp,
-								sizeof(rp));
 	hci_dev_unlock(hdev);
 	hci_dev_unlock(hdev);
-	hci_dev_put(hdev);
-
 	return err;
 	return err;
 }
 }
 
 
-static int disconnect(struct sock *sk, u16 index, unsigned char *data, u16 len)
+static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
+		      u16 len)
 {
 {
-	struct hci_dev *hdev;
-	struct mgmt_cp_disconnect *cp;
+	struct mgmt_cp_disconnect *cp = data;
 	struct hci_cp_disconnect dc;
 	struct hci_cp_disconnect dc;
 	struct pending_cmd *cmd;
 	struct pending_cmd *cmd;
 	struct hci_conn *conn;
 	struct hci_conn *conn;
@@ -1177,38 +1570,28 @@ static int disconnect(struct sock *sk, u16 index, unsigned char *data, u16 len)
 
 
 	BT_DBG("");
 	BT_DBG("");
 
 
-	cp = (void *) data;
-
-	if (len != sizeof(*cp))
-		return cmd_status(sk, index, MGMT_OP_DISCONNECT,
-						MGMT_STATUS_INVALID_PARAMS);
-
-	hdev = hci_dev_get(index);
-	if (!hdev)
-		return cmd_status(sk, index, MGMT_OP_DISCONNECT,
-						MGMT_STATUS_INVALID_PARAMS);
-
 	hci_dev_lock(hdev);
 	hci_dev_lock(hdev);
 
 
 	if (!test_bit(HCI_UP, &hdev->flags)) {
 	if (!test_bit(HCI_UP, &hdev->flags)) {
-		err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
-						MGMT_STATUS_NOT_POWERED);
+		err = cmd_status(sk, hdev->id, MGMT_OP_DISCONNECT,
+				 MGMT_STATUS_NOT_POWERED);
 		goto failed;
 		goto failed;
 	}
 	}
 
 
 	if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
 	if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
-		err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
-							MGMT_STATUS_BUSY);
+		err = cmd_status(sk, hdev->id, MGMT_OP_DISCONNECT,
+				 MGMT_STATUS_BUSY);
 		goto failed;
 		goto failed;
 	}
 	}
 
 
-	conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
-	if (!conn)
-		conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->bdaddr);
+	if (cp->addr.type == MGMT_ADDR_BREDR)
+		conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
+	else
+		conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
 
 
 	if (!conn) {
 	if (!conn) {
-		err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
-						MGMT_STATUS_NOT_CONNECTED);
+		err = cmd_status(sk, hdev->id, MGMT_OP_DISCONNECT,
+				 MGMT_STATUS_NOT_CONNECTED);
 		goto failed;
 		goto failed;
 	}
 	}
 
 
@@ -1227,8 +1610,6 @@ static int disconnect(struct sock *sk, u16 index, unsigned char *data, u16 len)
 
 
 failed:
 failed:
 	hci_dev_unlock(hdev);
 	hci_dev_unlock(hdev);
-	hci_dev_put(hdev);
-
 	return err;
 	return err;
 }
 }
 
 
@@ -1251,41 +1632,42 @@ static u8 link_to_mgmt(u8 link_type, u8 addr_type)
 	}
 	}
 }
 }
 
 
-static int get_connections(struct sock *sk, u16 index)
+static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data,
+			   u16 data_len)
 {
 {
 	struct mgmt_rp_get_connections *rp;
 	struct mgmt_rp_get_connections *rp;
-	struct hci_dev *hdev;
 	struct hci_conn *c;
 	struct hci_conn *c;
-	struct list_head *p;
 	size_t rp_len;
 	size_t rp_len;
-	u16 count;
-	int i, err;
+	int err;
+	u16 i;
 
 
 	BT_DBG("");
 	BT_DBG("");
 
 
-	hdev = hci_dev_get(index);
-	if (!hdev)
-		return cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS,
-						MGMT_STATUS_INVALID_PARAMS);
-
 	hci_dev_lock(hdev);
 	hci_dev_lock(hdev);
 
 
-	count = 0;
-	list_for_each(p, &hdev->conn_hash.list) {
-		count++;
+	if (!hdev_is_powered(hdev)) {
+		err = cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS,
+				 MGMT_STATUS_NOT_POWERED);
+		goto unlock;
+	}
+
+	i = 0;
+	list_for_each_entry(c, &hdev->conn_hash.list, list) {
+		if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
+			i++;
 	}
 	}
 
 
-	rp_len = sizeof(*rp) + (count * sizeof(struct mgmt_addr_info));
+	rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
 	rp = kmalloc(rp_len, GFP_ATOMIC);
 	rp = kmalloc(rp_len, GFP_ATOMIC);
 	if (!rp) {
 	if (!rp) {
 		err = -ENOMEM;
 		err = -ENOMEM;
 		goto unlock;
 		goto unlock;
 	}
 	}
 
 
-	put_unaligned_le16(count, &rp->conn_count);
-
 	i = 0;
 	i = 0;
 	list_for_each_entry(c, &hdev->conn_hash.list, list) {
 	list_for_each_entry(c, &hdev->conn_hash.list, list) {
+		if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
+			continue;
 		bacpy(&rp->addr[i].bdaddr, &c->dst);
 		bacpy(&rp->addr[i].bdaddr, &c->dst);
 		rp->addr[i].type = link_to_mgmt(c->type, c->dst_type);
 		rp->addr[i].type = link_to_mgmt(c->type, c->dst_type);
 		if (rp->addr[i].type == MGMT_ADDR_INVALID)
 		if (rp->addr[i].type == MGMT_ADDR_INVALID)
@@ -1293,85 +1675,77 @@ static int get_connections(struct sock *sk, u16 index)
 		i++;
 		i++;
 	}
 	}
 
 
+	put_unaligned_le16(i, &rp->conn_count);
+
 	/* Recalculate length in case of filtered SCO connections, etc */
 	/* Recalculate length in case of filtered SCO connections, etc */
 	rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
 	rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
 
 
-	err = cmd_complete(sk, index, MGMT_OP_GET_CONNECTIONS, rp, rp_len);
+	err = cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp,
+			   rp_len);
 
 
-unlock:
 	kfree(rp);
 	kfree(rp);
+
+unlock:
 	hci_dev_unlock(hdev);
 	hci_dev_unlock(hdev);
-	hci_dev_put(hdev);
 	return err;
 	return err;
 }
 }
 
 
-static int send_pin_code_neg_reply(struct sock *sk, u16 index,
-		struct hci_dev *hdev, struct mgmt_cp_pin_code_neg_reply *cp)
+static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
+				   struct mgmt_cp_pin_code_neg_reply *cp)
 {
 {
 	struct pending_cmd *cmd;
 	struct pending_cmd *cmd;
 	int err;
 	int err;
 
 
 	cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
 	cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
-								sizeof(*cp));
+			       sizeof(*cp));
 	if (!cmd)
 	if (!cmd)
 		return -ENOMEM;
 		return -ENOMEM;
 
 
-	err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY, sizeof(cp->bdaddr),
-								&cp->bdaddr);
+	err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
+			   sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
 	if (err < 0)
 	if (err < 0)
 		mgmt_pending_remove(cmd);
 		mgmt_pending_remove(cmd);
 
 
 	return err;
 	return err;
 }
 }
 
 
-static int pin_code_reply(struct sock *sk, u16 index, unsigned char *data,
-									u16 len)
+static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data,
+			  u16 len)
 {
 {
-	struct hci_dev *hdev;
 	struct hci_conn *conn;
 	struct hci_conn *conn;
-	struct mgmt_cp_pin_code_reply *cp;
-	struct mgmt_cp_pin_code_neg_reply ncp;
+	struct mgmt_cp_pin_code_reply *cp = data;
 	struct hci_cp_pin_code_reply reply;
 	struct hci_cp_pin_code_reply reply;
 	struct pending_cmd *cmd;
 	struct pending_cmd *cmd;
 	int err;
 	int err;
 
 
 	BT_DBG("");
 	BT_DBG("");
 
 
-	cp = (void *) data;
-
-	if (len != sizeof(*cp))
-		return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
-						MGMT_STATUS_INVALID_PARAMS);
-
-	hdev = hci_dev_get(index);
-	if (!hdev)
-		return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
-						MGMT_STATUS_INVALID_PARAMS);
-
 	hci_dev_lock(hdev);
 	hci_dev_lock(hdev);
 
 
-	if (!test_bit(HCI_UP, &hdev->flags)) {
-		err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
-						MGMT_STATUS_NOT_POWERED);
+	if (!hdev_is_powered(hdev)) {
+		err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
+				 MGMT_STATUS_NOT_POWERED);
 		goto failed;
 		goto failed;
 	}
 	}
 
 
-	conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
+	conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
 	if (!conn) {
 	if (!conn) {
-		err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
-						MGMT_STATUS_NOT_CONNECTED);
+		err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
+				 MGMT_STATUS_NOT_CONNECTED);
 		goto failed;
 		goto failed;
 	}
 	}
 
 
 	if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
 	if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
-		bacpy(&ncp.bdaddr, &cp->bdaddr);
+		struct mgmt_cp_pin_code_neg_reply ncp;
+
+		memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
 
 
 		BT_ERR("PIN code is not 16 bytes long");
 		BT_ERR("PIN code is not 16 bytes long");
 
 
-		err = send_pin_code_neg_reply(sk, index, hdev, &ncp);
+		err = send_pin_code_neg_reply(sk, hdev, &ncp);
 		if (err >= 0)
 		if (err >= 0)
-			err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
-						MGMT_STATUS_INVALID_PARAMS);
+			err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
+					 MGMT_STATUS_INVALID_PARAMS);
 
 
 		goto failed;
 		goto failed;
 	}
 	}
@@ -1382,7 +1756,7 @@ static int pin_code_reply(struct sock *sk, u16 index, unsigned char *data,
 		goto failed;
 		goto failed;
 	}
 	}
 
 
-	bacpy(&reply.bdaddr, &cp->bdaddr);
+	bacpy(&reply.bdaddr, &cp->addr.bdaddr);
 	reply.pin_len = cp->pin_len;
 	reply.pin_len = cp->pin_len;
 	memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
 	memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
 
 
@@ -1392,67 +1766,39 @@ static int pin_code_reply(struct sock *sk, u16 index, unsigned char *data,
 
 
 failed:
 failed:
 	hci_dev_unlock(hdev);
 	hci_dev_unlock(hdev);
-	hci_dev_put(hdev);
-
 	return err;
 	return err;
 }
 }
 
 
-static int pin_code_neg_reply(struct sock *sk, u16 index, unsigned char *data,
-									u16 len)
+static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
+			      void *data, u16 len)
 {
 {
-	struct hci_dev *hdev;
-	struct mgmt_cp_pin_code_neg_reply *cp;
+	struct mgmt_cp_pin_code_neg_reply *cp = data;
 	int err;
 	int err;
 
 
 	BT_DBG("");
 	BT_DBG("");
 
 
-	cp = (void *) data;
-
-	if (len != sizeof(*cp))
-		return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
-						MGMT_STATUS_INVALID_PARAMS);
-
-	hdev = hci_dev_get(index);
-	if (!hdev)
-		return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
-						MGMT_STATUS_INVALID_PARAMS);
-
 	hci_dev_lock(hdev);
 	hci_dev_lock(hdev);
 
 
-	if (!test_bit(HCI_UP, &hdev->flags)) {
-		err = cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
-						MGMT_STATUS_NOT_POWERED);
+	if (!hdev_is_powered(hdev)) {
+		err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
+				 MGMT_STATUS_NOT_POWERED);
 		goto failed;
 		goto failed;
 	}
 	}
 
 
-	err = send_pin_code_neg_reply(sk, index, hdev, cp);
+	err = send_pin_code_neg_reply(sk, hdev, cp);
 
 
 failed:
 failed:
 	hci_dev_unlock(hdev);
 	hci_dev_unlock(hdev);
-	hci_dev_put(hdev);
-
 	return err;
 	return err;
 }
 }
 
 
-static int set_io_capability(struct sock *sk, u16 index, unsigned char *data,
-									u16 len)
+static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
+			     u16 len)
 {
 {
-	struct hci_dev *hdev;
-	struct mgmt_cp_set_io_capability *cp;
+	struct mgmt_cp_set_io_capability *cp = data;
 
 
 	BT_DBG("");
 	BT_DBG("");
 
 
-	cp = (void *) data;
-
-	if (len != sizeof(*cp))
-		return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY,
-						MGMT_STATUS_INVALID_PARAMS);
-
-	hdev = hci_dev_get(index);
-	if (!hdev)
-		return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY,
-						MGMT_STATUS_INVALID_PARAMS);
-
 	hci_dev_lock(hdev);
 	hci_dev_lock(hdev);
 
 
 	hdev->io_capability = cp->io_capability;
 	hdev->io_capability = cp->io_capability;
@@ -1461,9 +1807,9 @@ static int set_io_capability(struct sock *sk, u16 index, unsigned char *data,
 							hdev->io_capability);
 							hdev->io_capability);
 
 
 	hci_dev_unlock(hdev);
 	hci_dev_unlock(hdev);
-	hci_dev_put(hdev);
 
 
-	return cmd_complete(sk, index, MGMT_OP_SET_IO_CAPABILITY, NULL, 0);
+	return cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0, NULL,
+			    0);
 }
 }
 
 
 static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
 static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
@@ -1491,9 +1837,9 @@ static void pairing_complete(struct pending_cmd *cmd, u8 status)
 
 
 	bacpy(&rp.addr.bdaddr, &conn->dst);
 	bacpy(&rp.addr.bdaddr, &conn->dst);
 	rp.addr.type = link_to_mgmt(conn->type, conn->dst_type);
 	rp.addr.type = link_to_mgmt(conn->type, conn->dst_type);
-	rp.status = status;
 
 
-	cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, &rp, sizeof(rp));
+	cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, status,
+		     &rp, sizeof(rp));
 
 
 	/* So we don't get further callbacks for this connection */
 	/* So we don't get further callbacks for this connection */
 	conn->connect_cfm_cb = NULL;
 	conn->connect_cfm_cb = NULL;
@@ -1515,13 +1861,13 @@ static void pairing_complete_cb(struct hci_conn *conn, u8 status)
 	if (!cmd)
 	if (!cmd)
 		BT_DBG("Unable to find a pending command");
 		BT_DBG("Unable to find a pending command");
 	else
 	else
-		pairing_complete(cmd, status);
+		pairing_complete(cmd, mgmt_status(status));
 }
 }
 
 
-static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len)
+static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
+		       u16 len)
 {
 {
-	struct hci_dev *hdev;
-	struct mgmt_cp_pair_device *cp;
+	struct mgmt_cp_pair_device *cp = data;
 	struct mgmt_rp_pair_device rp;
 	struct mgmt_rp_pair_device rp;
 	struct pending_cmd *cmd;
 	struct pending_cmd *cmd;
 	u8 sec_level, auth_type;
 	u8 sec_level, auth_type;
@@ -1530,19 +1876,14 @@ static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len)
 
 
 	BT_DBG("");
 	BT_DBG("");
 
 
-	cp = (void *) data;
-
-	if (len != sizeof(*cp))
-		return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE,
-						MGMT_STATUS_INVALID_PARAMS);
-
-	hdev = hci_dev_get(index);
-	if (!hdev)
-		return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE,
-						MGMT_STATUS_INVALID_PARAMS);
-
 	hci_dev_lock(hdev);
 	hci_dev_lock(hdev);
 
 
+	if (!hdev_is_powered(hdev)) {
+		err = cmd_status(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
+				 MGMT_STATUS_NOT_POWERED);
+		goto unlock;
+	}
+
 	sec_level = BT_SECURITY_MEDIUM;
 	sec_level = BT_SECURITY_MEDIUM;
 	if (cp->io_cap == 0x03)
 	if (cp->io_cap == 0x03)
 		auth_type = HCI_AT_DEDICATED_BONDING;
 		auth_type = HCI_AT_DEDICATED_BONDING;
@@ -1551,27 +1892,26 @@ static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len)
 
 
 	if (cp->addr.type == MGMT_ADDR_BREDR)
 	if (cp->addr.type == MGMT_ADDR_BREDR)
 		conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr, sec_level,
 		conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr, sec_level,
-								auth_type);
+				   auth_type);
 	else
 	else
 		conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr, sec_level,
 		conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr, sec_level,
-								auth_type);
+				   auth_type);
 
 
 	memset(&rp, 0, sizeof(rp));
 	memset(&rp, 0, sizeof(rp));
 	bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
 	bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
 	rp.addr.type = cp->addr.type;
 	rp.addr.type = cp->addr.type;
 
 
 	if (IS_ERR(conn)) {
 	if (IS_ERR(conn)) {
-		rp.status = -PTR_ERR(conn);
-		err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE,
-							&rp, sizeof(rp));
+		err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
+				   MGMT_STATUS_CONNECT_FAILED, &rp,
+				   sizeof(rp));
 		goto unlock;
 		goto unlock;
 	}
 	}
 
 
 	if (conn->connect_cfm_cb) {
 	if (conn->connect_cfm_cb) {
 		hci_conn_put(conn);
 		hci_conn_put(conn);
-		rp.status = EBUSY;
-		err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE,
-							&rp, sizeof(rp));
+		err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
+				   MGMT_STATUS_BUSY, &rp, sizeof(rp));
 		goto unlock;
 		goto unlock;
 	}
 	}
 
 
@@ -1599,58 +1939,88 @@ static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len)
 
 
 unlock:
 unlock:
 	hci_dev_unlock(hdev);
 	hci_dev_unlock(hdev);
-	hci_dev_put(hdev);
-
 	return err;
 	return err;
 }
 }
 
 
-static int user_pairing_resp(struct sock *sk, u16 index, bdaddr_t *bdaddr,
-					u16 mgmt_op, u16 hci_op, __le32 passkey)
+static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
+			      u16 len)
 {
 {
+	struct mgmt_addr_info *addr = data;
 	struct pending_cmd *cmd;
 	struct pending_cmd *cmd;
-	struct hci_dev *hdev;
 	struct hci_conn *conn;
 	struct hci_conn *conn;
 	int err;
 	int err;
 
 
-	hdev = hci_dev_get(index);
-	if (!hdev)
-		return cmd_status(sk, index, mgmt_op,
-						MGMT_STATUS_INVALID_PARAMS);
+	BT_DBG("");
 
 
 	hci_dev_lock(hdev);
 	hci_dev_lock(hdev);
 
 
-	if (!test_bit(HCI_UP, &hdev->flags)) {
-		err = cmd_status(sk, index, mgmt_op, MGMT_STATUS_NOT_POWERED);
+	if (!hdev_is_powered(hdev)) {
+		err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
+				 MGMT_STATUS_NOT_POWERED);
+		goto unlock;
+	}
+
+	cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
+	if (!cmd) {
+		err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
+				 MGMT_STATUS_INVALID_PARAMS);
+		goto unlock;
+	}
+
+	conn = cmd->user_data;
+
+	if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
+		err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
+				 MGMT_STATUS_INVALID_PARAMS);
+		goto unlock;
+	}
+
+	pairing_complete(cmd, MGMT_STATUS_CANCELLED);
+
+	err = cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
+			   addr, sizeof(*addr));
+unlock:
+	hci_dev_unlock(hdev);
+	return err;
+}
+
+static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
+			     bdaddr_t *bdaddr, u8 type, u16 mgmt_op,
+			     u16 hci_op, __le32 passkey)
+{
+	struct pending_cmd *cmd;
+	struct hci_conn *conn;
+	int err;
+
+	hci_dev_lock(hdev);
+
+	if (!hdev_is_powered(hdev)) {
+		err = cmd_status(sk, hdev->id, mgmt_op,
+				 MGMT_STATUS_NOT_POWERED);
 		goto done;
 		goto done;
 	}
 	}
 
 
-	/*
-	 * Check for an existing ACL link, if present pair via
-	 * HCI commands.
-	 *
-	 * If no ACL link is present, check for an LE link and if
-	 * present, pair via the SMP engine.
-	 *
-	 * If neither ACL nor LE links are present, fail with error.
-	 */
-	conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, bdaddr);
-	if (!conn) {
+	if (type == MGMT_ADDR_BREDR)
+		conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, bdaddr);
+	else
 		conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, bdaddr);
 		conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, bdaddr);
-		if (!conn) {
-			err = cmd_status(sk, index, mgmt_op,
-						MGMT_STATUS_NOT_CONNECTED);
-			goto done;
-		}
 
 
+	if (!conn) {
+		err = cmd_status(sk, hdev->id, mgmt_op,
+				 MGMT_STATUS_NOT_CONNECTED);
+		goto done;
+	}
+
+	if (type == MGMT_ADDR_LE_PUBLIC || type == MGMT_ADDR_LE_RANDOM) {
 		/* Continue with pairing via SMP */
 		/* Continue with pairing via SMP */
 		err = smp_user_confirm_reply(conn, mgmt_op, passkey);
 		err = smp_user_confirm_reply(conn, mgmt_op, passkey);
 
 
 		if (!err)
 		if (!err)
-			err = cmd_status(sk, index, mgmt_op,
-							MGMT_STATUS_SUCCESS);
+			err = cmd_status(sk, hdev->id, mgmt_op,
+					 MGMT_STATUS_SUCCESS);
 		else
 		else
-			err = cmd_status(sk, index, mgmt_op,
-							MGMT_STATUS_FAILED);
+			err = cmd_status(sk, hdev->id, mgmt_op,
+					 MGMT_STATUS_FAILED);
 
 
 		goto done;
 		goto done;
 	}
 	}
@@ -1676,94 +2046,96 @@ static int user_pairing_resp(struct sock *sk, u16 index, bdaddr_t *bdaddr,
 
 
 done:
 done:
 	hci_dev_unlock(hdev);
 	hci_dev_unlock(hdev);
-	hci_dev_put(hdev);
-
 	return err;
 	return err;
 }
 }
 
 
-static int user_confirm_reply(struct sock *sk, u16 index, void *data, u16 len)
+static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data,
+			      u16 len)
 {
 {
-	struct mgmt_cp_user_confirm_reply *cp = (void *) data;
+	struct mgmt_cp_user_confirm_reply *cp = data;
 
 
 	BT_DBG("");
 	BT_DBG("");
 
 
 	if (len != sizeof(*cp))
 	if (len != sizeof(*cp))
-		return cmd_status(sk, index, MGMT_OP_USER_CONFIRM_REPLY,
-						MGMT_STATUS_INVALID_PARAMS);
+		return cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
+				  MGMT_STATUS_INVALID_PARAMS);
 
 
-	return user_pairing_resp(sk, index, &cp->bdaddr,
-			MGMT_OP_USER_CONFIRM_REPLY,
-			HCI_OP_USER_CONFIRM_REPLY, 0);
+	return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
+				 MGMT_OP_USER_CONFIRM_REPLY,
+				 HCI_OP_USER_CONFIRM_REPLY, 0);
 }
 }
 
 
-static int user_confirm_neg_reply(struct sock *sk, u16 index, void *data,
-									u16 len)
+static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
+				  void *data, u16 len)
 {
 {
 	struct mgmt_cp_user_confirm_neg_reply *cp = data;
 	struct mgmt_cp_user_confirm_neg_reply *cp = data;
 
 
 	BT_DBG("");
 	BT_DBG("");
 
 
-	if (len != sizeof(*cp))
-		return cmd_status(sk, index, MGMT_OP_USER_CONFIRM_NEG_REPLY,
-						MGMT_STATUS_INVALID_PARAMS);
-
-	return user_pairing_resp(sk, index, &cp->bdaddr,
-			MGMT_OP_USER_CONFIRM_NEG_REPLY,
-			HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
+	return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
+				 MGMT_OP_USER_CONFIRM_NEG_REPLY,
+				 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
 }
 }
 
 
-static int user_passkey_reply(struct sock *sk, u16 index, void *data, u16 len)
+static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data,
+			      u16 len)
 {
 {
-	struct mgmt_cp_user_passkey_reply *cp = (void *) data;
+	struct mgmt_cp_user_passkey_reply *cp = data;
 
 
 	BT_DBG("");
 	BT_DBG("");
 
 
-	if (len != sizeof(*cp))
-		return cmd_status(sk, index, MGMT_OP_USER_PASSKEY_REPLY,
-									EINVAL);
-
-	return user_pairing_resp(sk, index, &cp->bdaddr,
-			MGMT_OP_USER_PASSKEY_REPLY,
-			HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
+	return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
+				 MGMT_OP_USER_PASSKEY_REPLY,
+				 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
 }
 }
 
 
-static int user_passkey_neg_reply(struct sock *sk, u16 index, void *data,
-									u16 len)
+static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
+				  void *data, u16 len)
 {
 {
-	struct mgmt_cp_user_passkey_neg_reply *cp = (void *) data;
+	struct mgmt_cp_user_passkey_neg_reply *cp = data;
 
 
 	BT_DBG("");
 	BT_DBG("");
 
 
-	if (len != sizeof(*cp))
-		return cmd_status(sk, index, MGMT_OP_USER_PASSKEY_NEG_REPLY,
-									EINVAL);
-
-	return user_pairing_resp(sk, index, &cp->bdaddr,
-			MGMT_OP_USER_PASSKEY_NEG_REPLY,
-			HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
+	return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
+				 MGMT_OP_USER_PASSKEY_NEG_REPLY,
+				 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
 }
 }
 
 
-static int set_local_name(struct sock *sk, u16 index, unsigned char *data,
-								u16 len)
+static int update_name(struct hci_dev *hdev, const char *name)
 {
 {
-	struct mgmt_cp_set_local_name *mgmt_cp = (void *) data;
-	struct hci_cp_write_local_name hci_cp;
-	struct hci_dev *hdev;
+	struct hci_cp_write_local_name cp;
+
+	memcpy(cp.name, name, sizeof(cp.name));
+
+	return hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(cp), &cp);
+}
+
+static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
+			  u16 len)
+{
+	struct mgmt_cp_set_local_name *cp = data;
 	struct pending_cmd *cmd;
 	struct pending_cmd *cmd;
 	int err;
 	int err;
 
 
 	BT_DBG("");
 	BT_DBG("");
 
 
-	if (len != sizeof(*mgmt_cp))
-		return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME,
-						MGMT_STATUS_INVALID_PARAMS);
+	hci_dev_lock(hdev);
 
 
-	hdev = hci_dev_get(index);
-	if (!hdev)
-		return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME,
-						MGMT_STATUS_INVALID_PARAMS);
+	memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
 
 
-	hci_dev_lock(hdev);
+	if (!hdev_is_powered(hdev)) {
+		memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
+
+		err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
+				   data, len);
+		if (err < 0)
+			goto failed;
+
+		err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data, len,
+				 sk);
+
+		goto failed;
+	}
 
 
 	cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
 	cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
 	if (!cmd) {
 	if (!cmd) {
@@ -1771,49 +2143,40 @@ static int set_local_name(struct sock *sk, u16 index, unsigned char *data,
 		goto failed;
 		goto failed;
 	}
 	}
 
 
-	memcpy(hci_cp.name, mgmt_cp->name, sizeof(hci_cp.name));
-	err = hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(hci_cp),
-								&hci_cp);
+	err = update_name(hdev, cp->name);
 	if (err < 0)
 	if (err < 0)
 		mgmt_pending_remove(cmd);
 		mgmt_pending_remove(cmd);
 
 
 failed:
 failed:
 	hci_dev_unlock(hdev);
 	hci_dev_unlock(hdev);
-	hci_dev_put(hdev);
-
 	return err;
 	return err;
 }
 }
 
 
-static int read_local_oob_data(struct sock *sk, u16 index)
+static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
+			       void *data, u16 data_len)
 {
 {
-	struct hci_dev *hdev;
 	struct pending_cmd *cmd;
 	struct pending_cmd *cmd;
 	int err;
 	int err;
 
 
-	BT_DBG("hci%u", index);
-
-	hdev = hci_dev_get(index);
-	if (!hdev)
-		return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
-						MGMT_STATUS_INVALID_PARAMS);
+	BT_DBG("%s", hdev->name);
 
 
 	hci_dev_lock(hdev);
 	hci_dev_lock(hdev);
 
 
-	if (!test_bit(HCI_UP, &hdev->flags)) {
-		err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
-						MGMT_STATUS_NOT_POWERED);
+	if (!hdev_is_powered(hdev)) {
+		err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
+				 MGMT_STATUS_NOT_POWERED);
 		goto unlock;
 		goto unlock;
 	}
 	}
 
 
 	if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
 	if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
-		err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
-						MGMT_STATUS_NOT_SUPPORTED);
+		err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
+				 MGMT_STATUS_NOT_SUPPORTED);
 		goto unlock;
 		goto unlock;
 	}
 	}
 
 
 	if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
 	if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
-		err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
-							MGMT_STATUS_BUSY);
+		err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
+				 MGMT_STATUS_BUSY);
 		goto unlock;
 		goto unlock;
 	}
 	}
 
 
@@ -1829,104 +2192,112 @@ static int read_local_oob_data(struct sock *sk, u16 index)
 
 
 unlock:
 unlock:
 	hci_dev_unlock(hdev);
 	hci_dev_unlock(hdev);
-	hci_dev_put(hdev);
-
 	return err;
 	return err;
 }
 }
 
 
-static int add_remote_oob_data(struct sock *sk, u16 index, unsigned char *data,
-									u16 len)
+static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
+			       void *data, u16 len)
 {
 {
-	struct hci_dev *hdev;
-	struct mgmt_cp_add_remote_oob_data *cp = (void *) data;
+	struct mgmt_cp_add_remote_oob_data *cp = data;
+	u8 status;
 	int err;
 	int err;
 
 
-	BT_DBG("hci%u ", index);
-
-	if (len != sizeof(*cp))
-		return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
-						MGMT_STATUS_INVALID_PARAMS);
-
-	hdev = hci_dev_get(index);
-	if (!hdev)
-		return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
-						MGMT_STATUS_INVALID_PARAMS);
+	BT_DBG("%s ", hdev->name);
 
 
 	hci_dev_lock(hdev);
 	hci_dev_lock(hdev);
 
 
-	err = hci_add_remote_oob_data(hdev, &cp->bdaddr, cp->hash,
-								cp->randomizer);
+	if (!hdev_is_powered(hdev)) {
+		err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA,
+				   MGMT_STATUS_NOT_POWERED, &cp->addr,
+				   sizeof(cp->addr));
+		goto unlock;
+	}
+
+	err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash,
+				      cp->randomizer);
 	if (err < 0)
 	if (err < 0)
-		err = cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
-							MGMT_STATUS_FAILED);
+		status = MGMT_STATUS_FAILED;
 	else
 	else
-		err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, NULL,
-									0);
+		status = 0;
 
 
-	hci_dev_unlock(hdev);
-	hci_dev_put(hdev);
+	err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA, status,
+			   &cp->addr, sizeof(cp->addr));
 
 
+unlock:
+	hci_dev_unlock(hdev);
 	return err;
 	return err;
 }
 }
 
 
-static int remove_remote_oob_data(struct sock *sk, u16 index,
-						unsigned char *data, u16 len)
+static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
+						void *data, u16 len)
 {
 {
-	struct hci_dev *hdev;
-	struct mgmt_cp_remove_remote_oob_data *cp = (void *) data;
+	struct mgmt_cp_remove_remote_oob_data *cp = data;
+	u8 status;
 	int err;
 	int err;
 
 
-	BT_DBG("hci%u ", index);
+	BT_DBG("%s", hdev->name);
 
 
-	if (len != sizeof(*cp))
-		return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
-						MGMT_STATUS_INVALID_PARAMS);
+	hci_dev_lock(hdev);
+
+	if (!hdev_is_powered(hdev)) {
+		err = cmd_complete(sk, hdev->id,
+				   MGMT_OP_REMOVE_REMOTE_OOB_DATA,
+				   MGMT_STATUS_NOT_POWERED, &cp->addr,
+				   sizeof(cp->addr));
+		goto unlock;
+	}
+
+	err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
+	if (err < 0)
+		status = MGMT_STATUS_INVALID_PARAMS;
+	else
+		status = 0;
+
+	err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
+			   status, &cp->addr, sizeof(cp->addr));
 
 
-	hdev = hci_dev_get(index);
-	if (!hdev)
-		return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
-						MGMT_STATUS_INVALID_PARAMS);
+unlock:
+	hci_dev_unlock(hdev);
+	return err;
+}
+
+int mgmt_interleaved_discovery(struct hci_dev *hdev)
+{
+	int err;
+
+	BT_DBG("%s", hdev->name);
 
 
 	hci_dev_lock(hdev);
 	hci_dev_lock(hdev);
 
 
-	err = hci_remove_remote_oob_data(hdev, &cp->bdaddr);
+	err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR_LE);
 	if (err < 0)
 	if (err < 0)
-		err = cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
-						MGMT_STATUS_INVALID_PARAMS);
-	else
-		err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
-								NULL, 0);
+		hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
 
 
 	hci_dev_unlock(hdev);
 	hci_dev_unlock(hdev);
-	hci_dev_put(hdev);
 
 
 	return err;
 	return err;
 }
 }
 
 
-static int start_discovery(struct sock *sk, u16 index,
-						unsigned char *data, u16 len)
+static int start_discovery(struct sock *sk, struct hci_dev *hdev,
+			   void *data, u16 len)
 {
 {
-	struct mgmt_cp_start_discovery *cp = (void *) data;
+	struct mgmt_cp_start_discovery *cp = data;
 	struct pending_cmd *cmd;
 	struct pending_cmd *cmd;
-	struct hci_dev *hdev;
 	int err;
 	int err;
 
 
-	BT_DBG("hci%u", index);
-
-	if (len != sizeof(*cp))
-		return cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
-						MGMT_STATUS_INVALID_PARAMS);
-
-	hdev = hci_dev_get(index);
-	if (!hdev)
-		return cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
-						MGMT_STATUS_INVALID_PARAMS);
+	BT_DBG("%s", hdev->name);
 
 
 	hci_dev_lock(hdev);
 	hci_dev_lock(hdev);
 
 
-	if (!test_bit(HCI_UP, &hdev->flags)) {
-		err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
-						MGMT_STATUS_NOT_POWERED);
+	if (!hdev_is_powered(hdev)) {
+		err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
+				 MGMT_STATUS_NOT_POWERED);
+		goto failed;
+	}
+
+	if (hdev->discovery.state != DISCOVERY_STOPPED) {
+		err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
+				 MGMT_STATUS_BUSY);
 		goto failed;
 		goto failed;
 	}
 	}
 
 
@@ -1936,137 +2307,217 @@ static int start_discovery(struct sock *sk, u16 index,
 		goto failed;
 		goto failed;
 	}
 	}
 
 
-	err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
+	hdev->discovery.type = cp->type;
+
+	switch (hdev->discovery.type) {
+	case DISCOV_TYPE_BREDR:
+		if (lmp_bredr_capable(hdev))
+			err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
+		else
+			err = -ENOTSUPP;
+		break;
+
+	case DISCOV_TYPE_LE:
+		if (lmp_host_le_capable(hdev))
+			err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT,
+					  LE_SCAN_WIN, LE_SCAN_TIMEOUT_LE_ONLY);
+		else
+			err = -ENOTSUPP;
+		break;
+
+	case DISCOV_TYPE_INTERLEAVED:
+		if (lmp_host_le_capable(hdev) && lmp_bredr_capable(hdev))
+			err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT,
+					  LE_SCAN_WIN,
+					  LE_SCAN_TIMEOUT_BREDR_LE);
+		else
+			err = -ENOTSUPP;
+		break;
+
+	default:
+		err = -EINVAL;
+	}
+
 	if (err < 0)
 	if (err < 0)
 		mgmt_pending_remove(cmd);
 		mgmt_pending_remove(cmd);
+	else
+		hci_discovery_set_state(hdev, DISCOVERY_STARTING);
 
 
 failed:
 failed:
 	hci_dev_unlock(hdev);
 	hci_dev_unlock(hdev);
-	hci_dev_put(hdev);
-
 	return err;
 	return err;
 }
 }
 
 
-static int stop_discovery(struct sock *sk, u16 index)
+static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
+			  u16 len)
 {
 {
-	struct hci_dev *hdev;
+	struct mgmt_cp_stop_discovery *mgmt_cp = data;
 	struct pending_cmd *cmd;
 	struct pending_cmd *cmd;
+	struct hci_cp_remote_name_req_cancel cp;
+	struct inquiry_entry *e;
 	int err;
 	int err;
 
 
-	BT_DBG("hci%u", index);
-
-	hdev = hci_dev_get(index);
-	if (!hdev)
-		return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY,
-						MGMT_STATUS_INVALID_PARAMS);
+	BT_DBG("%s", hdev->name);
 
 
 	hci_dev_lock(hdev);
 	hci_dev_lock(hdev);
 
 
+	if (!hci_discovery_active(hdev)) {
+		err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
+				   MGMT_STATUS_REJECTED, &mgmt_cp->type,
+				   sizeof(mgmt_cp->type));
+		goto unlock;
+	}
+
+	if (hdev->discovery.type != mgmt_cp->type) {
+		err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
+				   MGMT_STATUS_INVALID_PARAMS, &mgmt_cp->type,
+				   sizeof(mgmt_cp->type));
+		goto unlock;
+	}
+
 	cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
 	cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
 	if (!cmd) {
 	if (!cmd) {
 		err = -ENOMEM;
 		err = -ENOMEM;
-		goto failed;
+		goto unlock;
 	}
 	}
 
 
-	err = hci_cancel_inquiry(hdev);
+	if (hdev->discovery.state == DISCOVERY_FINDING) {
+		err = hci_cancel_inquiry(hdev);
+		if (err < 0)
+			mgmt_pending_remove(cmd);
+		else
+			hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
+		goto unlock;
+	}
+
+	e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY, NAME_PENDING);
+	if (!e) {
+		mgmt_pending_remove(cmd);
+		err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY, 0,
+				   &mgmt_cp->type, sizeof(mgmt_cp->type));
+		hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
+		goto unlock;
+	}
+
+	bacpy(&cp.bdaddr, &e->data.bdaddr);
+	err = hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ_CANCEL, sizeof(cp),
+			   &cp);
 	if (err < 0)
 	if (err < 0)
 		mgmt_pending_remove(cmd);
 		mgmt_pending_remove(cmd);
+	else
+		hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
 
 
-failed:
+unlock:
 	hci_dev_unlock(hdev);
 	hci_dev_unlock(hdev);
-	hci_dev_put(hdev);
-
 	return err;
 	return err;
 }
 }
 
 
-static int block_device(struct sock *sk, u16 index, unsigned char *data,
-								u16 len)
+static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
+			u16 len)
 {
 {
-	struct hci_dev *hdev;
-	struct mgmt_cp_block_device *cp = (void *) data;
+	struct mgmt_cp_confirm_name *cp = data;
+	struct inquiry_entry *e;
 	int err;
 	int err;
 
 
-	BT_DBG("hci%u", index);
+	BT_DBG("%s", hdev->name);
 
 
-	if (len != sizeof(*cp))
-		return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
-						MGMT_STATUS_INVALID_PARAMS);
+	hci_dev_lock(hdev);
 
 
-	hdev = hci_dev_get(index);
-	if (!hdev)
-		return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
-						MGMT_STATUS_INVALID_PARAMS);
+	if (!hci_discovery_active(hdev)) {
+		err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
+				 MGMT_STATUS_FAILED);
+		goto failed;
+	}
+
+	e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
+	if (!e) {
+		err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
+				 MGMT_STATUS_INVALID_PARAMS);
+		goto failed;
+	}
+
+	if (cp->name_known) {
+		e->name_state = NAME_KNOWN;
+		list_del(&e->list);
+	} else {
+		e->name_state = NAME_NEEDED;
+		hci_inquiry_cache_update_resolve(hdev, e);
+	}
+
+	err = 0;
+
+failed:
+	hci_dev_unlock(hdev);
+	return err;
+}
+
+static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
+			u16 len)
+{
+	struct mgmt_cp_block_device *cp = data;
+	u8 status;
+	int err;
+
+	BT_DBG("%s", hdev->name);
 
 
 	hci_dev_lock(hdev);
 	hci_dev_lock(hdev);
 
 
-	err = hci_blacklist_add(hdev, &cp->bdaddr);
+	err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
 	if (err < 0)
 	if (err < 0)
-		err = cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
-							MGMT_STATUS_FAILED);
+		status = MGMT_STATUS_FAILED;
 	else
 	else
-		err = cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE,
-							NULL, 0);
+		status = 0;
+
+	err = cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
+			   &cp->addr, sizeof(cp->addr));
 
 
 	hci_dev_unlock(hdev);
 	hci_dev_unlock(hdev);
-	hci_dev_put(hdev);
 
 
 	return err;
 	return err;
 }
 }
 
 
-static int unblock_device(struct sock *sk, u16 index, unsigned char *data,
-								u16 len)
+static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
+			  u16 len)
 {
 {
-	struct hci_dev *hdev;
-	struct mgmt_cp_unblock_device *cp = (void *) data;
+	struct mgmt_cp_unblock_device *cp = data;
+	u8 status;
 	int err;
 	int err;
 
 
-	BT_DBG("hci%u", index);
-
-	if (len != sizeof(*cp))
-		return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
-						MGMT_STATUS_INVALID_PARAMS);
-
-	hdev = hci_dev_get(index);
-	if (!hdev)
-		return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
-						MGMT_STATUS_INVALID_PARAMS);
+	BT_DBG("%s", hdev->name);
 
 
 	hci_dev_lock(hdev);
 	hci_dev_lock(hdev);
 
 
-	err = hci_blacklist_del(hdev, &cp->bdaddr);
-
+	err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
 	if (err < 0)
 	if (err < 0)
-		err = cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
-						MGMT_STATUS_INVALID_PARAMS);
+		status = MGMT_STATUS_INVALID_PARAMS;
 	else
 	else
-		err = cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE,
-								NULL, 0);
+		status = 0;
+
+	err = cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
+			   &cp->addr, sizeof(cp->addr));
 
 
 	hci_dev_unlock(hdev);
 	hci_dev_unlock(hdev);
-	hci_dev_put(hdev);
 
 
 	return err;
 	return err;
 }
 }
 
 
-static int set_fast_connectable(struct sock *sk, u16 index,
-					unsigned char *data, u16 len)
+static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
+				void *data, u16 len)
 {
 {
-	struct hci_dev *hdev;
-	struct mgmt_mode *cp = (void *) data;
+	struct mgmt_mode *cp = data;
 	struct hci_cp_write_page_scan_activity acp;
 	struct hci_cp_write_page_scan_activity acp;
 	u8 type;
 	u8 type;
 	int err;
 	int err;
 
 
-	BT_DBG("hci%u", index);
+	BT_DBG("%s", hdev->name);
 
 
-	if (len != sizeof(*cp))
-		return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
-						MGMT_STATUS_INVALID_PARAMS);
+	if (!hdev_is_powered(hdev))
+		return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
+				  MGMT_STATUS_NOT_POWERED);
 
 
-	hdev = hci_dev_get(index);
-	if (!hdev)
-		return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
-						MGMT_STATUS_INVALID_PARAMS);
+	if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
+		return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
+				  MGMT_STATUS_REJECTED);
 
 
 	hci_dev_lock(hdev);
 	hci_dev_lock(hdev);
 
 
@@ -2080,35 +2531,128 @@ static int set_fast_connectable(struct sock *sk, u16 index,
 
 
 	acp.window = 0x0012;	/* default 11.25 msec page scan window */
 	acp.window = 0x0012;	/* default 11.25 msec page scan window */
 
 
-	err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
-						sizeof(acp), &acp);
+	err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY, sizeof(acp),
+			   &acp);
 	if (err < 0) {
 	if (err < 0) {
-		err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
-							MGMT_STATUS_FAILED);
+		err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
+				 MGMT_STATUS_FAILED);
 		goto done;
 		goto done;
 	}
 	}
 
 
 	err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
 	err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
 	if (err < 0) {
 	if (err < 0) {
-		err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
-							MGMT_STATUS_FAILED);
+		err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
+				 MGMT_STATUS_FAILED);
 		goto done;
 		goto done;
 	}
 	}
 
 
-	err = cmd_complete(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
-							NULL, 0);
+	err = cmd_complete(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE, 0,
+			   NULL, 0);
 done:
 done:
 	hci_dev_unlock(hdev);
 	hci_dev_unlock(hdev);
-	hci_dev_put(hdev);
-
 	return err;
 	return err;
 }
 }
 
 
+static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
+			       void *cp_data, u16 len)
+{
+	struct mgmt_cp_load_long_term_keys *cp = cp_data;
+	u16 key_count, expected_len;
+	int i;
+
+	key_count = get_unaligned_le16(&cp->key_count);
+
+	expected_len = sizeof(*cp) + key_count *
+					sizeof(struct mgmt_ltk_info);
+	if (expected_len != len) {
+		BT_ERR("load_keys: expected %u bytes, got %u bytes",
+							len, expected_len);
+		return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
+				  EINVAL);
+	}
+
+	BT_DBG("%s key_count %u", hdev->name, key_count);
+
+	hci_dev_lock(hdev);
+
+	hci_smp_ltks_clear(hdev);
+
+	for (i = 0; i < key_count; i++) {
+		struct mgmt_ltk_info *key = &cp->keys[i];
+		u8 type;
+
+		if (key->master)
+			type = HCI_SMP_LTK;
+		else
+			type = HCI_SMP_LTK_SLAVE;
+
+		hci_add_ltk(hdev, &key->addr.bdaddr, key->addr.type,
+			    type, 0, key->authenticated, key->val,
+			    key->enc_size, key->ediv, key->rand);
+	}
+
+	hci_dev_unlock(hdev);
+
+	return 0;
+}
+
+struct mgmt_handler {
+	int (*func) (struct sock *sk, struct hci_dev *hdev, void *data,
+		     u16 data_len);
+	bool var_len;
+	size_t data_len;
+} mgmt_handlers[] = {
+	{ NULL }, /* 0x0000 (no command) */
+	{ read_version,           false, MGMT_READ_VERSION_SIZE },
+	{ read_commands,          false, MGMT_READ_COMMANDS_SIZE },
+	{ read_index_list,        false, MGMT_READ_INDEX_LIST_SIZE },
+	{ read_controller_info,   false, MGMT_READ_INFO_SIZE },
+	{ set_powered,            false, MGMT_SETTING_SIZE },
+	{ set_discoverable,       false, MGMT_SET_DISCOVERABLE_SIZE },
+	{ set_connectable,        false, MGMT_SETTING_SIZE },
+	{ set_fast_connectable,   false, MGMT_SETTING_SIZE },
+	{ set_pairable,           false, MGMT_SETTING_SIZE },
+	{ set_link_security,      false, MGMT_SETTING_SIZE },
+	{ set_ssp,                false, MGMT_SETTING_SIZE },
+	{ set_hs,                 false, MGMT_SETTING_SIZE },
+	{ set_le,                 false, MGMT_SETTING_SIZE },
+	{ set_dev_class,          false, MGMT_SET_DEV_CLASS_SIZE },
+	{ set_local_name,         false, MGMT_SET_LOCAL_NAME_SIZE },
+	{ add_uuid,               false, MGMT_ADD_UUID_SIZE },
+	{ remove_uuid,            false, MGMT_REMOVE_UUID_SIZE },
+	{ load_link_keys,         true,  MGMT_LOAD_LINK_KEYS_SIZE },
+	{ load_long_term_keys,    true,  MGMT_LOAD_LONG_TERM_KEYS_SIZE },
+	{ disconnect,             false, MGMT_DISCONNECT_SIZE },
+	{ get_connections,        false, MGMT_GET_CONNECTIONS_SIZE },
+	{ pin_code_reply,         false, MGMT_PIN_CODE_REPLY_SIZE },
+	{ pin_code_neg_reply,     false, MGMT_PIN_CODE_NEG_REPLY_SIZE },
+	{ set_io_capability,      false, MGMT_SET_IO_CAPABILITY_SIZE },
+	{ pair_device,            false, MGMT_PAIR_DEVICE_SIZE },
+	{ cancel_pair_device,     false, MGMT_CANCEL_PAIR_DEVICE_SIZE },
+	{ unpair_device,          false, MGMT_UNPAIR_DEVICE_SIZE },
+	{ user_confirm_reply,     false, MGMT_USER_CONFIRM_REPLY_SIZE },
+	{ user_confirm_neg_reply, false, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
+	{ user_passkey_reply,     false, MGMT_USER_PASSKEY_REPLY_SIZE },
+	{ user_passkey_neg_reply, false, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
+	{ read_local_oob_data,    false, MGMT_READ_LOCAL_OOB_DATA_SIZE },
+	{ add_remote_oob_data,    false, MGMT_ADD_REMOTE_OOB_DATA_SIZE },
+	{ remove_remote_oob_data, false, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
+	{ start_discovery,        false, MGMT_START_DISCOVERY_SIZE },
+	{ stop_discovery,         false, MGMT_STOP_DISCOVERY_SIZE },
+	{ confirm_name,           false, MGMT_CONFIRM_NAME_SIZE },
+	{ block_device,           false, MGMT_BLOCK_DEVICE_SIZE },
+	{ unblock_device,         false, MGMT_UNBLOCK_DEVICE_SIZE },
+};
+
+
 int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
 int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
 {
 {
-	unsigned char *buf;
+	void *buf;
+	u8 *cp;
 	struct mgmt_hdr *hdr;
 	struct mgmt_hdr *hdr;
 	u16 opcode, index, len;
 	u16 opcode, index, len;
+	struct hci_dev *hdev = NULL;
+	struct mgmt_handler *handler;
 	int err;
 	int err;
 
 
 	BT_DBG("got %zu bytes", msglen);
 	BT_DBG("got %zu bytes", msglen);
@@ -2125,7 +2669,7 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
 		goto done;
 		goto done;
 	}
 	}
 
 
-	hdr = (struct mgmt_hdr *) buf;
+	hdr = buf;
 	opcode = get_unaligned_le16(&hdr->opcode);
 	opcode = get_unaligned_le16(&hdr->opcode);
 	index = get_unaligned_le16(&hdr->index);
 	index = get_unaligned_le16(&hdr->index);
 	len = get_unaligned_le16(&hdr->len);
 	len = get_unaligned_le16(&hdr->len);
@@ -2135,117 +2679,54 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
 		goto done;
 		goto done;
 	}
 	}
 
 
-	switch (opcode) {
-	case MGMT_OP_READ_VERSION:
-		err = read_version(sk);
-		break;
-	case MGMT_OP_READ_INDEX_LIST:
-		err = read_index_list(sk);
-		break;
-	case MGMT_OP_READ_INFO:
-		err = read_controller_info(sk, index);
-		break;
-	case MGMT_OP_SET_POWERED:
-		err = set_powered(sk, index, buf + sizeof(*hdr), len);
-		break;
-	case MGMT_OP_SET_DISCOVERABLE:
-		err = set_discoverable(sk, index, buf + sizeof(*hdr), len);
-		break;
-	case MGMT_OP_SET_CONNECTABLE:
-		err = set_connectable(sk, index, buf + sizeof(*hdr), len);
-		break;
-	case MGMT_OP_SET_FAST_CONNECTABLE:
-		err = set_fast_connectable(sk, index, buf + sizeof(*hdr),
-								len);
-		break;
-	case MGMT_OP_SET_PAIRABLE:
-		err = set_pairable(sk, index, buf + sizeof(*hdr), len);
-		break;
-	case MGMT_OP_ADD_UUID:
-		err = add_uuid(sk, index, buf + sizeof(*hdr), len);
-		break;
-	case MGMT_OP_REMOVE_UUID:
-		err = remove_uuid(sk, index, buf + sizeof(*hdr), len);
-		break;
-	case MGMT_OP_SET_DEV_CLASS:
-		err = set_dev_class(sk, index, buf + sizeof(*hdr), len);
-		break;
-	case MGMT_OP_LOAD_LINK_KEYS:
-		err = load_link_keys(sk, index, buf + sizeof(*hdr), len);
-		break;
-	case MGMT_OP_REMOVE_KEYS:
-		err = remove_keys(sk, index, buf + sizeof(*hdr), len);
-		break;
-	case MGMT_OP_DISCONNECT:
-		err = disconnect(sk, index, buf + sizeof(*hdr), len);
-		break;
-	case MGMT_OP_GET_CONNECTIONS:
-		err = get_connections(sk, index);
-		break;
-	case MGMT_OP_PIN_CODE_REPLY:
-		err = pin_code_reply(sk, index, buf + sizeof(*hdr), len);
-		break;
-	case MGMT_OP_PIN_CODE_NEG_REPLY:
-		err = pin_code_neg_reply(sk, index, buf + sizeof(*hdr), len);
-		break;
-	case MGMT_OP_SET_IO_CAPABILITY:
-		err = set_io_capability(sk, index, buf + sizeof(*hdr), len);
-		break;
-	case MGMT_OP_PAIR_DEVICE:
-		err = pair_device(sk, index, buf + sizeof(*hdr), len);
-		break;
-	case MGMT_OP_USER_CONFIRM_REPLY:
-		err = user_confirm_reply(sk, index, buf + sizeof(*hdr), len);
-		break;
-	case MGMT_OP_USER_CONFIRM_NEG_REPLY:
-		err = user_confirm_neg_reply(sk, index, buf + sizeof(*hdr),
-									len);
-		break;
-	case MGMT_OP_USER_PASSKEY_REPLY:
-		err = user_passkey_reply(sk, index, buf + sizeof(*hdr), len);
-		break;
-	case MGMT_OP_USER_PASSKEY_NEG_REPLY:
-		err = user_passkey_neg_reply(sk, index, buf + sizeof(*hdr),
-									len);
-		break;
-	case MGMT_OP_SET_LOCAL_NAME:
-		err = set_local_name(sk, index, buf + sizeof(*hdr), len);
-		break;
-	case MGMT_OP_READ_LOCAL_OOB_DATA:
-		err = read_local_oob_data(sk, index);
-		break;
-	case MGMT_OP_ADD_REMOTE_OOB_DATA:
-		err = add_remote_oob_data(sk, index, buf + sizeof(*hdr), len);
-		break;
-	case MGMT_OP_REMOVE_REMOTE_OOB_DATA:
-		err = remove_remote_oob_data(sk, index, buf + sizeof(*hdr),
-									len);
-		break;
-	case MGMT_OP_START_DISCOVERY:
-		err = start_discovery(sk, index, buf + sizeof(*hdr), len);
-		break;
-	case MGMT_OP_STOP_DISCOVERY:
-		err = stop_discovery(sk, index);
-		break;
-	case MGMT_OP_BLOCK_DEVICE:
-		err = block_device(sk, index, buf + sizeof(*hdr), len);
-		break;
-	case MGMT_OP_UNBLOCK_DEVICE:
-		err = unblock_device(sk, index, buf + sizeof(*hdr), len);
-		break;
-	default:
+	if (index != MGMT_INDEX_NONE) {
+		hdev = hci_dev_get(index);
+		if (!hdev) {
+			err = cmd_status(sk, index, opcode,
+					 MGMT_STATUS_INVALID_INDEX);
+			goto done;
+		}
+	}
+
+	if (opcode >= ARRAY_SIZE(mgmt_handlers) ||
+					mgmt_handlers[opcode].func == NULL) {
 		BT_DBG("Unknown op %u", opcode);
 		BT_DBG("Unknown op %u", opcode);
 		err = cmd_status(sk, index, opcode,
 		err = cmd_status(sk, index, opcode,
-						MGMT_STATUS_UNKNOWN_COMMAND);
-		break;
+				 MGMT_STATUS_UNKNOWN_COMMAND);
+		goto done;
+	}
+
+	if ((hdev && opcode < MGMT_OP_READ_INFO) ||
+			(!hdev && opcode >= MGMT_OP_READ_INFO)) {
+		err = cmd_status(sk, index, opcode,
+				 MGMT_STATUS_INVALID_INDEX);
+		goto done;
 	}
 	}
 
 
+	handler = &mgmt_handlers[opcode];
+
+	if ((handler->var_len && len < handler->data_len) ||
+			(!handler->var_len && len != handler->data_len)) {
+		err = cmd_status(sk, index, opcode,
+				 MGMT_STATUS_INVALID_PARAMS);
+		goto done;
+	}
+
+	if (hdev)
+		mgmt_init_hdev(sk, hdev);
+
+	cp = buf + sizeof(*hdr);
+
+	err = handler->func(sk, hdev, cp, len);
 	if (err < 0)
 	if (err < 0)
 		goto done;
 		goto done;
 
 
 	err = msglen;
 	err = msglen;
 
 
 done:
 done:
+	if (hdev)
+		hci_dev_put(hdev);
+
 	kfree(buf);
 	kfree(buf);
 	return err;
 	return err;
 }
 }
@@ -2265,7 +2746,7 @@ int mgmt_index_added(struct hci_dev *hdev)
 
 
 int mgmt_index_removed(struct hci_dev *hdev)
 int mgmt_index_removed(struct hci_dev *hdev)
 {
 {
-	u8 status = ENODEV;
+	u8 status = MGMT_STATUS_INVALID_INDEX;
 
 
 	mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
 	mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
 
 
@@ -2273,9 +2754,9 @@ int mgmt_index_removed(struct hci_dev *hdev)
 }
 }
 
 
 struct cmd_lookup {
 struct cmd_lookup {
-	u8 val;
 	struct sock *sk;
 	struct sock *sk;
 	struct hci_dev *hdev;
 	struct hci_dev *hdev;
+	u8 mgmt_status;
 };
 };
 
 
 static void settings_rsp(struct pending_cmd *cmd, void *data)
 static void settings_rsp(struct pending_cmd *cmd, void *data)
@@ -2296,63 +2777,91 @@ static void settings_rsp(struct pending_cmd *cmd, void *data)
 
 
 int mgmt_powered(struct hci_dev *hdev, u8 powered)
 int mgmt_powered(struct hci_dev *hdev, u8 powered)
 {
 {
-	struct cmd_lookup match = { powered, NULL, hdev };
-	__le32 ev;
-	int ret;
+	struct cmd_lookup match = { NULL, hdev };
+	int err;
+
+	if (!test_bit(HCI_MGMT, &hdev->dev_flags))
+		return 0;
 
 
 	mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
 	mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
 
 
-	if (!powered) {
-		u8 status = ENETDOWN;
+	if (powered) {
+		u8 scan = 0;
+
+		if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
+			scan |= SCAN_PAGE;
+		if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
+			scan |= SCAN_INQUIRY;
+
+		if (scan)
+			hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
+
+		update_class(hdev);
+		update_name(hdev, hdev->dev_name);
+		update_eir(hdev);
+	} else {
+		u8 status = MGMT_STATUS_NOT_POWERED;
 		mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
 		mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
 	}
 	}
 
 
-	ev = cpu_to_le32(get_current_settings(hdev));
-
-	ret = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev),
-								match.sk);
+	err = new_settings(hdev, match.sk);
 
 
 	if (match.sk)
 	if (match.sk)
 		sock_put(match.sk);
 		sock_put(match.sk);
 
 
-	return ret;
+	return err;
 }
 }
 
 
 int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
 int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
 {
 {
-	struct cmd_lookup match = { discoverable, NULL, hdev };
-	__le32 ev;
-	int ret;
+	struct cmd_lookup match = { NULL, hdev };
+	bool changed = false;
+	int err = 0;
+
+	if (discoverable) {
+		if (!test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
+			changed = true;
+	} else {
+		if (test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
+			changed = true;
+	}
 
 
-	mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp, &match);
+	mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp,
+			     &match);
 
 
-	ev = cpu_to_le32(get_current_settings(hdev));
+	if (changed)
+		err = new_settings(hdev, match.sk);
 
 
-	ret = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev),
-								match.sk);
 	if (match.sk)
 	if (match.sk)
 		sock_put(match.sk);
 		sock_put(match.sk);
 
 
-	return ret;
+	return err;
 }
 }
 
 
 int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
 int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
 {
 {
-	__le32 ev;
-	struct cmd_lookup match = { connectable, NULL, hdev };
-	int ret;
+	struct cmd_lookup match = { NULL, hdev };
+	bool changed = false;
+	int err = 0;
 
 
-	mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, settings_rsp,
-								&match);
+	if (connectable) {
+		if (!test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags))
+			changed = true;
+	} else {
+		if (test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags))
+			changed = true;
+	}
 
 
-	ev = cpu_to_le32(get_current_settings(hdev));
+	mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, settings_rsp,
+			     &match);
 
 
-	ret = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), match.sk);
+	if (changed)
+		err = new_settings(hdev, match.sk);
 
 
 	if (match.sk)
 	if (match.sk)
 		sock_put(match.sk);
 		sock_put(match.sk);
 
 
-	return ret;
+	return err;
 }
 }
 
 
 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)
@@ -2361,24 +2870,24 @@ int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
 
 
 	if (scan & SCAN_PAGE)
 	if (scan & SCAN_PAGE)
 		mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
 		mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
-						cmd_status_rsp, &mgmt_err);
+				     cmd_status_rsp, &mgmt_err);
 
 
 	if (scan & SCAN_INQUIRY)
 	if (scan & SCAN_INQUIRY)
 		mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
 		mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
-						cmd_status_rsp, &mgmt_err);
+				     cmd_status_rsp, &mgmt_err);
 
 
 	return 0;
 	return 0;
 }
 }
 
 
-int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
-								u8 persistent)
+int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key, u8 persistent)
 {
 {
 	struct mgmt_ev_new_link_key ev;
 	struct mgmt_ev_new_link_key ev;
 
 
 	memset(&ev, 0, sizeof(ev));
 	memset(&ev, 0, sizeof(ev));
 
 
 	ev.store_hint = persistent;
 	ev.store_hint = persistent;
-	bacpy(&ev.key.bdaddr, &key->bdaddr);
+	bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
+	ev.key.addr.type = MGMT_ADDR_BREDR;
 	ev.key.type = key->type;
 	ev.key.type = key->type;
 	memcpy(ev.key.val, key->val, 16);
 	memcpy(ev.key.val, key->val, 16);
 	ev.key.pin_len = key->pin_len;
 	ev.key.pin_len = key->pin_len;
@@ -2386,15 +2895,54 @@ int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
 	return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
 	return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
 }
 }
 
 
-int mgmt_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
-								u8 addr_type)
+int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
 {
 {
-	struct mgmt_addr_info ev;
+	struct mgmt_ev_new_long_term_key ev;
 
 
-	bacpy(&ev.bdaddr, bdaddr);
-	ev.type = link_to_mgmt(link_type, addr_type);
+	memset(&ev, 0, sizeof(ev));
+
+	ev.store_hint = persistent;
+	bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
+	ev.key.addr.type = key->bdaddr_type;
+	ev.key.authenticated = key->authenticated;
+	ev.key.enc_size = key->enc_size;
+	ev.key.ediv = key->ediv;
 
 
-	return mgmt_event(MGMT_EV_CONNECTED, hdev, &ev, sizeof(ev), NULL);
+	if (key->type == HCI_SMP_LTK)
+		ev.key.master = 1;
+
+	memcpy(ev.key.rand, key->rand, sizeof(key->rand));
+	memcpy(ev.key.val, key->val, sizeof(key->val));
+
+	return mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev),
+			  NULL);
+}
+
+int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
+			  u8 addr_type, u32 flags, u8 *name, u8 name_len,
+			  u8 *dev_class)
+{
+	char buf[512];
+	struct mgmt_ev_device_connected *ev = (void *) buf;
+	u16 eir_len = 0;
+
+	bacpy(&ev->addr.bdaddr, bdaddr);
+	ev->addr.type = link_to_mgmt(link_type, addr_type);
+
+	ev->flags = __cpu_to_le32(flags);
+
+	if (name_len > 0)
+		eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
+					  name, name_len);
+
+	if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
+		eir_len = eir_append_data(&ev->eir[eir_len], eir_len,
+					  EIR_CLASS_OF_DEV, dev_class, 3);
+
+	put_unaligned_le16(eir_len, &ev->eir_len);
+
+	return mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
+			  sizeof(*ev) + eir_len, NULL);
 }
 }
 
 
 static void disconnect_rsp(struct pending_cmd *cmd, void *data)
 static void disconnect_rsp(struct pending_cmd *cmd, void *data)
@@ -2403,10 +2951,11 @@ static void disconnect_rsp(struct pending_cmd *cmd, void *data)
 	struct sock **sk = data;
 	struct sock **sk = data;
 	struct mgmt_rp_disconnect rp;
 	struct mgmt_rp_disconnect rp;
 
 
-	bacpy(&rp.bdaddr, &cp->bdaddr);
-	rp.status = 0;
+	bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
+	rp.addr.type = cp->addr.type;
 
 
-	cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, &rp, sizeof(rp));
+	cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp,
+		     sizeof(rp));
 
 
 	*sk = cmd->sk;
 	*sk = cmd->sk;
 	sock_hold(*sk);
 	sock_hold(*sk);
@@ -2414,25 +2963,25 @@ static void disconnect_rsp(struct pending_cmd *cmd, void *data)
 	mgmt_pending_remove(cmd);
 	mgmt_pending_remove(cmd);
 }
 }
 
 
-static void remove_keys_rsp(struct pending_cmd *cmd, void *data)
+static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
 {
 {
-	u8 *status = data;
-	struct mgmt_cp_remove_keys *cp = cmd->param;
-	struct mgmt_rp_remove_keys rp;
+	struct hci_dev *hdev = data;
+	struct mgmt_cp_unpair_device *cp = cmd->param;
+	struct mgmt_rp_unpair_device rp;
 
 
 	memset(&rp, 0, sizeof(rp));
 	memset(&rp, 0, sizeof(rp));
-	bacpy(&rp.bdaddr, &cp->bdaddr);
-	if (status != NULL)
-		rp.status = *status;
+	bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
+	rp.addr.type = cp->addr.type;
+
+	device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
 
 
-	cmd_complete(cmd->sk, cmd->index, MGMT_OP_REMOVE_KEYS, &rp,
-								sizeof(rp));
+	cmd_complete(cmd->sk, cmd->index, cmd->opcode, 0, &rp, sizeof(rp));
 
 
 	mgmt_pending_remove(cmd);
 	mgmt_pending_remove(cmd);
 }
 }
 
 
-int mgmt_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
-								u8 addr_type)
+int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
+			     u8 link_type, u8 addr_type)
 {
 {
 	struct mgmt_addr_info ev;
 	struct mgmt_addr_info ev;
 	struct sock *sk = NULL;
 	struct sock *sk = NULL;
@@ -2443,45 +2992,44 @@ int mgmt_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
 	bacpy(&ev.bdaddr, bdaddr);
 	bacpy(&ev.bdaddr, bdaddr);
 	ev.type = link_to_mgmt(link_type, addr_type);
 	ev.type = link_to_mgmt(link_type, addr_type);
 
 
-	err = mgmt_event(MGMT_EV_DISCONNECTED, hdev, &ev, sizeof(ev), sk);
+	err = mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev),
+			 sk);
 
 
 	if (sk)
 	if (sk)
-		sock_put(sk);
+	  sock_put(sk);
 
 
-	mgmt_pending_foreach(MGMT_OP_REMOVE_KEYS, hdev, remove_keys_rsp, NULL);
+	mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
+			     hdev);
 
 
 	return err;
 	return err;
 }
 }
 
 
-int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 status)
+int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
+			   u8 link_type, u8 addr_type, u8 status)
 {
 {
+	struct mgmt_rp_disconnect rp;
 	struct pending_cmd *cmd;
 	struct pending_cmd *cmd;
-	u8 mgmt_err = mgmt_status(status);
 	int err;
 	int err;
 
 
 	cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
 	cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
 	if (!cmd)
 	if (!cmd)
 		return -ENOENT;
 		return -ENOENT;
 
 
-	if (bdaddr) {
-		struct mgmt_rp_disconnect rp;
-
-		bacpy(&rp.bdaddr, bdaddr);
-		rp.status = status;
+	bacpy(&rp.addr.bdaddr, bdaddr);
+	rp.addr.type = link_to_mgmt(link_type, addr_type);
 
 
-		err = cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
-							&rp, sizeof(rp));
-	} else
-		err = cmd_status(cmd->sk, hdev->id, MGMT_OP_DISCONNECT,
-								mgmt_err);
+	err = cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
+			   mgmt_status(status), &rp, sizeof(rp));
 
 
 	mgmt_pending_remove(cmd);
 	mgmt_pending_remove(cmd);
 
 
+	mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
+									hdev);
 	return err;
 	return err;
 }
 }
 
 
 int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
 int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
-						u8 addr_type, u8 status)
+			u8 addr_type, u8 status)
 {
 {
 	struct mgmt_ev_connect_failed ev;
 	struct mgmt_ev_connect_failed ev;
 
 
@@ -2496,15 +3044,16 @@ int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
 {
 {
 	struct mgmt_ev_pin_code_request ev;
 	struct mgmt_ev_pin_code_request ev;
 
 
-	bacpy(&ev.bdaddr, bdaddr);
+	bacpy(&ev.addr.bdaddr, bdaddr);
+	ev.addr.type = MGMT_ADDR_BREDR;
 	ev.secure = secure;
 	ev.secure = secure;
 
 
 	return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
 	return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
-									NULL);
+			  NULL);
 }
 }
 
 
 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)
 {
 {
 	struct pending_cmd *cmd;
 	struct pending_cmd *cmd;
 	struct mgmt_rp_pin_code_reply rp;
 	struct mgmt_rp_pin_code_reply rp;
@@ -2514,11 +3063,11 @@ int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
 	if (!cmd)
 	if (!cmd)
 		return -ENOENT;
 		return -ENOENT;
 
 
-	bacpy(&rp.bdaddr, bdaddr);
-	rp.status = mgmt_status(status);
+	bacpy(&rp.addr.bdaddr, bdaddr);
+	rp.addr.type = MGMT_ADDR_BREDR;
 
 
-	err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY, &rp,
-								sizeof(rp));
+	err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
+			   mgmt_status(status), &rp, sizeof(rp));
 
 
 	mgmt_pending_remove(cmd);
 	mgmt_pending_remove(cmd);
 
 
@@ -2526,7 +3075,7 @@ int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
 }
 }
 
 
 int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
 int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
-								u8 status)
+				     u8 status)
 {
 {
 	struct pending_cmd *cmd;
 	struct pending_cmd *cmd;
 	struct mgmt_rp_pin_code_reply rp;
 	struct mgmt_rp_pin_code_reply rp;
@@ -2536,11 +3085,11 @@ int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
 	if (!cmd)
 	if (!cmd)
 		return -ENOENT;
 		return -ENOENT;
 
 
-	bacpy(&rp.bdaddr, bdaddr);
-	rp.status = mgmt_status(status);
+	bacpy(&rp.addr.bdaddr, bdaddr);
+	rp.addr.type = MGMT_ADDR_BREDR;
 
 
-	err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY, &rp,
-								sizeof(rp));
+	err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
+			   mgmt_status(status), &rp, sizeof(rp));
 
 
 	mgmt_pending_remove(cmd);
 	mgmt_pending_remove(cmd);
 
 
@@ -2548,34 +3097,39 @@ int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
 }
 }
 
 
 int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
 int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
-						__le32 value, u8 confirm_hint)
+			      u8 link_type, u8 addr_type, __le32 value,
+			      u8 confirm_hint)
 {
 {
 	struct mgmt_ev_user_confirm_request ev;
 	struct mgmt_ev_user_confirm_request ev;
 
 
 	BT_DBG("%s", hdev->name);
 	BT_DBG("%s", hdev->name);
 
 
-	bacpy(&ev.bdaddr, bdaddr);
+	bacpy(&ev.addr.bdaddr, bdaddr);
+	ev.addr.type = link_to_mgmt(link_type, addr_type);
 	ev.confirm_hint = confirm_hint;
 	ev.confirm_hint = confirm_hint;
 	put_unaligned_le32(value, &ev.value);
 	put_unaligned_le32(value, &ev.value);
 
 
 	return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
 	return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
-									NULL);
+			  NULL);
 }
 }
 
 
-int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr)
+int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
+						u8 link_type, u8 addr_type)
 {
 {
 	struct mgmt_ev_user_passkey_request ev;
 	struct mgmt_ev_user_passkey_request ev;
 
 
 	BT_DBG("%s", hdev->name);
 	BT_DBG("%s", hdev->name);
 
 
-	bacpy(&ev.bdaddr, bdaddr);
+	bacpy(&ev.addr.bdaddr, bdaddr);
+	ev.addr.type = link_to_mgmt(link_type, addr_type);
 
 
 	return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
 	return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
-									NULL);
+			  NULL);
 }
 }
 
 
 static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
 static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
-							u8 status, u8 opcode)
+					u8 link_type, u8 addr_type, u8 status,
+					u8 opcode)
 {
 {
 	struct pending_cmd *cmd;
 	struct pending_cmd *cmd;
 	struct mgmt_rp_user_confirm_reply rp;
 	struct mgmt_rp_user_confirm_reply rp;
@@ -2585,9 +3139,10 @@ static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
 	if (!cmd)
 	if (!cmd)
 		return -ENOENT;
 		return -ENOENT;
 
 
-	bacpy(&rp.bdaddr, bdaddr);
-	rp.status = mgmt_status(status);
-	err = cmd_complete(cmd->sk, hdev->id, opcode, &rp, sizeof(rp));
+	bacpy(&rp.addr.bdaddr, bdaddr);
+	rp.addr.type = link_to_mgmt(link_type, addr_type);
+	err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status),
+			   &rp, sizeof(rp));
 
 
 	mgmt_pending_remove(cmd);
 	mgmt_pending_remove(cmd);
 
 
@@ -2595,72 +3150,215 @@ static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
 }
 }
 
 
 int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
 int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
-								u8 status)
+				     u8 link_type, u8 addr_type, u8 status)
 {
 {
-	return user_pairing_resp_complete(hdev, bdaddr, status,
-						MGMT_OP_USER_CONFIRM_REPLY);
+	return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
+					  status, MGMT_OP_USER_CONFIRM_REPLY);
 }
 }
 
 
-int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev,
-						bdaddr_t *bdaddr, u8 status)
+int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
+					 u8 link_type, u8 addr_type, u8 status)
 {
 {
-	return user_pairing_resp_complete(hdev, bdaddr, status,
-					MGMT_OP_USER_CONFIRM_NEG_REPLY);
+	return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
+					  status, MGMT_OP_USER_CONFIRM_NEG_REPLY);
 }
 }
 
 
 int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
 int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
-								u8 status)
+				     u8 link_type, u8 addr_type, u8 status)
 {
 {
-	return user_pairing_resp_complete(hdev, bdaddr, status,
-						MGMT_OP_USER_PASSKEY_REPLY);
+	return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
+					  status, MGMT_OP_USER_PASSKEY_REPLY);
 }
 }
 
 
-int mgmt_user_passkey_neg_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 link_type, u8 addr_type, u8 status)
 {
 {
-	return user_pairing_resp_complete(hdev, bdaddr, status,
-					MGMT_OP_USER_PASSKEY_NEG_REPLY);
+	return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
+					  status, MGMT_OP_USER_PASSKEY_NEG_REPLY);
 }
 }
 
 
-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 link_type,
+		     u8 addr_type, u8 status)
 {
 {
 	struct mgmt_ev_auth_failed ev;
 	struct mgmt_ev_auth_failed ev;
 
 
-	bacpy(&ev.bdaddr, bdaddr);
+	bacpy(&ev.addr.bdaddr, bdaddr);
+	ev.addr.type = link_to_mgmt(link_type, addr_type);
 	ev.status = mgmt_status(status);
 	ev.status = mgmt_status(status);
 
 
 	return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
 	return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
 }
 }
 
 
+int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
+{
+	struct cmd_lookup match = { NULL, hdev };
+	bool changed = false;
+	int err = 0;
+
+	if (status) {
+		u8 mgmt_err = mgmt_status(status);
+		mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
+				     cmd_status_rsp, &mgmt_err);
+		return 0;
+	}
+
+	if (test_bit(HCI_AUTH, &hdev->flags)) {
+		if (!test_and_set_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
+			changed = true;
+	} else {
+		if (test_and_clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
+			changed = true;
+	}
+
+	mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
+			     &match);
+
+	if (changed)
+		err = new_settings(hdev, match.sk);
+
+	if (match.sk)
+		sock_put(match.sk);
+
+	return err;
+}
+
+static int clear_eir(struct hci_dev *hdev)
+{
+	struct hci_cp_write_eir cp;
+
+	if (!(hdev->features[6] & LMP_EXT_INQ))
+		return 0;
+
+	memset(hdev->eir, 0, sizeof(hdev->eir));
+
+	memset(&cp, 0, sizeof(cp));
+
+	return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
+}
+
+int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
+{
+	struct cmd_lookup match = { NULL, hdev };
+	bool changed = false;
+	int err = 0;
+
+	if (status) {
+		u8 mgmt_err = mgmt_status(status);
+
+		if (enable && test_and_clear_bit(HCI_SSP_ENABLED,
+						 &hdev->dev_flags))
+			err = new_settings(hdev, NULL);
+
+		mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
+				     &mgmt_err);
+
+		return err;
+	}
+
+	if (enable) {
+		if (!test_and_set_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
+			changed = true;
+	} else {
+		if (test_and_clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
+			changed = true;
+	}
+
+	mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
+
+	if (changed)
+		err = new_settings(hdev, match.sk);
+
+	if (match.sk)
+		sock_put(match.sk);
+
+	if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
+		update_eir(hdev);
+	else
+		clear_eir(hdev);
+
+	return err;
+}
+
+static void class_rsp(struct pending_cmd *cmd, void *data)
+{
+	struct cmd_lookup *match = data;
+
+	cmd_complete(cmd->sk, cmd->index, cmd->opcode, match->mgmt_status,
+		     match->hdev->dev_class, 3);
+
+	list_del(&cmd->list);
+
+	if (match->sk == NULL) {
+		match->sk = cmd->sk;
+		sock_hold(match->sk);
+	}
+
+	mgmt_pending_free(cmd);
+}
+
+int mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
+				   u8 status)
+{
+	struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
+	int err = 0;
+
+	clear_bit(HCI_PENDING_CLASS, &hdev->dev_flags);
+
+	mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, class_rsp, &match);
+	mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, class_rsp, &match);
+	mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, class_rsp, &match);
+
+	if (!status)
+		err = mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class,
+				 3, NULL);
+
+	if (match.sk)
+		sock_put(match.sk);
+
+	return err;
+}
+
 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)
 {
 {
 	struct pending_cmd *cmd;
 	struct pending_cmd *cmd;
 	struct mgmt_cp_set_local_name ev;
 	struct mgmt_cp_set_local_name ev;
-	int err;
+	bool changed = false;
+	int err = 0;
+
+	if (memcmp(name, hdev->dev_name, sizeof(hdev->dev_name)) != 0) {
+		memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
+		changed = true;
+	}
 
 
 	memset(&ev, 0, sizeof(ev));
 	memset(&ev, 0, sizeof(ev));
 	memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
 	memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
+	memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
 
 
 	cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
 	cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
 	if (!cmd)
 	if (!cmd)
 		goto send_event;
 		goto send_event;
 
 
+	/* Always assume that either the short or the complete name has
+	 * changed if there was a pending mgmt command */
+	changed = true;
+
 	if (status) {
 	if (status) {
 		err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
 		err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
-							mgmt_status(status));
+				 mgmt_status(status));
 		goto failed;
 		goto failed;
 	}
 	}
 
 
-	update_eir(hdev);
-
-	err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, &ev,
-								sizeof(ev));
+	err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0, &ev,
+			   sizeof(ev));
 	if (err < 0)
 	if (err < 0)
 		goto failed;
 		goto failed;
 
 
 send_event:
 send_event:
-	err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
-							cmd ? cmd->sk : NULL);
+	if (changed)
+		err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev,
+				 sizeof(ev), cmd ? cmd->sk : NULL);
+
+	update_eir(hdev);
 
 
 failed:
 failed:
 	if (cmd)
 	if (cmd)
@@ -2669,7 +3367,7 @@ failed:
 }
 }
 
 
 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)
 {
 {
 	struct pending_cmd *cmd;
 	struct pending_cmd *cmd;
 	int err;
 	int err;
@@ -2681,9 +3379,8 @@ int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
 		return -ENOENT;
 		return -ENOENT;
 
 
 	if (status) {
 	if (status) {
-		err = cmd_status(cmd->sk, hdev->id,
-						MGMT_OP_READ_LOCAL_OOB_DATA,
-						mgmt_status(status));
+		err = cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
+				 mgmt_status(status));
 	} else {
 	} else {
 		struct mgmt_rp_read_local_oob_data rp;
 		struct mgmt_rp_read_local_oob_data rp;
 
 
@@ -2691,8 +3388,8 @@ int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
 		memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
 		memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
 
 
 		err = cmd_complete(cmd->sk, hdev->id,
 		err = cmd_complete(cmd->sk, hdev->id,
-						MGMT_OP_READ_LOCAL_OOB_DATA,
-						&rp, sizeof(rp));
+				   MGMT_OP_READ_LOCAL_OOB_DATA, 0, &rp,
+				   sizeof(rp));
 	}
 	}
 
 
 	mgmt_pending_remove(cmd);
 	mgmt_pending_remove(cmd);
@@ -2700,48 +3397,120 @@ int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
 	return err;
 	return err;
 }
 }
 
 
+int mgmt_le_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
+{
+	struct cmd_lookup match = { NULL, hdev };
+	bool changed = false;
+	int err = 0;
+
+	if (status) {
+		u8 mgmt_err = mgmt_status(status);
+
+		if (enable && test_and_clear_bit(HCI_LE_ENABLED,
+						 &hdev->dev_flags))
+		  err = new_settings(hdev, NULL);
+
+		mgmt_pending_foreach(MGMT_OP_SET_LE, hdev,
+				     cmd_status_rsp, &mgmt_err);
+
+		return err;
+	}
+
+	if (enable) {
+		if (!test_and_set_bit(HCI_LE_ENABLED, &hdev->dev_flags))
+			changed = true;
+	} else {
+		if (test_and_clear_bit(HCI_LE_ENABLED, &hdev->dev_flags))
+			changed = true;
+	}
+
+	mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
+
+	if (changed)
+		err = new_settings(hdev, match.sk);
+
+	if (match.sk)
+		sock_put(match.sk);
+
+	return err;
+}
+
 int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
 int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
-				u8 addr_type, u8 *dev_class, s8 rssi, u8 *eir)
+		      u8 addr_type, u8 *dev_class, s8 rssi, u8 cfm_name, u8
+		      ssp, u8 *eir, u16 eir_len)
 {
 {
-	struct mgmt_ev_device_found ev;
+	char buf[512];
+	struct mgmt_ev_device_found *ev = (void *) buf;
+	size_t ev_size;
 
 
-	memset(&ev, 0, sizeof(ev));
+	/* Leave 5 bytes for a potential CoD field */
+	if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
+		return -EINVAL;
 
 
-	bacpy(&ev.addr.bdaddr, bdaddr);
-	ev.addr.type = link_to_mgmt(link_type, addr_type);
-	ev.rssi = rssi;
+	memset(buf, 0, sizeof(buf));
+
+	bacpy(&ev->addr.bdaddr, bdaddr);
+	ev->addr.type = link_to_mgmt(link_type, addr_type);
+	ev->rssi = rssi;
+	if (cfm_name)
+		ev->flags[0] |= MGMT_DEV_FOUND_CONFIRM_NAME;
+	if (!ssp)
+		ev->flags[0] |= MGMT_DEV_FOUND_LEGACY_PAIRING;
 
 
-	if (eir)
-		memcpy(ev.eir, eir, sizeof(ev.eir));
+	if (eir_len > 0)
+		memcpy(ev->eir, eir, eir_len);
 
 
-	if (dev_class)
-		memcpy(ev.dev_class, dev_class, sizeof(ev.dev_class));
+	if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
+		eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
+					  dev_class, 3);
 
 
-	return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, &ev, sizeof(ev), NULL);
+	put_unaligned_le16(eir_len, &ev->eir_len);
+
+	ev_size = sizeof(*ev) + eir_len;
+
+	return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
 }
 }
 
 
-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 link_type,
+		     u8 addr_type, s8 rssi, u8 *name, u8 name_len)
 {
 {
-	struct mgmt_ev_remote_name ev;
+	struct mgmt_ev_device_found *ev;
+	char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
+	u16 eir_len;
 
 
-	memset(&ev, 0, sizeof(ev));
+	ev = (struct mgmt_ev_device_found *) buf;
 
 
-	bacpy(&ev.bdaddr, bdaddr);
-	memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
+	memset(buf, 0, sizeof(buf));
+
+	bacpy(&ev->addr.bdaddr, bdaddr);
+	ev->addr.type = link_to_mgmt(link_type, addr_type);
+	ev->rssi = rssi;
 
 
-	return mgmt_event(MGMT_EV_REMOTE_NAME, hdev, &ev, sizeof(ev), NULL);
+	eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
+				  name_len);
+
+	put_unaligned_le16(eir_len, &ev->eir_len);
+
+	return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev,
+			  sizeof(*ev) + eir_len, NULL);
 }
 }
 
 
 int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
 int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
 {
 {
 	struct pending_cmd *cmd;
 	struct pending_cmd *cmd;
+	u8 type;
 	int err;
 	int err;
 
 
+	hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
+
 	cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
 	cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
 	if (!cmd)
 	if (!cmd)
 		return -ENOENT;
 		return -ENOENT;
 
 
-	err = cmd_status(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status));
+	type = hdev->discovery.type;
+
+	err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
+			   &type, sizeof(type));
 	mgmt_pending_remove(cmd);
 	mgmt_pending_remove(cmd);
 
 
 	return err;
 	return err;
@@ -2756,7 +3525,8 @@ int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
 	if (!cmd)
 	if (!cmd)
 		return -ENOENT;
 		return -ENOENT;
 
 
-	err = cmd_status(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status));
+	err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
+			   &hdev->discovery.type, sizeof(hdev->discovery.type));
 	mgmt_pending_remove(cmd);
 	mgmt_pending_remove(cmd);
 
 
 	return err;
 	return err;
@@ -2764,44 +3534,61 @@ 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)
 {
 {
+	struct mgmt_ev_discovering ev;
 	struct pending_cmd *cmd;
 	struct pending_cmd *cmd;
 
 
+	BT_DBG("%s discovering %u", hdev->name, discovering);
+
 	if (discovering)
 	if (discovering)
 		cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
 		cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
 	else
 	else
 		cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
 		cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
 
 
 	if (cmd != NULL) {
 	if (cmd != NULL) {
-		cmd_complete(cmd->sk, hdev->id, cmd->opcode, NULL, 0);
+		u8 type = hdev->discovery.type;
+
+		cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0, &type,
+			     sizeof(type));
 		mgmt_pending_remove(cmd);
 		mgmt_pending_remove(cmd);
 	}
 	}
 
 
-	return mgmt_event(MGMT_EV_DISCOVERING, hdev, &discovering,
-						sizeof(discovering), NULL);
+	memset(&ev, 0, sizeof(ev));
+	ev.type = hdev->discovery.type;
+	ev.discovering = discovering;
+
+	return mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
 }
 }
 
 
-int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr)
+int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
 {
 {
 	struct pending_cmd *cmd;
 	struct pending_cmd *cmd;
 	struct mgmt_ev_device_blocked ev;
 	struct mgmt_ev_device_blocked ev;
 
 
 	cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
 	cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
 
 
-	bacpy(&ev.bdaddr, bdaddr);
+	bacpy(&ev.addr.bdaddr, bdaddr);
+	ev.addr.type = type;
 
 
 	return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
 	return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
-							cmd ? cmd->sk : NULL);
+			  cmd ? cmd->sk : NULL);
 }
 }
 
 
-int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr)
+int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
 {
 {
 	struct pending_cmd *cmd;
 	struct pending_cmd *cmd;
 	struct mgmt_ev_device_unblocked ev;
 	struct mgmt_ev_device_unblocked ev;
 
 
 	cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
 	cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
 
 
-	bacpy(&ev.bdaddr, bdaddr);
+	bacpy(&ev.addr.bdaddr, bdaddr);
+	ev.addr.type = type;
 
 
 	return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
 	return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
-							cmd ? cmd->sk : NULL);
+			  cmd ? cmd->sk : NULL);
 }
 }
+
+module_param(enable_hs, bool, 0644);
+MODULE_PARM_DESC(enable_hs, "Enable High Speed support");
+
+module_param(enable_le, bool, 0644);
+MODULE_PARM_DESC(enable_le, "Enable Low Energy support");

+ 3 - 3
net/bluetooth/rfcomm/tty.c

@@ -196,7 +196,7 @@ static DEVICE_ATTR(channel, S_IRUGO, show_channel, NULL);
 static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc)
 static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc)
 {
 {
 	struct rfcomm_dev *dev, *entry;
 	struct rfcomm_dev *dev, *entry;
-	struct list_head *head = &rfcomm_dev_list, *p;
+	struct list_head *head = &rfcomm_dev_list;
 	int err = 0;
 	int err = 0;
 
 
 	BT_DBG("id %d channel %d", req->dev_id, req->channel);
 	BT_DBG("id %d channel %d", req->dev_id, req->channel);
@@ -215,7 +215,7 @@ static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc)
 				break;
 				break;
 
 
 			dev->id++;
 			dev->id++;
-			head = p;
+			head = &entry->list;
 		}
 		}
 	} else {
 	} else {
 		dev->id = req->dev_id;
 		dev->id = req->dev_id;
@@ -229,7 +229,7 @@ static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc)
 			if (entry->id > dev->id - 1)
 			if (entry->id > dev->id - 1)
 				break;
 				break;
 
 
-			head = p;
+			head = &entry->list;
 		}
 		}
 	}
 	}
 
 

+ 60 - 48
net/bluetooth/smp.c

@@ -29,7 +29,7 @@
 #include <linux/scatterlist.h>
 #include <linux/scatterlist.h>
 #include <crypto/b128ops.h>
 #include <crypto/b128ops.h>
 
 
-#define SMP_TIMEOUT 30000 /* 30 seconds */
+#define SMP_TIMEOUT	msecs_to_jiffies(30000)
 
 
 static inline void swap128(u8 src[16], u8 dst[16])
 static inline void swap128(u8 src[16], u8 dst[16])
 {
 {
@@ -186,8 +186,7 @@ static void smp_send_cmd(struct l2cap_conn *conn, u8 code, u16 len, void *data)
 	hci_send_acl(conn->hchan, skb, 0);
 	hci_send_acl(conn->hchan, skb, 0);
 
 
 	cancel_delayed_work_sync(&conn->security_timer);
 	cancel_delayed_work_sync(&conn->security_timer);
-	schedule_delayed_work(&conn->security_timer,
-					msecs_to_jiffies(SMP_TIMEOUT));
+	schedule_delayed_work(&conn->security_timer, SMP_TIMEOUT);
 }
 }
 
 
 static __u8 authreq_to_seclevel(__u8 authreq)
 static __u8 authreq_to_seclevel(__u8 authreq)
@@ -217,7 +216,7 @@ static void build_pairing_cmd(struct l2cap_conn *conn,
 {
 {
 	u8 dist_keys = 0;
 	u8 dist_keys = 0;
 
 
-	if (test_bit(HCI_PAIRABLE, &conn->hcon->hdev->flags)) {
+	if (test_bit(HCI_PAIRABLE, &conn->hcon->hdev->dev_flags)) {
 		dist_keys = SMP_DIST_ENC_KEY;
 		dist_keys = SMP_DIST_ENC_KEY;
 		authreq |= SMP_AUTH_BONDING;
 		authreq |= SMP_AUTH_BONDING;
 	} else {
 	} else {
@@ -250,21 +249,27 @@ static u8 check_enc_key_size(struct l2cap_conn *conn, __u8 max_key_size)
 			(max_key_size < SMP_MIN_ENC_KEY_SIZE))
 			(max_key_size < SMP_MIN_ENC_KEY_SIZE))
 		return SMP_ENC_KEY_SIZE;
 		return SMP_ENC_KEY_SIZE;
 
 
-	smp->smp_key_size = max_key_size;
+	smp->enc_key_size = max_key_size;
 
 
 	return 0;
 	return 0;
 }
 }
 
 
 static void smp_failure(struct l2cap_conn *conn, u8 reason, u8 send)
 static void smp_failure(struct l2cap_conn *conn, u8 reason, u8 send)
 {
 {
+	struct hci_conn *hcon = conn->hcon;
+
 	if (send)
 	if (send)
 		smp_send_cmd(conn, SMP_CMD_PAIRING_FAIL, sizeof(reason),
 		smp_send_cmd(conn, SMP_CMD_PAIRING_FAIL, sizeof(reason),
 								&reason);
 								&reason);
 
 
-	clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->hcon->pend);
-	mgmt_auth_failed(conn->hcon->hdev, conn->dst, reason);
-	cancel_delayed_work_sync(&conn->security_timer);
-	smp_chan_destroy(conn);
+	clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->hcon->flags);
+	mgmt_auth_failed(conn->hcon->hdev, conn->dst, hcon->type,
+			 hcon->dst_type, reason);
+
+	if (test_and_clear_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags)) {
+		cancel_delayed_work_sync(&conn->security_timer);
+		smp_chan_destroy(conn);
+	}
 }
 }
 
 
 #define JUST_WORKS	0x00
 #define JUST_WORKS	0x00
@@ -305,7 +310,7 @@ static int tk_request(struct l2cap_conn *conn, u8 remote_oob, u8 auth,
 			remote_io > SMP_IO_KEYBOARD_DISPLAY)
 			remote_io > SMP_IO_KEYBOARD_DISPLAY)
 		method = JUST_WORKS;
 		method = JUST_WORKS;
 	else
 	else
-		method = gen_method[local_io][remote_io];
+		method = gen_method[remote_io][local_io];
 
 
 	/* If not bonding, don't ask user to confirm a Zero TK */
 	/* If not bonding, don't ask user to confirm a Zero TK */
 	if (!(auth & SMP_AUTH_BONDING) && method == JUST_CFM)
 	if (!(auth & SMP_AUTH_BONDING) && method == JUST_CFM)
@@ -346,9 +351,11 @@ static int tk_request(struct l2cap_conn *conn, u8 remote_oob, u8 auth,
 	hci_dev_lock(hcon->hdev);
 	hci_dev_lock(hcon->hdev);
 
 
 	if (method == REQ_PASSKEY)
 	if (method == REQ_PASSKEY)
-		ret = mgmt_user_passkey_request(hcon->hdev, conn->dst);
+		ret = mgmt_user_passkey_request(hcon->hdev, conn->dst,
+						hcon->type, hcon->dst_type);
 	else
 	else
 		ret = mgmt_user_confirm_request(hcon->hdev, conn->dst,
 		ret = mgmt_user_confirm_request(hcon->hdev, conn->dst,
+						hcon->type, hcon->dst_type,
 						cpu_to_le32(passkey), 0);
 						cpu_to_le32(passkey), 0);
 
 
 	hci_dev_unlock(hcon->hdev);
 	hci_dev_unlock(hcon->hdev);
@@ -377,12 +384,11 @@ static void confirm_work(struct work_struct *work)
 
 
 	if (conn->hcon->out)
 	if (conn->hcon->out)
 		ret = smp_c1(tfm, smp->tk, smp->prnd, smp->preq, smp->prsp, 0,
 		ret = smp_c1(tfm, smp->tk, smp->prnd, smp->preq, smp->prsp, 0,
-				conn->src, conn->hcon->dst_type, conn->dst,
-				res);
+			     conn->src, conn->hcon->dst_type, conn->dst, res);
 	else
 	else
 		ret = smp_c1(tfm, smp->tk, smp->prnd, smp->preq, smp->prsp,
 		ret = smp_c1(tfm, smp->tk, smp->prnd, smp->preq, smp->prsp,
-				conn->hcon->dst_type, conn->dst, 0, conn->src,
-				res);
+			     conn->hcon->dst_type, conn->dst, 0, conn->src,
+			     res);
 	if (ret) {
 	if (ret) {
 		reason = SMP_UNSPECIFIED;
 		reason = SMP_UNSPECIFIED;
 		goto error;
 		goto error;
@@ -417,12 +423,10 @@ static void random_work(struct work_struct *work)
 
 
 	if (hcon->out)
 	if (hcon->out)
 		ret = smp_c1(tfm, smp->tk, smp->rrnd, smp->preq, smp->prsp, 0,
 		ret = smp_c1(tfm, smp->tk, smp->rrnd, smp->preq, smp->prsp, 0,
-				conn->src, hcon->dst_type, conn->dst,
-				res);
+			     conn->src, hcon->dst_type, conn->dst, res);
 	else
 	else
 		ret = smp_c1(tfm, smp->tk, smp->rrnd, smp->preq, smp->prsp,
 		ret = smp_c1(tfm, smp->tk, smp->rrnd, smp->preq, smp->prsp,
-				hcon->dst_type, conn->dst, 0, conn->src,
-				res);
+			     hcon->dst_type, conn->dst, 0, conn->src, res);
 	if (ret) {
 	if (ret) {
 		reason = SMP_UNSPECIFIED;
 		reason = SMP_UNSPECIFIED;
 		goto error;
 		goto error;
@@ -446,16 +450,16 @@ static void random_work(struct work_struct *work)
 		smp_s1(tfm, smp->tk, smp->rrnd, smp->prnd, key);
 		smp_s1(tfm, smp->tk, smp->rrnd, smp->prnd, key);
 		swap128(key, stk);
 		swap128(key, stk);
 
 
-		memset(stk + smp->smp_key_size, 0,
-				SMP_MAX_ENC_KEY_SIZE - smp->smp_key_size);
+		memset(stk + smp->enc_key_size, 0,
+		       SMP_MAX_ENC_KEY_SIZE - smp->enc_key_size);
 
 
-		if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend)) {
+		if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &hcon->flags)) {
 			reason = SMP_UNSPECIFIED;
 			reason = SMP_UNSPECIFIED;
 			goto error;
 			goto error;
 		}
 		}
 
 
 		hci_le_start_enc(hcon, ediv, rand, stk);
 		hci_le_start_enc(hcon, ediv, rand, stk);
-		hcon->enc_key_size = smp->smp_key_size;
+		hcon->enc_key_size = smp->enc_key_size;
 	} else {
 	} else {
 		u8 stk[16], r[16], rand[8];
 		u8 stk[16], r[16], rand[8];
 		__le16 ediv;
 		__le16 ediv;
@@ -469,11 +473,12 @@ static void random_work(struct work_struct *work)
 		smp_s1(tfm, smp->tk, smp->prnd, smp->rrnd, key);
 		smp_s1(tfm, smp->tk, smp->prnd, smp->rrnd, key);
 		swap128(key, stk);
 		swap128(key, stk);
 
 
-		memset(stk + smp->smp_key_size, 0,
-				SMP_MAX_ENC_KEY_SIZE - smp->smp_key_size);
+		memset(stk + smp->enc_key_size, 0,
+				SMP_MAX_ENC_KEY_SIZE - smp->enc_key_size);
 
 
-		hci_add_ltk(hcon->hdev, 0, conn->dst, smp->smp_key_size,
-							ediv, rand, stk);
+		hci_add_ltk(hcon->hdev, conn->dst, hcon->dst_type,
+			    HCI_SMP_STK_SLAVE, 0, 0, stk, smp->enc_key_size,
+			    ediv, rand);
 	}
 	}
 
 
 	return;
 	return;
@@ -506,7 +511,7 @@ void smp_chan_destroy(struct l2cap_conn *conn)
 {
 {
 	struct smp_chan *smp = conn->smp_chan;
 	struct smp_chan *smp = conn->smp_chan;
 
 
-	clear_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->pend);
+	BUG_ON(!smp);
 
 
 	if (smp->tfm)
 	if (smp->tfm)
 		crypto_free_blkcipher(smp->tfm);
 		crypto_free_blkcipher(smp->tfm);
@@ -571,7 +576,7 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb)
 	if (conn->hcon->link_mode & HCI_LM_MASTER)
 	if (conn->hcon->link_mode & HCI_LM_MASTER)
 		return SMP_CMD_NOTSUPP;
 		return SMP_CMD_NOTSUPP;
 
 
-	if (!test_and_set_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->pend))
+	if (!test_and_set_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags))
 		smp = smp_chan_create(conn);
 		smp = smp_chan_create(conn);
 
 
 	smp = conn->smp_chan;
 	smp = conn->smp_chan;
@@ -584,6 +589,8 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb)
 	if (req->auth_req & SMP_AUTH_BONDING)
 	if (req->auth_req & SMP_AUTH_BONDING)
 		auth = req->auth_req;
 		auth = req->auth_req;
 
 
+	conn->hcon->pending_sec_level = authreq_to_seclevel(auth);
+
 	build_pairing_cmd(conn, req, &rsp, auth);
 	build_pairing_cmd(conn, req, &rsp, auth);
 
 
 	key_size = min(req->max_key_size, rsp.max_key_size);
 	key_size = min(req->max_key_size, rsp.max_key_size);
@@ -698,23 +705,18 @@ static u8 smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb)
 
 
 static u8 smp_ltk_encrypt(struct l2cap_conn *conn)
 static u8 smp_ltk_encrypt(struct l2cap_conn *conn)
 {
 {
-	struct link_key *key;
-	struct key_master_id *master;
+	struct smp_ltk *key;
 	struct hci_conn *hcon = conn->hcon;
 	struct hci_conn *hcon = conn->hcon;
 
 
-	key = hci_find_link_key_type(hcon->hdev, conn->dst,
-						HCI_LK_SMP_LTK);
+	key = hci_find_ltk_by_addr(hcon->hdev, conn->dst, hcon->dst_type);
 	if (!key)
 	if (!key)
 		return 0;
 		return 0;
 
 
-	if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND,
-					&hcon->pend))
+	if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &hcon->flags))
 		return 1;
 		return 1;
 
 
-	master = (void *) key->data;
-	hci_le_start_enc(hcon, master->ediv, master->rand,
-						key->val);
-	hcon->enc_key_size = key->pin_len;
+	hci_le_start_enc(hcon, key->ediv, key->rand, key->val);
+	hcon->enc_key_size = key->enc_size;
 
 
 	return 1;
 	return 1;
 
 
@@ -733,7 +735,7 @@ static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb)
 	if (smp_ltk_encrypt(conn))
 	if (smp_ltk_encrypt(conn))
 		return 0;
 		return 0;
 
 
-	if (test_and_set_bit(HCI_CONN_LE_SMP_PEND, &hcon->pend))
+	if (test_and_set_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags))
 		return 0;
 		return 0;
 
 
 	smp = smp_chan_create(conn);
 	smp = smp_chan_create(conn);
@@ -772,7 +774,7 @@ int smp_conn_security(struct l2cap_conn *conn, __u8 sec_level)
 		if (smp_ltk_encrypt(conn))
 		if (smp_ltk_encrypt(conn))
 			goto done;
 			goto done;
 
 
-	if (test_and_set_bit(HCI_CONN_LE_SMP_PEND, &hcon->pend))
+	if (test_and_set_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags))
 		return 0;
 		return 0;
 
 
 	smp = smp_chan_create(conn);
 	smp = smp_chan_create(conn);
@@ -817,13 +819,19 @@ static int smp_cmd_master_ident(struct l2cap_conn *conn, struct sk_buff *skb)
 {
 {
 	struct smp_cmd_master_ident *rp = (void *) skb->data;
 	struct smp_cmd_master_ident *rp = (void *) skb->data;
 	struct smp_chan *smp = conn->smp_chan;
 	struct smp_chan *smp = conn->smp_chan;
+	struct hci_dev *hdev = conn->hcon->hdev;
+	struct hci_conn *hcon = conn->hcon;
+	u8 authenticated;
 
 
 	skb_pull(skb, sizeof(*rp));
 	skb_pull(skb, sizeof(*rp));
 
 
-	hci_add_ltk(conn->hcon->hdev, 1, conn->dst, smp->smp_key_size,
-						rp->ediv, rp->rand, smp->tk);
-
+	hci_dev_lock(hdev);
+	authenticated = (conn->hcon->sec_level == BT_SECURITY_HIGH);
+	hci_add_ltk(conn->hcon->hdev, conn->dst, hcon->dst_type,
+		    HCI_SMP_LTK, 1, authenticated, smp->tk, smp->enc_key_size,
+		    rp->ediv, rp->rand);
 	smp_distribute_keys(conn, 1);
 	smp_distribute_keys(conn, 1);
+	hci_dev_unlock(hdev);
 
 
 	return 0;
 	return 0;
 }
 }
@@ -908,7 +916,7 @@ int smp_distribute_keys(struct l2cap_conn *conn, __u8 force)
 
 
 	BT_DBG("conn %p force %d", conn, force);
 	BT_DBG("conn %p force %d", conn, force);
 
 
-	if (!test_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->pend))
+	if (!test_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags))
 		return 0;
 		return 0;
 
 
 	rsp = (void *) &smp->prsp[1];
 	rsp = (void *) &smp->prsp[1];
@@ -933,6 +941,8 @@ int smp_distribute_keys(struct l2cap_conn *conn, __u8 force)
 	if (*keydist & SMP_DIST_ENC_KEY) {
 	if (*keydist & SMP_DIST_ENC_KEY) {
 		struct smp_cmd_encrypt_info enc;
 		struct smp_cmd_encrypt_info enc;
 		struct smp_cmd_master_ident ident;
 		struct smp_cmd_master_ident ident;
+		struct hci_conn *hcon = conn->hcon;
+		u8 authenticated;
 		__le16 ediv;
 		__le16 ediv;
 
 
 		get_random_bytes(enc.ltk, sizeof(enc.ltk));
 		get_random_bytes(enc.ltk, sizeof(enc.ltk));
@@ -941,8 +951,10 @@ int smp_distribute_keys(struct l2cap_conn *conn, __u8 force)
 
 
 		smp_send_cmd(conn, SMP_CMD_ENCRYPT_INFO, sizeof(enc), &enc);
 		smp_send_cmd(conn, SMP_CMD_ENCRYPT_INFO, sizeof(enc), &enc);
 
 
-		hci_add_ltk(conn->hcon->hdev, 1, conn->dst, smp->smp_key_size,
-						ediv, ident.rand, enc.ltk);
+		authenticated = hcon->sec_level == BT_SECURITY_HIGH;
+		hci_add_ltk(conn->hcon->hdev, conn->dst, hcon->dst_type,
+			    HCI_SMP_LTK_SLAVE, 1, authenticated,
+			    enc.ltk, smp->enc_key_size, ediv, ident.rand);
 
 
 		ident.ediv = cpu_to_le16(ediv);
 		ident.ediv = cpu_to_le16(ediv);
 
 
@@ -982,7 +994,7 @@ int smp_distribute_keys(struct l2cap_conn *conn, __u8 force)
 	}
 	}
 
 
 	if (conn->hcon->out || force) {
 	if (conn->hcon->out || force) {
-		clear_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->pend);
+		clear_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags);
 		cancel_delayed_work_sync(&conn->security_timer);
 		cancel_delayed_work_sync(&conn->security_timer);
 		smp_chan_destroy(conn);
 		smp_chan_destroy(conn);
 	}
 	}