Bluetooth: Reject pairing requests when in non-pairable mode
authorJohan Hedberg <johan.hedberg@nokia.com>
Tue, 4 Jan 2011 13:40:05 +0000 (15:40 +0200)
committerGustavo F. Padovan <padovan@profusion.mobi>
Tue, 8 Feb 2011 03:40:06 +0000 (01:40 -0200)
This patch adds the necessary logic to act accordingly when the
HCI_PAIRABLE flag is not set. In that case PIN code replies as well as
Secure Simple Pairing requests without a NoBonding requirement need to
be rejected.

Signed-off-by: Johan Hedberg <johan.hedberg@nokia.com>
Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi>
include/net/bluetooth/hci.h
include/net/bluetooth/hci_core.h
net/bluetooth/hci_event.c

index f0c25b5..65cab13 100644 (file)
@@ -384,6 +384,12 @@ struct hci_cp_reject_sync_conn_req {
        __u8     reason;
 } __packed;
 
+#define HCI_OP_IO_CAPABILITY_NEG_REPLY 0x0434
+struct hci_cp_io_capability_neg_reply {
+       bdaddr_t bdaddr;
+       __u8     reason;
+} __packed;
+
 #define HCI_OP_SNIFF_MODE              0x0803
 struct hci_cp_sniff_mode {
        __le16   handle;
@@ -840,6 +846,14 @@ struct hci_ev_io_capa_request {
        bdaddr_t bdaddr;
 } __packed;
 
+#define HCI_EV_IO_CAPA_REPLY           0x32
+struct hci_ev_io_capa_reply {
+       bdaddr_t bdaddr;
+       __u8     capability;
+       __u8     oob_data;
+       __u8     authentication;
+} __packed;
+
 #define HCI_EV_SIMPLE_PAIR_COMPLETE    0x36
 struct hci_ev_simple_pair_complete {
        __u8     status;
index 8ee0b8b..dc8084a 100644 (file)
@@ -201,6 +201,10 @@ struct hci_conn {
        __u16            disc_timeout;
        unsigned long    pend;
 
+       __u8            remote_cap;
+       __u8            remote_oob;
+       __u8            remote_auth;
+
        unsigned int     sent;
 
        struct sk_buff_head data_q;
index a8a38f1..cf3014a 100644 (file)
@@ -1595,6 +1595,10 @@ static inline void hci_pin_code_request_evt(struct hci_dev *hdev, struct sk_buff
                hci_conn_put(conn);
        }
 
+       if (!test_bit(HCI_PAIRABLE, &hdev->flags))
+               hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
+                                       sizeof(ev->bdaddr), &ev->bdaddr);
+
        hci_dev_unlock(hdev);
 }
 
@@ -1885,9 +1889,52 @@ static inline void hci_io_capa_request_evt(struct hci_dev *hdev, struct sk_buff
        hci_dev_lock(hdev);
 
        conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
-       if (conn)
-               hci_conn_hold(conn);
+       if (!conn)
+               goto unlock;
+
+       hci_conn_hold(conn);
+
+       if (!test_bit(HCI_MGMT, &hdev->flags))
+               goto unlock;
+
+       if (test_bit(HCI_PAIRABLE, &hdev->flags) ||
+                       (conn->remote_auth & ~0x01) == HCI_AT_NO_BONDING) {
+               /* FIXME: Do IO capa response based on information
+                * provided through the management interface */
+       } else {
+               struct hci_cp_io_capability_neg_reply cp;
+
+               bacpy(&cp.bdaddr, &ev->bdaddr);
+               cp.reason = 0x16; /* Pairing not allowed */
 
+               hci_send_cmd(hdev, HCI_OP_IO_CAPABILITY_NEG_REPLY,
+                                                       sizeof(cp), &cp);
+       }
+
+unlock:
+       hci_dev_unlock(hdev);
+}
+
+static inline void hci_io_capa_reply_evt(struct hci_dev *hdev, struct sk_buff *skb)
+{
+       struct hci_ev_io_capa_reply *ev = (void *) skb->data;
+       struct hci_conn *conn;
+
+       BT_DBG("%s", hdev->name);
+
+       hci_dev_lock(hdev);
+
+       conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
+       if (!conn)
+               goto unlock;
+
+       hci_conn_hold(conn);
+
+       conn->remote_cap = ev->capability;
+       conn->remote_oob = ev->oob_data;
+       conn->remote_auth = ev->authentication;
+
+unlock:
        hci_dev_unlock(hdev);
 }
 
@@ -2051,6 +2098,10 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
                hci_io_capa_request_evt(hdev, skb);
                break;
 
+       case HCI_EV_IO_CAPA_REPLY:
+               hci_io_capa_reply_evt(hdev, skb);
+               break;
+
        case HCI_EV_SIMPLE_PAIR_COMPLETE:
                hci_simple_pair_complete_evt(hdev, skb);
                break;