Merge tag 'master-2014-12-08' of git://git.kernel.org/pub/scm/linux/kernel/git/linvil...
authorDavid S. Miller <davem@davemloft.net>
Tue, 9 Dec 2014 23:12:03 +0000 (18:12 -0500)
committerDavid S. Miller <davem@davemloft.net>
Tue, 9 Dec 2014 23:12:03 +0000 (18:12 -0500)
John W. Linville says:

====================
pull request: wireless-next 2014-12-08

Please pull this last batch of pending wireless updates for the 3.19 tree...

For the wireless bits, Johannes says:

"This time I have Felix's no-status rate control work, which will allow
drivers to work better with rate control even if they don't have perfect
status reporting. In addition to this, a small hwsim fix from Patrik,
one of the regulatory patches from Arik, and a number of cleanups and
fixes I did myself.

Of note is a patch where I disable CFG80211_WEXT so that compatibility
is no longer selectable - this is intended as a wake-up call for anyone
who's still using it, and is still easily worked around (it's a one-line
patch) before we fully remove the code as well in the future."

For the Bluetooth bits, Johan says:

"Here's one more bluetooth-next pull request for 3.19:

 - Minor cleanups for ieee802154 & mac802154
 - Fix for the kernel warning with !TASK_RUNNING reported by Kirill A.
   Shutemov
 - Support for another ath3k device
 - Fix for tracking link key based security level
 - Device tree bindings for btmrvl + a state update fix
 - Fix for wrong ACL flags on LE links"

And...

"In addition to the previous one this contains two more cleanups to
mac802154 as well as support for some new HCI features from the
Bluetooth 4.2 specification.

From the original request:

'Here's what should be the last bluetooth-next pull request for 3.19.
It's rather large but the majority of it is the Low Energy Secure
Connections feature that's part of the Bluetooth 4.2 specification. The
specification went public only this week so we couldn't publish the
corresponding code before that. The code itself can nevertheless be
considered fairly mature as it's been in development for over 6 months
and gone through several interoperability test events.

Besides LE SC the pull request contains an important fix for command
complete events for mgmt sockets which also fixes some leaks of hci_conn
objects when powering off or unplugging Bluetooth adapters.

A smaller feature that's part of the pull request is service discovery
support. This is like normal device discovery except that devices not
matching specific UUIDs or strong enough RSSI are filtered out.

Other changes that the pull request contains are firmware dump support
to the btmrvl driver, firmware download support for Broadcom BCM20702A0
variants, as well as some coding style cleanups in 6lowpan &
ieee802154/mac802154 code.'"

For the NFC bits, Samuel says:

"With this one we get:

- NFC digital improvements for DEP support: Chaining, NACK and ATN
  support added.

- NCI improvements: Support for p2p target, SE IO operand addition,
  SE operands extensions to support proprietary implementations, and
  a few fixes.

- NFC HCI improvements: OPEN_PIPE and NOTIFY_ALL_CLEARED support,
  and SE IO operand addition.

- A bunch of minor improvements and fixes for STMicro st21nfcb and
  st21nfca"

For the iwlwifi bits, Emmanuel says:

"Major works are CSA and TDLS. On top of that I have a new
firmware API for scan and a few rate control improvements.
Johannes find a few tricks to improve our CPU utilization
and adds support for a new spin of 7265 called 7265D.
Along with this a few random things that don't stand out."

And...

"I deprecate here -8.ucode since -9 has been published long ago.
Along with that I have a new activity, we have now better
a infrastructure for firmware debugging. This will allow to
have configurable probes insides the firmware.
Luca continues his work on NetDetect, this feature is now
complete. All the rest is minor fixes here and there."

For the Atheros bits, Kalle says:

"Only ath10k changes this time and no major changes. Most visible are:

o new debugfs interface for runtime firmware debugging (Yanbo)

o fix shared WEP (Sujith)

o don't rebuild whenever kernel version changes (Johannes)

o lots of refactoring to make it easier to add new hw support (Michal)

There's also smaller fixes and improvements with no point of listing
here."

In addition, there are a few last minute updates to ath5k,
ath9k, brcmfmac, brcmsmac, mwifiex, rt2x00, rtlwifi, and wil6210.
Also included is a pull of the wireless tree to pick-up the fixes
originally included in "pull request: wireless 2014-12-03"...

Please let me know if there are problems!
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
1  2 
MAINTAINERS
net/bluetooth/af_bluetooth.c
net/bluetooth/mgmt.c
net/ieee802154/dgram.c
net/ieee802154/raw.c
net/nfc/llcp_commands.c
net/nfc/llcp_sock.c

diff --combined MAINTAINERS
@@@ -1088,33 -1088,33 +1088,33 @@@ L:   linux-arm-kernel@lists.infradead.or
  S:    Maintained
  
  ARM/TEXAS INSTRUMENT KEYSTONE ARCHITECTURE
 -M:    Santosh Shilimkar <santosh.shilimkar@ti.com>
 +M:    Santosh Shilimkar <ssantosh@kernel.org>
  L:    linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
  S:    Maintained
  F:    arch/arm/mach-keystone/
  T:    git git://git.kernel.org/pub/scm/linux/kernel/git/ssantosh/linux-keystone.git
  
  ARM/TEXAS INSTRUMENT KEYSTONE CLOCK FRAMEWORK
 -M:    Santosh Shilimkar <santosh.shilimkar@ti.com>
 +M:    Santosh Shilimkar <ssantosh@kernel.org>
  L:    linux-kernel@vger.kernel.org
  S:    Maintained
  F:    drivers/clk/keystone/
  
  ARM/TEXAS INSTRUMENT KEYSTONE ClOCKSOURCE
 -M:    Santosh Shilimkar <santosh.shilimkar@ti.com>
 +M:    Santosh Shilimkar <ssantosh@kernel.org>
  L:    linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
  L:    linux-kernel@vger.kernel.org
  S:    Maintained
  F:    drivers/clocksource/timer-keystone.c
  
  ARM/TEXAS INSTRUMENT KEYSTONE RESET DRIVER
 -M:    Santosh Shilimkar <santosh.shilimkar@ti.com>
 +M:    Santosh Shilimkar <ssantosh@kernel.org>
  L:    linux-kernel@vger.kernel.org
  S:    Maintained
  F:    drivers/power/reset/keystone-reset.c
  
  ARM/TEXAS INSTRUMENT AEMIF/EMIF DRIVERS
 -M:    Santosh Shilimkar <santosh.shilimkar@ti.com>
 +M:    Santosh Shilimkar <ssantosh@kernel.org>
  L:    linux-kernel@vger.kernel.org
  S:    Maintained
  F:    drivers/memory/*emif*
@@@ -1543,7 -1543,6 +1543,7 @@@ F:      arch/arm/mach-pxa/include/mach/z2.
  
  ARM/ZYNQ ARCHITECTURE
  M:    Michal Simek <michal.simek@xilinx.com>
 +R:    Sören Brinkmann <soren.brinkmann@xilinx.com>
  L:    linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
  W:    http://wiki.xilinx.com
  T:    git git://git.xilinx.com/linux-xlnx.git
@@@ -1750,13 -1749,6 +1750,13 @@@ M:    Nicolas Ferre <nicolas.ferre@atmel.c
  S:    Supported
  F:    drivers/spi/spi-atmel.*
  
 +ATMEL SSC DRIVER
 +M:    Bo Shen <voice.shen@atmel.com>
 +L:    linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 +S:    Supported
 +F:    drivers/misc/atmel-ssc.c
 +F:    include/linux/atmel-ssc.h
 +
  ATMEL Timer Counter (TC) AND CLOCKSOURCE DRIVERS
  M:    Nicolas Ferre <nicolas.ferre@atmel.com>
  L:    linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
@@@ -2070,15 -2062,17 +2070,15 @@@ F:   arch/arm/configs/bcm_defconfi
  F:    drivers/mmc/host/sdhci-bcm-kona.c
  F:    drivers/clocksource/bcm_kona_timer.c
  
 -BROADCOM BCM2835 ARM ARCHICTURE
 +BROADCOM BCM2835 ARM ARCHITECTURE
  M:    Stephen Warren <swarren@wwwdotorg.org>
 +M:    Lee Jones <lee@kernel.org>
  L:    linux-rpi-kernel@lists.infradead.org (moderated for non-subscribers)
 -T:    git git://git.kernel.org/pub/scm/linux/kernel/git/swarren/linux-rpi.git
 +T:    git git://git.kernel.org/pub/scm/linux/kernel/git/rpi/linux-rpi.git
  S:    Maintained
 -F:    arch/arm/mach-bcm/board_bcm2835.c
 -F:    arch/arm/boot/dts/bcm2835*
 -F:    arch/arm/configs/bcm2835_defconfig
 -F:    drivers/*/*bcm2835*
 +N:    bcm2835
  
 -BROADCOM BCM5301X ARM ARCHICTURE
 +BROADCOM BCM5301X ARM ARCHITECTURE
  M:    Hauke Mehrtens <hauke@hauke-m.de>
  L:    linux-arm-kernel@lists.infradead.org
  S:    Maintained
@@@ -2752,13 -2746,6 +2752,13 @@@ W:    http://www.chelsio.co
  S:    Supported
  F:    drivers/net/ethernet/chelsio/cxgb3/
  
 +CXGB3 ISCSI DRIVER (CXGB3I)
 +M:      Karen Xie <kxie@chelsio.com>
 +L:      linux-scsi@vger.kernel.org
 +W:      http://www.chelsio.com
 +S:      Supported
 +F:      drivers/scsi/cxgbi/cxgb3i
 +
  CXGB3 IWARP RNIC DRIVER (IW_CXGB3)
  M:    Steve Wise <swise@chelsio.com>
  L:    linux-rdma@vger.kernel.org
@@@ -2773,13 -2760,6 +2773,13 @@@ W:    http://www.chelsio.co
  S:    Supported
  F:    drivers/net/ethernet/chelsio/cxgb4/
  
 +CXGB4 ISCSI DRIVER (CXGB4I)
 +M:      Karen Xie <kxie@chelsio.com>
 +L:      linux-scsi@vger.kernel.org
 +W:      http://www.chelsio.com
 +S:      Supported
 +F:      drivers/scsi/cxgbi/cxgb4i
 +
  CXGB4 IWARP RNIC DRIVER (IW_CXGB4)
  M:    Steve Wise <swise@chelsio.com>
  L:    linux-rdma@vger.kernel.org
@@@ -4336,10 -4316,8 +4336,10 @@@ F:    Documentation/blockdev/cpqarray.tx
  F:    drivers/block/cpqarray.*
  
  HEWLETT-PACKARD SMART ARRAY RAID DRIVER (hpsa)
 -M:    "Stephen M. Cameron" <scameron@beardog.cce.hp.com>
 +M:    Don Brace <don.brace@pmcs.com>
  L:    iss_storagedev@hp.com
 +L:    storagedev@pmcs.com
 +L:    linux-scsi@vger.kernel.org
  S:    Supported
  F:    Documentation/scsi/hpsa.txt
  F:    drivers/scsi/hpsa*.[ch]
@@@ -4347,10 -4325,8 +4347,10 @@@ F:    include/linux/cciss*.
  F:    include/uapi/linux/cciss*.h
  
  HEWLETT-PACKARD SMART CISS RAID DRIVER (cciss)
 -M:    Mike Miller <mike.miller@hp.com>
 +M:    Don Brace <don.brace@pmcs.com>
  L:    iss_storagedev@hp.com
 +L:    storagedev@pmcs.com
 +L:    linux-scsi@vger.kernel.org
  S:    Supported
  F:    Documentation/blockdev/cciss.txt
  F:    drivers/block/cciss*
@@@ -4636,7 -4612,7 +4636,7 @@@ S:      Supporte
  F:    drivers/crypto/nx/
  
  IBM Power 842 compression accelerator
 -M:    Nathan Fontenot <nfont@linux.vnet.ibm.com>
 +M:    Dan Streetman <ddstreet@us.ibm.com>
  S:    Supported
  F:    drivers/crypto/nx/nx-842.c
  F:    include/linux/nx842.h
@@@ -4745,7 -4721,6 +4745,7 @@@ L:      linux-iio@vger.kernel.or
  S:    Maintained
  F:    drivers/iio/
  F:    drivers/staging/iio/
 +F:    include/linux/iio/
  
  IKANOS/ADI EAGLE ADSL USB DRIVER
  M:    Matthieu Castet <castet.matthieu@free.fr>
@@@ -5877,14 -5852,6 +5877,14 @@@ S:    Maintaine
  F:    drivers/net/macvlan.c
  F:    include/linux/if_macvlan.h
  
 +MAILBOX API
 +M:    Jassi Brar <jassisinghbrar@gmail.com>
 +L:    linux-kernel@vger.kernel.org
 +S:    Maintained
 +F:    drivers/mailbox/
 +F:    include/linux/mailbox_client.h
 +F:    include/linux/mailbox_controller.h
 +
  MAN-PAGES: MANUAL PAGES FOR LINUX -- Sections 2, 3, 4, 5, and 7
  M:    Michael Kerrisk <mtk.manpages@gmail.com>
  W:    http://www.kernel.org/doc/man-pages
@@@ -5896,11 -5863,6 +5896,11 @@@ M:    Russell King <rmk+kernel@arm.linux.o
  S:    Maintained
  F:    drivers/gpu/drm/armada/
  
 +MARVELL 88E6352 DSA support
 +M:    Guenter Roeck <linux@roeck-us.net>
 +S:    Maintained
 +F:    drivers/net/dsa/mv88e6352.c
 +
  MARVELL GIGABIT ETHERNET DRIVERS (skge/sky2)
  M:    Mirko Lindner <mlindner@marvell.com>
  M:    Stephen Hemminger <stephen@networkplumber.org>
@@@ -6631,23 -6593,6 +6631,23 @@@ T:    git git://git.kernel.org/pub/scm/lin
  S:    Maintained
  F:    arch/arm/*omap*/
  F:    drivers/i2c/busses/i2c-omap.c
 +F:    drivers/irqchip/irq-omap-intc.c
 +F:    drivers/mfd/*omap*.c
 +F:    drivers/mfd/menelaus.c
 +F:    drivers/mfd/palmas.c
 +F:    drivers/mfd/tps65217.c
 +F:    drivers/mfd/tps65218.c
 +F:    drivers/mfd/tps65910.c
 +F:    drivers/mfd/twl-core.[ch]
 +F:    drivers/mfd/twl4030*.c
 +F:    drivers/mfd/twl6030*.c
 +F:    drivers/mfd/twl6040*.c
 +F:    drivers/regulator/palmas-regulator*.c
 +F:    drivers/regulator/pbias-regulator.c
 +F:    drivers/regulator/tps65217-regulator.c
 +F:    drivers/regulator/tps65218-regulator.c
 +F:    drivers/regulator/tps65910-regulator.c
 +F:    drivers/regulator/twl-regulator.c
  F:    include/linux/i2c-omap.h
  
  OMAP DEVICE TREE SUPPORT
@@@ -6658,9 -6603,6 +6658,9 @@@ L:      devicetree@vger.kernel.or
  S:    Maintained
  F:    arch/arm/boot/dts/*omap*
  F:    arch/arm/boot/dts/*am3*
 +F:    arch/arm/boot/dts/*am4*
 +F:    arch/arm/boot/dts/*am5*
 +F:    arch/arm/boot/dts/*dra7*
  
  OMAP CLOCK FRAMEWORK SUPPORT
  M:    Paul Walmsley <paul@pwsan.com>
@@@ -6760,7 -6702,7 +6760,7 @@@ F:      arch/arm/*omap*/usb
  
  OMAP GPIO DRIVER
  M:    Javier Martinez Canillas <javier@dowhile0.org>
 -M:    Santosh Shilimkar <santosh.shilimkar@ti.com>
 +M:    Santosh Shilimkar <ssantosh@kernel.org>
  M:    Kevin Hilman <khilman@deeprootsystems.com>
  L:    linux-omap@vger.kernel.org
  S:    Maintained
@@@ -6898,7 -6840,7 +6898,7 @@@ S:      Orpha
  F:    drivers/net/wireless/orinoco/
  
  OSD LIBRARY and FILESYSTEM
 -M:    Boaz Harrosh <bharrosh@panasas.com>
 +M:    Boaz Harrosh <ooo@electrozaur.com>
  M:    Benny Halevy <bhalevy@primarydata.com>
  L:    osd-dev@open-osd.org
  W:    http://open-osd.org
@@@ -6908,14 -6850,6 +6908,14 @@@ F:    drivers/scsi/osd
  F:    include/scsi/osd_*
  F:    fs/exofs/
  
 +OVERLAY FILESYSTEM
 +M:    Miklos Szeredi <miklos@szeredi.hu>
 +L:    linux-unionfs@vger.kernel.org
 +T:    git git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/vfs.git
 +S:    Supported
 +F:    fs/overlayfs/
 +F:    Documentation/filesystems/overlayfs.txt
 +
  P54 WIRELESS DRIVER
  M:    Christian Lamparter <chunkeey@googlemail.com>
  L:    linux-wireless@vger.kernel.org
@@@ -7237,7 -7171,6 +7237,7 @@@ F:      drivers/crypto/picoxcell
  
  PIN CONTROL SUBSYSTEM
  M:    Linus Walleij <linus.walleij@linaro.org>
 +L:    linux-gpio@vger.kernel.org
  S:    Maintained
  F:    drivers/pinctrl/
  F:    include/linux/pinctrl/
@@@ -7865,13 -7798,6 +7865,13 @@@ F:    drivers/hid/hid-roccat
  F:    include/linux/hid-roccat*
  F:    Documentation/ABI/*/sysfs-driver-hid-roccat*
  
 +ROCKER DRIVER
 +M:    Jiri Pirko <jiri@resnulli.us>
 +M:    Scott Feldman <sfeldma@gmail.com>
 +L:    netdev@vger.kernel.org
 +S:    Supported
 +F:    drivers/net/ethernet/rocker/
 +
  ROCKETPORT DRIVER
  P:    Comtrol Corp.
  W:    http://www.comtrol.com
@@@ -7919,11 -7845,10 +7919,10 @@@ S:   Maintaine
  F:    drivers/media/dvb-frontends/rtl2832_sdr*
  
  RTL8180 WIRELESS DRIVER
- M:    "John W. Linville" <linville@tuxdriver.com>
  L:    linux-wireless@vger.kernel.org
  W:    http://wireless.kernel.org/
  T:    git git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-testing.git
- S:    Maintained
+ S:    Orphan
  F:    drivers/net/wireless/rtl818x/rtl8180/
  
  RTL8187 WIRELESS DRIVER
@@@ -8549,6 -8474,7 +8548,6 @@@ F:      arch/arm/mach-s3c24xx/bast-irq.
  TI DAVINCI MACHINE SUPPORT
  M:    Sekhar Nori <nsekhar@ti.com>
  M:    Kevin Hilman <khilman@deeprootsystems.com>
 -L:    davinci-linux-open-source@linux.davincidsp.com (moderated for non-subscribers)
  T:    git git://gitorious.org/linux-davinci/linux-davinci.git
  Q:    http://patchwork.kernel.org/project/linux-davinci/list/
  S:    Supported
@@@ -8558,6 -8484,7 +8557,6 @@@ F:      drivers/i2c/busses/i2c-davinci.
  TI DAVINCI SERIES MEDIA DRIVER
  M:    Lad, Prabhakar <prabhakar.csengg@gmail.com>
  L:    linux-media@vger.kernel.org
 -L:    davinci-linux-open-source@linux.davincidsp.com (moderated for non-subscribers)
  W:    http://linuxtv.org/
  Q:    http://patchwork.linuxtv.org/project/linux-media/list/
  T:    git git://linuxtv.org/mhadli/v4l-dvb-davinci_devices.git
@@@ -9066,13 -8993,6 +9065,13 @@@ F:    lib/swiotlb.
  F:    arch/*/kernel/pci-swiotlb.c
  F:    include/linux/swiotlb.h
  
 +SWITCHDEV
 +M:    Jiri Pirko <jiri@resnulli.us>
 +L:    netdev@vger.kernel.org
 +S:    Supported
 +F:    net/switchdev/
 +F:    include/net/switchdev.h
 +
  SYNOPSYS ARC ARCHITECTURE
  M:    Vineet Gupta <vgupta@synopsys.com>
  S:    Supported
@@@ -9368,7 -9288,7 +9367,7 @@@ F:      drivers/mmc/host/tifm_sd.
  F:    include/linux/tifm.h
  
  TI KEYSTONE MULTICORE NAVIGATOR DRIVERS
 -M:    Santosh Shilimkar <santosh.shilimkar@ti.com>
 +M:    Santosh Shilimkar <ssantosh@kernel.org>
  L:    linux-kernel@vger.kernel.org
  L:    linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
  S:    Maintained
@@@ -9681,6 -9601,7 +9680,6 @@@ F:     drivers/staging/unisys
  
  UNIVERSAL FLASH STORAGE HOST CONTROLLER DRIVER
  M:    Vinayak Holikatti <vinholikatti@gmail.com>
 -M:    Santosh Y <santoshsy@gmail.com>
  L:    linux-scsi@vger.kernel.org
  S:    Supported
  F:    Documentation/scsi/ufs.txt
@@@ -9774,6 -9695,11 +9773,6 @@@ S:     Maintaine
  F:    Documentation/hid/hiddev.txt
  F:    drivers/hid/usbhid/
  
 -USB/IP DRIVERS
 -L:    linux-usb@vger.kernel.org
 -S:    Orphan
 -F:    drivers/staging/usbip/
 -
  USB ISP116X DRIVER
  M:    Olav Kongas <ok@artecdesign.ee>
  L:    linux-usb@vger.kernel.org
@@@ -31,7 -31,7 +31,7 @@@
  #include <net/bluetooth/bluetooth.h>
  #include <linux/proc_fs.h>
  
- #define VERSION "2.19"
+ #define VERSION "2.20"
  
  /* Bluetooth sockets */
  #define BT_MAX_PROTO  8
@@@ -237,7 -237,7 +237,7 @@@ int bt_sock_recvmsg(struct kiocb *iocb
        }
  
        skb_reset_transport_header(skb);
 -      err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
 +      err = skb_copy_datagram_msg(skb, 0, msg, copied);
        if (err == 0) {
                sock_recv_ts_and_drops(msg, sk, skb);
  
@@@ -328,7 -328,7 +328,7 @@@ int bt_sock_stream_recvmsg(struct kioc
                }
  
                chunk = min_t(unsigned int, skb->len, size);
 -              if (skb_copy_datagram_iovec(skb, 0, msg->msg_iov, chunk)) {
 +              if (skb_copy_datagram_msg(skb, 0, msg, chunk)) {
                        skb_queue_head(&sk->sk_receive_queue, skb);
                        if (!copied)
                                copied = -EFAULT;
diff --combined net/bluetooth/mgmt.c
@@@ -35,7 -35,7 +35,7 @@@
  #include "smp.h"
  
  #define MGMT_VERSION  1
- #define MGMT_REVISION 7
+ #define MGMT_REVISION 8
  
  static const u16 mgmt_commands[] = {
        MGMT_OP_READ_INDEX_LIST,
@@@ -93,6 -93,7 +93,7 @@@
        MGMT_OP_READ_CONFIG_INFO,
        MGMT_OP_SET_EXTERNAL_CONFIG,
        MGMT_OP_SET_PUBLIC_ADDRESS,
+       MGMT_OP_START_SERVICE_DISCOVERY,
  };
  
  static const u16 mgmt_events[] = {
@@@ -134,8 -135,10 +135,10 @@@ struct pending_cmd 
        u16 opcode;
        int index;
        void *param;
+       size_t param_len;
        struct sock *sk;
        void *user_data;
+       void (*cmd_complete)(struct pending_cmd *cmd, u8 status);
  };
  
  /* HCI to MGMT error code conversion table */
@@@ -574,6 -577,7 +577,7 @@@ static u32 get_supported_settings(struc
        if (lmp_le_capable(hdev)) {
                settings |= MGMT_SETTING_LE;
                settings |= MGMT_SETTING_ADVERTISING;
+               settings |= MGMT_SETTING_SECURE_CONN;
                settings |= MGMT_SETTING_PRIVACY;
        }
  
@@@ -1202,14 -1206,13 +1206,13 @@@ static struct pending_cmd *mgmt_pending
        cmd->opcode = opcode;
        cmd->index = hdev->id;
  
-       cmd->param = kmalloc(len, GFP_KERNEL);
+       cmd->param = kmemdup(data, len, GFP_KERNEL);
        if (!cmd->param) {
                kfree(cmd);
                return NULL;
        }
  
-       if (data)
-               memcpy(cmd->param, data, len);
+       cmd->param_len = len;
  
        cmd->sk = sk;
        sock_hold(sk);
@@@ -1469,6 -1472,32 +1472,32 @@@ static void cmd_status_rsp(struct pendi
        mgmt_pending_remove(cmd);
  }
  
+ static void cmd_complete_rsp(struct pending_cmd *cmd, void *data)
+ {
+       if (cmd->cmd_complete) {
+               u8 *status = data;
+               cmd->cmd_complete(cmd, *status);
+               mgmt_pending_remove(cmd);
+               return;
+       }
+       cmd_status_rsp(cmd, data);
+ }
+ static void generic_cmd_complete(struct pending_cmd *cmd, u8 status)
+ {
+       cmd_complete(cmd->sk, cmd->index, cmd->opcode, status, cmd->param,
+                    cmd->param_len);
+ }
+ static void addr_cmd_complete(struct pending_cmd *cmd, u8 status)
+ {
+       cmd_complete(cmd->sk, cmd->index, cmd->opcode, status, cmd->param,
+                    sizeof(struct mgmt_addr_info));
+ }
  static u8 mgmt_bredr_support(struct hci_dev *hdev)
  {
        if (!lmp_bredr_capable(hdev))
@@@ -2792,6 -2821,8 +2821,8 @@@ static int unpair_device(struct sock *s
                goto unlock;
        }
  
+       cmd->cmd_complete = addr_cmd_complete;
        dc.handle = cpu_to_le16(conn->handle);
        dc.reason = 0x13; /* Remote User Terminated Connection */
        err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
@@@ -2855,6 -2886,8 +2886,8 @@@ static int disconnect(struct sock *sk, 
                goto failed;
        }
  
+       cmd->cmd_complete = generic_cmd_complete;
        err = hci_disconnect(conn, HCI_ERROR_REMOTE_USER_TERM);
        if (err < 0)
                mgmt_pending_remove(cmd);
@@@ -3007,6 -3040,8 +3040,8 @@@ static int pin_code_reply(struct sock *
                goto failed;
        }
  
+       cmd->cmd_complete = addr_cmd_complete;
        bacpy(&reply.bdaddr, &cp->addr.bdaddr);
        reply.pin_len = cp->pin_len;
        memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
@@@ -3096,7 -3131,7 +3131,7 @@@ void mgmt_smp_complete(struct hci_conn 
  
        cmd = find_pairing(conn);
        if (cmd)
-               pairing_complete(cmd, status);
+               cmd->cmd_complete(cmd, status);
  }
  
  static void pairing_complete_cb(struct hci_conn *conn, u8 status)
        if (!cmd)
                BT_DBG("Unable to find a pending command");
        else
-               pairing_complete(cmd, mgmt_status(status));
+               cmd->cmd_complete(cmd, mgmt_status(status));
  }
  
  static void le_pairing_complete_cb(struct hci_conn *conn, u8 status)
        if (!cmd)
                BT_DBG("Unable to find a pending command");
        else
-               pairing_complete(cmd, mgmt_status(status));
+               cmd->cmd_complete(cmd, mgmt_status(status));
  }
  
  static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
                goto unlock;
        }
  
+       cmd->cmd_complete = pairing_complete;
        /* For LE, just connecting isn't a proof that the pairing finished */
        if (cp->addr.type == BDADDR_BREDR) {
                conn->connect_cfm_cb = pairing_complete_cb;
@@@ -3338,6 -3375,8 +3375,8 @@@ static int user_pairing_resp(struct soc
                goto done;
        }
  
+       cmd->cmd_complete = addr_cmd_complete;
        /* Continue with pairing via HCI */
        if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
                struct hci_cp_user_passkey_reply cp;
@@@ -3562,7 -3601,7 +3601,7 @@@ static int read_local_oob_data(struct s
                goto unlock;
        }
  
-       if (test_bit(HCI_SC_ENABLED, &hdev->dev_flags))
+       if (bredr_sc_enabled(hdev))
                err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_EXT_DATA,
                                   0, NULL);
        else
@@@ -3598,7 -3637,8 +3637,8 @@@ static int add_remote_oob_data(struct s
                }
  
                err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr,
-                                             cp->hash, cp->rand);
+                                             cp->addr.type, cp->hash,
+                                             cp->rand, NULL, NULL);
                if (err < 0)
                        status = MGMT_STATUS_FAILED;
                else
                                   status, &cp->addr, sizeof(cp->addr));
        } else if (len == MGMT_ADD_REMOTE_OOB_EXT_DATA_SIZE) {
                struct mgmt_cp_add_remote_oob_ext_data *cp = data;
+               u8 *rand192, *hash192;
                u8 status;
  
                if (cp->addr.type != BDADDR_BREDR) {
                        goto unlock;
                }
  
-               err = hci_add_remote_oob_ext_data(hdev, &cp->addr.bdaddr,
-                                                 cp->hash192, cp->rand192,
-                                                 cp->hash256, cp->rand256);
+               if (bdaddr_type_is_le(cp->addr.type)) {
+                       rand192 = NULL;
+                       hash192 = NULL;
+               } else {
+                       rand192 = cp->rand192;
+                       hash192 = cp->hash192;
+               }
+               err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr,
+                                             cp->addr.type, hash192, rand192,
+                                             cp->hash256, cp->rand256);
                if (err < 0)
                        status = MGMT_STATUS_FAILED;
                else
@@@ -3661,7 -3710,7 +3710,7 @@@ static int remove_remote_oob_data(struc
                goto done;
        }
  
-       err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
+       err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr, cp->addr.type);
        if (err < 0)
                status = MGMT_STATUS_INVALID_PARAMS;
        else
        return err;
  }
  
- static int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
+ static bool trigger_discovery(struct hci_request *req, u8 *status)
  {
-       struct pending_cmd *cmd;
-       u8 type;
+       struct hci_dev *hdev = req->hdev;
+       struct hci_cp_le_set_scan_param param_cp;
+       struct hci_cp_le_set_scan_enable enable_cp;
+       struct hci_cp_inquiry inq_cp;
+       /* General inquiry access code (GIAC) */
+       u8 lap[3] = { 0x33, 0x8b, 0x9e };
+       u8 own_addr_type;
        int err;
  
-       hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
+       switch (hdev->discovery.type) {
+       case DISCOV_TYPE_BREDR:
+               *status = mgmt_bredr_support(hdev);
+               if (*status)
+                       return false;
  
-       cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
-       if (!cmd)
-               return -ENOENT;
+               if (test_bit(HCI_INQUIRY, &hdev->flags)) {
+                       *status = MGMT_STATUS_BUSY;
+                       return false;
+               }
  
-       type = hdev->discovery.type;
+               hci_inquiry_cache_flush(hdev);
  
-       err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
-                          &type, sizeof(type));
-       mgmt_pending_remove(cmd);
+               memset(&inq_cp, 0, sizeof(inq_cp));
+               memcpy(&inq_cp.lap, lap, sizeof(inq_cp.lap));
+               inq_cp.length = DISCOV_BREDR_INQUIRY_LEN;
+               hci_req_add(req, HCI_OP_INQUIRY, sizeof(inq_cp), &inq_cp);
+               break;
  
-       return err;
+       case DISCOV_TYPE_LE:
+       case DISCOV_TYPE_INTERLEAVED:
+               *status = mgmt_le_support(hdev);
+               if (*status)
+                       return false;
+               if (hdev->discovery.type == DISCOV_TYPE_INTERLEAVED &&
+                   !test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
+                       *status = MGMT_STATUS_NOT_SUPPORTED;
+                       return false;
+               }
+               if (test_bit(HCI_LE_ADV, &hdev->dev_flags)) {
+                       /* Don't let discovery abort an outgoing
+                        * connection attempt that's using directed
+                        * advertising.
+                        */
+                       if (hci_conn_hash_lookup_state(hdev, LE_LINK,
+                                                      BT_CONNECT)) {
+                               *status = MGMT_STATUS_REJECTED;
+                               return false;
+                       }
+                       disable_advertising(req);
+               }
+               /* If controller is scanning, it means the background scanning
+                * is running. Thus, we should temporarily stop it in order to
+                * set the discovery scanning parameters.
+                */
+               if (test_bit(HCI_LE_SCAN, &hdev->dev_flags))
+                       hci_req_add_le_scan_disable(req);
+               memset(&param_cp, 0, sizeof(param_cp));
+               /* All active scans will be done with either a resolvable
+                * private address (when privacy feature has been enabled)
+                * or unresolvable private address.
+                */
+               err = hci_update_random_address(req, true, &own_addr_type);
+               if (err < 0) {
+                       *status = MGMT_STATUS_FAILED;
+                       return false;
+               }
+               param_cp.type = LE_SCAN_ACTIVE;
+               param_cp.interval = cpu_to_le16(DISCOV_LE_SCAN_INT);
+               param_cp.window = cpu_to_le16(DISCOV_LE_SCAN_WIN);
+               param_cp.own_address_type = own_addr_type;
+               hci_req_add(req, HCI_OP_LE_SET_SCAN_PARAM, sizeof(param_cp),
+                           &param_cp);
+               memset(&enable_cp, 0, sizeof(enable_cp));
+               enable_cp.enable = LE_SCAN_ENABLE;
+               enable_cp.filter_dup = LE_SCAN_FILTER_DUP_ENABLE;
+               hci_req_add(req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(enable_cp),
+                           &enable_cp);
+               break;
+       default:
+               *status = MGMT_STATUS_INVALID_PARAMS;
+               return false;
+       }
+       return true;
  }
  
  static void start_discovery_complete(struct hci_dev *hdev, u8 status)
  {
-       unsigned long timeout = 0;
+       struct pending_cmd *cmd;
+       unsigned long timeout;
  
        BT_DBG("status %d", status);
  
+       hci_dev_lock(hdev);
+       cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
+       if (!cmd)
+               cmd = mgmt_pending_find(MGMT_OP_START_SERVICE_DISCOVERY, hdev);
+       if (cmd) {
+               cmd->cmd_complete(cmd, mgmt_status(status));
+               mgmt_pending_remove(cmd);
+       }
        if (status) {
-               hci_dev_lock(hdev);
-               mgmt_start_discovery_failed(hdev, status);
-               hci_dev_unlock(hdev);
-               return;
+               hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
+               goto unlock;
        }
  
-       hci_dev_lock(hdev);
        hci_discovery_set_state(hdev, DISCOVERY_FINDING);
-       hci_dev_unlock(hdev);
  
        switch (hdev->discovery.type) {
        case DISCOV_TYPE_LE:
                timeout = msecs_to_jiffies(DISCOV_LE_TIMEOUT);
                break;
        case DISCOV_TYPE_INTERLEAVED:
                timeout = msecs_to_jiffies(hdev->discov_interleaved_timeout);
                break;
        case DISCOV_TYPE_BREDR:
+               timeout = 0;
                break;
        default:
                BT_ERR("Invalid discovery type %d", hdev->discovery.type);
+               timeout = 0;
+               break;
        }
  
-       if (!timeout)
-               return;
+       if (timeout)
+               queue_delayed_work(hdev->workqueue,
+                                  &hdev->le_scan_disable, timeout);
  
-       queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable, timeout);
+ unlock:
+       hci_dev_unlock(hdev);
  }
  
  static int start_discovery(struct sock *sk, struct hci_dev *hdev,
  {
        struct mgmt_cp_start_discovery *cp = data;
        struct pending_cmd *cmd;
-       struct hci_cp_le_set_scan_param param_cp;
-       struct hci_cp_le_set_scan_enable enable_cp;
-       struct hci_cp_inquiry inq_cp;
        struct hci_request req;
-       /* General inquiry access code (GIAC) */
-       u8 lap[3] = { 0x33, 0x8b, 0x9e };
-       u8 status, own_addr_type;
+       u8 status;
        int err;
  
        BT_DBG("%s", hdev->name);
                goto failed;
        }
  
-       if (test_bit(HCI_PERIODIC_INQ, &hdev->dev_flags)) {
+       if (hdev->discovery.state != DISCOVERY_STOPPED ||
+           test_bit(HCI_PERIODIC_INQ, &hdev->dev_flags)) {
                err = cmd_complete(sk, hdev->id, MGMT_OP_START_DISCOVERY,
                                   MGMT_STATUS_BUSY, &cp->type,
                                   sizeof(cp->type));
                goto failed;
        }
  
-       if (hdev->discovery.state != DISCOVERY_STOPPED) {
-               err = cmd_complete(sk, hdev->id, MGMT_OP_START_DISCOVERY,
-                                  MGMT_STATUS_BUSY, &cp->type,
-                                  sizeof(cp->type));
-               goto failed;
-       }
-       cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
+       cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, data, len);
        if (!cmd) {
                err = -ENOMEM;
                goto failed;
        }
  
+       cmd->cmd_complete = generic_cmd_complete;
+       /* Clear the discovery filter first to free any previously
+        * allocated memory for the UUID list.
+        */
+       hci_discovery_filter_clear(hdev);
        hdev->discovery.type = cp->type;
+       hdev->discovery.report_invalid_rssi = false;
  
        hci_req_init(&req, hdev);
  
-       switch (hdev->discovery.type) {
-       case DISCOV_TYPE_BREDR:
-               status = mgmt_bredr_support(hdev);
-               if (status) {
-                       err = cmd_complete(sk, hdev->id,
-                                          MGMT_OP_START_DISCOVERY, status,
-                                          &cp->type, sizeof(cp->type));
-                       mgmt_pending_remove(cmd);
-                       goto failed;
-               }
+       if (!trigger_discovery(&req, &status)) {
+               err = cmd_complete(sk, hdev->id, MGMT_OP_START_DISCOVERY,
+                                  status, &cp->type, sizeof(cp->type));
+               mgmt_pending_remove(cmd);
+               goto failed;
+       }
  
-               if (test_bit(HCI_INQUIRY, &hdev->flags)) {
-                       err = cmd_complete(sk, hdev->id,
-                                          MGMT_OP_START_DISCOVERY,
-                                          MGMT_STATUS_BUSY, &cp->type,
-                                          sizeof(cp->type));
-                       mgmt_pending_remove(cmd);
-                       goto failed;
-               }
+       err = hci_req_run(&req, start_discovery_complete);
+       if (err < 0) {
+               mgmt_pending_remove(cmd);
+               goto failed;
+       }
  
-               hci_inquiry_cache_flush(hdev);
+       hci_discovery_set_state(hdev, DISCOVERY_STARTING);
  
-               memset(&inq_cp, 0, sizeof(inq_cp));
-               memcpy(&inq_cp.lap, lap, sizeof(inq_cp.lap));
-               inq_cp.length = DISCOV_BREDR_INQUIRY_LEN;
-               hci_req_add(&req, HCI_OP_INQUIRY, sizeof(inq_cp), &inq_cp);
-               break;
+ failed:
+       hci_dev_unlock(hdev);
+       return err;
+ }
  
-       case DISCOV_TYPE_LE:
-       case DISCOV_TYPE_INTERLEAVED:
-               status = mgmt_le_support(hdev);
-               if (status) {
-                       err = cmd_complete(sk, hdev->id,
-                                          MGMT_OP_START_DISCOVERY, status,
-                                          &cp->type, sizeof(cp->type));
-                       mgmt_pending_remove(cmd);
-                       goto failed;
-               }
+ static void service_discovery_cmd_complete(struct pending_cmd *cmd, u8 status)
+ {
+       cmd_complete(cmd->sk, cmd->index, cmd->opcode, status, cmd->param, 1);
+ }
  
-               if (hdev->discovery.type == DISCOV_TYPE_INTERLEAVED &&
-                   !test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
-                       err = cmd_complete(sk, hdev->id,
-                                          MGMT_OP_START_DISCOVERY,
-                                          MGMT_STATUS_NOT_SUPPORTED,
-                                          &cp->type, sizeof(cp->type));
-                       mgmt_pending_remove(cmd);
-                       goto failed;
-               }
+ static int start_service_discovery(struct sock *sk, struct hci_dev *hdev,
+                                  void *data, u16 len)
+ {
+       struct mgmt_cp_start_service_discovery *cp = data;
+       struct pending_cmd *cmd;
+       struct hci_request req;
+       const u16 max_uuid_count = ((U16_MAX - sizeof(*cp)) / 16);
+       u16 uuid_count, expected_len;
+       u8 status;
+       int err;
  
-               if (test_bit(HCI_LE_ADV, &hdev->dev_flags)) {
-                       /* Don't let discovery abort an outgoing
-                        * connection attempt that's using directed
-                        * advertising.
-                        */
-                       if (hci_conn_hash_lookup_state(hdev, LE_LINK,
-                                                      BT_CONNECT)) {
-                               err = cmd_complete(sk, hdev->id,
-                                                  MGMT_OP_START_DISCOVERY,
-                                                  MGMT_STATUS_REJECTED,
-                                                  &cp->type,
-                                                  sizeof(cp->type));
-                               mgmt_pending_remove(cmd);
-                               goto failed;
-                       }
+       BT_DBG("%s", hdev->name);
  
-                       disable_advertising(&req);
-               }
+       hci_dev_lock(hdev);
  
-               /* If controller is scanning, it means the background scanning
-                * is running. Thus, we should temporarily stop it in order to
-                * set the discovery scanning parameters.
-                */
-               if (test_bit(HCI_LE_SCAN, &hdev->dev_flags))
-                       hci_req_add_le_scan_disable(&req);
+       if (!hdev_is_powered(hdev)) {
+               err = cmd_complete(sk, hdev->id,
+                                  MGMT_OP_START_SERVICE_DISCOVERY,
+                                  MGMT_STATUS_NOT_POWERED,
+                                  &cp->type, sizeof(cp->type));
+               goto failed;
+       }
  
-               memset(&param_cp, 0, sizeof(param_cp));
+       if (hdev->discovery.state != DISCOVERY_STOPPED ||
+           test_bit(HCI_PERIODIC_INQ, &hdev->dev_flags)) {
+               err = cmd_complete(sk, hdev->id,
+                                  MGMT_OP_START_SERVICE_DISCOVERY,
+                                  MGMT_STATUS_BUSY, &cp->type,
+                                  sizeof(cp->type));
+               goto failed;
+       }
  
-               /* All active scans will be done with either a resolvable
-                * private address (when privacy feature has been enabled)
-                * or unresolvable private address.
-                */
-               err = hci_update_random_address(&req, true, &own_addr_type);
-               if (err < 0) {
+       uuid_count = __le16_to_cpu(cp->uuid_count);
+       if (uuid_count > max_uuid_count) {
+               BT_ERR("service_discovery: too big uuid_count value %u",
+                      uuid_count);
+               err = cmd_complete(sk, hdev->id,
+                                  MGMT_OP_START_SERVICE_DISCOVERY,
+                                  MGMT_STATUS_INVALID_PARAMS, &cp->type,
+                                  sizeof(cp->type));
+               goto failed;
+       }
+       expected_len = sizeof(*cp) + uuid_count * 16;
+       if (expected_len != len) {
+               BT_ERR("service_discovery: expected %u bytes, got %u bytes",
+                      expected_len, len);
+               err = cmd_complete(sk, hdev->id,
+                                  MGMT_OP_START_SERVICE_DISCOVERY,
+                                  MGMT_STATUS_INVALID_PARAMS, &cp->type,
+                                  sizeof(cp->type));
+               goto failed;
+       }
+       cmd = mgmt_pending_add(sk, MGMT_OP_START_SERVICE_DISCOVERY,
+                              hdev, data, len);
+       if (!cmd) {
+               err = -ENOMEM;
+               goto failed;
+       }
+       cmd->cmd_complete = service_discovery_cmd_complete;
+       /* Clear the discovery filter first to free any previously
+        * allocated memory for the UUID list.
+        */
+       hci_discovery_filter_clear(hdev);
+       hdev->discovery.type = cp->type;
+       hdev->discovery.rssi = cp->rssi;
+       hdev->discovery.uuid_count = uuid_count;
+       if (uuid_count > 0) {
+               hdev->discovery.uuids = kmemdup(cp->uuids, uuid_count * 16,
+                                               GFP_KERNEL);
+               if (!hdev->discovery.uuids) {
                        err = cmd_complete(sk, hdev->id,
-                                          MGMT_OP_START_DISCOVERY,
+                                          MGMT_OP_START_SERVICE_DISCOVERY,
                                           MGMT_STATUS_FAILED,
                                           &cp->type, sizeof(cp->type));
                        mgmt_pending_remove(cmd);
                        goto failed;
                }
+       }
  
-               param_cp.type = LE_SCAN_ACTIVE;
-               param_cp.interval = cpu_to_le16(DISCOV_LE_SCAN_INT);
-               param_cp.window = cpu_to_le16(DISCOV_LE_SCAN_WIN);
-               param_cp.own_address_type = own_addr_type;
-               hci_req_add(&req, HCI_OP_LE_SET_SCAN_PARAM, sizeof(param_cp),
-                           &param_cp);
-               memset(&enable_cp, 0, sizeof(enable_cp));
-               enable_cp.enable = LE_SCAN_ENABLE;
-               enable_cp.filter_dup = LE_SCAN_FILTER_DUP_ENABLE;
-               hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(enable_cp),
-                           &enable_cp);
-               break;
+       hci_req_init(&req, hdev);
  
-       default:
-               err = cmd_complete(sk, hdev->id, MGMT_OP_START_DISCOVERY,
-                                  MGMT_STATUS_INVALID_PARAMS,
-                                  &cp->type, sizeof(cp->type));
+       if (!trigger_discovery(&req, &status)) {
+               err = cmd_complete(sk, hdev->id,
+                                  MGMT_OP_START_SERVICE_DISCOVERY,
+                                  status, &cp->type, sizeof(cp->type));
                mgmt_pending_remove(cmd);
                goto failed;
        }
  
        err = hci_req_run(&req, start_discovery_complete);
-       if (err < 0)
+       if (err < 0) {
                mgmt_pending_remove(cmd);
-       else
-               hci_discovery_set_state(hdev, DISCOVERY_STARTING);
+               goto failed;
+       }
+       hci_discovery_set_state(hdev, DISCOVERY_STARTING);
  
  failed:
        hci_dev_unlock(hdev);
        return err;
  }
  
- static int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
+ static void stop_discovery_complete(struct hci_dev *hdev, u8 status)
  {
        struct pending_cmd *cmd;
-       int err;
  
-       cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
-       if (!cmd)
-               return -ENOENT;
-       err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
-                          &hdev->discovery.type, sizeof(hdev->discovery.type));
-       mgmt_pending_remove(cmd);
-       return err;
- }
- static void stop_discovery_complete(struct hci_dev *hdev, u8 status)
- {
        BT_DBG("status %d", status);
  
        hci_dev_lock(hdev);
  
-       if (status) {
-               mgmt_stop_discovery_failed(hdev, status);
-               goto unlock;
+       cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
+       if (cmd) {
+               cmd->cmd_complete(cmd, mgmt_status(status));
+               mgmt_pending_remove(cmd);
        }
  
-       hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
+       if (!status)
+               hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
  
- unlock:
        hci_dev_unlock(hdev);
  }
  
@@@ -3967,12 -4095,14 +4095,14 @@@ static int stop_discovery(struct sock *
                goto unlock;
        }
  
-       cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
+       cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, data, len);
        if (!cmd) {
                err = -ENOMEM;
                goto unlock;
        }
  
+       cmd->cmd_complete = generic_cmd_complete;
        hci_req_init(&req, hdev);
  
        hci_stop_discovery(&req);
@@@ -4572,18 -4702,13 +4702,13 @@@ static int set_secure_conn(struct sock 
  {
        struct mgmt_mode *cp = data;
        struct pending_cmd *cmd;
-       u8 val, status;
+       u8 val;
        int err;
  
        BT_DBG("request for %s", hdev->name);
  
-       status = mgmt_bredr_support(hdev);
-       if (status)
-               return cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
-                                 status);
-       if (!lmp_sc_capable(hdev) &&
-           !test_bit(HCI_FORCE_SC, &hdev->dbg_flags))
+       if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags) &&
+           !lmp_sc_capable(hdev) && !test_bit(HCI_FORCE_SC, &hdev->dbg_flags))
                return cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
                                  MGMT_STATUS_NOT_SUPPORTED);
  
  
        hci_dev_lock(hdev);
  
-       if (!hdev_is_powered(hdev)) {
+       if (!hdev_is_powered(hdev) ||
+           (!lmp_sc_capable(hdev) &&
+            !test_bit(HCI_FORCE_SC, &hdev->dbg_flags)) ||
+           !test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
                bool changed;
  
                if (cp->val) {
@@@ -4910,18 -5038,26 +5038,26 @@@ static int load_long_term_keys(struct s
                else
                        addr_type = ADDR_LE_DEV_RANDOM;
  
-               if (key->master)
-                       type = SMP_LTK;
-               else
-                       type = SMP_LTK_SLAVE;
                switch (key->type) {
                case MGMT_LTK_UNAUTHENTICATED:
                        authenticated = 0x00;
+                       type = key->master ? SMP_LTK : SMP_LTK_SLAVE;
                        break;
                case MGMT_LTK_AUTHENTICATED:
                        authenticated = 0x01;
+                       type = key->master ? SMP_LTK : SMP_LTK_SLAVE;
+                       break;
+               case MGMT_LTK_P256_UNAUTH:
+                       authenticated = 0x00;
+                       type = SMP_LTK_P256;
                        break;
+               case MGMT_LTK_P256_AUTH:
+                       authenticated = 0x01;
+                       type = SMP_LTK_P256;
+                       break;
+               case MGMT_LTK_P256_DEBUG:
+                       authenticated = 0x00;
+                       type = SMP_LTK_P256_DEBUG;
                default:
                        continue;
                }
        return err;
  }
  
- struct cmd_conn_lookup {
-       struct hci_conn *conn;
-       bool valid_tx_power;
-       u8 mgmt_status;
- };
- static void get_conn_info_complete(struct pending_cmd *cmd, void *data)
+ static void conn_info_cmd_complete(struct pending_cmd *cmd, u8 status)
  {
-       struct cmd_conn_lookup *match = data;
-       struct mgmt_cp_get_conn_info *cp;
-       struct mgmt_rp_get_conn_info rp;
        struct hci_conn *conn = cmd->user_data;
+       struct mgmt_rp_get_conn_info rp;
  
-       if (conn != match->conn)
-               return;
-       cp = (struct mgmt_cp_get_conn_info *) cmd->param;
-       memset(&rp, 0, sizeof(rp));
-       bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
-       rp.addr.type = cp->addr.type;
+       memcpy(&rp.addr, cmd->param, sizeof(rp.addr));
  
-       if (!match->mgmt_status) {
+       if (status == MGMT_STATUS_SUCCESS) {
                rp.rssi = conn->rssi;
-               if (match->valid_tx_power) {
-                       rp.tx_power = conn->tx_power;
-                       rp.max_tx_power = conn->max_tx_power;
-               } else {
-                       rp.tx_power = HCI_TX_POWER_INVALID;
-                       rp.max_tx_power = HCI_TX_POWER_INVALID;
-               }
+               rp.tx_power = conn->tx_power;
+               rp.max_tx_power = conn->max_tx_power;
+       } else {
+               rp.rssi = HCI_RSSI_INVALID;
+               rp.tx_power = HCI_TX_POWER_INVALID;
+               rp.max_tx_power = HCI_TX_POWER_INVALID;
        }
  
-       cmd_complete(cmd->sk, cmd->index, MGMT_OP_GET_CONN_INFO,
-                    match->mgmt_status, &rp, sizeof(rp));
+       cmd_complete(cmd->sk, cmd->index, MGMT_OP_GET_CONN_INFO, status,
+                    &rp, sizeof(rp));
  
        hci_conn_drop(conn);
        hci_conn_put(conn);
-       mgmt_pending_remove(cmd);
  }
  
- static void conn_info_refresh_complete(struct hci_dev *hdev, u8 status)
+ static void conn_info_refresh_complete(struct hci_dev *hdev, u8 hci_status)
  {
        struct hci_cp_read_rssi *cp;
+       struct pending_cmd *cmd;
        struct hci_conn *conn;
-       struct cmd_conn_lookup match;
        u16 handle;
+       u8 status;
  
-       BT_DBG("status 0x%02x", status);
+       BT_DBG("status 0x%02x", hci_status);
  
        hci_dev_lock(hdev);
  
-       /* TX power data is valid in case request completed successfully,
-        * otherwise we assume it's not valid. At the moment we assume that
-        * either both or none of current and max values are valid to keep code
-        * simple.
-        */
-       match.valid_tx_power = !status;
        /* Commands sent in request are either Read RSSI or Read Transmit Power
         * Level so we check which one was last sent to retrieve connection
         * handle.  Both commands have handle as first parameter so it's safe to
        cp = hci_sent_cmd_data(hdev, HCI_OP_READ_RSSI);
        if (!cp) {
                cp = hci_sent_cmd_data(hdev, HCI_OP_READ_TX_POWER);
-               status = 0;
+               status = MGMT_STATUS_SUCCESS;
+       } else {
+               status = mgmt_status(hci_status);
        }
  
        if (!cp) {
-               BT_ERR("invalid sent_cmd in response");
+               BT_ERR("invalid sent_cmd in conn_info response");
                goto unlock;
        }
  
        handle = __le16_to_cpu(cp->handle);
        conn = hci_conn_hash_lookup_handle(hdev, handle);
        if (!conn) {
-               BT_ERR("unknown handle (%d) in response", handle);
+               BT_ERR("unknown handle (%d) in conn_info response", handle);
                goto unlock;
        }
  
-       match.conn = conn;
-       match.mgmt_status = mgmt_status(status);
+       cmd = mgmt_pending_find_data(MGMT_OP_GET_CONN_INFO, hdev, conn);
+       if (!cmd)
+               goto unlock;
  
-       /* Cache refresh is complete, now reply for mgmt request for given
-        * connection only.
-        */
-       mgmt_pending_foreach(MGMT_OP_GET_CONN_INFO, hdev,
-                            get_conn_info_complete, &match);
+       cmd->cmd_complete(cmd, status);
+       mgmt_pending_remove(cmd);
  
  unlock:
        hci_dev_unlock(hdev);
@@@ -5080,6 -5191,12 +5191,12 @@@ static int get_conn_info(struct sock *s
                goto unlock;
        }
  
+       if (mgmt_pending_find_data(MGMT_OP_GET_CONN_INFO, hdev, conn)) {
+               err = cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
+                                  MGMT_STATUS_BUSY, &rp, sizeof(rp));
+               goto unlock;
+       }
        /* To avoid client trying to guess when to poll again for information we
         * calculate conn info age as random value between min/max set in hdev.
         */
  
                hci_conn_hold(conn);
                cmd->user_data = hci_conn_get(conn);
+               cmd->cmd_complete = conn_info_cmd_complete;
  
                conn->conn_info_timestamp = jiffies;
        } else {
@@@ -5152,10 -5270,40 +5270,40 @@@ unlock
        return err;
  }
  
- static void get_clock_info_complete(struct hci_dev *hdev, u8 status)
+ static void clock_info_cmd_complete(struct pending_cmd *cmd, u8 status)
  {
-       struct mgmt_cp_get_clock_info *cp;
+       struct hci_conn *conn = cmd->user_data;
        struct mgmt_rp_get_clock_info rp;
+       struct hci_dev *hdev;
+       memset(&rp, 0, sizeof(rp));
+       memcpy(&rp.addr, &cmd->param, sizeof(rp.addr));
+       if (status)
+               goto complete;
+       hdev = hci_dev_get(cmd->index);
+       if (hdev) {
+               rp.local_clock = cpu_to_le32(hdev->clock);
+               hci_dev_put(hdev);
+       }
+       if (conn) {
+               rp.piconet_clock = cpu_to_le32(conn->clock);
+               rp.accuracy = cpu_to_le16(conn->clock_accuracy);
+       }
+ complete:
+       cmd_complete(cmd->sk, cmd->index, cmd->opcode, status, &rp, sizeof(rp));
+       if (conn) {
+               hci_conn_drop(conn);
+               hci_conn_put(conn);
+       }
+ }
+ static void get_clock_info_complete(struct hci_dev *hdev, u8 status)
+ {
        struct hci_cp_read_clock *hci_cp;
        struct pending_cmd *cmd;
        struct hci_conn *conn;
        if (!cmd)
                goto unlock;
  
-       cp = cmd->param;
-       memset(&rp, 0, sizeof(rp));
-       memcpy(&rp.addr, &cp->addr, sizeof(rp.addr));
-       if (status)
-               goto send_rsp;
-       rp.local_clock = cpu_to_le32(hdev->clock);
-       if (conn) {
-               rp.piconet_clock = cpu_to_le32(conn->clock);
-               rp.accuracy = cpu_to_le16(conn->clock_accuracy);
-       }
- send_rsp:
-       cmd_complete(cmd->sk, cmd->index, cmd->opcode, mgmt_status(status),
-                    &rp, sizeof(rp));
+       cmd->cmd_complete(cmd, mgmt_status(status));
        mgmt_pending_remove(cmd);
-       if (conn) {
-               hci_conn_drop(conn);
-               hci_conn_put(conn);
-       }
  
  unlock:
        hci_dev_unlock(hdev);
@@@ -5257,6 -5384,8 +5384,8 @@@ static int get_clock_info(struct sock *
                goto unlock;
        }
  
+       cmd->cmd_complete = clock_info_cmd_complete;
        hci_req_init(&req, hdev);
  
        memset(&hci_cp, 0, sizeof(hci_cp));
@@@ -5746,6 -5875,7 +5875,7 @@@ static const struct mgmt_handler 
        { read_config_info,       false, MGMT_READ_CONFIG_INFO_SIZE },
        { set_external_config,    false, MGMT_SET_EXTERNAL_CONFIG_SIZE },
        { set_public_address,     false, MGMT_SET_PUBLIC_ADDRESS_SIZE },
+       { start_service_discovery,true,  MGMT_START_SERVICE_DISCOVERY_SIZE },
  };
  
  int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
        if (!buf)
                return -ENOMEM;
  
 -      if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
 +      if (memcpy_from_msg(buf, msg, msglen)) {
                err = -EFAULT;
                goto done;
        }
@@@ -5882,7 -6012,7 +6012,7 @@@ void mgmt_index_removed(struct hci_dev 
        if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
                return;
  
-       mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
+       mgmt_pending_foreach(0, hdev, cmd_complete_rsp, &status);
  
        if (test_bit(HCI_UNCONFIGURED, &hdev->dev_flags))
                mgmt_event(MGMT_EV_UNCONF_INDEX_REMOVED, hdev, NULL, 0, NULL);
@@@ -6017,7 -6147,7 +6147,7 @@@ int mgmt_powered(struct hci_dev *hdev, 
        }
  
        mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
-       mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status_not_powered);
+       mgmt_pending_foreach(0, hdev, cmd_complete_rsp, &status_not_powered);
  
        if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0)
                mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
@@@ -6101,8 -6231,19 +6231,19 @@@ void mgmt_new_link_key(struct hci_dev *
  
  static u8 mgmt_ltk_type(struct smp_ltk *ltk)
  {
-       if (ltk->authenticated)
-               return MGMT_LTK_AUTHENTICATED;
+       switch (ltk->type) {
+       case SMP_LTK:
+       case SMP_LTK_SLAVE:
+               if (ltk->authenticated)
+                       return MGMT_LTK_AUTHENTICATED;
+               return MGMT_LTK_UNAUTHENTICATED;
+       case SMP_LTK_P256:
+               if (ltk->authenticated)
+                       return MGMT_LTK_P256_AUTH;
+               return MGMT_LTK_P256_UNAUTH;
+       case SMP_LTK_P256_DEBUG:
+               return MGMT_LTK_P256_DEBUG;
+       }
  
        return MGMT_LTK_UNAUTHENTICATED;
  }
@@@ -6276,15 -6417,9 +6417,9 @@@ void mgmt_device_connected(struct hci_d
  
  static void disconnect_rsp(struct pending_cmd *cmd, void *data)
  {
-       struct mgmt_cp_disconnect *cp = cmd->param;
        struct sock **sk = data;
-       struct mgmt_rp_disconnect rp;
  
-       bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
-       rp.addr.type = cp->addr.type;
-       cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp,
-                    sizeof(rp));
+       cmd->cmd_complete(cmd, 0);
  
        *sk = cmd->sk;
        sock_hold(*sk);
@@@ -6296,16 -6431,10 +6431,10 @@@ static void unpair_device_rsp(struct pe
  {
        struct hci_dev *hdev = data;
        struct mgmt_cp_unpair_device *cp = cmd->param;
-       struct mgmt_rp_unpair_device rp;
-       memset(&rp, 0, sizeof(rp));
-       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, cmd->opcode, 0, &rp, sizeof(rp));
+       cmd->cmd_complete(cmd, 0);
        mgmt_pending_remove(cmd);
  }
  
@@@ -6366,7 -6495,6 +6495,6 @@@ void mgmt_disconnect_failed(struct hci_
  {
        u8 bdaddr_type = link_to_bdaddr(link_type, addr_type);
        struct mgmt_cp_disconnect *cp;
-       struct mgmt_rp_disconnect rp;
        struct pending_cmd *cmd;
  
        mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
        if (cp->addr.type != bdaddr_type)
                return;
  
-       bacpy(&rp.addr.bdaddr, bdaddr);
-       rp.addr.type = bdaddr_type;
-       cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
-                    mgmt_status(status), &rp, sizeof(rp));
+       cmd->cmd_complete(cmd, mgmt_status(status));
        mgmt_pending_remove(cmd);
  }
  
@@@ -6428,18 -6551,12 +6551,12 @@@ void mgmt_pin_code_reply_complete(struc
                                  u8 status)
  {
        struct pending_cmd *cmd;
-       struct mgmt_rp_pin_code_reply rp;
  
        cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
        if (!cmd)
                return;
  
-       bacpy(&rp.addr.bdaddr, bdaddr);
-       rp.addr.type = BDADDR_BREDR;
-       cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
-                    mgmt_status(status), &rp, sizeof(rp));
+       cmd->cmd_complete(cmd, mgmt_status(status));
        mgmt_pending_remove(cmd);
  }
  
@@@ -6447,18 -6564,12 +6564,12 @@@ void mgmt_pin_code_neg_reply_complete(s
                                      u8 status)
  {
        struct pending_cmd *cmd;
-       struct mgmt_rp_pin_code_reply rp;
  
        cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
        if (!cmd)
                return;
  
-       bacpy(&rp.addr.bdaddr, bdaddr);
-       rp.addr.type = BDADDR_BREDR;
-       cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
-                    mgmt_status(status), &rp, sizeof(rp));
+       cmd->cmd_complete(cmd, mgmt_status(status));
        mgmt_pending_remove(cmd);
  }
  
@@@ -6498,21 -6609,15 +6609,15 @@@ static int user_pairing_resp_complete(s
                                      u8 opcode)
  {
        struct pending_cmd *cmd;
-       struct mgmt_rp_user_confirm_reply rp;
-       int err;
  
        cmd = mgmt_pending_find(opcode, hdev);
        if (!cmd)
                return -ENOENT;
  
-       bacpy(&rp.addr.bdaddr, bdaddr);
-       rp.addr.type = link_to_bdaddr(link_type, addr_type);
-       err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status),
-                          &rp, sizeof(rp));
+       cmd->cmd_complete(cmd, mgmt_status(status));
        mgmt_pending_remove(cmd);
  
-       return err;
+       return 0;
  }
  
  int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
@@@ -6784,8 -6889,7 +6889,7 @@@ void mgmt_read_local_oob_data_complete(
                cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
                           mgmt_status(status));
        } else {
-               if (test_bit(HCI_SC_ENABLED, &hdev->dev_flags) &&
-                   hash256 && rand256) {
+               if (bredr_sc_enabled(hdev) && hash256 && rand256) {
                        struct mgmt_rp_read_local_oob_ext_data rp;
  
                        memcpy(rp.hash192, hash192, sizeof(rp.hash192));
        mgmt_pending_remove(cmd);
  }
  
+ static inline bool has_uuid(u8 *uuid, u16 uuid_count, u8 (*uuids)[16])
+ {
+       int i;
+       for (i = 0; i < uuid_count; i++) {
+               if (!memcmp(uuid, uuids[i], 16))
+                       return true;
+       }
+       return false;
+ }
+ static bool eir_has_uuids(u8 *eir, u16 eir_len, u16 uuid_count, u8 (*uuids)[16])
+ {
+       u16 parsed = 0;
+       while (parsed < eir_len) {
+               u8 field_len = eir[0];
+               u8 uuid[16];
+               int i;
+               if (field_len == 0)
+                       break;
+               if (eir_len - parsed < field_len + 1)
+                       break;
+               switch (eir[1]) {
+               case EIR_UUID16_ALL:
+               case EIR_UUID16_SOME:
+                       for (i = 0; i + 3 <= field_len; i += 2) {
+                               memcpy(uuid, bluetooth_base_uuid, 16);
+                               uuid[13] = eir[i + 3];
+                               uuid[12] = eir[i + 2];
+                               if (has_uuid(uuid, uuid_count, uuids))
+                                       return true;
+                       }
+                       break;
+               case EIR_UUID32_ALL:
+               case EIR_UUID32_SOME:
+                       for (i = 0; i + 5 <= field_len; i += 4) {
+                               memcpy(uuid, bluetooth_base_uuid, 16);
+                               uuid[15] = eir[i + 5];
+                               uuid[14] = eir[i + 4];
+                               uuid[13] = eir[i + 3];
+                               uuid[12] = eir[i + 2];
+                               if (has_uuid(uuid, uuid_count, uuids))
+                                       return true;
+                       }
+                       break;
+               case EIR_UUID128_ALL:
+               case EIR_UUID128_SOME:
+                       for (i = 0; i + 17 <= field_len; i += 16) {
+                               memcpy(uuid, eir + i + 2, 16);
+                               if (has_uuid(uuid, uuid_count, uuids))
+                                       return true;
+                       }
+                       break;
+               }
+               parsed += field_len + 1;
+               eir += field_len + 1;
+       }
+       return false;
+ }
  void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
                       u8 addr_type, u8 *dev_class, s8 rssi, u32 flags,
                       u8 *eir, u16 eir_len, u8 *scan_rsp, u8 scan_rsp_len)
        char buf[512];
        struct mgmt_ev_device_found *ev = (void *) buf;
        size_t ev_size;
+       bool match;
  
        /* Don't send events for a non-kernel initiated discovery. With
         * LE one exception is if we have pend_le_reports > 0 in which
                        return;
        }
  
+       /* When using service discovery with a RSSI threshold, then check
+        * if such a RSSI threshold is specified. If a RSSI threshold has
+        * been specified, then all results with a RSSI smaller than the
+        * RSSI threshold will be dropped.
+        *
+        * For BR/EDR devices (pre 1.2) providing no RSSI during inquiry,
+        * the results are also dropped.
+        */
+       if (hdev->discovery.rssi != HCI_RSSI_INVALID &&
+           (rssi < hdev->discovery.rssi || rssi == HCI_RSSI_INVALID))
+               return;
        /* Make sure that the buffer is big enough. The 5 extra bytes
         * are for the potential CoD field.
         */
  
        memset(buf, 0, sizeof(buf));
  
+       /* In case of device discovery with BR/EDR devices (pre 1.2), the
+        * RSSI value was reported as 0 when not available. This behavior
+        * is kept when using device discovery. This is required for full
+        * backwards compatibility with the API.
+        *
+        * However when using service discovery, the value 127 will be
+        * returned when the RSSI is not available.
+        */
+       if (rssi == HCI_RSSI_INVALID && !hdev->discovery.report_invalid_rssi)
+               rssi = 0;
        bacpy(&ev->addr.bdaddr, bdaddr);
        ev->addr.type = link_to_bdaddr(link_type, addr_type);
        ev->rssi = rssi;
        ev->flags = cpu_to_le32(flags);
  
-       if (eir_len > 0)
+       if (eir_len > 0) {
+               /* When using service discovery and a list of UUID is
+                * provided, results with no matching UUID should be
+                * dropped. In case there is a match the result is
+                * kept and checking possible scan response data
+                * will be skipped.
+                */
+               if (hdev->discovery.uuid_count > 0) {
+                       match = eir_has_uuids(eir, eir_len,
+                                             hdev->discovery.uuid_count,
+                                             hdev->discovery.uuids);
+                       if (!match)
+                               return;
+               }
+               /* Copy EIR or advertising data into event */
                memcpy(ev->eir, eir, eir_len);
+       } else {
+               /* When using service discovery and a list of UUID is
+                * provided, results with empty EIR or advertising data
+                * should be dropped since they do not match any UUID.
+                */
+               if (hdev->discovery.uuid_count > 0)
+                       return;
+       }
  
        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);
  
-       if (scan_rsp_len > 0)
+       if (scan_rsp_len > 0) {
+               /* When using service discovery and a list of UUID is
+                * provided, results with no matching UUID should be
+                * dropped if there is no previous match from the
+                * advertising data.
+                */
+               if (hdev->discovery.uuid_count > 0) {
+                       if (!match && !eir_has_uuids(scan_rsp, scan_rsp_len,
+                                                    hdev->discovery.uuid_count,
+                                                    hdev->discovery.uuids))
+                               return;
+               }
+               /* Append scan response data to event */
                memcpy(ev->eir + eir_len, scan_rsp, scan_rsp_len);
+       } else {
+               /* When using service discovery and a list of UUID is
+                * provided, results with empty scan response and no
+                * previous matched advertising data should be dropped.
+                */
+               if (hdev->discovery.uuid_count > 0 && !match)
+                       return;
+       }
  
        ev->eir_len = cpu_to_le16(eir_len + scan_rsp_len);
        ev_size = sizeof(*ev) + eir_len + scan_rsp_len;
@@@ -6886,23 -7125,9 +7125,9 @@@ void mgmt_remote_name(struct hci_dev *h
  void mgmt_discovering(struct hci_dev *hdev, u8 discovering)
  {
        struct mgmt_ev_discovering ev;
-       struct pending_cmd *cmd;
  
        BT_DBG("%s discovering %u", hdev->name, discovering);
  
-       if (discovering)
-               cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
-       else
-               cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
-       if (cmd != NULL) {
-               u8 type = hdev->discovery.type;
-               cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0, &type,
-                            sizeof(type));
-               mgmt_pending_remove(cmd);
-       }
        memset(&ev, 0, sizeof(ev));
        ev.type = hdev->discovery.type;
        ev.discovering = discovering;
diff --combined net/ieee802154/dgram.c
@@@ -154,7 -154,6 +154,6 @@@ static int dgram_ioctl(struct sock *sk
                spin_unlock_bh(&sk->sk_receive_queue.lock);
                return put_user(amount, (int __user *)arg);
        }
        }
  
        return -ENOIOCTLCMD;
@@@ -276,7 -275,7 +275,7 @@@ static int dgram_sendmsg(struct kiocb *
        if (err < 0)
                goto out_skb;
  
 -      err = memcpy_fromiovec(skb_put(skb, size), msg->msg_iov, size);
 +      err = memcpy_from_msg(skb_put(skb, size), msg, size);
        if (err < 0)
                goto out_skb;
  
@@@ -320,7 -319,7 +319,7 @@@ static int dgram_recvmsg(struct kiocb *
        }
  
        /* FIXME: skip headers if necessary ?! */
 -      err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
 +      err = skb_copy_datagram_msg(skb, 0, msg, copied);
        if (err)
                goto done;
  
diff --combined net/ieee802154/raw.c
@@@ -150,7 -150,7 +150,7 @@@ static int raw_sendmsg(struct kiocb *io
        skb_reset_mac_header(skb);
        skb_reset_network_header(skb);
  
 -      err = memcpy_fromiovec(skb_put(skb, size), msg->msg_iov, size);
 +      err = memcpy_from_msg(skb_put(skb, size), msg, size);
        if (err < 0)
                goto out_skb;
  
@@@ -191,7 -191,7 +191,7 @@@ static int raw_recvmsg(struct kiocb *io
                copied = len;
        }
  
 -      err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
 +      err = skb_copy_datagram_msg(skb, 0, msg, copied);
        if (err)
                goto done;
  
@@@ -221,7 -221,6 +221,6 @@@ static int raw_rcv_skb(struct sock *sk
        return NET_RX_SUCCESS;
  }
  
  void ieee802154_raw_deliver(struct net_device *dev, struct sk_buff *skb)
  {
        struct sock *sk;
diff --combined net/nfc/llcp_commands.c
@@@ -401,7 -401,8 +401,8 @@@ int nfc_llcp_send_connect(struct nfc_ll
        u8 *miux_tlv = NULL, miux_tlv_length;
        u8 *rw_tlv = NULL, rw_tlv_length, rw;
        int err;
-       u16 size = 0, miux;
+       u16 size = 0;
+       __be16 miux;
  
        pr_debug("Sending CONNECT\n");
  
@@@ -465,7 -466,8 +466,8 @@@ int nfc_llcp_send_cc(struct nfc_llcp_so
        u8 *miux_tlv = NULL, miux_tlv_length;
        u8 *rw_tlv = NULL, rw_tlv_length, rw;
        int err;
-       u16 size = 0, miux;
+       u16 size = 0;
+       __be16 miux;
  
        pr_debug("Sending CC\n");
  
@@@ -665,7 -667,7 +667,7 @@@ int nfc_llcp_send_i_frame(struct nfc_ll
        if (msg_data == NULL)
                return -ENOMEM;
  
 -      if (memcpy_fromiovec(msg_data, msg->msg_iov, len)) {
 +      if (memcpy_from_msg(msg_data, msg, len)) {
                kfree(msg_data);
                return -EFAULT;
        }
@@@ -731,7 -733,7 +733,7 @@@ int nfc_llcp_send_ui_frame(struct nfc_l
        if (msg_data == NULL)
                return -ENOMEM;
  
 -      if (memcpy_fromiovec(msg_data, msg->msg_iov, len)) {
 +      if (memcpy_from_msg(msg_data, msg, len)) {
                kfree(msg_data);
                return -EFAULT;
        }
diff --combined net/nfc/llcp_sock.c
@@@ -524,13 -524,13 +524,13 @@@ static int llcp_sock_getname(struct soc
  
  static inline unsigned int llcp_accept_poll(struct sock *parent)
  {
-       struct nfc_llcp_sock *llcp_sock, *n, *parent_sock;
+       struct nfc_llcp_sock *llcp_sock, *parent_sock;
        struct sock *sk;
  
        parent_sock = nfc_llcp_sock(parent);
  
-       list_for_each_entry_safe(llcp_sock, n, &parent_sock->accept_queue,
-                                accept_queue) {
+       list_for_each_entry(llcp_sock, &parent_sock->accept_queue,
+                           accept_queue) {
                sk = &llcp_sock->sk;
  
                if (sk->sk_state == LLCP_CONNECTED)
@@@ -832,7 -832,7 +832,7 @@@ static int llcp_sock_recvmsg(struct kio
        copied = min_t(unsigned int, rlen, len);
  
        cskb = skb;
 -      if (skb_copy_datagram_iovec(cskb, 0, msg->msg_iov, copied)) {
 +      if (skb_copy_datagram_msg(cskb, 0, msg, copied)) {
                if (!(flags & MSG_PEEK))
                        skb_queue_head(&sk->sk_receive_queue, skb);
                return -EFAULT;