]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - net/bluetooth/hci_request.c
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next
[karo-tx-linux.git] / net / bluetooth / hci_request.c
index b7369220c9efff616d13f3ad3aeec44c809bd4e0..981f8a202c27d2298a8a9459fa2a671cb3b3197a 100644 (file)
@@ -56,8 +56,8 @@ static int req_run(struct hci_request *req, hci_req_complete_t complete,
                return -ENODATA;
 
        skb = skb_peek_tail(&req->cmd_q);
-       bt_cb(skb)->req.complete = complete;
-       bt_cb(skb)->req.complete_skb = complete_skb;
+       bt_cb(skb)->hci.req_complete = complete;
+       bt_cb(skb)->hci.req_complete_skb = complete_skb;
 
        spin_lock_irqsave(&hdev->cmd_q.lock, flags);
        skb_queue_splice_tail(&req->cmd_q, &hdev->cmd_q);
@@ -99,7 +99,7 @@ struct sk_buff *hci_prepare_cmd(struct hci_dev *hdev, u16 opcode, u32 plen,
        BT_DBG("skb len %d", skb->len);
 
        bt_cb(skb)->pkt_type = HCI_COMMAND_PKT;
-       bt_cb(skb)->opcode = opcode;
+       bt_cb(skb)->hci.opcode = opcode;
 
        return skb;
 }
@@ -128,9 +128,9 @@ void hci_req_add_ev(struct hci_request *req, u16 opcode, u32 plen,
        }
 
        if (skb_queue_empty(&req->cmd_q))
-               bt_cb(skb)->req.start = true;
+               bt_cb(skb)->hci.req_start = true;
 
-       bt_cb(skb)->req.event = event;
+       bt_cb(skb)->hci.req_event = event;
 
        skb_queue_tail(&req->cmd_q, skb);
 }
@@ -564,3 +564,96 @@ void hci_update_background_scan(struct hci_dev *hdev)
        if (err && err != -ENODATA)
                BT_ERR("Failed to run HCI request: err %d", err);
 }
+
+void __hci_abort_conn(struct hci_request *req, struct hci_conn *conn,
+                     u8 reason)
+{
+       switch (conn->state) {
+       case BT_CONNECTED:
+       case BT_CONFIG:
+               if (conn->type == AMP_LINK) {
+                       struct hci_cp_disconn_phy_link cp;
+
+                       cp.phy_handle = HCI_PHY_HANDLE(conn->handle);
+                       cp.reason = reason;
+                       hci_req_add(req, HCI_OP_DISCONN_PHY_LINK, sizeof(cp),
+                                   &cp);
+               } else {
+                       struct hci_cp_disconnect dc;
+
+                       dc.handle = cpu_to_le16(conn->handle);
+                       dc.reason = reason;
+                       hci_req_add(req, HCI_OP_DISCONNECT, sizeof(dc), &dc);
+               }
+
+               conn->state = BT_DISCONN;
+
+               break;
+       case BT_CONNECT:
+               if (conn->type == LE_LINK) {
+                       if (test_bit(HCI_CONN_SCANNING, &conn->flags))
+                               break;
+                       hci_req_add(req, HCI_OP_LE_CREATE_CONN_CANCEL,
+                                   0, NULL);
+               } else if (conn->type == ACL_LINK) {
+                       if (req->hdev->hci_ver < BLUETOOTH_VER_1_2)
+                               break;
+                       hci_req_add(req, HCI_OP_CREATE_CONN_CANCEL,
+                                   6, &conn->dst);
+               }
+               break;
+       case BT_CONNECT2:
+               if (conn->type == ACL_LINK) {
+                       struct hci_cp_reject_conn_req rej;
+
+                       bacpy(&rej.bdaddr, &conn->dst);
+                       rej.reason = reason;
+
+                       hci_req_add(req, HCI_OP_REJECT_CONN_REQ,
+                                   sizeof(rej), &rej);
+               } else if (conn->type == SCO_LINK || conn->type == ESCO_LINK) {
+                       struct hci_cp_reject_sync_conn_req rej;
+
+                       bacpy(&rej.bdaddr, &conn->dst);
+
+                       /* SCO rejection has its own limited set of
+                        * allowed error values (0x0D-0x0F) which isn't
+                        * compatible with most values passed to this
+                        * function. To be safe hard-code one of the
+                        * values that's suitable for SCO.
+                        */
+                       rej.reason = HCI_ERROR_REMOTE_LOW_RESOURCES;
+
+                       hci_req_add(req, HCI_OP_REJECT_SYNC_CONN_REQ,
+                                   sizeof(rej), &rej);
+               }
+               break;
+       default:
+               conn->state = BT_CLOSED;
+               break;
+       }
+}
+
+static void abort_conn_complete(struct hci_dev *hdev, u8 status, u16 opcode)
+{
+       if (status)
+               BT_DBG("Failed to abort connection: status 0x%2.2x", status);
+}
+
+int hci_abort_conn(struct hci_conn *conn, u8 reason)
+{
+       struct hci_request req;
+       int err;
+
+       hci_req_init(&req, conn->hdev);
+
+       __hci_abort_conn(&req, conn, reason);
+
+       err = hci_req_run(&req, abort_conn_complete);
+       if (err && err != -ENODATA) {
+               BT_ERR("Failed to run HCI request: err %d", err);
+               return err;
+       }
+
+       return 0;
+}