u16 opcode)
 {
        struct mgmt_pending_cmd *cmd;
+       struct mgmt_cp_add_advertising *cp;
        struct mgmt_rp_add_advertising rp;
+       struct adv_info *adv_instance, *n;
+       u8 instance;
 
        BT_DBG("status %d", status);
 
 
        cmd = pending_find(MGMT_OP_ADD_ADVERTISING, hdev);
 
-       if (status) {
+       if (status)
                hci_dev_clear_flag(hdev, HCI_ADVERTISING_INSTANCE);
-               memset(&hdev->adv_instance, 0, sizeof(hdev->adv_instance));
-               advertising_removed(cmd ? cmd->sk : NULL, hdev, 1);
+
+       list_for_each_entry_safe(adv_instance, n, &hdev->adv_instances, list) {
+               if (!adv_instance->pending)
+                       continue;
+
+               if (!status) {
+                       adv_instance->pending = false;
+                       continue;
+               }
+
+               instance = adv_instance->instance;
+
+               if (hdev->cur_adv_instance == instance)
+                       cancel_adv_timeout(hdev);
+
+               hci_remove_adv_instance(hdev, instance);
+               advertising_removed(cmd ? cmd->sk : NULL, hdev, instance);
        }
 
        if (!cmd)
                goto unlock;
 
-       rp.instance = 0x01;
+       cp = cmd->param;
+       rp.instance = cp->instance;
 
        if (status)
                mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode,
        u32 flags;
        u32 supported_flags;
        u8 status;
-       u16 timeout;
+       u16 timeout, duration;
+       unsigned int prev_instance_cnt = hdev->adv_instance_cnt;
+       u8 schedule_instance = 0;
+       struct adv_info *next_instance;
        int err;
        struct mgmt_pending_cmd *cmd;
        struct hci_request req;
 
        flags = __le32_to_cpu(cp->flags);
        timeout = __le16_to_cpu(cp->timeout);
+       duration = __le16_to_cpu(cp->duration);
 
-       /* The current implementation only supports adding one instance and only
-        * a subset of the specified flags.
+       /* The current implementation only supports a subset of the specified
+        * flags.
         */
        supported_flags = get_supported_adv_flags(hdev);
-       if (cp->instance != 0x01 || (flags & ~supported_flags))
+       if (flags & ~supported_flags)
                return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
                                       MGMT_STATUS_INVALID_PARAMS);
 
                goto unlock;
        }
 
-       hdev->adv_instance.flags = flags;
-       hdev->adv_instance.adv_data_len = cp->adv_data_len;
-       hdev->adv_instance.scan_rsp_len = cp->scan_rsp_len;
-
-       if (cp->adv_data_len)
-               memcpy(hdev->adv_instance.adv_data, cp->data, cp->adv_data_len);
-
-       if (cp->scan_rsp_len)
-               memcpy(hdev->adv_instance.scan_rsp_data,
-                      cp->data + cp->adv_data_len, cp->scan_rsp_len);
+       err = hci_add_adv_instance(hdev, cp->instance, flags,
+                                  cp->adv_data_len, cp->data,
+                                  cp->scan_rsp_len,
+                                  cp->data + cp->adv_data_len,
+                                  timeout, duration);
+       if (err < 0) {
+               err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
+                                     MGMT_STATUS_FAILED);
+               goto unlock;
+       }
 
-       if (hdev->adv_instance_timeout)
-               cancel_delayed_work(&hdev->adv_instance_expire);
+       /* Only trigger an advertising added event if a new instance was
+        * actually added.
+        */
+       if (hdev->adv_instance_cnt > prev_instance_cnt)
+               advertising_added(sk, hdev, cp->instance);
 
-       hdev->adv_instance_timeout = timeout;
+       hci_dev_set_flag(hdev, HCI_ADVERTISING_INSTANCE);
 
-       if (timeout)
-               queue_delayed_work(hdev->workqueue,
-                                  &hdev->adv_instance_expire,
-                                  msecs_to_jiffies(timeout * 1000));
+       if (hdev->cur_adv_instance == cp->instance) {
+               /* If the currently advertised instance is being changed then
+                * cancel the current advertising and schedule the next
+                * instance. If there is only one instance then the overridden
+                * advertising data will be visible right away.
+                */
+               cancel_adv_timeout(hdev);
 
-       if (!hci_dev_test_and_set_flag(hdev, HCI_ADVERTISING_INSTANCE))
-               advertising_added(sk, hdev, 1);
+               next_instance = hci_get_next_instance(hdev, cp->instance);
+               if (next_instance)
+                       schedule_instance = next_instance->instance;
+       } else if (!hdev->adv_instance_timeout) {
+               /* Immediately advertise the new instance if no other
+                * instance is currently being advertised.
+                */
+               schedule_instance = cp->instance;
+       }
 
-       /* If the HCI_ADVERTISING flag is set or the device isn't powered then
-        * we have no HCI communication to make. Simply return.
+       /* If the HCI_ADVERTISING flag is set or the device isn't powered or
+        * there is no instance to be advertised then we have no HCI
+        * communication to make. Simply return.
         */
        if (!hdev_is_powered(hdev) ||
-           hci_dev_test_flag(hdev, HCI_ADVERTISING)) {
-               rp.instance = 0x01;
+           hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
+           !schedule_instance) {
+               rp.instance = cp->instance;
                err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
                                        MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
                goto unlock;
 
        hci_req_init(&req, hdev);
 
-       update_adv_data(&req);
-       update_scan_rsp_data(&req);
-       enable_advertising(&req);
+       err = schedule_adv_instance(&req, schedule_instance, true);
+
+       if (!err)
+               err = hci_req_run(&req, add_advertising_complete);
 
-       err = hci_req_run(&req, add_advertising_complete);
        if (err < 0)
                mgmt_pending_remove(cmd);