Bluetooth: Add debugfs support for max LE encryption key size
authorJohan Hedberg <johan.hedberg@intel.com>
Thu, 11 Jun 2015 10:52:26 +0000 (13:52 +0300)
committerMarcel Holtmann <marcel@holtmann.org>
Fri, 12 Jun 2015 09:38:45 +0000 (11:38 +0200)
This patch adds a debugfs control to set a different maximum LE
encryption key size. This is useful for testing that implementation of
the encryption key size handling is behaving correctly.

Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
net/bluetooth/smp.c

index 4bfaa3d3ed289c338766dd34df8561521c0200d6..d0220fb76dc02305b9c9b968289f9e19843a7ca8 100644 (file)
@@ -33,6 +33,9 @@
 #include "ecc.h"
 #include "smp.h"
 
+#define SMP_DEV(hdev) \
+       ((struct smp_dev *)((struct l2cap_chan *)((hdev)->smp_data))->data)
+
 /* Low-level debug macros to be used for stuff that we don't want
  * accidentially in dmesg, i.e. the values of the various crypto keys
  * and the inputs & outputs of crypto functions.
@@ -81,6 +84,8 @@ struct smp_dev {
        u8                      local_rand[16];
        bool                    debug_key;
 
+       u8                      max_key_size;
+
        struct crypto_blkcipher *tfm_aes;
        struct crypto_hash      *tfm_cmac;
 };
@@ -708,7 +713,7 @@ static void build_pairing_cmd(struct l2cap_conn *conn,
        if (rsp == NULL) {
                req->io_capability = conn->hcon->io_capability;
                req->oob_flag = oob_flag;
-               req->max_key_size = SMP_MAX_ENC_KEY_SIZE;
+               req->max_key_size = SMP_DEV(hdev)->max_key_size;
                req->init_key_dist = local_dist;
                req->resp_key_dist = remote_dist;
                req->auth_req = (authreq & AUTH_REQ_MASK(hdev));
@@ -719,7 +724,7 @@ static void build_pairing_cmd(struct l2cap_conn *conn,
 
        rsp->io_capability = conn->hcon->io_capability;
        rsp->oob_flag = oob_flag;
-       rsp->max_key_size = SMP_MAX_ENC_KEY_SIZE;
+       rsp->max_key_size = SMP_DEV(hdev)->max_key_size;
        rsp->init_key_dist = req->init_key_dist & remote_dist;
        rsp->resp_key_dist = req->resp_key_dist & local_dist;
        rsp->auth_req = (authreq & AUTH_REQ_MASK(hdev));
@@ -730,10 +735,11 @@ static void build_pairing_cmd(struct l2cap_conn *conn,
 static u8 check_enc_key_size(struct l2cap_conn *conn, __u8 max_key_size)
 {
        struct l2cap_chan *chan = conn->smp;
+       struct hci_dev *hdev = conn->hcon->hdev;
        struct smp_chan *smp = chan->data;
 
-       if ((max_key_size > SMP_MAX_ENC_KEY_SIZE) ||
-           (max_key_size < SMP_MIN_ENC_KEY_SIZE))
+       if (max_key_size > SMP_DEV(hdev)->max_key_size ||
+           max_key_size < SMP_MIN_ENC_KEY_SIZE)
                return SMP_ENC_KEY_SIZE;
 
        smp->enc_key_size = max_key_size;
@@ -3130,6 +3136,7 @@ static struct l2cap_chan *smp_add_cid(struct hci_dev *hdev, u16 cid)
 
        smp->tfm_aes = tfm_aes;
        smp->tfm_cmac = tfm_cmac;
+       smp->max_key_size = SMP_MAX_ENC_KEY_SIZE;
 
 create_chan:
        chan = l2cap_chan_create();
@@ -3252,6 +3259,49 @@ static const struct file_operations force_bredr_smp_fops = {
        .llseek         = default_llseek,
 };
 
+static ssize_t le_max_key_size_read(struct file *file,
+                                    char __user *user_buf,
+                                    size_t count, loff_t *ppos)
+{
+       struct hci_dev *hdev = file->private_data;
+       char buf[4];
+
+       snprintf(buf, sizeof(buf), "%2u\n", SMP_DEV(hdev)->max_key_size);
+
+       return simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf));
+}
+
+static ssize_t le_max_key_size_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));
+       u8 key_size;
+
+       if (copy_from_user(buf, user_buf, buf_size))
+               return -EFAULT;
+
+       buf[buf_size] = '\0';
+
+       sscanf(buf, "%hhu", &key_size);
+
+       if (key_size > SMP_MAX_ENC_KEY_SIZE || key_size < SMP_MIN_ENC_KEY_SIZE)
+               return -EINVAL;
+
+       SMP_DEV(hdev)->max_key_size = key_size;
+
+       return count;
+}
+
+static const struct file_operations le_max_key_size_fops = {
+       .open           = simple_open,
+       .read           = le_max_key_size_read,
+       .write          = le_max_key_size_write,
+       .llseek         = default_llseek,
+};
+
 int smp_register(struct hci_dev *hdev)
 {
        struct l2cap_chan *chan;
@@ -3276,6 +3326,9 @@ int smp_register(struct hci_dev *hdev)
 
        hdev->smp_data = chan;
 
+       debugfs_create_file("le_max_key_size", 0644, hdev->debugfs, hdev,
+                           &le_max_key_size_fops);
+
        /* If the controller does not support BR/EDR Secure Connections
         * feature, then the BR/EDR SMP channel shall not be present.
         *