Add commands for locking and unlocking SD cards by password. This is to be used
in conjunction with a kernel that enumerates locked sd cards and provides an 
ioctl
for rereading the card after unlocking.
 
Signed-off-by: Peter Turczak <pe...@turczak.de>
---
mmc.c      |   24 +++++++++-
mmc.h      |   12 +++++
mmc_cmds.c |  152 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
mmc_cmds.h |    4 ++
4 files changed, 189 insertions(+), 3 deletions(-)

diff --git a/mmc.c b/mmc.c
index 725b842..2f797ea 100644
--- a/mmc.c
+++ b/mmc.c
@@ -36,9 +36,9 @@ struct Command {
                                   if >= 0, number of arguments,
                                   if < 0, _minimum_ number of arguments */
        char    *verb;          /* verb */
-       char    *help;          /* help lines; from the 2nd line onward they 
+       char    *help;          /* help lines; from the 2nd line onward they
                                   are automatically indented */
-        char    *adv_help;      /* advanced help message; from the 2nd line 
+       char    *adv_help;      /* advanced help message; from the 2nd line
                                   onward they are automatically indented */

        /* the following fields are run-time filled by the program */
@@ -100,6 +100,26 @@ static struct Command commands[] = {
                "Permanently disable the eMMC H/W Reset feature on 
<device>.\nNOTE!  This is a one-time programmable (unreversible) change.",
          NULL
        },
+       { do_sd_password_set, -1,
+         "password set", "<password> <device>\n"
+               "Set password for unlocking the SD card, no not lock until next 
power up.",
+         NULL
+       },
+       { do_sd_password_lock, -1,
+         "password lock", "<password> <device>\n"
+               "Set password for unlocking the SD card, and lock now.",
+         NULL
+       },
+       { do_sd_password_unlock, -1,
+         "password unlock", "<password> <device>\n"
+               "Unlock the SD card until next power cycling.",
+         NULL
+       },
+       { do_sd_password_delete, -1,
+         "password delete", "<password> <device>\n"
+               "Remove set password from SD.",
+         NULL
+       },
        { do_sanitize, -1,
          "sanitize", "<device>\n"
                "Send Sanitize command to the <device>.\nThis will delete the 
unmapped memory region of the device.",
diff --git a/mmc.h b/mmc.h
index ad07b44..c578ba0 100644
--- a/mmc.h
+++ b/mmc.h
@@ -24,11 +24,15 @@
#define MMC_BLOCK_MAJOR                 179

/* From kernel linux/mmc/mmc.h */
+#define MMC_GO_IDLE_STATE      0   /* bc                          */
+#define MMC_SWITCH_MODE_WRITE_BYTE     0x03    /* Set target to value */
#define MMC_SWITCH              6       /* ac   [31:0] See below        R1b */
#define MMC_SEND_EXT_CSD        8       /* adtc                         R1  */
#define MMC_SEND_STATUS         13      /* ac   [31:16] RCA        R1  */
#define R1_SWITCH_ERROR   (1 << 7)  /* sx, c */
#define MMC_SWITCH_MODE_WRITE_BYTE      0x03    /* Set target to value */
+#define MMC_LOCK_UNLOCK                42   /* adtc                    R1b */
+#define MMC_SET_BLOCKLEN       16   /* ac   [31:0] block len   R1  */

/*
 * EXT_CSD fields
@@ -112,6 +116,9 @@

#define MMC_CMD_AC      (0 << 5)
#define MMC_CMD_ADTC    (1 << 5)
+#define MMC_CMD_BC      (2 << 5)
+#define MMC_CMD_BCR     (3 << 5)
+

#define MMC_RSP_SPI_S1  (1 << 7)                /* one status byte */
#define MMC_RSP_SPI_BUSY (1 << 10)              /* card may send busy */
@@ -121,3 +128,8 @@

#define MMC_RSP_R1      (MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE)
#define MMC_RSP_R1B     
(MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE|MMC_RSP_BUSY)
+
+#define MMC_LOCK_UNLOCK_ARG_ERASE      (1 << 3)
+#define MMC_LOCK_UNLOCK_ARG_LOCK       (1 << 2)
+#define MMC_LOCK_UNLOCK_ARG_CLR                (1 << 1)
+#define MMC_LOCK_UNLOCK_ARG_SET                (1 << 0)
diff --git a/mmc_cmds.c b/mmc_cmds.c
index ba4f9cf..f455860 100644
--- a/mmc_cmds.c
+++ b/mmc_cmds.c
@@ -26,6 +26,7 @@
#include <libgen.h>
#include <limits.h>
#include <ctype.h>
+#include <assert.h>

#include "mmc.h"
#include "mmc_cmds.h"
@@ -72,6 +73,38 @@ int write_extcsd_value(int fd, __u8 index, __u8 value)
        return ret;
}

+int get_rca(int fd)
+{
+char orig_filename[1024];
+char temp[1024];
+char *base;
+char *pos;
+
+       memset(orig_filename, 0, sizeof(orig_filename));
+       memset(temp, 0, sizeof(temp));
+
+       /* Get the block device name of the mmcblock device from the
+        * file descriptor
+        */
+       snprintf(temp, sizeof(temp)-1, "/proc/self/fd/%d", fd);
+       if (readlink(temp, orig_filename, sizeof(orig_filename)-1) < 0)
+               return -1;
+
+       /* Fetch the bus device from sysfs */
+       base = basename(orig_filename);
+       snprintf(temp, sizeof(temp)-1, "/sys/class/block/%s/device", base);
+       if (readlink(temp, orig_filename, sizeof(orig_filename)) < 0)
+               return -1;
+
+       /* Extract number from given path, assumed to be something
+        * like /sys/bus/mmc/mmc0:e624 , where e624 specifies the RCA
+        * value
+        */
+       assert(pos = strrchr(orig_filename, ':'));
+       pos++;
+       return strtol(pos, NULL, 16);
+}
+
int send_status(int fd, __u32 *response)
{
        int ret = 0;
@@ -79,7 +112,7 @@ int send_status(int fd, __u32 *response)

        memset(&idata, 0, sizeof(idata));
        idata.opcode = MMC_SEND_STATUS;
-       idata.arg = (1 << 16);
+       idata.arg = (get_rca(fd) << 16);
        idata.flags = MMC_RSP_R1 | MMC_CMD_AC;

        ret = ioctl(fd, MMC_IOC_CMD, &idata);
@@ -1032,6 +1065,123 @@ out_free:
        return ret;
}

+int sd_password_command(int fd, int arg, char *pass)
+{
+       int ret = 0;
+       int len;
+       int blocklen;
+       struct mmc_ioc_cmd idata;
+       __u8 data[512];
+       __u32 status;
+
+       /* Send password request */
+       memset(&data, 0, sizeof(data));
+       len = strlen(pass);
+       if (len > 16)
+               len = 16;
+       data[0] = arg;
+       data[1] = len;
+       memcpy(&data[2], pass, len);
+
+       /* Set block length */
+       blocklen = 18;
+
+       memset(&idata, 0, sizeof(idata));
+       idata.write_flag = 0;
+       idata.opcode = MMC_SET_BLOCKLEN;
+       idata.flags =  MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_BCR;
+       idata.arg = blocklen;
+       idata.blksz = 0;
+       idata.blocks = 0;
+       idata.cmd_timeout_ms = 500;
+
+       ret = ioctl(fd, MMC_IOC_CMD, &idata);
+       if (ret) {
+               perror("ioctl");
+               return ret;
+               }
+
+       memset(&idata, 0, sizeof(idata));
+       idata.write_flag = 1;
+       idata.opcode = MMC_LOCK_UNLOCK;
+       idata.flags =  MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
+       idata.arg = 0;
+       idata.blocks = 1;
+       idata.blksz = blocklen;
+       idata.cmd_timeout_ms = 500;
+       idata.data_ptr = (__u32)data;
+       ret = ioctl(fd, MMC_IOC_CMD, &idata);
+       if (ret) {
+               perror("ioctl");
+               return ret;
+               }
+
+       ret = send_status(fd, &status);
+       if (ret)
+               return ret;
+       /* Mask out status bits and return them.
+        * BIT24: CARD_IS_LOCKED
+        * BIT25: LOCK_UNLOCK_FAILED
+        */
+       if (ret & (1 << 24))
+               return ret >> 24;
+
+       printf("Unlocking succeeded!\n");
+
+       if (arg == 0) {
+               ret = ioctl(fd, MMC_IOC_RESCAN, NULL);
+               if (ret) {
+                       perror("ioctl");
+                       return ret;
+                       }
+       }
+       return ret;
+}
+
+int do_sd_password(int mmc_cmd, int nargs, char **argv)
+{
+       int fd;
+       char *device;
+       char *pass;
+       int ret;
+
+       CHECK(nargs != 3,
+               "Usage: mmc password set|lock|unlock|delete"
+                         " password </path/to/mmcblkX>\n", exit(1));
+
+       pass = argv[1];
+       device = argv[2];
+
+       fd = open(device, O_RDWR);
+       if (fd < 0) {
+               perror("open");
+               exit(1);
+       }
+
+       ret = (sd_password_command(fd, mmc_cmd, pass));
+       return ret;
+}
+
+int do_sd_password_set(int nargs, char **argv)
+{
+       return do_sd_password(MMC_LOCK_UNLOCK_ARG_SET, nargs, argv);
+}
+
+int do_sd_password_lock(int nargs, char **argv)
+{
+       return do_sd_password(MMC_LOCK_UNLOCK_ARG_LOCK, nargs, argv);
+}
+
+int do_sd_password_unlock(int nargs, char **argv)
+{
+       return do_sd_password(0, nargs, argv);
+}
+
+int do_sd_password_delete(int nargs, char **argv)
+{
+       return do_sd_password(MMC_LOCK_UNLOCK_ARG_CLR, nargs, argv);
+}
+
int do_sanitize(int nargs, char **argv)
{
        int fd, ret;
diff --git a/mmc_cmds.h b/mmc_cmds.h
index fa347f5..adff8b9 100644
--- a/mmc_cmds.h
+++ b/mmc_cmds.h
@@ -24,6 +24,10 @@ int do_write_boot_en(int nargs, char **argv);
int do_write_bkops_en(int nargs, char **argv);
int do_hwreset_en(int nargs, char **argv);
int do_hwreset_dis(int nargs, char **argv);
+int do_sd_password_delete(int nargs, char **argv);
+int do_sd_password_lock(int nargs, char **argv);
+int do_sd_password_set(int nargs, char **argv);
+int do_sd_password_unlock(int nargs, char **argv);
int do_sanitize(int nargs, char **argv);
int do_status_get(int nargs, char **argv);
int do_enh_area_set(int nargs, char **argv);
-- 
1.7.0.4

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

Reply via email to