Home | History | Annotate | Download | only in proxy
      1 /*
      2  * Copyright (C) 2016 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include <errno.h>
     18 #include <fcntl.h>
     19 #include <stdint.h>
     20 #include <stdio.h>
     21 #include <stdlib.h>
     22 #include <string.h>
     23 #include <sys/ioctl.h>
     24 #include <unistd.h>
     25 
     26 #include <linux/major.h>
     27 #include <linux/mmc/ioctl.h>
     28 
     29 #include "ipc.h"
     30 #include "log.h"
     31 #include "rpmb.h"
     32 #include "storage.h"
     33 
     34 #define MMC_READ_MULTIPLE_BLOCK 18
     35 #define MMC_WRITE_MULTIPLE_BLOCK 25
     36 #define MMC_RELIABLE_WRITE_FLAG (1 << 31)
     37 
     38 #define MMC_RSP_PRESENT (1 << 0)
     39 #define MMC_RSP_CRC (1 << 2)
     40 #define MMC_RSP_OPCODE (1 << 4)
     41 #define MMC_CMD_ADTC (1 << 5)
     42 #define MMC_RSP_SPI_S1 (1 << 7)
     43 #define MMC_RSP_R1 (MMC_RSP_PRESENT | MMC_RSP_CRC | MMC_RSP_OPCODE)
     44 #define MMC_RSP_SPI_R1 (MMC_RSP_SPI_S1)
     45 
     46 #define MMC_WRITE_FLAG_R 0
     47 #define MMC_WRITE_FLAG_W 1
     48 #define MMC_WRITE_FLAG_RELW (MMC_WRITE_FLAG_W | MMC_RELIABLE_WRITE_FLAG)
     49 
     50 #define MMC_BLOCK_SIZE 512
     51 
     52 static int rpmb_fd = -1;
     53 static uint8_t read_buf[4096];
     54 
     55 #ifdef RPMB_DEBUG
     56 
     57 static void print_buf(const char *prefix, const uint8_t *buf, size_t size)
     58 {
     59     size_t i;
     60 
     61     printf("%s @%p [%zu]", prefix, buf, size);
     62     for (i = 0; i < size; i++) {
     63         if (i && i % 32 == 0)
     64             printf("\n%*s", (int) strlen(prefix), "");
     65         printf(" %02x", buf[i]);
     66     }
     67     printf("\n");
     68     fflush(stdout);
     69 }
     70 
     71 #endif
     72 
     73 
     74 int rpmb_send(struct storage_msg *msg, const void *r, size_t req_len)
     75 {
     76     int rc;
     77     struct {
     78         struct mmc_ioc_multi_cmd multi;
     79         struct mmc_ioc_cmd cmd_buf[3];
     80     } mmc = {};
     81     struct mmc_ioc_cmd *cmd = mmc.multi.cmds;
     82     const struct storage_rpmb_send_req *req = r;
     83 
     84     if (req_len < sizeof(*req)) {
     85         ALOGW("malformed rpmb request: invalid length (%zu < %zu)\n",
     86               req_len, sizeof(*req));
     87         msg->result = STORAGE_ERR_NOT_VALID;
     88         goto err_response;
     89     }
     90 
     91     size_t expected_len =
     92             sizeof(*req) + req->reliable_write_size + req->write_size;
     93     if (req_len != expected_len) {
     94         ALOGW("malformed rpmb request: invalid length (%zu != %zu)\n",
     95               req_len, expected_len);
     96         msg->result = STORAGE_ERR_NOT_VALID;
     97         goto err_response;
     98     }
     99 
    100     const uint8_t *write_buf = req->payload;
    101     if (req->reliable_write_size) {
    102         if ((req->reliable_write_size % MMC_BLOCK_SIZE) != 0) {
    103             ALOGW("invalid reliable write size %u\n", req->reliable_write_size);
    104             msg->result = STORAGE_ERR_NOT_VALID;
    105             goto err_response;
    106         }
    107 
    108         cmd->write_flag = MMC_WRITE_FLAG_RELW;
    109         cmd->opcode = MMC_WRITE_MULTIPLE_BLOCK;
    110         cmd->flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
    111         cmd->blksz = MMC_BLOCK_SIZE;
    112         cmd->blocks = req->reliable_write_size / MMC_BLOCK_SIZE;
    113         mmc_ioc_cmd_set_data((*cmd), write_buf);
    114 #ifdef RPMB_DEBUG
    115         ALOGI("opcode: 0x%x, write_flag: 0x%x\n", cmd->opcode, cmd->write_flag);
    116         print_buf("request: ", write_buf, req->reliable_write_size);
    117 #endif
    118         write_buf += req->reliable_write_size;
    119         mmc.multi.num_of_cmds++;
    120         cmd++;
    121     }
    122 
    123     if (req->write_size) {
    124         if ((req->write_size % MMC_BLOCK_SIZE) != 0) {
    125             ALOGW("invalid write size %u\n", req->write_size);
    126             msg->result = STORAGE_ERR_NOT_VALID;
    127             goto err_response;
    128         }
    129 
    130         cmd->write_flag = MMC_WRITE_FLAG_W;
    131         cmd->opcode = MMC_WRITE_MULTIPLE_BLOCK;
    132         cmd->flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
    133         cmd->blksz = MMC_BLOCK_SIZE;
    134         cmd->blocks = req->write_size / MMC_BLOCK_SIZE;
    135         mmc_ioc_cmd_set_data((*cmd), write_buf);
    136 #ifdef RPMB_DEBUG
    137         ALOGI("opcode: 0x%x, write_flag: 0x%x\n", cmd->opcode, cmd->write_flag);
    138         print_buf("request: ", write_buf, req->write_size);
    139 #endif
    140         write_buf += req->write_size;
    141         mmc.multi.num_of_cmds++;
    142         cmd++;
    143     }
    144 
    145     if (req->read_size) {
    146         if (req->read_size % MMC_BLOCK_SIZE != 0 ||
    147             req->read_size > sizeof(read_buf)) {
    148             ALOGE("%s: invalid read size %u\n", __func__, req->read_size);
    149             msg->result = STORAGE_ERR_NOT_VALID;
    150             goto err_response;
    151         }
    152 
    153         cmd->write_flag = MMC_WRITE_FLAG_R;
    154         cmd->opcode = MMC_READ_MULTIPLE_BLOCK;
    155         cmd->flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC,
    156         cmd->blksz = MMC_BLOCK_SIZE;
    157         cmd->blocks = req->read_size / MMC_BLOCK_SIZE;
    158         mmc_ioc_cmd_set_data((*cmd), read_buf);
    159 #ifdef RPMB_DEBUG
    160         ALOGI("opcode: 0x%x, write_flag: 0x%x\n", cmd->opcode, cmd->write_flag);
    161 #endif
    162         mmc.multi.num_of_cmds++;
    163         cmd++;
    164     }
    165 
    166     rc = ioctl(rpmb_fd, MMC_IOC_MULTI_CMD, &mmc.multi);
    167     if (rc < 0) {
    168         ALOGE("%s: mmc ioctl failed: %d, %s\n", __func__, rc, strerror(errno));
    169         msg->result = STORAGE_ERR_GENERIC;
    170         goto err_response;
    171     }
    172 #ifdef RPMB_DEBUG
    173     if (req->read_size)
    174         print_buf("response: ", read_buf, req->read_size);
    175 #endif
    176 
    177     if (msg->flags & STORAGE_MSG_FLAG_POST_COMMIT) {
    178         /*
    179          * Nothing todo for post msg commit request as MMC_IOC_MULTI_CMD
    180          * is fully synchronous in this implementation.
    181          */
    182     }
    183 
    184     msg->result = STORAGE_NO_ERROR;
    185     return ipc_respond(msg, read_buf, req->read_size);
    186 
    187 err_response:
    188     return ipc_respond(msg, NULL, 0);
    189 }
    190 
    191 
    192 int rpmb_open(const char *rpmb_devname)
    193 {
    194     int rc;
    195 
    196     rc = open(rpmb_devname, O_RDWR, 0);
    197     if (rc < 0) {
    198         ALOGE("unable (%d) to open rpmb device '%s': %s\n",
    199               errno, rpmb_devname, strerror(errno));
    200         return rc;
    201     }
    202     rpmb_fd = rc;
    203     return 0;
    204 }
    205 
    206 void rpmb_close(void)
    207 {
    208     close(rpmb_fd);
    209     rpmb_fd = -1;
    210 }
    211 
    212