17a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev/*
27a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev * Copyright (C) 2016 The Android Open Source Project
37a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev *
47a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev * Licensed under the Apache License, Version 2.0 (the "License");
57a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev * you may not use this file except in compliance with the License.
67a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev * You may obtain a copy of the License at
77a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev *
87a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev *      http://www.apache.org/licenses/LICENSE-2.0
97a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev *
107a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev * Unless required by applicable law or agreed to in writing, software
117a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev * distributed under the License is distributed on an "AS IS" BASIS,
127a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
137a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev * See the License for the specific language governing permissions and
147a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev * limitations under the License.
157a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev */
167a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev
177a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev#include <errno.h>
187a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev#include <fcntl.h>
197a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev#include <stdint.h>
207a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev#include <stdio.h>
217a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev#include <stdlib.h>
227a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev#include <string.h>
237a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev#include <sys/ioctl.h>
24cfd5b080af8de527d768f0ff7902c26af8d49307Mark Salyzyn#include <unistd.h>
257a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev
267a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev#include <linux/major.h>
277a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev#include <linux/mmc/ioctl.h>
287a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev
297a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev#include "ipc.h"
307a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev#include "log.h"
317a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev#include "rpmb.h"
327a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev#include "storage.h"
337a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev
347a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev#define MMC_READ_MULTIPLE_BLOCK 18
357a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev#define MMC_WRITE_MULTIPLE_BLOCK 25
367a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev#define MMC_RELIABLE_WRITE_FLAG (1 << 31)
377a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev
387a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev#define MMC_RSP_PRESENT (1 << 0)
397a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev#define MMC_RSP_CRC (1 << 2)
407a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev#define MMC_RSP_OPCODE (1 << 4)
417a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev#define MMC_CMD_ADTC (1 << 5)
427a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev#define MMC_RSP_SPI_S1 (1 << 7)
437a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev#define MMC_RSP_R1 (MMC_RSP_PRESENT | MMC_RSP_CRC | MMC_RSP_OPCODE)
447a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev#define MMC_RSP_SPI_R1 (MMC_RSP_SPI_S1)
457a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev
467a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev#define MMC_WRITE_FLAG_R 0
477a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev#define MMC_WRITE_FLAG_W 1
487a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev#define MMC_WRITE_FLAG_RELW (MMC_WRITE_FLAG_W | MMC_RELIABLE_WRITE_FLAG)
497a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev
507a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev#define MMC_BLOCK_SIZE 512
517a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev
527a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleevstatic int rpmb_fd = -1;
537a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleevstatic uint8_t read_buf[4096];
547a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev
557a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev#ifdef RPMB_DEBUG
567a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev
577a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleevstatic void print_buf(const char *prefix, const uint8_t *buf, size_t size)
587a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev{
597a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev    size_t i;
607a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev
617a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev    printf("%s @%p [%zu]", prefix, buf, size);
627a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev    for (i = 0; i < size; i++) {
637a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev        if (i && i % 32 == 0)
647a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev            printf("\n%*s", (int) strlen(prefix), "");
657a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev        printf(" %02x", buf[i]);
667a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev    }
677a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev    printf("\n");
687a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev    fflush(stdout);
697a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev}
707a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev
717a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev#endif
727a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev
737a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev
747a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleevint rpmb_send(struct storage_msg *msg, const void *r, size_t req_len)
757a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev{
767a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev    int rc;
777a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev    struct {
787a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev        struct mmc_ioc_multi_cmd multi;
797a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev        struct mmc_ioc_cmd cmd_buf[3];
807a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev    } mmc = {};
817a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev    struct mmc_ioc_cmd *cmd = mmc.multi.cmds;
827a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev    const struct storage_rpmb_send_req *req = r;
837a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev
847a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev    if (req_len < sizeof(*req)) {
857a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev        ALOGW("malformed rpmb request: invalid length (%zu < %zu)\n",
867a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev              req_len, sizeof(*req));
877a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev        msg->result = STORAGE_ERR_NOT_VALID;
887a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev        goto err_response;
897a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev    }
907a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev
917a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev    size_t expected_len =
927a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev            sizeof(*req) + req->reliable_write_size + req->write_size;
937a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev    if (req_len != expected_len) {
947a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev        ALOGW("malformed rpmb request: invalid length (%zu != %zu)\n",
957a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev              req_len, expected_len);
967a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev        msg->result = STORAGE_ERR_NOT_VALID;
977a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev        goto err_response;
987a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev    }
997a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev
1007a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev    const uint8_t *write_buf = req->payload;
1017a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev    if (req->reliable_write_size) {
1027a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev        if ((req->reliable_write_size % MMC_BLOCK_SIZE) != 0) {
1037a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev            ALOGW("invalid reliable write size %u\n", req->reliable_write_size);
1047a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev            msg->result = STORAGE_ERR_NOT_VALID;
1057a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev            goto err_response;
1067a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev        }
1077a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev
1087a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev        cmd->write_flag = MMC_WRITE_FLAG_RELW;
1097a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev        cmd->opcode = MMC_WRITE_MULTIPLE_BLOCK;
1107a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev        cmd->flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
1117a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev        cmd->blksz = MMC_BLOCK_SIZE;
1127a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev        cmd->blocks = req->reliable_write_size / MMC_BLOCK_SIZE;
1137a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev        mmc_ioc_cmd_set_data((*cmd), write_buf);
1147a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev#ifdef RPMB_DEBUG
1157a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev        ALOGI("opcode: 0x%x, write_flag: 0x%x\n", cmd->opcode, cmd->write_flag);
1167a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev        print_buf("request: ", write_buf, req->reliable_write_size);
1177a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev#endif
1187a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev        write_buf += req->reliable_write_size;
1197a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev        mmc.multi.num_of_cmds++;
1207a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev        cmd++;
1217a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev    }
1227a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev
1237a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev    if (req->write_size) {
1247a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev        if ((req->write_size % MMC_BLOCK_SIZE) != 0) {
1257a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev            ALOGW("invalid write size %u\n", req->write_size);
1267a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev            msg->result = STORAGE_ERR_NOT_VALID;
1277a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev            goto err_response;
1287a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev        }
1297a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev
1307a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev        cmd->write_flag = MMC_WRITE_FLAG_W;
1317a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev        cmd->opcode = MMC_WRITE_MULTIPLE_BLOCK;
1327a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev        cmd->flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
1337a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev        cmd->blksz = MMC_BLOCK_SIZE;
1347a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev        cmd->blocks = req->write_size / MMC_BLOCK_SIZE;
1357a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev        mmc_ioc_cmd_set_data((*cmd), write_buf);
1367a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev#ifdef RPMB_DEBUG
1377a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev        ALOGI("opcode: 0x%x, write_flag: 0x%x\n", cmd->opcode, cmd->write_flag);
1387a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev        print_buf("request: ", write_buf, req->write_size);
1397a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev#endif
1407a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev        write_buf += req->write_size;
1417a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev        mmc.multi.num_of_cmds++;
1427a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev        cmd++;
1437a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev    }
1447a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev
1457a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev    if (req->read_size) {
1467a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev        if (req->read_size % MMC_BLOCK_SIZE != 0 ||
1477a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev            req->read_size > sizeof(read_buf)) {
1487a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev            ALOGE("%s: invalid read size %u\n", __func__, req->read_size);
1497a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev            msg->result = STORAGE_ERR_NOT_VALID;
1507a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev            goto err_response;
1517a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev        }
1527a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev
1537a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev        cmd->write_flag = MMC_WRITE_FLAG_R;
1547a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev        cmd->opcode = MMC_READ_MULTIPLE_BLOCK;
1557a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev        cmd->flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC,
1567a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev        cmd->blksz = MMC_BLOCK_SIZE;
1577a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev        cmd->blocks = req->read_size / MMC_BLOCK_SIZE;
1587a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev        mmc_ioc_cmd_set_data((*cmd), read_buf);
1597a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev#ifdef RPMB_DEBUG
1607a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev        ALOGI("opcode: 0x%x, write_flag: 0x%x\n", cmd->opcode, cmd->write_flag);
1617a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev#endif
1627a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev        mmc.multi.num_of_cmds++;
1637a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev        cmd++;
1647a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev    }
1657a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev
1667a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev    rc = ioctl(rpmb_fd, MMC_IOC_MULTI_CMD, &mmc.multi);
1677a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev    if (rc < 0) {
1687a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev        ALOGE("%s: mmc ioctl failed: %d, %s\n", __func__, rc, strerror(errno));
1697a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev        msg->result = STORAGE_ERR_GENERIC;
1707a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev        goto err_response;
1717a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev    }
1727a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev#ifdef RPMB_DEBUG
1737a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev    if (req->read_size)
1747a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev        print_buf("response: ", read_buf, req->read_size);
1757a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev#endif
1767a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev
1777a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev    if (msg->flags & STORAGE_MSG_FLAG_POST_COMMIT) {
1787a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev        /*
1797a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev         * Nothing todo for post msg commit request as MMC_IOC_MULTI_CMD
1807a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev         * is fully synchronous in this implementation.
1817a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev         */
1827a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev    }
1837a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev
1847a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev    msg->result = STORAGE_NO_ERROR;
1857a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev    return ipc_respond(msg, read_buf, req->read_size);
1867a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev
1877a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleeverr_response:
1887a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev    return ipc_respond(msg, NULL, 0);
1897a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev}
1907a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev
1917a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev
1927a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleevint rpmb_open(const char *rpmb_devname)
1937a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev{
1947a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev    int rc;
1957a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev
1967a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev    rc = open(rpmb_devname, O_RDWR, 0);
1977a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev    if (rc < 0) {
1987a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev        ALOGE("unable (%d) to open rpmb device '%s': %s\n",
1997a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev              errno, rpmb_devname, strerror(errno));
2007a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev        return rc;
2017a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev    }
2027a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev    rpmb_fd = rc;
2037a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev    return 0;
2047a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev}
2057a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev
2067a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleevvoid rpmb_close(void)
2077a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev{
2087a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev    close(rpmb_fd);
2097a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev    rpmb_fd = -1;
2107a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev}
2117a2bc37af59a0d9a931347316ac5c86435a1dccbMichael Ryleev
212