Merge branch 'for-upstream' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetoot...
authorDavid S. Miller <davem@davemloft.net>
Fri, 17 Apr 2020 17:48:46 +0000 (10:48 -0700)
committerDavid S. Miller <davem@davemloft.net>
Fri, 17 Apr 2020 17:48:46 +0000 (10:48 -0700)
Johan Hedberg says:

====================
pull request: bluetooth-next 2020-04-17

Here's the first bluetooth-next pull request for the 5.8 kernel:

 - Added debugfs option to control MITM flag usage during pairing
 - Added new BT_MODE socket option
 - Added support for Qualcom QCA6390 device
 - Added support for Realtek RTL8761B device
 - Added support for mSBC audio codec over USB endpoints
 - Added framework for Microsoft HCI vendor extensions
 - Added new Read Security Information management command
 - Fixes/cleanup to link layer privacy related code
 - Various other smaller cleanups & fixes
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
23 files changed:
Documentation/devicetree/bindings/net/qualcomm-bluetooth.txt
drivers/bluetooth/btqca.c
drivers/bluetooth/btqca.h
drivers/bluetooth/btrtl.c
drivers/bluetooth/btusb.c
drivers/bluetooth/hci_bcm.c
drivers/bluetooth/hci_qca.c
include/net/bluetooth/bluetooth.h
include/net/bluetooth/hci.h
include/net/bluetooth/hci_core.h
include/net/bluetooth/mgmt.h
net/bluetooth/Kconfig
net/bluetooth/Makefile
net/bluetooth/hci_conn.c
net/bluetooth/hci_core.c
net/bluetooth/hci_debugfs.c
net/bluetooth/hci_event.c
net/bluetooth/hci_request.c
net/bluetooth/l2cap_sock.c
net/bluetooth/mgmt.c
net/bluetooth/msft.c [new file with mode: 0644]
net/bluetooth/msft.h [new file with mode: 0644]
net/bluetooth/smp.c

index beca646..badf597 100644 (file)
@@ -13,6 +13,7 @@ Required properties:
    * "qcom,wcn3990-bt"
    * "qcom,wcn3991-bt"
    * "qcom,wcn3998-bt"
+   * "qcom,qca6390-bt"
 
 Optional properties for compatible string qcom,qca6174-bt:
 
index a16845c..3ea866d 100644 (file)
@@ -32,7 +32,7 @@ int qca_read_soc_version(struct hci_dev *hdev, u32 *soc_version,
         * VSE event. WCN3991 sends version command response as a payload to
         * command complete event.
         */
-       if (soc_type == QCA_WCN3991) {
+       if (soc_type >= QCA_WCN3991) {
                event_type = 0;
                rlen += 1;
                rtype = EDL_PATCH_VER_REQ_CMD;
@@ -69,7 +69,7 @@ int qca_read_soc_version(struct hci_dev *hdev, u32 *soc_version,
                goto out;
        }
 
-       if (soc_type == QCA_WCN3991)
+       if (soc_type >= QCA_WCN3991)
                memmove(&edl->data, &edl->data[1], sizeof(*ver));
 
        ver = (struct qca_btsoc_version *)(edl->data);
@@ -217,7 +217,7 @@ static void qca_tlv_check_data(struct qca_fw_config *config,
                                tlv_nvm->data[0] |= 0x80;
 
                                /* UART Baud Rate */
-                               if (soc_type == QCA_WCN3991)
+                               if (soc_type >= QCA_WCN3991)
                                        tlv_nvm->data[1] = nvm_baud_rate;
                                else
                                        tlv_nvm->data[2] = nvm_baud_rate;
@@ -268,7 +268,7 @@ static int qca_tlv_send_segment(struct hci_dev *hdev, int seg_size,
         * VSE event. WCN3991 sends version command response as a payload to
         * command complete event.
         */
-       if (soc_type == QCA_WCN3991) {
+       if (soc_type >= QCA_WCN3991) {
                event_type = 0;
                rlen = sizeof(*edl);
                rtype = EDL_PATCH_TLV_REQ_CMD;
@@ -301,7 +301,7 @@ static int qca_tlv_send_segment(struct hci_dev *hdev, int seg_size,
                err = -EIO;
        }
 
-       if (soc_type == QCA_WCN3991)
+       if (soc_type >= QCA_WCN3991)
                goto out;
 
        tlv_resp = (struct tlv_seg_resp *)(edl->data);
@@ -442,6 +442,11 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
                            (soc_ver & 0x0000000f);
                snprintf(config.fwname, sizeof(config.fwname),
                         "qca/crbtfw%02x.tlv", rom_ver);
+       } else if (soc_type == QCA_QCA6390) {
+               rom_ver = ((soc_ver & 0x00000f00) >> 0x04) |
+                           (soc_ver & 0x0000000f);
+               snprintf(config.fwname, sizeof(config.fwname),
+                        "qca/htbtfw%02x.tlv", rom_ver);
        } else {
                snprintf(config.fwname, sizeof(config.fwname),
                         "qca/rampatch_%08x.bin", soc_ver);
@@ -464,6 +469,9 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
        else if (qca_is_wcn399x(soc_type))
                snprintf(config.fwname, sizeof(config.fwname),
                         "qca/crnv%02x.bin", rom_ver);
+       else if (soc_type == QCA_QCA6390)
+               snprintf(config.fwname, sizeof(config.fwname),
+                        "qca/htnv%02x.bin", rom_ver);
        else
                snprintf(config.fwname, sizeof(config.fwname),
                         "qca/nvm_%08x.bin", soc_ver);
index e16a4d6..6e1e62d 100644 (file)
@@ -125,8 +125,9 @@ enum qca_btsoc_type {
        QCA_AR3002,
        QCA_ROME,
        QCA_WCN3990,
-       QCA_WCN3991,
        QCA_WCN3998,
+       QCA_WCN3991,
+       QCA_QCA6390,
 };
 
 #if IS_ENABLED(CONFIG_BT_QCA)
index 67f4bc2..3a9afc9 100644 (file)
@@ -130,12 +130,19 @@ static const struct id_table ic_id_table[] = {
          .cfg_name = "rtl_bt/rtl8821c_config" },
 
        /* 8761A */
-       { IC_MATCH_FL_LMPSUBV, RTL_ROM_LMP_8761A, 0x0,
+       { IC_INFO(RTL_ROM_LMP_8761A, 0xa),
          .config_needed = false,
          .has_rom_version = true,
          .fw_name  = "rtl_bt/rtl8761a_fw.bin",
          .cfg_name = "rtl_bt/rtl8761a_config" },
 
+       /* 8761B */
+       { IC_INFO(RTL_ROM_LMP_8761A, 0xb),
+         .config_needed = false,
+         .has_rom_version = true,
+         .fw_name  = "rtl_bt/rtl8761b_fw.bin",
+         .cfg_name = "rtl_bt/rtl8761b_config" },
+
        /* 8822C with UART interface */
        { .match_flags = IC_MATCH_FL_LMPSUBV | IC_MATCH_FL_HCIREV |
                         IC_MATCH_FL_HCIBUS,
@@ -267,6 +274,7 @@ static int rtlbt_parse_firmware(struct hci_dev *hdev,
                { RTL_ROM_LMP_8723B, 9 },       /* 8723D */
                { RTL_ROM_LMP_8821A, 10 },      /* 8821C */
                { RTL_ROM_LMP_8822B, 13 },      /* 8822C */
+               { RTL_ROM_LMP_8761A, 14 },      /* 8761B */
        };
 
        min_size = sizeof(struct rtl_epatch_header) + sizeof(extension_sig) + 3;
index 3bdec42..8711627 100644 (file)
@@ -492,6 +492,8 @@ struct btusb_data {
        __u8 cmdreq;
 
        unsigned int sco_num;
+       unsigned int air_mode;
+       bool usb_alt6_packet_flow;
        int isoc_altsetting;
        int suspend_count;
 
@@ -983,6 +985,42 @@ static void btusb_isoc_complete(struct urb *urb)
        }
 }
 
+static inline void __fill_isoc_descriptor_msbc(struct urb *urb, int len,
+                                              int mtu, struct btusb_data *data)
+{
+       int i, offset = 0;
+       unsigned int interval;
+
+       BT_DBG("len %d mtu %d", len, mtu);
+
+       /* For mSBC ALT 6 setting the host will send the packet at continuous
+        * flow. As per core spec 5, vol 4, part B, table 2.1. For ALT setting
+        * 6 the HCI PACKET INTERVAL should be 7.5ms for every usb packets.
+        * To maintain the rate we send 63bytes of usb packets alternatively for
+        * 7ms and 8ms to maintain the rate as 7.5ms.
+        */
+       if (data->usb_alt6_packet_flow) {
+               interval = 7;
+               data->usb_alt6_packet_flow = false;
+       } else {
+               interval = 6;
+               data->usb_alt6_packet_flow = true;
+       }
+
+       for (i = 0; i < interval; i++) {
+               urb->iso_frame_desc[i].offset = offset;
+               urb->iso_frame_desc[i].length = offset;
+       }
+
+       if (len && i < BTUSB_MAX_ISOC_FRAMES) {
+               urb->iso_frame_desc[i].offset = offset;
+               urb->iso_frame_desc[i].length = len;
+               i++;
+       }
+
+       urb->number_of_packets = i;
+}
+
 static inline void __fill_isoc_descriptor(struct urb *urb, int len, int mtu)
 {
        int i, offset = 0;
@@ -1386,9 +1424,13 @@ static struct urb *alloc_isoc_urb(struct hci_dev *hdev, struct sk_buff *skb)
 
        urb->transfer_flags  = URB_ISO_ASAP;
 
-       __fill_isoc_descriptor(urb, skb->len,
-                              le16_to_cpu(data->isoc_tx_ep->wMaxPacketSize));
-
+       if (data->isoc_altsetting == 6)
+               __fill_isoc_descriptor_msbc(urb, skb->len,
+                                           le16_to_cpu(data->isoc_tx_ep->wMaxPacketSize),
+                                           data);
+       else
+               __fill_isoc_descriptor(urb, skb->len,
+                                      le16_to_cpu(data->isoc_tx_ep->wMaxPacketSize));
        skb->dev = (void *)hdev;
 
        return urb;
@@ -1484,6 +1526,7 @@ static void btusb_notify(struct hci_dev *hdev, unsigned int evt)
 
        if (hci_conn_num(hdev, SCO_LINK) != data->sco_num) {
                data->sco_num = hci_conn_num(hdev, SCO_LINK);
+               data->air_mode = evt;
                schedule_work(&data->work);
        }
 }
@@ -1531,11 +1574,70 @@ static inline int __set_isoc_interface(struct hci_dev *hdev, int altsetting)
        return 0;
 }
 
+static int btusb_switch_alt_setting(struct hci_dev *hdev, int new_alts)
+{
+       struct btusb_data *data = hci_get_drvdata(hdev);
+       int err;
+
+       if (data->isoc_altsetting != new_alts) {
+               unsigned long flags;
+
+               clear_bit(BTUSB_ISOC_RUNNING, &data->flags);
+               usb_kill_anchored_urbs(&data->isoc_anchor);
+
+               /* When isochronous alternate setting needs to be
+                * changed, because SCO connection has been added
+                * or removed, a packet fragment may be left in the
+                * reassembling state. This could lead to wrongly
+                * assembled fragments.
+                *
+                * Clear outstanding fragment when selecting a new
+                * alternate setting.
+                */
+               spin_lock_irqsave(&data->rxlock, flags);
+               kfree_skb(data->sco_skb);
+               data->sco_skb = NULL;
+               spin_unlock_irqrestore(&data->rxlock, flags);
+
+               err = __set_isoc_interface(hdev, new_alts);
+               if (err < 0)
+                       return err;
+       }
+
+       if (!test_and_set_bit(BTUSB_ISOC_RUNNING, &data->flags)) {
+               if (btusb_submit_isoc_urb(hdev, GFP_KERNEL) < 0)
+                       clear_bit(BTUSB_ISOC_RUNNING, &data->flags);
+               else
+                       btusb_submit_isoc_urb(hdev, GFP_KERNEL);
+       }
+
+       return 0;
+}
+
+static struct usb_host_interface *btusb_find_altsetting(struct btusb_data *data,
+                                                       int alt)
+{
+       struct usb_interface *intf = data->isoc;
+       int i;
+
+       BT_DBG("Looking for Alt no :%d", alt);
+
+       if (!intf)
+               return NULL;
+
+       for (i = 0; i < intf->num_altsetting; i++) {
+               if (intf->altsetting[i].desc.bAlternateSetting == alt)
+                       return &intf->altsetting[i];
+       }
+
+       return NULL;
+}
+
 static void btusb_work(struct work_struct *work)
 {
        struct btusb_data *data = container_of(work, struct btusb_data, work);
        struct hci_dev *hdev = data->hdev;
-       int new_alts;
+       int new_alts = 0;
        int err;
 
        if (data->sco_num > 0) {
@@ -1550,44 +1652,27 @@ static void btusb_work(struct work_struct *work)
                        set_bit(BTUSB_DID_ISO_RESUME, &data->flags);
                }
 
-               if (hdev->voice_setting & 0x0020) {
-                       static const int alts[3] = { 2, 4, 5 };
+               if (data->air_mode == HCI_NOTIFY_ENABLE_SCO_CVSD) {
+                       if (hdev->voice_setting & 0x0020) {
+                               static const int alts[3] = { 2, 4, 5 };
 
-                       new_alts = alts[data->sco_num - 1];
-               } else {
-                       new_alts = data->sco_num;
-               }
-
-               if (data->isoc_altsetting != new_alts) {
-                       unsigned long flags;
-
-                       clear_bit(BTUSB_ISOC_RUNNING, &data->flags);
-                       usb_kill_anchored_urbs(&data->isoc_anchor);
-
-                       /* When isochronous alternate setting needs to be
-                        * changed, because SCO connection has been added
-                        * or removed, a packet fragment may be left in the
-                        * reassembling state. This could lead to wrongly
-                        * assembled fragments.
-                        *
-                        * Clear outstanding fragment when selecting a new
-                        * alternate setting.
-                        */
-                       spin_lock_irqsave(&data->rxlock, flags);
-                       kfree_skb(data->sco_skb);
-                       data->sco_skb = NULL;
-                       spin_unlock_irqrestore(&data->rxlock, flags);
+                               new_alts = alts[data->sco_num - 1];
+                       } else {
+                               new_alts = data->sco_num;
+                       }
+               } else if (data->air_mode == HCI_NOTIFY_ENABLE_SCO_TRANSP) {
 
-                       if (__set_isoc_interface(hdev, new_alts) < 0)
-                               return;
-               }
+                       data->usb_alt6_packet_flow = true;
 
-               if (!test_and_set_bit(BTUSB_ISOC_RUNNING, &data->flags)) {
-                       if (btusb_submit_isoc_urb(hdev, GFP_KERNEL) < 0)
-                               clear_bit(BTUSB_ISOC_RUNNING, &data->flags);
+                       /* Check if Alt 6 is supported for Transparent audio */
+                       if (btusb_find_altsetting(data, 6))
+                               new_alts = 6;
                        else
-                               btusb_submit_isoc_urb(hdev, GFP_KERNEL);
+                               bt_dev_err(hdev, "Device does not support ALT setting 6");
                }
+
+               if (btusb_switch_alt_setting(hdev, new_alts) < 0)
+                       bt_dev_err(hdev, "set USB alt:(%d) failed!", new_alts);
        } else {
                clear_bit(BTUSB_ISOC_RUNNING, &data->flags);
                usb_kill_anchored_urbs(&data->isoc_anchor);
@@ -2252,7 +2337,7 @@ static int btusb_setup_intel_new(struct hci_dev *hdev)
        if (ver.fw_variant == 0x23) {
                clear_bit(BTUSB_BOOTLOADER, &data->flags);
                btintel_check_bdaddr(hdev);
-               return 0;
+               goto finish;
        }
 
        /* If the device is not in bootloader mode, then the only possible
@@ -2452,6 +2537,23 @@ done:
         */
        btintel_load_ddc_config(hdev, fwname);
 
+       /* Read the Intel version information after loading the FW  */
+       err = btintel_read_version(hdev, &ver);
+       if (err)
+               return err;
+
+       btintel_version_info(hdev, &ver);
+
+finish:
+       /* All Intel controllers that support the Microsoft vendor
+        * extension are using 0xFC1E for VsMsftOpCode.
+        */
+       switch (ver.hw_variant) {
+       case 0x12:      /* ThP */
+               hci_set_msft_opcode(hdev, 0xFC1E);
+               break;
+       }
+
        /* Set the event mask for Intel specific vendor events. This enables
         * a few extra events that are useful during general operation. It
         * does not enable any debugging related events.
@@ -2461,13 +2563,6 @@ done:
         */
        btintel_set_event_mask(hdev, false);
 
-       /* Read the Intel version information after loading the FW  */
-       err = btintel_read_version(hdev, &ver);
-       if (err)
-               return err;
-
-       btintel_version_info(hdev, &ver);
-
        return 0;
 }
 
index b236cb1..19e4587 100644 (file)
@@ -118,6 +118,7 @@ struct bcm_device {
        u32                     oper_speed;
        int                     irq;
        bool                    irq_active_low;
+       bool                    irq_acquired;
 
 #ifdef CONFIG_PM
        struct hci_uart         *hu;
@@ -333,6 +334,8 @@ static int bcm_request_irq(struct bcm_data *bcm)
                goto unlock;
        }
 
+       bdev->irq_acquired = true;
+
        device_init_wakeup(bdev->dev, true);
 
        pm_runtime_set_autosuspend_delay(bdev->dev,
@@ -514,7 +517,7 @@ static int bcm_close(struct hci_uart *hu)
        }
 
        if (bdev) {
-               if (IS_ENABLED(CONFIG_PM) && bdev->irq > 0) {
+               if (IS_ENABLED(CONFIG_PM) && bdev->irq_acquired) {
                        devm_free_irq(bdev->dev, bdev->irq, bdev);
                        device_init_wakeup(bdev->dev, false);
                        pm_runtime_disable(bdev->dev);
@@ -1153,7 +1156,8 @@ static int bcm_of_probe(struct bcm_device *bdev)
        device_property_read_u8_array(bdev->dev, "brcm,bt-pcm-int-params",
                                      bdev->pcm_int_params, 5);
        bdev->irq = of_irq_get_byname(bdev->dev->of_node, "host-wakeup");
-
+       bdev->irq_active_low = irq_get_trigger_type(bdev->irq)
+                            & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_LEVEL_LOW);
        return 0;
 }
 
index 439392b..d0ac554 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/mod_devicetable.h>
 #include <linux/module.h>
 #include <linux/of_device.h>
+#include <linux/acpi.h>
 #include <linux/platform_device.h>
 #include <linux/regulator/consumer.h>
 #include <linux/serdev.h>
@@ -1596,7 +1597,7 @@ static int qca_setup(struct hci_uart *hu)
        set_bit(HCI_QUIRK_SIMULTANEOUS_DISCOVERY, &hdev->quirks);
 
        bt_dev_info(hdev, "setting up %s",
-               qca_is_wcn399x(soc_type) ? "wcn399x" : "ROME");
+               qca_is_wcn399x(soc_type) ? "wcn399x" : "ROME/QCA6390");
 
 retry:
        ret = qca_power_on(hdev);
@@ -1665,10 +1666,10 @@ retry:
        }
 
        /* Setup bdaddr */
-       if (qca_is_wcn399x(soc_type))
-               hu->hdev->set_bdaddr = qca_set_bdaddr;
-       else
+       if (soc_type == QCA_ROME)
                hu->hdev->set_bdaddr = qca_set_bdaddr_rome;
+       else
+               hu->hdev->set_bdaddr = qca_set_bdaddr;
 
        return ret;
 }
@@ -1721,6 +1722,11 @@ static const struct qca_vreg_data qca_soc_data_wcn3998 = {
        .num_vregs = 4,
 };
 
+static const struct qca_vreg_data qca_soc_data_qca6390 = {
+       .soc_type = QCA_QCA6390,
+       .num_vregs = 0,
+};
+
 static void qca_power_shutdown(struct hci_uart *hu)
 {
        struct qca_serdev *qcadev;
@@ -1764,7 +1770,7 @@ static int qca_power_off(struct hci_dev *hdev)
        enum qca_btsoc_type soc_type = qca_soc_type(hu);
 
        /* Stop sending shutdown command if soc crashes. */
-       if (qca_is_wcn399x(soc_type)
+       if (soc_type != QCA_ROME
                && qca->memdump_state == QCA_MEMDUMP_IDLE) {
                qca_send_pre_shutdown_cmd(hdev);
                usleep_range(8000, 10000);
@@ -1900,7 +1906,11 @@ static int qca_serdev_probe(struct serdev_device *serdev)
                        return err;
                }
        } else {
-               qcadev->btsoc_type = QCA_ROME;
+               if (data)
+                       qcadev->btsoc_type = data->soc_type;
+               else
+                       qcadev->btsoc_type = QCA_ROME;
+
                qcadev->bt_en = devm_gpiod_get_optional(&serdev->dev, "enable",
                                               GPIOD_OUT_LOW);
                if (!qcadev->bt_en) {
@@ -2044,21 +2054,37 @@ static int __maybe_unused qca_resume(struct device *dev)
 
 static SIMPLE_DEV_PM_OPS(qca_pm_ops, qca_suspend, qca_resume);
 
+#ifdef CONFIG_OF
 static const struct of_device_id qca_bluetooth_of_match[] = {
        { .compatible = "qcom,qca6174-bt" },
+       { .compatible = "qcom,qca6390-bt", .data = &qca_soc_data_qca6390},
        { .compatible = "qcom,wcn3990-bt", .data = &qca_soc_data_wcn3990},
        { .compatible = "qcom,wcn3991-bt", .data = &qca_soc_data_wcn3991},
        { .compatible = "qcom,wcn3998-bt", .data = &qca_soc_data_wcn3998},
        { /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, qca_bluetooth_of_match);
+#endif
+
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id qca_bluetooth_acpi_match[] = {
+       { "QCOM6390", (kernel_ulong_t)&qca_soc_data_qca6390 },
+       { "DLA16390", (kernel_ulong_t)&qca_soc_data_qca6390 },
+       { "DLB16390", (kernel_ulong_t)&qca_soc_data_qca6390 },
+       { "DLB26390", (kernel_ulong_t)&qca_soc_data_qca6390 },
+       { },
+};
+MODULE_DEVICE_TABLE(acpi, qca_bluetooth_acpi_match);
+#endif
+
 
 static struct serdev_device_driver qca_serdev_driver = {
        .probe = qca_serdev_probe,
        .remove = qca_serdev_remove,
        .driver = {
                .name = "hci_uart_qca",
-               .of_match_table = qca_bluetooth_of_match,
+               .of_match_table = of_match_ptr(qca_bluetooth_of_match),
+               .acpi_match_table = ACPI_PTR(qca_bluetooth_acpi_match),
                .pm = &qca_pm_ops,
        },
 };
index 1576353..3fa7b1e 100644 (file)
@@ -139,6 +139,14 @@ struct bt_voice {
 #define BT_PHY_LE_CODED_TX     0x00002000
 #define BT_PHY_LE_CODED_RX     0x00004000
 
+#define BT_MODE                        15
+
+#define BT_MODE_BASIC          0x00
+#define BT_MODE_ERTM           0x01
+#define BT_MODE_STREAMING      0x02
+#define BT_MODE_LE_FLOWCTL     0x03
+#define BT_MODE_EXT_FLOWCTL    0x04
+
 __printf(1, 2)
 void bt_info(const char *fmt, ...);
 __printf(1, 2)
index 5f60e13..1da8cec 100644 (file)
@@ -53,6 +53,9 @@
 #define HCI_NOTIFY_CONN_ADD            1
 #define HCI_NOTIFY_CONN_DEL            2
 #define HCI_NOTIFY_VOICE_SETTING       3
+#define HCI_NOTIFY_ENABLE_SCO_CVSD     4
+#define HCI_NOTIFY_ENABLE_SCO_TRANSP   5
+#define HCI_NOTIFY_DISABLE_SCO         6
 
 /* HCI bus types */
 #define HCI_VIRTUAL    0
@@ -65,6 +68,7 @@
 #define HCI_SPI                7
 #define HCI_I2C                8
 #define HCI_SMD                9
+#define HCI_VIRTIO     10
 
 /* HCI controller types */
 #define HCI_PRIMARY    0x00
@@ -294,6 +298,7 @@ enum {
        HCI_FORCE_STATIC_ADDR,
        HCI_LL_RPA_RESOLUTION,
        HCI_CMD_PENDING,
+       HCI_FORCE_NO_MITM,
 
        __HCI_NUM_FLAGS,
 };
@@ -455,12 +460,11 @@ enum {
 #define HCI_LE_SLAVE_FEATURES          0x08
 #define HCI_LE_PING                    0x10
 #define HCI_LE_DATA_LEN_EXT            0x20
-#define HCI_LE_PHY_2M                  0x01
-#define HCI_LE_PHY_CODED               0x08
-#define HCI_LE_EXT_ADV                 0x10
+#define HCI_LE_LL_PRIVACY              0x40
 #define HCI_LE_EXT_SCAN_POLICY         0x80
 #define HCI_LE_PHY_2M                  0x01
 #define HCI_LE_PHY_CODED               0x08
+#define HCI_LE_EXT_ADV                 0x10
 #define HCI_LE_CHAN_SEL_ALG2           0x40
 #define HCI_LE_CIS_MASTER              0x10
 #define HCI_LE_CIS_SLAVE               0x20
@@ -1272,6 +1276,13 @@ struct hci_rp_read_data_block_size {
 
 #define HCI_OP_READ_LOCAL_CODECS       0x100b
 
+#define HCI_OP_READ_LOCAL_PAIRING_OPTS 0x100c
+struct hci_rp_read_local_pairing_opts {
+       __u8     status;
+       __u8     pairing_opts;
+       __u8     max_key_size;
+} __packed;
+
 #define HCI_OP_READ_PAGE_SCAN_ACTIVITY 0x0c1b
 struct hci_rp_read_page_scan_activity {
        __u8     status;
index d4e2877..239ab72 100644 (file)
@@ -312,6 +312,8 @@ struct hci_dev {
        __u16           conn_info_max_age;
        __u16           auth_payload_timeout;
        __u8            min_enc_key_size;
+       __u8            max_enc_key_size;
+       __u8            pairing_opts;
        __u8            ssp_debug_mode;
        __u8            hw_error_code;
        __u32           clock;
@@ -484,6 +486,11 @@ struct hci_dev {
        struct led_trigger      *power_led;
 #endif
 
+#if IS_ENABLED(CONFIG_BT_MSFTEXT)
+       __u16                   msft_opcode;
+       void                    *msft_data;
+#endif
+
        int (*open)(struct hci_dev *hdev);
        int (*close)(struct hci_dev *hdev);
        int (*flush)(struct hci_dev *hdev);
@@ -638,6 +645,7 @@ extern struct mutex hci_cb_list_lock;
        do {                                                    \
                hci_dev_clear_flag(hdev, HCI_LE_SCAN);          \
                hci_dev_clear_flag(hdev, HCI_LE_ADV);           \
+               hci_dev_clear_flag(hdev, HCI_LL_RPA_RESOLUTION);\
                hci_dev_clear_flag(hdev, HCI_PERIODIC_INQ);     \
        } while (0)
 
@@ -1116,6 +1124,14 @@ int hci_recv_frame(struct hci_dev *hdev, struct sk_buff *skb);
 int hci_recv_diag(struct hci_dev *hdev, struct sk_buff *skb);
 __printf(2, 3) void hci_set_hw_info(struct hci_dev *hdev, const char *fmt, ...);
 __printf(2, 3) void hci_set_fw_info(struct hci_dev *hdev, const char *fmt, ...);
+
+static inline void hci_set_msft_opcode(struct hci_dev *hdev, __u16 opcode)
+{
+#if IS_ENABLED(CONFIG_BT_MSFTEXT)
+       hdev->msft_opcode = opcode;
+#endif
+}
+
 int hci_dev_open(__u16 dev);
 int hci_dev_close(__u16 dev);
 int hci_dev_do_close(struct hci_dev *hdev);
index f41cd87..65dd6fd 100644 (file)
@@ -674,6 +674,13 @@ struct mgmt_cp_set_blocked_keys {
 
 #define MGMT_OP_SET_WIDEBAND_SPEECH    0x0047
 
+#define MGMT_OP_READ_SECURITY_INFO     0x0048
+#define MGMT_READ_SECURITY_INFO_SIZE   0
+struct mgmt_rp_read_security_info {
+       __le16   sec_len;
+       __u8     sec[0];
+} __packed;
+
 #define MGMT_EV_CMD_COMPLETE           0x0001
 struct mgmt_ev_cmd_complete {
        __le16  opcode;
index 165148c..9e25c65 100644 (file)
@@ -93,6 +93,21 @@ config BT_LEDS
          This option selects a few LED triggers for different
          Bluetooth events.
 
+config BT_MSFTEXT
+       bool "Enable Microsoft extensions"
+       depends on BT
+       help
+         This options enables support for the Microsoft defined HCI
+         vendor extensions.
+
+config BT_DEBUGFS
+       bool "Export Bluetooth internals in debugfs"
+       depends on BT && DEBUG_FS
+       default y
+       help
+         Provide extensive information about internal Bluetooth states
+         in debugfs.
+
 config BT_SELFTEST
        bool "Bluetooth self testing support"
        depends on BT && DEBUG_KERNEL
@@ -120,12 +135,4 @@ config BT_SELFTEST_SMP
          Run test cases for SMP cryptographic functionality, including both
          legacy SMP as well as the Secure Connections features.
 
-config BT_DEBUGFS
-       bool "Export Bluetooth internals in debugfs"
-       depends on BT && DEBUG_FS
-       default y
-       help
-         Provide extensive information about internal Bluetooth states
-         in debugfs.
-
 source "drivers/bluetooth/Kconfig"
index fda41c0..41dd541 100644 (file)
@@ -19,5 +19,6 @@ bluetooth-y := af_bluetooth.o hci_core.o hci_conn.o hci_event.o mgmt.o \
 bluetooth-$(CONFIG_BT_BREDR) += sco.o
 bluetooth-$(CONFIG_BT_HS) += a2mp.o amp.o
 bluetooth-$(CONFIG_BT_LEDS) += leds.o
+bluetooth-$(CONFIG_BT_MSFTEXT) += msft.o
 bluetooth-$(CONFIG_BT_DEBUGFS) += hci_debugfs.o
 bluetooth-$(CONFIG_BT_SELFTEST) += selftest.o
index e245bc1..07c34c5 100644 (file)
@@ -122,8 +122,18 @@ static void hci_conn_cleanup(struct hci_conn *conn)
 
        hci_conn_hash_del(hdev, conn);
 
-       if (hdev->notify)
-               hdev->notify(hdev, HCI_NOTIFY_CONN_DEL);
+       if (conn->type == SCO_LINK || conn->type == ESCO_LINK) {
+               switch (conn->setting & SCO_AIRMODE_MASK) {
+               case SCO_AIRMODE_CVSD:
+               case SCO_AIRMODE_TRANSP:
+                       if (hdev->notify)
+                               hdev->notify(hdev, HCI_NOTIFY_DISABLE_SCO);
+                       break;
+               }
+       } else {
+               if (hdev->notify)
+                       hdev->notify(hdev, HCI_NOTIFY_CONN_DEL);
+       }
 
        hci_conn_del_sysfs(conn);
 
@@ -577,8 +587,15 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst,
        hci_dev_hold(hdev);
 
        hci_conn_hash_add(hdev, conn);
-       if (hdev->notify)
-               hdev->notify(hdev, HCI_NOTIFY_CONN_ADD);
+
+       /* The SCO and eSCO connections will only be notified when their
+        * setup has been completed. This is different to ACL links which
+        * can be notified right away.
+        */
+       if (conn->type != SCO_LINK && conn->type != ESCO_LINK) {
+               if (hdev->notify)
+                       hdev->notify(hdev, HCI_NOTIFY_CONN_ADD);
+       }
 
        hci_conn_init_sysfs(conn);
 
index 2e7bc2d..51d3992 100644 (file)
@@ -44,6 +44,7 @@
 #include "hci_debugfs.h"
 #include "smp.h"
 #include "leds.h"
+#include "msft.h"
 
 static void hci_rx_work(struct work_struct *work);
 static void hci_cmd_work(struct work_struct *work);
@@ -637,6 +638,14 @@ static int hci_init3_req(struct hci_request *req, unsigned long opt)
                if (hdev->le_features[0] & HCI_LE_DATA_LEN_EXT)
                        events[0] |= 0x40;      /* LE Data Length Change */
 
+               /* If the controller supports LL Privacy feature, enable
+                * the corresponding event.
+                */
+               if (hdev->le_features[0] & HCI_LE_LL_PRIVACY)
+                       events[1] |= 0x02;      /* LE Enhanced Connection
+                                                * Complete
+                                                */
+
                /* If the controller supports Extended Scanner Filter
                 * Policies, enable the correspondig event.
                 */
@@ -710,14 +719,6 @@ static int hci_init3_req(struct hci_request *req, unsigned long opt)
                                                 * Report
                                                 */
 
-               /* If the controller supports the LE Extended Create Connection
-                * command, enable the corresponding event.
-                */
-               if (use_ext_conn(hdev))
-                       events[1] |= 0x02;      /* LE Enhanced Connection
-                                                * Complete
-                                                */
-
                /* If the controller supports the LE Extended Advertising
                 * command, enable the corresponding event.
                 */
@@ -826,6 +827,10 @@ static int hci_init4_req(struct hci_request *req, unsigned long opt)
        if (hdev->commands[29] & 0x20)
                hci_req_add(req, HCI_OP_READ_LOCAL_CODECS, 0, NULL);
 
+       /* Read local pairing options if the HCI command is supported */
+       if (hdev->commands[41] & 0x08)
+               hci_req_add(req, HCI_OP_READ_LOCAL_PAIRING_OPTS, 0, NULL);
+
        /* Get MWS transport configuration if the HCI command is supported */
        if (hdev->commands[30] & 0x08)
                hci_req_add(req, HCI_OP_GET_MWS_TRANSPORT_CONFIG, 0, NULL);
@@ -1563,6 +1568,8 @@ setup_failed:
            hci_dev_test_flag(hdev, HCI_VENDOR_DIAG) && hdev->set_diag)
                ret = hdev->set_diag(hdev, true);
 
+       msft_do_open(hdev);
+
        clear_bit(HCI_INIT, &hdev->flags);
 
        if (!ret) {
@@ -1758,6 +1765,8 @@ int hci_dev_do_close(struct hci_dev *hdev)
 
        hci_sock_dev_event(hdev, HCI_DEV_DOWN);
 
+       msft_do_close(hdev);
+
        if (hdev->flush)
                hdev->flush(hdev);
 
@@ -4240,6 +4249,54 @@ static void __check_timeout(struct hci_dev *hdev, unsigned int cnt)
        }
 }
 
+/* Schedule SCO */
+static void hci_sched_sco(struct hci_dev *hdev)
+{
+       struct hci_conn *conn;
+       struct sk_buff *skb;
+       int quote;
+
+       BT_DBG("%s", hdev->name);
+
+       if (!hci_conn_num(hdev, SCO_LINK))
+               return;
+
+       while (hdev->sco_cnt && (conn = hci_low_sent(hdev, SCO_LINK, &quote))) {
+               while (quote-- && (skb = skb_dequeue(&conn->data_q))) {
+                       BT_DBG("skb %p len %d", skb, skb->len);
+                       hci_send_frame(hdev, skb);
+
+                       conn->sent++;
+                       if (conn->sent == ~0)
+                               conn->sent = 0;
+               }
+       }
+}
+
+static void hci_sched_esco(struct hci_dev *hdev)
+{
+       struct hci_conn *conn;
+       struct sk_buff *skb;
+       int quote;
+
+       BT_DBG("%s", hdev->name);
+
+       if (!hci_conn_num(hdev, ESCO_LINK))
+               return;
+
+       while (hdev->sco_cnt && (conn = hci_low_sent(hdev, ESCO_LINK,
+                                                    &quote))) {
+               while (quote-- && (skb = skb_dequeue(&conn->data_q))) {
+                       BT_DBG("skb %p len %d", skb, skb->len);
+                       hci_send_frame(hdev, skb);
+
+                       conn->sent++;
+                       if (conn->sent == ~0)
+                               conn->sent = 0;
+               }
+       }
+}
+
 static void hci_sched_acl_pkt(struct hci_dev *hdev)
 {
        unsigned int cnt = hdev->acl_cnt;
@@ -4271,6 +4328,10 @@ static void hci_sched_acl_pkt(struct hci_dev *hdev)
                        hdev->acl_cnt--;
                        chan->sent++;
                        chan->conn->sent++;
+
+                       /* Send pending SCO packets right away */
+                       hci_sched_sco(hdev);
+                       hci_sched_esco(hdev);
                }
        }
 
@@ -4355,54 +4416,6 @@ static void hci_sched_acl(struct hci_dev *hdev)
        }
 }
 
-/* Schedule SCO */
-static void hci_sched_sco(struct hci_dev *hdev)
-{
-       struct hci_conn *conn;
-       struct sk_buff *skb;
-       int quote;
-
-       BT_DBG("%s", hdev->name);
-
-       if (!hci_conn_num(hdev, SCO_LINK))
-               return;
-
-       while (hdev->sco_cnt && (conn = hci_low_sent(hdev, SCO_LINK, &quote))) {
-               while (quote-- && (skb = skb_dequeue(&conn->data_q))) {
-                       BT_DBG("skb %p len %d", skb, skb->len);
-                       hci_send_frame(hdev, skb);
-
-                       conn->sent++;
-                       if (conn->sent == ~0)
-                               conn->sent = 0;
-               }
-       }
-}
-
-static void hci_sched_esco(struct hci_dev *hdev)
-{
-       struct hci_conn *conn;
-       struct sk_buff *skb;
-       int quote;
-
-       BT_DBG("%s", hdev->name);
-
-       if (!hci_conn_num(hdev, ESCO_LINK))
-               return;
-
-       while (hdev->sco_cnt && (conn = hci_low_sent(hdev, ESCO_LINK,
-                                                    &quote))) {
-               while (quote-- && (skb = skb_dequeue(&conn->data_q))) {
-                       BT_DBG("skb %p len %d", skb, skb->len);
-                       hci_send_frame(hdev, skb);
-
-                       conn->sent++;
-                       if (conn->sent == ~0)
-                               conn->sent = 0;
-               }
-       }
-}
-
 static void hci_sched_le(struct hci_dev *hdev)
 {
        struct hci_chan *chan;
@@ -4437,6 +4450,10 @@ static void hci_sched_le(struct hci_dev *hdev)
                        cnt--;
                        chan->sent++;
                        chan->conn->sent++;
+
+                       /* Send pending SCO packets right away */
+                       hci_sched_sco(hdev);
+                       hci_sched_esco(hdev);
                }
        }
 
@@ -4459,9 +4476,9 @@ static void hci_tx_work(struct work_struct *work)
 
        if (!hci_dev_test_flag(hdev, HCI_USER_CHANNEL)) {
                /* Schedule queues and send stuff to HCI driver */
-               hci_sched_acl(hdev);
                hci_sched_sco(hdev);
                hci_sched_esco(hdev);
+               hci_sched_acl(hdev);
                hci_sched_le(hdev);
        }
 
index 6b1314c..5e8af26 100644 (file)
@@ -1075,6 +1075,50 @@ DEFINE_SIMPLE_ATTRIBUTE(auth_payload_timeout_fops,
                        auth_payload_timeout_get,
                        auth_payload_timeout_set, "%llu\n");
 
+static ssize_t force_no_mitm_read(struct file *file,
+                                 char __user *user_buf,
+                                 size_t count, loff_t *ppos)
+{
+       struct hci_dev *hdev = file->private_data;
+       char buf[3];
+
+       buf[0] = hci_dev_test_flag(hdev, HCI_FORCE_NO_MITM) ? 'Y' : 'N';
+       buf[1] = '\n';
+       buf[2] = '\0';
+       return simple_read_from_buffer(user_buf, count, ppos, buf, 2);
+}
+
+static ssize_t force_no_mitm_write(struct file *file,
+                                  const char __user *user_buf,
+                                  size_t count, loff_t *ppos)
+{
+       struct hci_dev *hdev = file->private_data;
+       char buf[32];
+       size_t buf_size = min(count, (sizeof(buf) - 1));
+       bool enable;
+
+       if (copy_from_user(buf, user_buf, buf_size))
+               return -EFAULT;
+
+       buf[buf_size] = '\0';
+       if (strtobool(buf, &enable))
+               return -EINVAL;
+
+       if (enable == hci_dev_test_flag(hdev, HCI_FORCE_NO_MITM))
+               return -EALREADY;
+
+       hci_dev_change_flag(hdev, HCI_FORCE_NO_MITM);
+
+       return count;
+}
+
+static const struct file_operations force_no_mitm_fops = {
+       .open           = simple_open,
+       .read           = force_no_mitm_read,
+       .write          = force_no_mitm_write,
+       .llseek         = default_llseek,
+};
+
 DEFINE_QUIRK_ATTRIBUTE(quirk_strict_duplicate_filter,
                       HCI_QUIRK_STRICT_DUPLICATE_FILTER);
 DEFINE_QUIRK_ATTRIBUTE(quirk_simultaneous_discovery,
@@ -1134,6 +1178,8 @@ void hci_debugfs_create_le(struct hci_dev *hdev)
                            &max_key_size_fops);
        debugfs_create_file("auth_payload_timeout", 0644, hdev->debugfs, hdev,
                            &auth_payload_timeout_fops);
+       debugfs_create_file("force_no_mitm", 0644, hdev->debugfs, hdev,
+                           &force_no_mitm_fops);
 
        debugfs_create_file("quirk_strict_duplicate_filter", 0644,
                            hdev->debugfs, hdev,
index 0a591be..966fc54 100644 (file)
@@ -35,6 +35,7 @@
 #include "a2mp.h"
 #include "amp.h"
 #include "smp.h"
+#include "msft.h"
 
 #define ZERO_KEY "\x00\x00\x00\x00\x00\x00\x00\x00" \
                 "\x00\x00\x00\x00\x00\x00\x00\x00"
@@ -746,6 +747,23 @@ static void hci_cc_read_bd_addr(struct hci_dev *hdev, struct sk_buff *skb)
                bacpy(&hdev->setup_addr, &rp->bdaddr);
 }
 
+static void hci_cc_read_local_pairing_opts(struct hci_dev *hdev,
+                                          struct sk_buff *skb)
+{
+       struct hci_rp_read_local_pairing_opts *rp = (void *) skb->data;
+
+       BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
+
+       if (rp->status)
+               return;
+
+       if (hci_dev_test_flag(hdev, HCI_SETUP) ||
+           hci_dev_test_flag(hdev, HCI_CONFIG)) {
+               hdev->pairing_opts = rp->pairing_opts;
+               hdev->max_enc_key_size = rp->max_key_size;
+       }
+}
+
 static void hci_cc_read_page_scan_activity(struct hci_dev *hdev,
                                           struct sk_buff *skb)
 {
@@ -2607,8 +2625,16 @@ static void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
        if (ev->status) {
                hci_connect_cfm(conn, ev->status);
                hci_conn_del(conn);
-       } else if (ev->link_type != ACL_LINK)
+       } else if (ev->link_type == SCO_LINK) {
+               switch (conn->setting & SCO_AIRMODE_MASK) {
+               case SCO_AIRMODE_CVSD:
+                       if (hdev->notify)
+                               hdev->notify(hdev, HCI_NOTIFY_ENABLE_SCO_CVSD);
+                       break;
+               }
+
                hci_connect_cfm(conn, ev->status);
+       }
 
 unlock:
        hci_dev_unlock(hdev);
@@ -3334,6 +3360,10 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb,
                hci_cc_read_bd_addr(hdev, skb);
                break;
 
+       case HCI_OP_READ_LOCAL_PAIRING_OPTS:
+               hci_cc_read_local_pairing_opts(hdev, skb);
+               break;
+
        case HCI_OP_READ_PAGE_SCAN_ACTIVITY:
                hci_cc_read_page_scan_activity(hdev, skb);
                break;
@@ -4307,6 +4337,19 @@ static void hci_sync_conn_complete_evt(struct hci_dev *hdev,
                break;
        }
 
+       bt_dev_dbg(hdev, "SCO connected with air mode: %02x", ev->air_mode);
+
+       switch (conn->setting & SCO_AIRMODE_MASK) {
+       case SCO_AIRMODE_CVSD:
+               if (hdev->notify)
+                       hdev->notify(hdev, HCI_NOTIFY_ENABLE_SCO_CVSD);
+               break;
+       case SCO_AIRMODE_TRANSP:
+               if (hdev->notify)
+                       hdev->notify(hdev, HCI_NOTIFY_ENABLE_SCO_TRANSP);
+               break;
+       }
+
        hci_connect_cfm(conn, ev->status);
        if (ev->status)
                hci_conn_del(conn);
@@ -5269,7 +5312,7 @@ static struct hci_conn *check_pending_le_conn(struct hci_dev *hdev,
                case HCI_AUTO_CONN_ALWAYS:
                        /* Devices advertising with ADV_IND or ADV_DIRECT_IND
                         * are triggering a connection attempt. This means
-                        * that incoming connectioms from slave device are
+                        * that incoming connections from slave device are
                         * accepted and also outgoing connections to slave
                         * devices are established when found.
                         */
@@ -5353,7 +5396,8 @@ static void process_adv_report(struct hci_dev *hdev, u8 type, bdaddr_t *bdaddr,
 
        /* Adjust for actual length */
        if (len != real_len) {
-               bt_dev_err_ratelimited(hdev, "advertising data len corrected");
+               bt_dev_err_ratelimited(hdev, "advertising data len corrected %u -> %u",
+                                      len, real_len);
                len = real_len;
        }
 
@@ -6145,6 +6189,10 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
                hci_num_comp_blocks_evt(hdev, skb);
                break;
 
+       case HCI_EV_VENDOR:
+               msft_vendor_evt(hdev, skb);
+               break;
+
        default:
                BT_DBG("%s event 0x%2.2x", hdev->name, event);
                break;
index 649e1e5..9ea4010 100644 (file)
@@ -2723,6 +2723,8 @@ static int active_scan(struct hci_request *req, unsigned long opt)
        uint16_t interval = opt;
        struct hci_dev *hdev = req->hdev;
        u8 own_addr_type;
+       /* White list is not used for discovery */
+       u8 filter_policy = 0x00;
        int err;
 
        BT_DBG("%s", hdev->name);
@@ -2744,7 +2746,7 @@ static int active_scan(struct hci_request *req, unsigned long opt)
                own_addr_type = ADDR_LE_DEV_PUBLIC;
 
        hci_req_start_scan(req, LE_SCAN_ACTIVE, interval, DISCOV_LE_SCAN_WIN,
-                          own_addr_type, 0);
+                          own_addr_type, filter_policy);
        return 0;
 }
 
index 117ba20..1cea42e 100644 (file)
@@ -395,6 +395,24 @@ static int l2cap_sock_getname(struct socket *sock, struct sockaddr *addr,
        return sizeof(struct sockaddr_l2);
 }
 
+static int l2cap_get_mode(struct l2cap_chan *chan)
+{
+       switch (chan->mode) {
+       case L2CAP_MODE_BASIC:
+               return BT_MODE_BASIC;
+       case L2CAP_MODE_ERTM:
+               return BT_MODE_ERTM;
+       case L2CAP_MODE_STREAMING:
+               return BT_MODE_STREAMING;
+       case L2CAP_MODE_LE_FLOWCTL:
+               return BT_MODE_LE_FLOWCTL;
+       case L2CAP_MODE_EXT_FLOWCTL:
+               return BT_MODE_EXT_FLOWCTL;
+       }
+
+       return -EINVAL;
+}
+
 static int l2cap_sock_getsockopt_old(struct socket *sock, int optname,
                                     char __user *optval, int __user *optlen)
 {
@@ -424,6 +442,20 @@ static int l2cap_sock_getsockopt_old(struct socket *sock, int optname,
                        break;
                }
 
+               /* Only BR/EDR modes are supported here */
+               switch (chan->mode) {
+               case L2CAP_MODE_BASIC:
+               case L2CAP_MODE_ERTM:
+               case L2CAP_MODE_STREAMING:
+                       break;
+               default:
+                       err = -EINVAL;
+                       break;
+               }
+
+               if (err < 0)
+                       break;
+
                memset(&opts, 0, sizeof(opts));
                opts.imtu     = chan->imtu;
                opts.omtu     = chan->omtu;
@@ -508,7 +540,7 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname,
        struct bt_security sec;
        struct bt_power pwr;
        u32 phys;
-       int len, err = 0;
+       int len, mode, err = 0;
 
        BT_DBG("sk %p", sk);
 
@@ -624,6 +656,27 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname,
                        err = -EFAULT;
                break;
 
+       case BT_MODE:
+               if (!enable_ecred) {
+                       err = -ENOPROTOOPT;
+                       break;
+               }
+
+               if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
+                       err = -EINVAL;
+                       break;
+               }
+
+               mode = l2cap_get_mode(chan);
+               if (mode < 0) {
+                       err = mode;
+                       break;
+               }
+
+               if (put_user(mode, (u8 __user *) optval))
+                       err = -EFAULT;
+               break;
+
        default:
                err = -ENOPROTOOPT;
                break;
@@ -698,10 +751,8 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname,
                        break;
                }
 
-               chan->mode = opts.mode;
-               switch (chan->mode) {
-               case L2CAP_MODE_LE_FLOWCTL:
-                       break;
+               /* Only BR/EDR modes are supported here */
+               switch (opts.mode) {
                case L2CAP_MODE_BASIC:
                        clear_bit(CONF_STATE2_DEVICE, &chan->conf_state);
                        break;
@@ -715,6 +766,11 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname,
                        break;
                }
 
+               if (err < 0)
+                       break;
+
+               chan->mode = opts.mode;
+
                BT_DBG("mode 0x%2.2x", chan->mode);
 
                chan->imtu = opts.imtu;
@@ -763,6 +819,45 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname,
        return err;
 }
 
+static int l2cap_set_mode(struct l2cap_chan *chan, u8 mode)
+{
+       switch (mode) {
+       case BT_MODE_BASIC:
+               if (bdaddr_type_is_le(chan->src_type))
+                       return -EINVAL;
+               mode = L2CAP_MODE_BASIC;
+               clear_bit(CONF_STATE2_DEVICE, &chan->conf_state);
+               break;
+       case BT_MODE_ERTM:
+               if (!disable_ertm || bdaddr_type_is_le(chan->src_type))
+                       return -EINVAL;
+               mode = L2CAP_MODE_ERTM;
+               break;
+       case BT_MODE_STREAMING:
+               if (!disable_ertm || bdaddr_type_is_le(chan->src_type))
+                       return -EINVAL;
+               mode = L2CAP_MODE_STREAMING;
+               break;
+       case BT_MODE_LE_FLOWCTL:
+               if (!bdaddr_type_is_le(chan->src_type))
+                       return -EINVAL;
+               mode = L2CAP_MODE_LE_FLOWCTL;
+               break;
+       case BT_MODE_EXT_FLOWCTL:
+               /* TODO: Add support for ECRED PDUs to BR/EDR */
+               if (!bdaddr_type_is_le(chan->src_type))
+                       return -EINVAL;
+               mode = L2CAP_MODE_EXT_FLOWCTL;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       chan->mode = mode;
+
+       return 0;
+}
+
 static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname,
                                 char __user *optval, unsigned int optlen)
 {
@@ -968,6 +1063,39 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname,
 
                break;
 
+       case BT_MODE:
+               if (!enable_ecred) {
+                       err = -ENOPROTOOPT;
+                       break;
+               }
+
+               BT_DBG("sk->sk_state %u", sk->sk_state);
+
+               if (sk->sk_state != BT_BOUND) {
+                       err = -EINVAL;
+                       break;
+               }
+
+               if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
+                       err = -EINVAL;
+                       break;
+               }
+
+               if (get_user(opt, (u8 __user *) optval)) {
+                       err = -EFAULT;
+                       break;
+               }
+
+               BT_DBG("opt %u", opt);
+
+               err = l2cap_set_mode(chan, opt);
+               if (err)
+                       break;
+
+               BT_DBG("mode 0x%2.2x", chan->mode);
+
+               break;
+
        default:
                err = -ENOPROTOOPT;
                break;
index 6552003..f8c0a4f 100644 (file)
@@ -38,7 +38,7 @@
 #include "mgmt_util.h"
 
 #define MGMT_VERSION   1
-#define MGMT_REVISION  16
+#define MGMT_REVISION  17
 
 static const u16 mgmt_commands[] = {
        MGMT_OP_READ_INDEX_LIST,
@@ -108,6 +108,7 @@ static const u16 mgmt_commands[] = {
        MGMT_OP_SET_APPEARANCE,
        MGMT_OP_SET_BLOCKED_KEYS,
        MGMT_OP_SET_WIDEBAND_SPEECH,
+       MGMT_OP_READ_SECURITY_INFO,
 };
 
 static const u16 mgmt_events[] = {
@@ -155,6 +156,7 @@ static const u16 mgmt_untrusted_commands[] = {
        MGMT_OP_READ_CONFIG_INFO,
        MGMT_OP_READ_EXT_INDEX_LIST,
        MGMT_OP_READ_EXT_INFO,
+       MGMT_OP_READ_SECURITY_INFO,
 };
 
 static const u16 mgmt_untrusted_events[] = {
@@ -3659,6 +3661,55 @@ unlock:
        return err;
 }
 
+static int read_security_info(struct sock *sk, struct hci_dev *hdev,
+                             void *data, u16 data_len)
+{
+       char buf[16];
+       struct mgmt_rp_read_security_info *rp = (void *)buf;
+       u16 sec_len = 0;
+       u8 flags = 0;
+
+       bt_dev_dbg(hdev, "sock %p", sk);
+
+       memset(&buf, 0, sizeof(buf));
+
+       hci_dev_lock(hdev);
+
+       /* When the Read Simple Pairing Options command is supported, then
+        * the remote public key validation is supported.
+        */
+       if (hdev->commands[41] & 0x08)
+               flags |= 0x01;  /* Remote public key validation (BR/EDR) */
+
+       flags |= 0x02;          /* Remote public key validation (LE) */
+
+       /* When the Read Encryption Key Size command is supported, then the
+        * encryption key size is enforced.
+        */
+       if (hdev->commands[20] & 0x10)
+               flags |= 0x04;  /* Encryption key size enforcement (BR/EDR) */
+
+       flags |= 0x08;          /* Encryption key size enforcement (LE) */
+
+       sec_len = eir_append_data(rp->sec, sec_len, 0x01, &flags, 1);
+
+       /* When the Read Simple Pairing Options command is supported, then
+        * also max encryption key size information is provided.
+        */
+       if (hdev->commands[41] & 0x08)
+               sec_len = eir_append_le16(rp->sec, sec_len, 0x02,
+                                         hdev->max_enc_key_size);
+
+       sec_len = eir_append_le16(rp->sec, sec_len, 0x03, SMP_MAX_ENC_KEY_SIZE);
+
+       rp->sec_len = cpu_to_le16(sec_len);
+
+       hci_dev_unlock(hdev);
+
+       return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_SECURITY_INFO, 0,
+                                rp, sizeof(*rp) + sec_len);
+}
+
 static void read_local_oob_data_complete(struct hci_dev *hdev, u8 status,
                                         u16 opcode, struct sk_buff *skb)
 {
@@ -7099,6 +7150,8 @@ static const struct hci_mgmt_handler mgmt_handlers[] = {
        { set_blocked_keys,        MGMT_OP_SET_BLOCKED_KEYS_SIZE,
                                                HCI_MGMT_VAR_LEN },
        { set_wideband_speech,     MGMT_SETTING_SIZE },
+       { read_security_info,      MGMT_READ_SECURITY_INFO_SIZE,
+                                               HCI_MGMT_UNTRUSTED },
 };
 
 void mgmt_index_added(struct hci_dev *hdev)
diff --git a/net/bluetooth/msft.c b/net/bluetooth/msft.c
new file mode 100644 (file)
index 0000000..d6c4e6b
--- /dev/null
@@ -0,0 +1,141 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2020 Google Corporation
+ */
+
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci_core.h>
+
+#include "msft.h"
+
+#define MSFT_OP_READ_SUPPORTED_FEATURES                0x00
+struct msft_cp_read_supported_features {
+       __u8   sub_opcode;
+} __packed;
+struct msft_rp_read_supported_features {
+       __u8   status;
+       __u8   sub_opcode;
+       __le64 features;
+       __u8   evt_prefix_len;
+       __u8   evt_prefix[0];
+} __packed;
+
+struct msft_data {
+       __u64 features;
+       __u8  evt_prefix_len;
+       __u8  *evt_prefix;
+};
+
+static bool read_supported_features(struct hci_dev *hdev,
+                                   struct msft_data *msft)
+{
+       struct msft_cp_read_supported_features cp;
+       struct msft_rp_read_supported_features *rp;
+       struct sk_buff *skb;
+
+       cp.sub_opcode = MSFT_OP_READ_SUPPORTED_FEATURES;
+
+       skb = __hci_cmd_sync(hdev, hdev->msft_opcode, sizeof(cp), &cp,
+                            HCI_CMD_TIMEOUT);
+       if (IS_ERR(skb)) {
+               bt_dev_err(hdev, "Failed to read MSFT supported features (%ld)",
+                          PTR_ERR(skb));
+               return false;
+       }
+
+       if (skb->len < sizeof(*rp)) {
+               bt_dev_err(hdev, "MSFT supported features length mismatch");
+               goto failed;
+       }
+
+       rp = (struct msft_rp_read_supported_features *)skb->data;
+
+       if (rp->sub_opcode != MSFT_OP_READ_SUPPORTED_FEATURES)
+               goto failed;
+
+       if (rp->evt_prefix_len > 0) {
+               msft->evt_prefix = kmemdup(rp->evt_prefix, rp->evt_prefix_len,
+                                          GFP_KERNEL);
+               if (!msft->evt_prefix)
+                       goto failed;
+       }
+
+       msft->evt_prefix_len = rp->evt_prefix_len;
+       msft->features = __le64_to_cpu(rp->features);
+
+       kfree_skb(skb);
+       return true;
+
+failed:
+       kfree_skb(skb);
+       return false;
+}
+
+void msft_do_open(struct hci_dev *hdev)
+{
+       struct msft_data *msft;
+
+       if (hdev->msft_opcode == HCI_OP_NOP)
+               return;
+
+       bt_dev_dbg(hdev, "Initialize MSFT extension");
+
+       msft = kzalloc(sizeof(*msft), GFP_KERNEL);
+       if (!msft)
+               return;
+
+       if (!read_supported_features(hdev, msft)) {
+               kfree(msft);
+               return;
+       }
+
+       hdev->msft_data = msft;
+}
+
+void msft_do_close(struct hci_dev *hdev)
+{
+       struct msft_data *msft = hdev->msft_data;
+
+       if (!msft)
+               return;
+
+       bt_dev_dbg(hdev, "Cleanup of MSFT extension");
+
+       hdev->msft_data = NULL;
+
+       kfree(msft->evt_prefix);
+       kfree(msft);
+}
+
+void msft_vendor_evt(struct hci_dev *hdev, struct sk_buff *skb)
+{
+       struct msft_data *msft = hdev->msft_data;
+       u8 event;
+
+       if (!msft)
+               return;
+
+       /* When the extension has defined an event prefix, check that it
+        * matches, and otherwise just return.
+        */
+       if (msft->evt_prefix_len > 0) {
+               if (skb->len < msft->evt_prefix_len)
+                       return;
+
+               if (memcmp(skb->data, msft->evt_prefix, msft->evt_prefix_len))
+                       return;
+
+               skb_pull(skb, msft->evt_prefix_len);
+       }
+
+       /* Every event starts at least with an event code and the rest of
+        * the data is variable and depends on the event code.
+        */
+       if (skb->len < 1)
+               return;
+
+       event = *skb->data;
+       skb_pull(skb, 1);
+
+       bt_dev_dbg(hdev, "MSFT vendor event %u", event);
+}
diff --git a/net/bluetooth/msft.h b/net/bluetooth/msft.h
new file mode 100644 (file)
index 0000000..5aa9130
--- /dev/null
@@ -0,0 +1,18 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2020 Google Corporation
+ */
+
+#if IS_ENABLED(CONFIG_BT_MSFTEXT)
+
+void msft_do_open(struct hci_dev *hdev);
+void msft_do_close(struct hci_dev *hdev);
+void msft_vendor_evt(struct hci_dev *hdev, struct sk_buff *skb);
+
+#else
+
+static inline void msft_do_open(struct hci_dev *hdev) {}
+static inline void msft_do_close(struct hci_dev *hdev) {}
+static inline void msft_vendor_evt(struct hci_dev *hdev, struct sk_buff *skb) {}
+
+#endif
index 1476a91..df22cbf 100644 (file)
@@ -854,7 +854,7 @@ static int tk_request(struct l2cap_conn *conn, u8 remote_oob, u8 auth,
        struct l2cap_chan *chan = conn->smp;
        struct smp_chan *smp = chan->data;
        u32 passkey = 0;
-       int ret = 0;
+       int ret;
 
        /* Initialize key for JUST WORKS */
        memset(smp->tk, 0, sizeof(smp->tk));
@@ -883,9 +883,16 @@ static int tk_request(struct l2cap_conn *conn, u8 remote_oob, u8 auth,
            hcon->io_capability == HCI_IO_NO_INPUT_OUTPUT)
                smp->method = JUST_WORKS;
 
-       /* If Just Works, Continue with Zero TK */
+       /* If Just Works, Continue with Zero TK and ask user-space for
+        * confirmation */
        if (smp->method == JUST_WORKS) {
-               set_bit(SMP_FLAG_TK_VALID, &smp->flags);
+               ret = mgmt_user_confirm_request(hcon->hdev, &hcon->dst,
+                                               hcon->type,
+                                               hcon->dst_type,
+                                               passkey, 1);
+               if (ret)
+                       return ret;
+               set_bit(SMP_FLAG_WAIT_USER, &smp->flags);
                return 0;
        }
 
@@ -2194,7 +2201,7 @@ mackey_and_ltk:
        if (err)
                return SMP_UNSPECIFIED;
 
-       if (smp->method == JUST_WORKS || smp->method == REQ_OOB) {
+       if (smp->method == REQ_OOB) {
                if (hcon->out) {
                        sc_dhkey_check(smp);
                        SMP_ALLOW_CMD(smp, SMP_CMD_DHKEY_CHECK);
@@ -2209,6 +2216,9 @@ mackey_and_ltk:
        confirm_hint = 0;
 
 confirm:
+       if (smp->method == JUST_WORKS)
+               confirm_hint = 1;
+
        err = mgmt_user_confirm_request(hcon->hdev, &hcon->dst, hcon->type,
                                        hcon->dst_type, passkey, confirm_hint);
        if (err)
@@ -2385,12 +2395,17 @@ int smp_conn_security(struct hci_conn *hcon, __u8 sec_level)
                        authreq |= SMP_AUTH_CT2;
        }
 
-       /* Require MITM if IO Capability allows or the security level
-        * requires it.
+       /* Don't attempt to set MITM if setting is overridden by debugfs
+        * Needed to pass certification test SM/MAS/PKE/BV-01-C
         */
-       if (hcon->io_capability != HCI_IO_NO_INPUT_OUTPUT ||
-           hcon->pending_sec_level > BT_SECURITY_MEDIUM)
-               authreq |= SMP_AUTH_MITM;
+       if (!hci_dev_test_flag(hcon->hdev, HCI_FORCE_NO_MITM)) {
+               /* Require MITM if IO Capability allows or the security level
+                * requires it.
+                */
+               if (hcon->io_capability != HCI_IO_NO_INPUT_OUTPUT ||
+                   hcon->pending_sec_level > BT_SECURITY_MEDIUM)
+                       authreq |= SMP_AUTH_MITM;
+       }
 
        if (hcon->role == HCI_ROLE_MASTER) {
                struct smp_cmd_pairing cp;