From: Al Cooper <[email protected]>

Use the kernel "KEYS" subsystem to get a password for a card based on
the card's CID. This code was based on a patch set submitted by
Anderson Briglia in 2006.

refs #SWLINUX-2545

Signed-off-by: Al Cooper <[email protected]>
---
 drivers/mmc/core/Kconfig |  8 +++++
 drivers/mmc/core/core.c  | 86 ++++++++++++++++++++++++++++++++++++++++++++++++
 drivers/mmc/core/core.h  | 16 ++++++++-
 3 files changed, 109 insertions(+), 1 deletion(-)

diff --git a/drivers/mmc/core/Kconfig b/drivers/mmc/core/Kconfig
index 269d072..b0ba79d 100644
--- a/drivers/mmc/core/Kconfig
+++ b/drivers/mmc/core/Kconfig
@@ -26,3 +26,11 @@ config MMC_CLKGATE
          support handling this in order for it to be of any use.
 
          If unsure, say N.
+
+config MMC_LOCK
+       bool "MMC/SD password based card lock/unlock"
+       select KEYS
+       help
+         This will add the ability to lock/unlock SD and MMC cards.
+
+         If unsure, say N.
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 49a5bca..510927f 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -27,6 +27,7 @@
 #include <linux/fault-inject.h>
 #include <linux/random.h>
 #include <linux/slab.h>
+#include <linux/key-type.h>
 
 #include <linux/mmc/card.h>
 #include <linux/mmc/host.h>
@@ -2705,6 +2706,78 @@ void mmc_init_context_info(struct mmc_host *host)
        init_waitqueue_head(&host->context_info.wait);
 }
 
+#ifdef CONFIG_MMC_LOCK
+
+int mmc_get_password(struct mmc_card *card, struct mmc_password *password)
+{
+       struct key *mmc_key;
+       char key_desc[(sizeof(card->raw_cid) * 2) + 1];
+
+       /* Use the CID to uniquely identify the card */
+       snprintf(key_desc, sizeof(key_desc), "%08x%08x%08x%08x",
+                card->raw_cid[0], card->raw_cid[1],
+                card->raw_cid[2], card->raw_cid[3]);
+
+       mmc_key = request_key(&mmc_key_type, key_desc,
+                             "password");
+       if (IS_ERR(mmc_key)) {
+               dev_warn(&card->dev, "Error, request_key %ld\n",
+                        PTR_ERR(mmc_key));
+               return PTR_ERR(mmc_key);
+       }
+       dev_dbg(&card->dev, "Found matching key\n");
+       memcpy(&password->password, mmc_key->payload.data,
+              mmc_key->datalen);
+       password->length = mmc_key->datalen;
+       key_put(mmc_key);
+
+       return 0;
+}
+
+
+static int mmc_key_instantiate(struct key *key,
+                              struct key_preparsed_payload *prep)
+{
+       char *payload;
+
+       if (prep->datalen <= 0 || prep->datalen > MMC_PASSWORD_MAX ||
+           !prep->data) {
+               pr_warn("Invalid data\n");
+               return  -EINVAL;
+       }
+
+       payload = kmalloc(prep->datalen, GFP_KERNEL);
+       if (!payload)
+               return -ENOMEM;
+       memcpy(payload, prep->data, prep->datalen);
+       key->payload.data = payload;
+       key->datalen = prep->datalen;
+       return 0;
+}
+
+static int mmc_key_match(const struct key *key, const void *description)
+{
+       pr_debug("mmc_key_match: %s, %s\n",
+                key->description, (char *)description);
+       return strcmp(key->description, description) == 0;
+}
+
+/*
+ * dispose of the data dangling from the corpse of a mmc key
+ */
+static void mmc_key_destroy(struct key *key)
+{
+       kfree(key->payload.data);
+}
+
+struct key_type mmc_key_type = {
+       .name           = "mmc",
+       .instantiate    = mmc_key_instantiate,
+       .match          = mmc_key_match,
+       .destroy        = mmc_key_destroy,
+};
+#endif /* CONFIG_MMC_LOCK */
+
 static int __init mmc_init(void)
 {
        int ret;
@@ -2725,8 +2798,18 @@ static int __init mmc_init(void)
        if (ret)
                goto unregister_host_class;
 
+#ifdef CONFIG_MMC_LOCK
+       ret = register_key_type(&mmc_key_type);
+       if (ret)
+               goto unregister_sdio_bus;
+#endif /* CONFIG_MMC_LOCK */
+
        return 0;
 
+#ifdef CONFIG_MMC_LOCK
+unregister_sdio_bus:
+       sdio_unregister_bus();
+#endif /* CONFIG_MMC_LOCK */
 unregister_host_class:
        mmc_unregister_host_class();
 unregister_bus:
@@ -2739,6 +2822,9 @@ destroy_workqueue:
 
 static void __exit mmc_exit(void)
 {
+#ifdef CONFIG_MMC_LOCK
+       unregister_key_type(&mmc_key_type);
+#endif /* CONFIG_MMC_LOCK */
        sdio_unregister_bus();
        mmc_unregister_host_class();
        mmc_unregister_bus();
diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h
index 5345d15..dcf516d 100644
--- a/drivers/mmc/core/core.h
+++ b/drivers/mmc/core/core.h
@@ -81,5 +81,19 @@ void mmc_add_card_debugfs(struct mmc_card *card);
 void mmc_remove_card_debugfs(struct mmc_card *card);
 
 void mmc_init_context_info(struct mmc_host *host);
-#endif
 
+/* Lock/Unlock functionality */
+int mmc_unlock_card(struct mmc_card *card);
+
+#ifdef CONFIG_MMC_LOCK
+#define MMC_PASSWORD_MAX 16
+struct mmc_password {
+       char password[MMC_PASSWORD_MAX];
+       int length;
+};
+extern struct key_type mmc_key_type;
+
+int mmc_get_password(struct mmc_card *card, struct mmc_password *password);
+#endif /* CONFIG_MMC_LOCK */
+
+#endif
-- 
1.8.1.3


--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to